diff --git a/gfx/common/vulkan_common.c b/gfx/common/vulkan_common.c index 6db044c2b0..ca7bbd6e13 100644 --- a/gfx/common/vulkan_common.c +++ b/gfx/common/vulkan_common.c @@ -2612,12 +2612,6 @@ void vulkan_context_destroy(gfx_ctx_vulkan_data_t *vk, } } -static void vulkan_recycle_acquire_semaphore(struct vulkan_context *ctx, VkSemaphore sem) -{ - assert(ctx->num_recycled_acquire_semaphores < VULKAN_MAX_SWAPCHAIN_IMAGES); - ctx->swapchain_recycled_semaphores[ctx->num_recycled_acquire_semaphores++] = sem; -} - static void vulkan_acquire_clear_fences(gfx_ctx_vulkan_data_t *vk) { unsigned i; @@ -2632,7 +2626,12 @@ static void vulkan_acquire_clear_fences(gfx_ctx_vulkan_data_t *vk) vk->context.swapchain_fences_signalled[i] = false; if (vk->context.swapchain_wait_semaphores[i]) - vulkan_recycle_acquire_semaphore(&vk->context, vk->context.swapchain_wait_semaphores[i]); + { + struct vulkan_context *ctx = &vk->context; + VkSemaphore sem = vk->context.swapchain_wait_semaphores[i]; + assert(ctx->num_recycled_acquire_semaphores < VULKAN_MAX_SWAPCHAIN_IMAGES); + ctx->swapchain_recycled_semaphores[ctx->num_recycled_acquire_semaphores++] = sem; + } vk->context.swapchain_wait_semaphores[i] = VK_NULL_HANDLE; } @@ -2689,7 +2688,12 @@ static void vulkan_acquire_wait_fences(gfx_ctx_vulkan_data_t *vk) vk->context.swapchain_fences_signalled[index] = false; if (vk->context.swapchain_wait_semaphores[index] != VK_NULL_HANDLE) - vulkan_recycle_acquire_semaphore(&vk->context, vk->context.swapchain_wait_semaphores[index]); + { + struct vulkan_context *ctx = &vk->context; + VkSemaphore sem = vk->context.swapchain_wait_semaphores[index]; + assert(ctx->num_recycled_acquire_semaphores < VULKAN_MAX_SWAPCHAIN_IMAGES); + ctx->swapchain_recycled_semaphores[ctx->num_recycled_acquire_semaphores++] = sem; + } vk->context.swapchain_wait_semaphores[index] = VK_NULL_HANDLE; } @@ -2812,7 +2816,12 @@ retry: { vk->context.has_acquired_swapchain = false; if (semaphore) - vulkan_recycle_acquire_semaphore(&vk->context, semaphore); + { + struct vulkan_context *ctx = &vk->context; + VkSemaphore sem = semaphore; + assert(ctx->num_recycled_acquire_semaphores < VULKAN_MAX_SWAPCHAIN_IMAGES); + ctx->swapchain_recycled_semaphores[ctx->num_recycled_acquire_semaphores++] = sem; + } } #ifdef WSI_HARDENING_TEST @@ -3244,46 +3253,6 @@ bool vulkan_create_swapchain(gfx_ctx_vulkan_data_t *vk, return true; } -void vulkan_initialize_render_pass(VkDevice device, VkFormat format, - VkRenderPass *render_pass) -{ - VkAttachmentReference color_ref; - VkRenderPassCreateInfo rp_info; - VkAttachmentDescription attachment; - VkSubpassDescription subpass = {0}; - - 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.pipelineBindPoint = VK_PIPELINE_BIND_POINT_GRAPHICS; - subpass.colorAttachmentCount = 1; - subpass.pColorAttachments = &color_ref; - - vkCreateRenderPass(device, &rp_info, NULL, render_pass); -} - void vulkan_set_uniform_buffer( VkDevice device, VkDescriptorSet set, @@ -3312,253 +3281,3 @@ void vulkan_set_uniform_buffer( vkUpdateDescriptorSets(device, 1, &write, 0, NULL); } - -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[0].subresourceRange.baseArrayLayer = 0; - barriers[1].subresourceRange.layerCount = VK_REMAINING_ARRAY_LAYERS; - - vkCmdPipelineBarrier(cmd, - VK_PIPELINE_STAGE_ALL_GRAPHICS_BIT, - VK_PIPELINE_STAGE_TRANSFER_BIT, - false, - 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, - false, - 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, - false, - 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); -} - -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); -} diff --git a/gfx/common/vulkan_common.h b/gfx/common/vulkan_common.h index 303a0177c8..e6e86be243 100644 --- a/gfx/common/vulkan_common.h +++ b/gfx/common/vulkan_common.h @@ -798,24 +798,6 @@ void vulkan_set_uniform_buffer( VkDeviceSize offset, VkDeviceSize range); -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); - -void vulkan_framebuffer_clear(VkImage image, VkCommandBuffer cmd); - -void vulkan_initialize_render_pass(VkDevice device, - VkFormat format, VkRenderPass *render_pass); - RETRO_END_DECLS #endif diff --git a/gfx/drivers_shader/shader_vulkan.cpp b/gfx/drivers_shader/shader_vulkan.cpp index 16147f8501..cbd2c262f7 100644 --- a/gfx/drivers_shader/shader_vulkan.cpp +++ b/gfx/drivers_shader/shader_vulkan.cpp @@ -430,6 +430,257 @@ struct vulkan_filter_chain void update_history_info(); }; +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[0].subresourceRange.baseArrayLayer = 0; + barriers[1].subresourceRange.layerCount = VK_REMAINING_ARRAY_LAYERS; + + vkCmdPipelineBarrier(cmd, + VK_PIPELINE_STAGE_ALL_GRAPHICS_BIT, + VK_PIPELINE_STAGE_TRANSFER_BIT, + false, + 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, + false, + 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, + false, + 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); +} + +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 uint32_t find_memory_type_fallback( const VkPhysicalDeviceMemoryProperties &mem_props, uint32_t device_reqs, uint32_t host_reqs) @@ -2322,6 +2573,7 @@ void Pass::build_commands( }; vkCmdSetViewport(cmd, 0, 1, ¤t_viewport); vkCmdSetScissor(cmd, 0, 1, &sci); + vkCmdDraw(cmd, 4, 1, 0, 0); } else { @@ -2341,12 +2593,7 @@ void Pass::build_commands( vkCmdSetViewport(cmd, 0, 1, &_vp); vkCmdSetScissor(cmd, 0, 1, &sci); - } - - vkCmdDraw(cmd, 4, 1, 0, 0); - - if (!final_pass) - { + vkCmdDraw(cmd, 4, 1, 0, 0); vkCmdEndRenderPass(cmd); if (framebuffer->get_levels() > 1) @@ -2375,6 +2622,47 @@ void Pass::build_commands( } } +static void vulkan_initialize_render_pass(VkDevice device, VkFormat format, + VkRenderPass *render_pass) +{ + VkAttachmentReference color_ref; + VkRenderPassCreateInfo rp_info; + VkAttachmentDescription attachment; + VkSubpassDescription subpass = {0}; + + 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.pipelineBindPoint = VK_PIPELINE_BIND_POINT_GRAPHICS; + subpass.colorAttachmentCount = 1; + subpass.pColorAttachments = &color_ref; + + vkCreateRenderPass(device, &rp_info, NULL, render_pass); +} + + Framebuffer::Framebuffer( VkDevice device, const VkPhysicalDeviceMemoryProperties &mem_props,