Move C Vulkan code over from shader_vulkan.cpp to vulkan_common.c

This commit is contained in:
libretroadmin 2024-07-22 00:52:31 +02:00
parent 6e279814b9
commit c99c5399f5
3 changed files with 322 additions and 304 deletions

View File

@ -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, &region);
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);
}

View File

@ -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

View File

@ -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, &region);
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;