diff --git a/src/gpu/gpu.h b/src/gpu/gpu.h index b8803f3..fe85b2d 100644 --- a/src/gpu/gpu.h +++ b/src/gpu/gpu.h @@ -305,6 +305,13 @@ typedef struct GpuImageCreateRequest { GpuImageSubresourceRange subresource; } GpuImageCreateRequest; +typedef struct GpuCommandPool GpuCommandPool; + +typedef struct GpuLoadImageFromFileRequest { + GpuCommandPool *command_pool; + WpStr8RO filename; +} GpuLoadImageFromFileRequest; + typedef enum GpuBufferUsage { GPU_BUFFER_USAGE_TRANSFER_SRC = wpU32Const(1) << 0, GPU_BUFFER_USAGE_TRANSFER_DST = wpU32Const(1) << 1, @@ -403,8 +410,6 @@ typedef struct GpuSwapchainsPresentResult { GpuSwapchainPresentErrorArray errors; } GpuSwapchainsPresentResult; -typedef struct GpuCommandPool GpuCommandPool; - typedef struct GpuCommandBuffer GpuCommandBuffer; typedef GpuCommandBuffer **GpuCommandBufferPtrArray; @@ -1095,14 +1100,30 @@ typedef struct GpuCmdPushConstantsRequest { u32 total_size_in_bytes; } GpuCmdPushConstantsRequest; -typedef struct GpuCmdDrawIndexedRequest { +typedef struct GpuImageSubresourceLayers { + GpuImageAspect aspect_mask; + u32 mip_level; + u32 base_array_layer; + u32 layer_count; +} GpuImageSubresourceLayers; + +typedef struct GpuImageBlit { + GpuOffset3d src_offsets[2]; + GpuOffset3d dst_offsets[2]; + GpuImageSubresourceLayers src_subresource; + GpuImageSubresourceLayers dst_subresource; +} GpuImageBlit; +typedef GpuImageBlit *GpuImageBlitArray; + +typedef struct GpuCmdBlitImageRequest { GpuCommandBuffer *command_buffer; - u32 index_count; - u32 instance_count; - u32 first_index; - i32 vertex_offset; - u32 first_instance; -} GpuCmdDrawIndexedRequest; + GpuImage *src_image; + GpuImage *dst_image; + GpuImageBlitArray regions; + GpuImageLayout src_image_layout; + GpuImageLayout dst_image_layout; + GpuFilter filter; +} GpuCmdBlitImageRequest; typedef struct GpuCmdDrawRequest { GpuCommandBuffer *command_buffer; @@ -1112,6 +1133,15 @@ typedef struct GpuCmdDrawRequest { u32 first_instance; } GpuCmdDrawRequest; +typedef struct GpuCmdDrawIndexedRequest { + GpuCommandBuffer *command_buffer; + u32 index_count; + u32 instance_count; + u32 first_index; + i32 vertex_offset; + u32 first_instance; +} GpuCmdDrawIndexedRequest; + typedef struct GpuCmdDispatchRequest { GpuCommandBuffer *command_buffer; u32 group_count_x; @@ -1157,7 +1187,9 @@ GpuSampler *gpuCreateSampler(const WpAllocator *allocator, Gp void gpuDestroySampler(GpuSampler *sampler); GpuImage *gpuCreateImage(const WpAllocator *allocator, GpuImageCreateRequest request); void gpuDestroyImage(GpuImage *image); -ivec3s gpuImageGetSize(GpuImage *image); +GpuImage *gpuLoadImageFromFile(const WpAllocator *allocator, const WpAllocator *temp, + GpuLoadImageFromFileRequest request); +ivec3s gpuGetImageSize(GpuImage *image); GpuBuffer gpuCreateBuffer(const WpAllocator *allocator, GpuBufferCreateRequest request); void gpuDestroyBuffer(GpuBuffer *buffer); GpuFence *gpuCreateFence(const WpAllocator *allocator, GpuDevice *device); @@ -1207,6 +1239,7 @@ void gpuCmdBindDescriptorSets(const WpAllocator *temp, void gpuCmdBindVertexBuffers(const WpAllocator *temp, GpuCmdBindVertexBuffersRequest request); void gpuCmdBindIndexBuffer(GpuCmdBindIndexBufferRequest request); void gpuCmdPushConstants(GpuCmdPushConstantsRequest request); +void gpuCmdBlitImage(const WpAllocator *temp, GpuCmdBlitImageRequest request); void gpuCmdDraw(GpuCmdDrawRequest request); void gpuCmdDrawIndexed(GpuCmdDrawIndexedRequest request); void gpuCmdDispatch(GpuCmdDispatchRequest request); diff --git a/src/gpu/vulkan/vk_gpu.c b/src/gpu/vulkan/vk_gpu.c index 40c0664..958270d 100644 --- a/src/gpu/vulkan/vk_gpu.c +++ b/src/gpu/vulkan/vk_gpu.c @@ -7,6 +7,9 @@ #include "../../window/window_inc.h" #include "../../wapp/wapp.h" #include "../../cglm/struct.h" +#include +#define STB_IMAGE_IMPLEMENTATION +#include "../../stb_image/stb_image.h" #include #ifdef USE_SDL_WINDOW_BACKEND @@ -73,6 +76,7 @@ typedef VkImageMemoryBarrier2 *VkImageMemoryBarrier typedef VkRenderingAttachmentInfo *VkRenderingAttachmentInfoArray; typedef VkSemaphoreSubmitInfo *VkSemaphoreSubmitInfoArray; typedef VkCommandBufferSubmitInfo *VkCommandBufferSubmitInfoArray; +typedef VkImageBlit2 *VkImageBlit2Array; struct GpuInstance { VkInstance vk_instance; @@ -486,9 +490,25 @@ GpuDevice *gpuCreateDevice(const WpAllocator *allocator, GpuPhysicalDevice physi 0, &device->vk_queue); VmaVulkanFunctions vk_functions = { - .vkGetInstanceProcAddr = vkGetInstanceProcAddr, - .vkGetDeviceProcAddr = vkGetDeviceProcAddr, - .vkCreateImage = vkCreateImage, + vkGetInstanceProcAddr = vkGetInstanceProcAddr, + vkGetDeviceProcAddr = vkGetDeviceProcAddr, + vkGetPhysicalDeviceProperties = vkGetPhysicalDeviceProperties, + vkGetPhysicalDeviceMemoryProperties = vkGetPhysicalDeviceMemoryProperties, + vkAllocateMemory = vkAllocateMemory, + vkFreeMemory = vkFreeMemory, + vkMapMemory = vkMapMemory, + vkUnmapMemory = vkUnmapMemory, + vkFlushMappedMemoryRanges = vkFlushMappedMemoryRanges, + vkInvalidateMappedMemoryRanges = vkInvalidateMappedMemoryRanges, + vkBindBufferMemory = vkBindBufferMemory, + vkBindImageMemory = vkBindImageMemory, + vkGetBufferMemoryRequirements = vkGetBufferMemoryRequirements, + vkGetImageMemoryRequirements = vkGetImageMemoryRequirements, + vkCreateBuffer = vkCreateBuffer, + vkDestroyBuffer = vkDestroyBuffer, + vkCreateImage = vkCreateImage, + vkDestroyImage = vkDestroyImage, + vkCmdCopyBuffer = vkCmdCopyBuffer, }; VmaAllocatorCreateInfo allocator_create_info = { @@ -875,7 +895,7 @@ GpuImage *gpuCreateImage(const WpAllocator *allocator, GpuImageCreateRequest req vk_result = vmaCreateImage(request.device->allocator, &image_create_info, &alloc_create_info, &output->vk_image, &output->allocation, NULL); - assertWithLogger(vk_result == VK_SUCCESS, &logger, "Failed to create depth image"); + assertWithLogger(vk_result == VK_SUCCESS, &logger, "Failed to create image"); VkImageViewCreateInfo view_create_info = { .sType = VK_STRUCTURE_TYPE_IMAGE_VIEW_CREATE_INFO, @@ -888,10 +908,11 @@ GpuImage *gpuCreateImage(const WpAllocator *allocator, GpuImageCreateRequest req }; vk_result = vkCreateImageView(request.device->vk_device, &view_create_info, NULL, &output->vk_view); - assertWithLogger(vk_result == VK_SUCCESS, &logger, "Failed to create depth image view"); + assertWithLogger(vk_result == VK_SUCCESS, &logger, "Failed to create image view"); output->size = request.size; output->format = format; + output->device = request.device; wpLogDebug(&logger, wpStr8Lit("Created Vulkan image")); @@ -903,7 +924,42 @@ void gpuDestroyImage(GpuImage *image) { vmaDestroyImage(image->device->allocator, image->vk_image, image->allocation); } -ivec3s gpuImageGetSize(GpuImage *image) { +GpuImage *gpuLoadImageFromFile(const WpAllocator *allocator, const WpAllocator *temp, + GpuLoadImageFromFileRequest request) { + char *buf = wpMemAllocatorAlloc(temp, request.filename.size + 1); + assertWithLogger(buf != NULL, &logger, "Failed to allocate temp filename buffer"); + + wpStr8CopyToCstr(buf, &request.filename, request.filename.size + 1); + + i32 width, height, channels; + const u8 *data = stbi_load(buf, &width, &height, &channels, 4); + assertWithLogger(data != NULL, &logger, "Failed to load image data"); + + GpuImageCreateRequest img_request = { + .device = request.command_pool->device, + .size = { .x = width, .y = height, .z = 1 }, + .type = GPU_IMAGE_TYPE_2D, + .format = GPU_FORMAT_R8G8B8A8_SRGB, + .samples = GPU_SAMPLE_COUNT_1, + .tiling = GPU_IMAGE_TILING_OPTIMAL, + .usage = GPU_IMAGE_USAGE_SAMPLED | GPU_IMAGE_USAGE_TRANSFER_SRC | GPU_IMAGE_USAGE_TRANSFER_DST, + .layout = GPU_IMAGE_LAYOUT_UNDEFINED, + .subresource = { + .aspect = GPU_IMAGE_ASPECT_COLOR, + .base_mip_level = 0, + .level_count = 1, + .base_array_layer = 0, + .layer_count = 1, + }, + }; + GpuImage *output = gpuCreateImage(allocator, img_request); + + stbi_image_free((void *)data); + + return output; +} + +ivec3s gpuGetImageSize(GpuImage *image) { return image->size; } @@ -2031,6 +2087,66 @@ void gpuCmdPushConstants(GpuCmdPushConstantsRequest request) { request.total_size_in_bytes, request.values); } +void gpuCmdBlitImage(const WpAllocator *temp, GpuCmdBlitImageRequest request) { + u64 region_count = wpArrayCount(request.regions); + VkImageBlit2Array regions = wpArrayAllocCapacity(VkImageBlit2, temp, region_count, WP_ARRAY_INIT_FILLED); + assertWithLogger(regions != NULL, &logger, "Failed to allocate temp blit regions array"); + + for (u64 i = 0; i < region_count; ++i) { + regions[i] = (VkImageBlit2){ + .sType = VK_STRUCTURE_TYPE_IMAGE_BLIT_2, + .srcSubresource = { + .aspectMask = vkImageAspectFromGpuImageAspect(request.regions[i].src_subresource.aspect_mask), + .mipLevel = request.regions[i].src_subresource.mip_level, + .baseArrayLayer = request.regions[i].src_subresource.base_array_layer, + .layerCount = request.regions[i].src_subresource.layer_count, + }, + .srcOffsets = { + [0] = { + .x = request.regions[i].src_offsets[0].x, + .y = request.regions[i].src_offsets[0].y, + .z = request.regions[i].src_offsets[0].z, + }, + [1] = { + .x = request.regions[i].src_offsets[1].x, + .y = request.regions[i].src_offsets[1].y, + .z = request.regions[i].src_offsets[1].z, + }, + }, + .dstSubresource = { + .aspectMask = vkImageAspectFromGpuImageAspect(request.regions[i].dst_subresource.aspect_mask), + .mipLevel = request.regions[i].dst_subresource.mip_level, + .baseArrayLayer = request.regions[i].dst_subresource.base_array_layer, + .layerCount = request.regions[i].dst_subresource.layer_count, + }, + .dstOffsets = { + [0] = { + .x = request.regions[i].dst_offsets[0].x, + .y = request.regions[i].dst_offsets[0].y, + .z = request.regions[i].dst_offsets[0].z, + }, + [1] = { + .x = request.regions[i].dst_offsets[1].x, + .y = request.regions[i].dst_offsets[1].y, + .z = request.regions[i].dst_offsets[1].z, + }, + }, + }; + } + + VkBlitImageInfo2 info = { + .sType = VK_STRUCTURE_TYPE_BLIT_IMAGE_INFO_2, + .srcImage = request.src_image->vk_image, + .srcImageLayout = vkImageLayoutFromGpuImageLayout(request.src_image_layout), + .dstImage = request.dst_image->vk_image, + .dstImageLayout = vkImageLayoutFromGpuImageLayout(request.dst_image_layout), + .regionCount = region_count, + .pRegions = regions, + .filter = vkFilterFromGpuFilter(request.filter), + }; + vkCmdBlitImage2(request.command_buffer->vk_buffer, &info); +} + void gpuCmdDraw(GpuCmdDrawRequest request) { vkCmdDraw(request.command_buffer->vk_buffer, request.vertex_count, request.instance_count, request.first_vertex, request.first_instance); diff --git a/src/main.c b/src/main.c index ac97d40..857679b 100644 --- a/src/main.c +++ b/src/main.c @@ -160,6 +160,12 @@ i32 main(void) { wpFileRead(code, spirv, code_size); + GpuLoadImageFromFileRequest load_img_req = { + .command_pool = pool, + .filename = wpStr8LitRo("/home/abdelrahman/Pictures/800px-Trumpets02262006.jpg"), + }; + GpuImage *texture = gpuLoadImageFromFile(&arena, &temp_arena, load_img_req); + GpuShaderCreateRequest shader_request = { .device = device, .code = (void *)code, @@ -517,6 +523,7 @@ i32 main(void) { gpuDestroyPipelineLayout(layout); gpuDestroyBuffer(&shader_data); gpuDestroyShader(shader); + gpuDestroyImage(texture); gpuDestroyCommandPool(pool); gpuDestroyBuffer(&vertex_buffer); gpuDestroySwapchain(swapchain);