vulkan/wsi: Add support for image -> image blits

The win32 swapchain can be backed by a DXGI swapchain, but such swapchains
are incompatible with STORAGE images (AKA UNORDERED_ACCESS usage in
DXGI). So, we need to allocate an intermediate image that will serve as
a render-target, and copy this image to the WSI image when QueuePresent()
is called. That's pretty similar to what we do for the buffer blit case,
except the image -> buffer copy is replaced by an image -> image copy.

Reviewed-by: Jesse Natalie <jenatali@microsoft.com>
Reviewed-by: Daniel Stone <daniels@collabora.com>
Reviewed-by: Jason Ekstrand <jason.ekstrand@collabora.com>
Part-of: <https://gitlab.freedesktop.org/mesa/mesa/-/merge_requests/16200>
This commit is contained in:
Boris Brezillon
2022-04-27 18:25:34 +02:00
committed by Marge Bot
parent 65e4873d82
commit 2975a7f453
3 changed files with 114 additions and 41 deletions

View File

@@ -146,6 +146,7 @@ wsi_device_init(struct wsi_device *wsi,
WSI_GET_CB(BindImageMemory); WSI_GET_CB(BindImageMemory);
WSI_GET_CB(BeginCommandBuffer); WSI_GET_CB(BeginCommandBuffer);
WSI_GET_CB(CmdPipelineBarrier); WSI_GET_CB(CmdPipelineBarrier);
WSI_GET_CB(CmdCopyImage);
WSI_GET_CB(CmdCopyImageToBuffer); WSI_GET_CB(CmdCopyImageToBuffer);
WSI_GET_CB(CreateBuffer); WSI_GET_CB(CreateBuffer);
WSI_GET_CB(CreateCommandPool); WSI_GET_CB(CreateCommandPool);
@@ -693,6 +694,7 @@ wsi_destroy_image(const struct wsi_swapchain *chain,
wsi->FreeMemory(chain->device, image->memory, &chain->alloc); wsi->FreeMemory(chain->device, image->memory, &chain->alloc);
wsi->DestroyImage(chain->device, image->image, &chain->alloc); wsi->DestroyImage(chain->device, image->image, &chain->alloc);
wsi->DestroyImage(chain->device, image->blit.image, &chain->alloc);
wsi->FreeMemory(chain->device, image->blit.memory, &chain->alloc); wsi->FreeMemory(chain->device, image->blit.memory, &chain->alloc);
wsi->DestroyBuffer(chain->device, image->blit.buffer, &chain->alloc); wsi->DestroyBuffer(chain->device, image->blit.buffer, &chain->alloc);
} }
@@ -1533,6 +1535,8 @@ wsi_create_buffer_blit_context(const struct wsi_swapchain *chain,
VkExternalMemoryHandleTypeFlags handle_types, VkExternalMemoryHandleTypeFlags handle_types,
bool implicit_sync) bool implicit_sync)
{ {
assert(chain->blit.type == WSI_SWAPCHAIN_BUFFER_BLIT);
const struct wsi_device *wsi = chain->wsi; const struct wsi_device *wsi = chain->wsi;
VkResult result; VkResult result;
@@ -1671,63 +1675,116 @@ wsi_finish_create_blit_context(const struct wsi_swapchain *chain,
}; };
wsi->BeginCommandBuffer(image->blit.cmd_buffers[i], &begin_info); wsi->BeginCommandBuffer(image->blit.cmd_buffers[i], &begin_info);
VkImageMemoryBarrier img_mem_barrier = { VkImageMemoryBarrier img_mem_barriers[] = {
.sType = VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER, {
.pNext = NULL, .sType = VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER,
.srcAccessMask = 0, .pNext = NULL,
.dstAccessMask = VK_ACCESS_TRANSFER_READ_BIT, .srcAccessMask = 0,
.oldLayout = VK_IMAGE_LAYOUT_PRESENT_SRC_KHR, .dstAccessMask = VK_ACCESS_TRANSFER_READ_BIT,
.newLayout = VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL, .oldLayout = VK_IMAGE_LAYOUT_PRESENT_SRC_KHR,
.srcQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED, .newLayout = VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL,
.dstQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED, .srcQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED,
.image = image->image, .dstQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED,
.subresourceRange = { .image = image->image,
.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT, .subresourceRange = {
.baseMipLevel = 0, .aspectMask = VK_IMAGE_ASPECT_COLOR_BIT,
.levelCount = 1, .baseMipLevel = 0,
.baseArrayLayer = 0, .levelCount = 1,
.layerCount = 1, .baseArrayLayer = 0,
.layerCount = 1,
},
},
{
.sType = VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER,
.pNext = NULL,
.srcAccessMask = 0,
.dstAccessMask = VK_ACCESS_TRANSFER_WRITE_BIT,
.oldLayout = VK_IMAGE_LAYOUT_PRESENT_SRC_KHR,
.newLayout = VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL,
.srcQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED,
.dstQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED,
.image = image->blit.image,
.subresourceRange = {
.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT,
.baseMipLevel = 0,
.levelCount = 1,
.baseArrayLayer = 0,
.layerCount = 1,
},
}, },
}; };
uint32_t img_mem_barrier_count =
chain->blit.type == WSI_SWAPCHAIN_BUFFER_BLIT ? 1 : 2;
wsi->CmdPipelineBarrier(image->blit.cmd_buffers[i], wsi->CmdPipelineBarrier(image->blit.cmd_buffers[i],
VK_PIPELINE_STAGE_TOP_OF_PIPE_BIT, VK_PIPELINE_STAGE_TOP_OF_PIPE_BIT,
VK_PIPELINE_STAGE_TRANSFER_BIT, VK_PIPELINE_STAGE_TRANSFER_BIT,
0, 0,
0, NULL, 0, NULL,
0, NULL, 0, NULL,
1, &img_mem_barrier); 1, img_mem_barriers);
struct VkBufferImageCopy buffer_image_copy = { if (chain->blit.type == WSI_SWAPCHAIN_BUFFER_BLIT) {
.bufferOffset = 0, struct VkBufferImageCopy buffer_image_copy = {
.bufferRowLength = info->linear_stride / .bufferOffset = 0,
vk_format_get_blocksize(info->create.format), .bufferRowLength = info->linear_stride /
.bufferImageHeight = 0, vk_format_get_blocksize(info->create.format),
.imageSubresource = { .bufferImageHeight = 0,
.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT, .imageSubresource = {
.mipLevel = 0, .aspectMask = VK_IMAGE_ASPECT_COLOR_BIT,
.baseArrayLayer = 0, .mipLevel = 0,
.layerCount = 1, .baseArrayLayer = 0,
}, .layerCount = 1,
.imageOffset = { .x = 0, .y = 0, .z = 0 }, },
.imageExtent = info->create.extent, .imageOffset = { .x = 0, .y = 0, .z = 0 },
}; .imageExtent = info->create.extent,
wsi->CmdCopyImageToBuffer(image->blit.cmd_buffers[i], };
image->image, wsi->CmdCopyImageToBuffer(image->blit.cmd_buffers[i],
VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL, image->image,
image->blit.buffer, VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL,
1, &buffer_image_copy); image->blit.buffer,
1, &buffer_image_copy);
} else {
struct VkImageCopy image_copy = {
.srcSubresource = {
.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT,
.mipLevel = 0,
.baseArrayLayer = 0,
.layerCount = 1,
},
.srcOffset = { .x = 0, .y = 0, .z = 0 },
.dstSubresource = {
.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT,
.mipLevel = 0,
.baseArrayLayer = 0,
.layerCount = 1,
},
.dstOffset = { .x = 0, .y = 0, .z = 0 },
.extent = info->create.extent,
};
img_mem_barrier.srcAccessMask = VK_ACCESS_TRANSFER_READ_BIT; wsi->CmdCopyImage(image->blit.cmd_buffers[i],
img_mem_barrier.dstAccessMask = 0; image->image,
img_mem_barrier.oldLayout = VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL; VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL,
img_mem_barrier.newLayout = VK_IMAGE_LAYOUT_PRESENT_SRC_KHR; image->blit.image,
VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL,
1, &image_copy);
}
img_mem_barriers[0].srcAccessMask = VK_ACCESS_TRANSFER_READ_BIT;
img_mem_barriers[0].dstAccessMask = 0;
img_mem_barriers[0].oldLayout = VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL;
img_mem_barriers[0].newLayout = VK_IMAGE_LAYOUT_PRESENT_SRC_KHR;
img_mem_barriers[1].srcAccessMask = VK_ACCESS_TRANSFER_WRITE_BIT;
img_mem_barriers[1].dstAccessMask = 0;
img_mem_barriers[1].oldLayout = VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL;
img_mem_barriers[1].newLayout = VK_IMAGE_LAYOUT_PRESENT_SRC_KHR;
wsi->CmdPipelineBarrier(image->blit.cmd_buffers[i], wsi->CmdPipelineBarrier(image->blit.cmd_buffers[i],
VK_PIPELINE_STAGE_TRANSFER_BIT, VK_PIPELINE_STAGE_TRANSFER_BIT,
VK_PIPELINE_STAGE_BOTTOM_OF_PIPE_BIT, VK_PIPELINE_STAGE_BOTTOM_OF_PIPE_BIT,
0, 0,
0, NULL, 0, NULL,
0, NULL, 0, NULL,
1, &img_mem_barrier); img_mem_barrier_count, img_mem_barriers);
result = wsi->EndCommandBuffer(image->blit.cmd_buffers[i]); result = wsi->EndCommandBuffer(image->blit.cmd_buffers[i]);
if (result != VK_SUCCESS) if (result != VK_SUCCESS)
@@ -1768,6 +1825,15 @@ wsi_configure_buffer_image(UNUSED const struct wsi_swapchain *chain,
info->finish_create = wsi_finish_create_blit_context; info->finish_create = wsi_finish_create_blit_context;
} }
void
wsi_configure_image_blit_image(UNUSED const struct wsi_swapchain *chain,
struct wsi_image_info *info)
{
info->create.usage |= VK_IMAGE_USAGE_TRANSFER_SRC_BIT;
info->wsi.blit_src = true;
info->finish_create = wsi_finish_create_blit_context;
}
static VkResult static VkResult
wsi_create_cpu_linear_image_mem(const struct wsi_swapchain *chain, wsi_create_cpu_linear_image_mem(const struct wsi_swapchain *chain,
const struct wsi_image_info *info, const struct wsi_image_info *info,

View File

@@ -208,6 +208,7 @@ struct wsi_device {
WSI_CB(BindImageMemory); WSI_CB(BindImageMemory);
WSI_CB(BeginCommandBuffer); WSI_CB(BeginCommandBuffer);
WSI_CB(CmdPipelineBarrier); WSI_CB(CmdPipelineBarrier);
WSI_CB(CmdCopyImage);
WSI_CB(CmdCopyImageToBuffer); WSI_CB(CmdCopyImageToBuffer);
WSI_CB(CreateBuffer); WSI_CB(CreateBuffer);
WSI_CB(CreateCommandPool); WSI_CB(CreateCommandPool);

View File

@@ -104,6 +104,7 @@ struct wsi_image_info {
enum wsi_swapchain_blit_type { enum wsi_swapchain_blit_type {
WSI_SWAPCHAIN_NO_BLIT, WSI_SWAPCHAIN_NO_BLIT,
WSI_SWAPCHAIN_BUFFER_BLIT, WSI_SWAPCHAIN_BUFFER_BLIT,
WSI_SWAPCHAIN_IMAGE_BLIT,
}; };
struct wsi_image { struct wsi_image {
@@ -112,6 +113,7 @@ struct wsi_image {
struct { struct {
VkBuffer buffer; VkBuffer buffer;
VkImage image;
VkDeviceMemory memory; VkDeviceMemory memory;
VkCommandBuffer *cmd_buffers; VkCommandBuffer *cmd_buffers;
} blit; } blit;
@@ -245,6 +247,10 @@ wsi_configure_buffer_image(UNUSED const struct wsi_swapchain *chain,
uint32_t stride_align, uint32_t size_align, uint32_t stride_align, uint32_t size_align,
struct wsi_image_info *info); struct wsi_image_info *info);
void
wsi_configure_image_blit_image(UNUSED const struct wsi_swapchain *chain,
struct wsi_image_info *info);
VkResult VkResult
wsi_configure_image(const struct wsi_swapchain *chain, wsi_configure_image(const struct wsi_swapchain *chain,
const VkSwapchainCreateInfoKHR *pCreateInfo, const VkSwapchainCreateInfoKHR *pCreateInfo,