diff --git a/src/gpu/gpu.h b/src/gpu/gpu.h index 52e4d1a..34051b1 100644 --- a/src/gpu/gpu.h +++ b/src/gpu/gpu.h @@ -1166,12 +1166,21 @@ typedef struct GpuCmdDispatchBaseRequest { u32 group_count_z; } GpuCmdDispatchBaseRequest; -typedef struct GpuQueueSubmitRequest { - GpuSemaphorePtrArray wait_semaphores; - GpuPipelineStageFlagsArray wait_dst_stage_masks; - GpuCommandBufferPtrArray command_buffers; - GpuSemaphorePtrArray signal_semaphores; -} GpuQueueSubmitRequest; +typedef struct GpuBufferImageCopy { + GpuImageSubresourceLayers image_subresource; + GpuOffset3d image_offset; + GpuExtent3d image_extent; + u64 buffer_offset; +} GpuBufferImageCopy; +typedef GpuBufferImageCopy *GpuBufferImageCopyArray; + +typedef struct GpuCmdCopyBufferToImageRequest { + GpuCommandBuffer *command_buffer; + GpuBuffer *src_buffer; + GpuImage *dst_image; + GpuImageLayout dst_image_layout; + GpuBufferImageCopyArray copy_regions; +} GpuCmdCopyBufferToImageRequest; GpuInstance *gpuInit(const WpAllocator *allocator, GpuInitRequest request); GpuPhysicalDevice gpuFindPhysicalDevice(const WpAllocator *allocator, const WpAllocator *temp, @@ -1252,6 +1261,7 @@ void gpuCmdDraw(GpuCmdDrawRequest request); void gpuCmdDrawIndexed(GpuCmdDrawIndexedRequest request); void gpuCmdDispatch(GpuCmdDispatchRequest request); void gpuCmdDispatchBase(GpuCmdDispatchBaseRequest request); +void gpuCmdCopyBufferToImage(const WpAllocator *temp, GpuCmdCopyBufferToImageRequest request); #ifdef WP_PLATFORM_CPP END_C_LINKAGE diff --git a/src/gpu/vulkan/vk_gpu.c b/src/gpu/vulkan/vk_gpu.c index 730aa45..b40a9fe 100644 --- a/src/gpu/vulkan/vk_gpu.c +++ b/src/gpu/vulkan/vk_gpu.c @@ -77,6 +77,7 @@ typedef VkRenderingAttachmentInfo *VkRenderingAttachmen typedef VkSemaphoreSubmitInfo *VkSemaphoreSubmitInfoArray; typedef VkCommandBufferSubmitInfo *VkCommandBufferSubmitInfoArray; typedef VkImageBlit2 *VkImageBlit2Array; +typedef VkBufferImageCopy *VkBufferImageCopyArray; struct GpuInstance { VkInstance vk_instance; @@ -890,8 +891,24 @@ GpuImage *gpuCreateImage(const WpAllocator *allocator, GpuImageCreateRequest req .initialLayout = vkImageLayoutFromGpuImageLayout(request.layout), }; + // Check if the image requires a dedicated allocation + VkMemoryDedicatedRequirements dedicated_memory_reqs = { + .sType = VK_STRUCTURE_TYPE_MEMORY_DEDICATED_REQUIREMENTS, + }; + VkMemoryRequirements2 memory_reqs = { + .sType = VK_STRUCTURE_TYPE_MEMORY_REQUIREMENTS_2, + .pNext = &dedicated_memory_reqs, + }; + VkDeviceImageMemoryRequirements image_memory_reqs = { + .sType = VK_STRUCTURE_TYPE_DEVICE_IMAGE_MEMORY_REQUIREMENTS, + .pCreateInfo = &image_create_info, + }; + vkGetDeviceImageMemoryRequirements(request.device->vk_device, &image_memory_reqs, &memory_reqs); + + b8 requires_dedicated_memory = dedicated_memory_reqs.requiresDedicatedAllocation || + dedicated_memory_reqs.prefersDedicatedAllocation; VmaAllocationCreateInfo alloc_create_info = { - .flags = VMA_ALLOCATION_CREATE_DEDICATED_MEMORY_BIT, + .flags = requires_dedicated_memory ? VMA_ALLOCATION_CREATE_DEDICATED_MEMORY_BIT : 0, .usage = VMA_MEMORY_USAGE_AUTO, }; @@ -934,11 +951,14 @@ GpuImage *gpuLoadImageFromFile(const WpAllocator *allocator, const WpAllocator * wpStr8CopyToCstr(buf, &request.filename, request.filename.size + 1); i32 width, height, channels; - const u8 *data = stbi_load(buf, &width, &height, &channels, 4); + i32 requested_channels = 4; + const u8 *data = stbi_load(buf, &width, &height, &channels, requested_channels); assertWithLogger(data != NULL, &logger, "Failed to load image data"); + GpuDevice *device = request.command_pool->device; + GpuImageCreateRequest img_request = { - .device = request.command_pool->device, + .device = device, .size = { .x = width, .y = height, .z = 1 }, .type = GPU_IMAGE_TYPE_2D, .format = GPU_FORMAT_R8G8B8A8_SRGB, @@ -956,14 +976,15 @@ GpuImage *gpuLoadImageFromFile(const WpAllocator *allocator, const WpAllocator * }; GpuImage *output = gpuCreateImage(allocator, img_request); - u64 data_size = width * height * channels * sizeof(u8); + u64 data_size = width * height * requested_channels * sizeof(u8); GpuBufferCreateRequest temp_buf_request = { - .device = request.command_pool->device, + .device = device, .size = data_size, .usage = GPU_BUFFER_USAGE_TRANSFER_SRC, }; GpuBuffer temp_storage = gpuCreateBuffer(allocator, temp_buf_request); memcpy(temp_storage.cpu_mapping, data, data_size); + gpuFlushBuffer((GpuBufferFlushRequest){ .device = device, .buffer = temp_storage }); stbi_image_free((void *)data); @@ -974,6 +995,95 @@ GpuImage *gpuLoadImageFromFile(const WpAllocator *allocator, const WpAllocator * GpuCommandBufferPtrArray cbs = gpuAllocateCommandBuffers(allocator, temp, cb_request); GpuCommandBuffer *cb = cbs[0]; + gpuBeginCommandBuffer((GpuCommandBufferBeginRequest){ .command_buffer = cb, .one_time_submit = true }); + + GpuImageMemoryBarrier image_barrier = { + .image = output, + .src_stage_mask = GPU_PIPELINE_STAGE_NONE, + .src_access_mask = GPU_ACCESS_NONE, + .dst_stage_mask = GPU_PIPELINE_STAGE_TRANSFER, + .dst_access_mask = GPU_ACCESS_TRANSFER_WRITE, + .old_layout = GPU_IMAGE_LAYOUT_UNDEFINED, + .new_layout = GPU_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, + .subresource = { + .aspect = GPU_IMAGE_ASPECT_COLOR, + .level_count = 1, + .layer_count = 1, + } + }; + + GpuCmdPipelineBarrierRequest barrier_req = { + .command_buffer = cb, + .info = (GpuDependencyInfo){ + .image_memory_barriers = wpArray(GpuImageMemoryBarrier, image_barrier), + }, + }; + gpuCmdPipelineBarrier(temp, barrier_req); + + GpuCmdCopyBufferToImageRequest copy_req = { + .command_buffer = cb, + .src_buffer = &temp_storage, + .dst_image = output, + .dst_image_layout = GPU_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, + .copy_regions = wpArray( + GpuBufferImageCopy, + (GpuBufferImageCopy){ + .image_subresource = { .layer_count = 1, .aspect_mask = GPU_IMAGE_ASPECT_COLOR }, + .image_extent = { .width = width, .height = height, .depth = 1 }, + } + ), + }; + gpuCmdCopyBufferToImage(temp, copy_req); + + image_barrier = (GpuImageMemoryBarrier){ + .image = output, + .src_stage_mask = GPU_PIPELINE_STAGE_TRANSFER, + .src_access_mask = GPU_ACCESS_TRANSFER_WRITE, + .dst_stage_mask = GPU_PIPELINE_STAGE_FRAGMENT_SHADER, + .dst_access_mask = GPU_ACCESS_SHADER_READ, + .old_layout = GPU_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, + .new_layout = GPU_IMAGE_LAYOUT_READ_ONLY_OPTIMAL, + .subresource = { + .aspect = GPU_IMAGE_ASPECT_COLOR, + .level_count = 1, + .layer_count = 1, + } + }; + barrier_req = (GpuCmdPipelineBarrierRequest){ + .command_buffer = cb, + .info = (GpuDependencyInfo){ + .image_memory_barriers = wpArray(GpuImageMemoryBarrier, image_barrier), + }, + }; + gpuCmdPipelineBarrier(temp, barrier_req); + + gpuEndCommandBuffer(cb); + + GpuFence *fence = gpuCreateFence(allocator, device); + + GpuResetFencesRequest reset_req = { + .device = device, + .fences = wpArray(GpuFence *, fence) + }; + gpuResetFences(temp, reset_req); + + GpuCommandBuffersSubmitRequest submit_req = { + .device = device, + .command_buffers = cbs, + .fence = fence, + }; + gpuSubmitCommandBuffers(temp, submit_req); + + GpuWaitForFencesRequest wait_req = { + .device = device, + .fences = wpArray(GpuFence *, fence), + .timeout = UINT64_MAX, + }; + gpuWaitForFences(temp, wait_req); + + gpuDestroyFence(fence); + gpuDestroyBuffer(&temp_storage); + return output; } @@ -2193,6 +2303,35 @@ void gpuCmdDispatchBase(GpuCmdDispatchBaseRequest request) { request.group_count_z); } +void gpuCmdCopyBufferToImage(const WpAllocator *temp, GpuCmdCopyBufferToImageRequest request) { + u64 region_count = wpArrayCount(request.copy_regions); + VkBufferImageCopyArray copy_regions = wpArrayAllocCapacity(VkBufferImageCopy, temp, region_count, + WP_ARRAY_INIT_FILLED); + assertWithLogger(copy_regions != NULL, &logger, "Failed to allocate temp copy buffer to image arrays"); + + for (u64 i = 0; i < region_count; ++i) { + copy_regions[i] = (VkBufferImageCopy){ + .bufferOffset = request.copy_regions[i].buffer_offset, + .imageSubresource = (VkImageSubresourceLayers){ + .aspectMask = vkImageAspectFromGpuImageAspect(request.copy_regions[i].image_subresource.aspect_mask), + .baseArrayLayer = request.copy_regions[i].image_subresource.base_array_layer, + .layerCount = request.copy_regions[i].image_subresource.layer_count, + .mipLevel = request.copy_regions[i].image_subresource.mip_level, + }, + .imageOffset = (VkOffset3D){ .x = request.copy_regions[i].image_offset.x, + .y = request.copy_regions[i].image_offset.y, + .z = request.copy_regions[i].image_offset.z }, + .imageExtent = (VkExtent3D){ .width = request.copy_regions[i].image_extent.width, + .height = request.copy_regions[i].image_extent.height, + .depth = request.copy_regions[i].image_extent.depth }, + }; + } + + vkCmdCopyBufferToImage(request.command_buffer->vk_buffer, request.src_buffer->internal->vk_buffer, + request.dst_image->vk_image, vkImageLayoutFromGpuImageLayout(request.dst_image_layout), + wpArrayCount(copy_regions), copy_regions); +} + wp_intern VkExtensions getInstanceExtensions(void) { Config config = configGet(); VkExtensions output = {0}; diff --git a/src/main.c b/src/main.c index ceecf18..2f18035 100644 --- a/src/main.c +++ b/src/main.c @@ -165,11 +165,11 @@ i32 main(void) { wpFileRead(code, spirv, code_size); - // GpuLoadImageFromFileRequest load_img_req = { - // .command_pool = pool, - // .filename = wpStr8LitRo("assets/collections.png"), - // }; - // GpuImage *texture = gpuLoadImageFromFile(&arena, &temp_arena, load_img_req); + GpuLoadImageFromFileRequest load_img_req = { + .command_pool = pool, + .filename = wpStr8LitRo("assets/collections.png"), + }; + GpuImage *texture = gpuLoadImageFromFile(&arena, &temp_arena, load_img_req); GpuShaderCreateRequest shader_request = { .device = device, @@ -626,7 +626,7 @@ i32 main(void) { gpuDestroyDescriptorPool(desc_pool); gpuDestroyBuffer(&shader_data); gpuDestroyShader(shader); - // gpuDestroyImage(texture); + gpuDestroyImage(texture); gpuDestroyCommandPool(pool); gpuDestroyBuffer(&vert_idx_buffer); gpuDestroySwapchain(swapchain);