mirror of
https://github.com/libretro/RetroArch
synced 2025-03-29 22:20:21 +00:00
Move C Vulkan code over from shader_vulkan.cpp to vulkan_common.c
This commit is contained in:
parent
6e279814b9
commit
c99c5399f5
@ -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);
|
||||
}
|
||||
|
@ -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
|
||||
|
@ -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;
|
||||
|
Loading…
x
Reference in New Issue
Block a user