From c99c5399f55171771a1a203155f4540b9fee8dc2 Mon Sep 17 00:00:00 2001 From: libretroadmin Date: Mon, 22 Jul 2024 00:52:31 +0200 Subject: [PATCH] Move C Vulkan code over from shader_vulkan.cpp to vulkan_common.c --- gfx/common/vulkan_common.c | 304 ++++++++++++++++++++++++++- gfx/common/vulkan_common.h | 20 +- gfx/drivers_shader/shader_vulkan.cpp | 302 -------------------------- 3 files changed, 322 insertions(+), 304 deletions(-) diff --git a/gfx/common/vulkan_common.c b/gfx/common/vulkan_common.c index 5d13e16720..2326c581cf 100644 --- a/gfx/common/vulkan_common.c +++ b/gfx/common/vulkan_common.c @@ -862,7 +862,7 @@ static VkInstance vulkan_context_create_instance_wrapper(void *opaque, const VkI const char **instance_extensions = (const char**)malloc((info.enabledExtensionCount + 3 + ARRAY_SIZE(vulkan_optional_device_extensions)) * sizeof(const char *)); const char **instance_layers = (const char**)malloc((info.enabledLayerCount + 1) * sizeof(const char *)); - + const char *required_extensions[3]; uint32_t required_extension_count = 0; @@ -2629,3 +2629,305 @@ void vulkan_present(gfx_ctx_vulkan_data_t *vk, unsigned index) slock_unlock(vk->context.queue_lock); #endif } + +void vulkan_initialize_render_pass(VkDevice device, VkFormat format, + VkRenderPass *render_pass) +{ + VkAttachmentReference color_ref; + VkRenderPassCreateInfo rp_info; + VkAttachmentDescription attachment; + VkSubpassDescription subpass; + + rp_info.sType = VK_STRUCTURE_TYPE_RENDER_PASS_CREATE_INFO; + rp_info.pNext = NULL; + rp_info.flags = 0; + rp_info.attachmentCount = 1; + rp_info.pAttachments = &attachment; + rp_info.subpassCount = 1; + rp_info.pSubpasses = &subpass; + rp_info.dependencyCount = 0; + rp_info.pDependencies = NULL; + + color_ref.attachment = 0; + color_ref.layout = VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL; + + /* We will always write to the entire framebuffer, + * so we don't really need to clear. */ + attachment.flags = 0; + attachment.format = format; + attachment.samples = VK_SAMPLE_COUNT_1_BIT; + attachment.loadOp = VK_ATTACHMENT_LOAD_OP_DONT_CARE; + attachment.storeOp = VK_ATTACHMENT_STORE_OP_STORE; + attachment.stencilLoadOp = VK_ATTACHMENT_LOAD_OP_DONT_CARE; + attachment.stencilStoreOp = VK_ATTACHMENT_STORE_OP_DONT_CARE; + attachment.initialLayout = VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL; + attachment.finalLayout = VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL; + + subpass.flags = 0; + subpass.pipelineBindPoint = VK_PIPELINE_BIND_POINT_GRAPHICS; + subpass.inputAttachmentCount = 0; + subpass.pInputAttachments = NULL; + subpass.colorAttachmentCount = 1; + subpass.pColorAttachments = &color_ref; + subpass.pResolveAttachments = NULL; + subpass.pDepthStencilAttachment = NULL; + subpass.preserveAttachmentCount = 0; + subpass.pPreserveAttachments = NULL; + + vkCreateRenderPass(device, &rp_info, NULL, render_pass); +} + +void vulkan_framebuffer_clear(VkImage image, VkCommandBuffer cmd) +{ + VkClearColorValue color; + VkImageSubresourceRange range; + + VULKAN_IMAGE_LAYOUT_TRANSITION_LEVELS(cmd, + image, + VK_REMAINING_MIP_LEVELS, + VK_IMAGE_LAYOUT_UNDEFINED, + VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, + 0, + VK_ACCESS_TRANSFER_WRITE_BIT, + VK_PIPELINE_STAGE_TOP_OF_PIPE_BIT, + VK_PIPELINE_STAGE_TRANSFER_BIT, + VK_QUEUE_FAMILY_IGNORED, + VK_QUEUE_FAMILY_IGNORED); + + color.float32[0] = 0.0f; + color.float32[1] = 0.0f; + color.float32[2] = 0.0f; + color.float32[3] = 0.0f; + range.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT; + range.baseMipLevel = 0; + range.levelCount = 1; + range.baseArrayLayer = 0; + range.layerCount = 1; + + vkCmdClearColorImage(cmd, + image, + VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, + &color, + 1, + &range); + + VULKAN_IMAGE_LAYOUT_TRANSITION_LEVELS(cmd, + image, + VK_REMAINING_MIP_LEVELS, + VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, + VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL, + VK_ACCESS_TRANSFER_WRITE_BIT, + VK_ACCESS_SHADER_READ_BIT, + VK_PIPELINE_STAGE_TRANSFER_BIT, + VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT, + VK_QUEUE_FAMILY_IGNORED, + VK_QUEUE_FAMILY_IGNORED); +} + +void vulkan_framebuffer_generate_mips( + VkFramebuffer framebuffer, + VkImage image, + struct Size2D size, + VkCommandBuffer cmd, + unsigned levels + ) +{ + unsigned i; + /* This is run every frame, so make sure + * we aren't opting into the "lazy" way of doing this. :) */ + VkImageMemoryBarrier barriers[2]; + + /* First, transfer the input mip level to TRANSFER_SRC_OPTIMAL. + * This should allow the surface to stay compressed. + * All subsequent mip-layers are now transferred into DST_OPTIMAL from + * UNDEFINED at this point. + */ + + /* Input */ + barriers[0].sType = VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER; + barriers[0].pNext = NULL; + barriers[0].srcAccessMask = VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT; + barriers[0].dstAccessMask = VK_ACCESS_TRANSFER_READ_BIT; + barriers[0].oldLayout = VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL; + barriers[0].newLayout = VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL; + barriers[0].srcQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED; + barriers[0].dstQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED; + barriers[0].image = image; + barriers[0].subresourceRange.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT; + barriers[0].subresourceRange.baseMipLevel = 0; + barriers[0].subresourceRange.levelCount = 1; + barriers[0].subresourceRange.baseArrayLayer = 0; + barriers[0].subresourceRange.layerCount = VK_REMAINING_ARRAY_LAYERS; + + /* The rest of the mip chain */ + barriers[1].sType = VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER; + barriers[1].pNext = NULL; + barriers[1].srcAccessMask = 0; + barriers[1].dstAccessMask = VK_ACCESS_TRANSFER_WRITE_BIT; + barriers[1].oldLayout = VK_IMAGE_LAYOUT_UNDEFINED; + barriers[1].newLayout = VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL; + barriers[1].srcQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED; + barriers[1].dstQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED; + barriers[1].image = image; + barriers[1].subresourceRange.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT; + barriers[1].subresourceRange.baseMipLevel = 1; + barriers[1].subresourceRange.levelCount = VK_REMAINING_MIP_LEVELS; + barriers[1].subresourceRange.baseArrayLayer = 0; + barriers[1].subresourceRange.layerCount = VK_REMAINING_ARRAY_LAYERS; + + vkCmdPipelineBarrier(cmd, + VK_PIPELINE_STAGE_ALL_GRAPHICS_BIT, + VK_PIPELINE_STAGE_TRANSFER_BIT, + 0, + 0, + NULL, + 0, + NULL, + 2, + barriers); + + for (i = 1; i < levels; i++) + { + unsigned src_width, src_height, target_width, target_height; + VkImageBlit blit_region = {{0}}; + + /* For subsequent passes, we have to transition + * from DST_OPTIMAL to SRC_OPTIMAL, + * but only do so one mip-level at a time. */ + if (i > 1) + { + barriers[0].srcAccessMask = VK_ACCESS_TRANSFER_WRITE_BIT; + barriers[0].dstAccessMask = VK_ACCESS_TRANSFER_READ_BIT; + barriers[0].subresourceRange.baseMipLevel = i - 1; + barriers[0].subresourceRange.levelCount = 1; + barriers[0].oldLayout = VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL; + barriers[0].newLayout = VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL; + + vkCmdPipelineBarrier(cmd, + VK_PIPELINE_STAGE_TRANSFER_BIT, + VK_PIPELINE_STAGE_TRANSFER_BIT, + 0, + 0, + NULL, + 0, + NULL, + 1, + barriers); + } + + src_width = MAX(size.width >> (i - 1), 1u); + src_height = MAX(size.height >> (i - 1), 1u); + target_width = MAX(size.width >> i, 1u); + target_height = MAX(size.height >> i, 1u); + + blit_region.srcSubresource.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT; + blit_region.srcSubresource.mipLevel = i - 1; + blit_region.srcSubresource.baseArrayLayer = 0; + blit_region.srcSubresource.layerCount = 1; + blit_region.dstSubresource = blit_region.srcSubresource; + blit_region.dstSubresource.mipLevel = i; + blit_region.srcOffsets[1].x = src_width; + blit_region.srcOffsets[1].y = src_height; + blit_region.srcOffsets[1].z = 1; + blit_region.dstOffsets[1].x = target_width; + blit_region.dstOffsets[1].y = target_height; + blit_region.dstOffsets[1].z = 1; + + vkCmdBlitImage(cmd, + image, VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL, + image, VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, + 1, &blit_region, VK_FILTER_LINEAR); + } + + /* We are now done, and we have all mip-levels except + * the last in TRANSFER_SRC_OPTIMAL, + * and the last one still on TRANSFER_DST_OPTIMAL, + * so do a final barrier which + * moves everything to SHADER_READ_ONLY_OPTIMAL in + * one go along with the execution barrier to next pass. + * Read-to-read memory barrier, so only need execution + * barrier for first transition. + */ + barriers[0].srcAccessMask = VK_ACCESS_TRANSFER_READ_BIT; + barriers[0].dstAccessMask = VK_ACCESS_SHADER_READ_BIT; + barriers[0].subresourceRange.baseMipLevel = 0; + barriers[0].subresourceRange.levelCount = levels - 1; + barriers[0].oldLayout = VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL; + barriers[0].newLayout = VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL; + + /* This is read-after-write barrier. */ + barriers[1].srcAccessMask = VK_ACCESS_TRANSFER_WRITE_BIT; + barriers[1].dstAccessMask = VK_ACCESS_SHADER_READ_BIT; + barriers[1].subresourceRange.baseMipLevel = levels - 1; + barriers[1].subresourceRange.levelCount = 1; + barriers[1].oldLayout = VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL; + barriers[1].newLayout = VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL; + + vkCmdPipelineBarrier(cmd, + VK_PIPELINE_STAGE_TRANSFER_BIT, + VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT, + 0, + 0, + NULL, + 0, + NULL, + 2, barriers); + + /* Next pass will wait for ALL_GRAPHICS_BIT, and since + * we have dstStage as FRAGMENT_SHADER, + * the dependency chain will ensure we don't start + * next pass until the mipchain is complete. */ +} + +void vulkan_framebuffer_copy(VkImage image, + struct Size2D size, + VkCommandBuffer cmd, + VkImage src_image, VkImageLayout src_layout) +{ + VkImageCopy region; + + VULKAN_IMAGE_LAYOUT_TRANSITION_LEVELS( + cmd, + image, + VK_REMAINING_MIP_LEVELS, + VK_IMAGE_LAYOUT_UNDEFINED, + VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, + 0, + VK_ACCESS_TRANSFER_WRITE_BIT, + VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT, + VK_PIPELINE_STAGE_TRANSFER_BIT, + VK_QUEUE_FAMILY_IGNORED, + VK_QUEUE_FAMILY_IGNORED); + + region.srcSubresource.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT; + region.srcSubresource.mipLevel = 0; + region.srcSubresource.baseArrayLayer = 0; + region.srcSubresource.layerCount = 1; + region.srcOffset.x = 0; + region.srcOffset.y = 0; + region.srcOffset.z = 0; + region.dstSubresource = region.srcSubresource; + region.dstOffset.x = 0; + region.dstOffset.y = 0; + region.dstOffset.z = 0; + region.extent.width = size.width; + region.extent.height = size.height; + region.extent.depth = 1; + + vkCmdCopyImage(cmd, + src_image, src_layout, + image, VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, + 1, ®ion); + + VULKAN_IMAGE_LAYOUT_TRANSITION_LEVELS(cmd, + image, + VK_REMAINING_MIP_LEVELS, + VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, + VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL, + VK_ACCESS_TRANSFER_WRITE_BIT, + VK_ACCESS_SHADER_READ_BIT, + VK_PIPELINE_STAGE_TRANSFER_BIT, + VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT, + VK_QUEUE_FAMILY_IGNORED, + VK_QUEUE_FAMILY_IGNORED); +} diff --git a/gfx/common/vulkan_common.h b/gfx/common/vulkan_common.h index 8a6df58ff3..42bbe1b282 100644 --- a/gfx/common/vulkan_common.h +++ b/gfx/common/vulkan_common.h @@ -368,7 +368,7 @@ typedef struct vulkan_context VkFormat swapchain_format; #ifdef VULKAN_HDR_SWAPCHAIN VkColorSpaceKHR swapchain_colour_space; -#endif /* VULKAN_HDR_SWAPCHAIN */ +#endif /* VULKAN_HDR_SWAPCHAIN */ VkSemaphore swapchain_semaphores[VULKAN_MAX_SWAPCHAIN_IMAGES]; VkSemaphore swapchain_acquire_semaphore; @@ -739,6 +739,24 @@ void vulkan_debug_mark_memory(VkDevice device, VkDeviceMemory memory); bool vulkan_is_hdr10_format(VkFormat format); #endif /* VULKAN_HDR_SWAPCHAIN */ +void vulkan_initialize_render_pass(VkDevice device, VkFormat format, + VkRenderPass *render_pass); + +void vulkan_framebuffer_clear(VkImage image, VkCommandBuffer cmd); + +void vulkan_framebuffer_generate_mips( + VkFramebuffer framebuffer, + VkImage image, + struct Size2D size, + VkCommandBuffer cmd, + unsigned levels + ); + +void vulkan_framebuffer_copy(VkImage image, + struct Size2D size, + VkCommandBuffer cmd, + VkImage src_image, VkImageLayout src_layout); + RETRO_END_DECLS #endif diff --git a/gfx/drivers_shader/shader_vulkan.cpp b/gfx/drivers_shader/shader_vulkan.cpp index 83cb5f789f..3474e7a903 100644 --- a/gfx/drivers_shader/shader_vulkan.cpp +++ b/gfx/drivers_shader/shader_vulkan.cpp @@ -46,308 +46,6 @@ static const uint32_t opaque_frag[] = #include "../drivers/vulkan_shaders/opaque.frag.inc" ; -static void vulkan_initialize_render_pass(VkDevice device, VkFormat format, - VkRenderPass *render_pass) -{ - VkAttachmentReference color_ref; - VkRenderPassCreateInfo rp_info; - VkAttachmentDescription attachment; - VkSubpassDescription subpass; - - rp_info.sType = VK_STRUCTURE_TYPE_RENDER_PASS_CREATE_INFO; - rp_info.pNext = NULL; - rp_info.flags = 0; - rp_info.attachmentCount = 1; - rp_info.pAttachments = &attachment; - rp_info.subpassCount = 1; - rp_info.pSubpasses = &subpass; - rp_info.dependencyCount = 0; - rp_info.pDependencies = NULL; - - color_ref.attachment = 0; - color_ref.layout = VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL; - - /* We will always write to the entire framebuffer, - * so we don't really need to clear. */ - attachment.flags = 0; - attachment.format = format; - attachment.samples = VK_SAMPLE_COUNT_1_BIT; - attachment.loadOp = VK_ATTACHMENT_LOAD_OP_DONT_CARE; - attachment.storeOp = VK_ATTACHMENT_STORE_OP_STORE; - attachment.stencilLoadOp = VK_ATTACHMENT_LOAD_OP_DONT_CARE; - attachment.stencilStoreOp = VK_ATTACHMENT_STORE_OP_DONT_CARE; - attachment.initialLayout = VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL; - attachment.finalLayout = VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL; - - subpass.flags = 0; - subpass.pipelineBindPoint = VK_PIPELINE_BIND_POINT_GRAPHICS; - subpass.inputAttachmentCount = 0; - subpass.pInputAttachments = NULL; - subpass.colorAttachmentCount = 1; - subpass.pColorAttachments = &color_ref; - subpass.pResolveAttachments = NULL; - subpass.pDepthStencilAttachment = NULL; - subpass.preserveAttachmentCount = 0; - subpass.pPreserveAttachments = NULL; - - vkCreateRenderPass(device, &rp_info, NULL, render_pass); -} - -static void vulkan_framebuffer_clear(VkImage image, VkCommandBuffer cmd) -{ - VkClearColorValue color; - VkImageSubresourceRange range; - - VULKAN_IMAGE_LAYOUT_TRANSITION_LEVELS(cmd, - image, - VK_REMAINING_MIP_LEVELS, - VK_IMAGE_LAYOUT_UNDEFINED, - VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, - 0, - VK_ACCESS_TRANSFER_WRITE_BIT, - VK_PIPELINE_STAGE_TOP_OF_PIPE_BIT, - VK_PIPELINE_STAGE_TRANSFER_BIT, - VK_QUEUE_FAMILY_IGNORED, - VK_QUEUE_FAMILY_IGNORED); - - color.float32[0] = 0.0f; - color.float32[1] = 0.0f; - color.float32[2] = 0.0f; - color.float32[3] = 0.0f; - range.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT; - range.baseMipLevel = 0; - range.levelCount = 1; - range.baseArrayLayer = 0; - range.layerCount = 1; - - vkCmdClearColorImage(cmd, - image, - VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, - &color, - 1, - &range); - - VULKAN_IMAGE_LAYOUT_TRANSITION_LEVELS(cmd, - image, - VK_REMAINING_MIP_LEVELS, - VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, - VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL, - VK_ACCESS_TRANSFER_WRITE_BIT, - VK_ACCESS_SHADER_READ_BIT, - VK_PIPELINE_STAGE_TRANSFER_BIT, - VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT, - VK_QUEUE_FAMILY_IGNORED, - VK_QUEUE_FAMILY_IGNORED); -} - -static void vulkan_framebuffer_generate_mips( - VkFramebuffer framebuffer, - VkImage image, - struct Size2D size, - VkCommandBuffer cmd, - unsigned levels - ) -{ - unsigned i; - /* This is run every frame, so make sure - * we aren't opting into the "lazy" way of doing this. :) */ - VkImageMemoryBarrier barriers[2]; - - /* First, transfer the input mip level to TRANSFER_SRC_OPTIMAL. - * This should allow the surface to stay compressed. - * All subsequent mip-layers are now transferred into DST_OPTIMAL from - * UNDEFINED at this point. - */ - - /* Input */ - barriers[0].sType = VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER; - barriers[0].pNext = NULL; - barriers[0].srcAccessMask = VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT; - barriers[0].dstAccessMask = VK_ACCESS_TRANSFER_READ_BIT; - barriers[0].oldLayout = VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL; - barriers[0].newLayout = VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL; - barriers[0].srcQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED; - barriers[0].dstQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED; - barriers[0].image = image; - barriers[0].subresourceRange.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT; - barriers[0].subresourceRange.baseMipLevel = 0; - barriers[0].subresourceRange.levelCount = 1; - barriers[0].subresourceRange.baseArrayLayer = 0; - barriers[0].subresourceRange.layerCount = VK_REMAINING_ARRAY_LAYERS; - - /* The rest of the mip chain */ - barriers[1].sType = VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER; - barriers[1].pNext = NULL; - barriers[1].srcAccessMask = 0; - barriers[1].dstAccessMask = VK_ACCESS_TRANSFER_WRITE_BIT; - barriers[1].oldLayout = VK_IMAGE_LAYOUT_UNDEFINED; - barriers[1].newLayout = VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL; - barriers[1].srcQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED; - barriers[1].dstQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED; - barriers[1].image = image; - barriers[1].subresourceRange.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT; - barriers[1].subresourceRange.baseMipLevel = 1; - barriers[1].subresourceRange.levelCount = VK_REMAINING_MIP_LEVELS; - barriers[1].subresourceRange.baseArrayLayer = 0; - barriers[1].subresourceRange.layerCount = VK_REMAINING_ARRAY_LAYERS; - - vkCmdPipelineBarrier(cmd, - VK_PIPELINE_STAGE_ALL_GRAPHICS_BIT, - VK_PIPELINE_STAGE_TRANSFER_BIT, - 0, - 0, - NULL, - 0, - NULL, - 2, - barriers); - - for (i = 1; i < levels; i++) - { - unsigned src_width, src_height, target_width, target_height; - VkImageBlit blit_region = {{0}}; - - /* For subsequent passes, we have to transition - * from DST_OPTIMAL to SRC_OPTIMAL, - * but only do so one mip-level at a time. */ - if (i > 1) - { - barriers[0].srcAccessMask = VK_ACCESS_TRANSFER_WRITE_BIT; - barriers[0].dstAccessMask = VK_ACCESS_TRANSFER_READ_BIT; - barriers[0].subresourceRange.baseMipLevel = i - 1; - barriers[0].subresourceRange.levelCount = 1; - barriers[0].oldLayout = VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL; - barriers[0].newLayout = VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL; - - vkCmdPipelineBarrier(cmd, - VK_PIPELINE_STAGE_TRANSFER_BIT, - VK_PIPELINE_STAGE_TRANSFER_BIT, - 0, - 0, - NULL, - 0, - NULL, - 1, - barriers); - } - - src_width = MAX(size.width >> (i - 1), 1u); - src_height = MAX(size.height >> (i - 1), 1u); - target_width = MAX(size.width >> i, 1u); - target_height = MAX(size.height >> i, 1u); - - blit_region.srcSubresource.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT; - blit_region.srcSubresource.mipLevel = i - 1; - blit_region.srcSubresource.baseArrayLayer = 0; - blit_region.srcSubresource.layerCount = 1; - blit_region.dstSubresource = blit_region.srcSubresource; - blit_region.dstSubresource.mipLevel = i; - blit_region.srcOffsets[1].x = src_width; - blit_region.srcOffsets[1].y = src_height; - blit_region.srcOffsets[1].z = 1; - blit_region.dstOffsets[1].x = target_width; - blit_region.dstOffsets[1].y = target_height; - blit_region.dstOffsets[1].z = 1; - - vkCmdBlitImage(cmd, - image, VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL, - image, VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, - 1, &blit_region, VK_FILTER_LINEAR); - } - - /* We are now done, and we have all mip-levels except - * the last in TRANSFER_SRC_OPTIMAL, - * and the last one still on TRANSFER_DST_OPTIMAL, - * so do a final barrier which - * moves everything to SHADER_READ_ONLY_OPTIMAL in - * one go along with the execution barrier to next pass. - * Read-to-read memory barrier, so only need execution - * barrier for first transition. - */ - barriers[0].srcAccessMask = VK_ACCESS_TRANSFER_READ_BIT; - barriers[0].dstAccessMask = VK_ACCESS_SHADER_READ_BIT; - barriers[0].subresourceRange.baseMipLevel = 0; - barriers[0].subresourceRange.levelCount = levels - 1; - barriers[0].oldLayout = VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL; - barriers[0].newLayout = VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL; - - /* This is read-after-write barrier. */ - barriers[1].srcAccessMask = VK_ACCESS_TRANSFER_WRITE_BIT; - barriers[1].dstAccessMask = VK_ACCESS_SHADER_READ_BIT; - barriers[1].subresourceRange.baseMipLevel = levels - 1; - barriers[1].subresourceRange.levelCount = 1; - barriers[1].oldLayout = VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL; - barriers[1].newLayout = VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL; - - vkCmdPipelineBarrier(cmd, - VK_PIPELINE_STAGE_TRANSFER_BIT, - VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT, - 0, - 0, - NULL, - 0, - NULL, - 2, barriers); - - /* Next pass will wait for ALL_GRAPHICS_BIT, and since - * we have dstStage as FRAGMENT_SHADER, - * the dependency chain will ensure we don't start - * next pass until the mipchain is complete. */ -} - -static void vulkan_framebuffer_copy(VkImage image, - struct Size2D size, - VkCommandBuffer cmd, - VkImage src_image, VkImageLayout src_layout) -{ - VkImageCopy region; - - VULKAN_IMAGE_LAYOUT_TRANSITION_LEVELS( - cmd, - image, - VK_REMAINING_MIP_LEVELS, - VK_IMAGE_LAYOUT_UNDEFINED, - VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, - 0, - VK_ACCESS_TRANSFER_WRITE_BIT, - VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT, - VK_PIPELINE_STAGE_TRANSFER_BIT, - VK_QUEUE_FAMILY_IGNORED, - VK_QUEUE_FAMILY_IGNORED); - - region.srcSubresource.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT; - region.srcSubresource.mipLevel = 0; - region.srcSubresource.baseArrayLayer = 0; - region.srcSubresource.layerCount = 1; - region.srcOffset.x = 0; - region.srcOffset.y = 0; - region.srcOffset.z = 0; - region.dstSubresource = region.srcSubresource; - region.dstOffset.x = 0; - region.dstOffset.y = 0; - region.dstOffset.z = 0; - region.extent.width = size.width; - region.extent.height = size.height; - region.extent.depth = 1; - - vkCmdCopyImage(cmd, - src_image, src_layout, - image, VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, - 1, ®ion); - - VULKAN_IMAGE_LAYOUT_TRANSITION_LEVELS(cmd, - image, - VK_REMAINING_MIP_LEVELS, - VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, - VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL, - VK_ACCESS_TRANSFER_WRITE_BIT, - VK_ACCESS_SHADER_READ_BIT, - VK_PIPELINE_STAGE_TRANSFER_BIT, - VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT, - VK_QUEUE_FAMILY_IGNORED, - VK_QUEUE_FAMILY_IGNORED); -} - struct Texture { vulkan_filter_chain_texture texture;