v3dv: implement partial buffer copies to depth/stencil images

Part-of: <https://gitlab.freedesktop.org/mesa/mesa/-/merge_requests/6766>
This commit is contained in:
Iago Toral Quiroga
2020-05-08 11:19:13 +02:00
committed by Marge Bot
parent df364f9e10
commit 21633aa112
+126 -34
View File
@@ -1830,23 +1830,73 @@ copy_buffer_to_image_blit(struct v3dv_cmd_buffer *cmd_buffer,
struct v3dv_buffer *buffer,
const VkBufferImageCopy *region)
{
/* Select a copy format for the blit operation */
VkFormat format;
switch (image->cpp) {
/* Generally, the bpp of the data in the buffer matches that of the
* destination image. The exception is the case where we are uploading
* stencil (8bpp) to a combined d24s8 image (32bpp).
*/
uint32_t buffer_bpp = image->cpp;
const VkImageAspectFlags copy_aspect = region->imageSubresource.aspectMask;
VkImageAspectFlags upload_aspect = copy_aspect;
/* We are about to upload the buffer data to an image so we can then
* blit that to our destination region. Because we are going to implement
* the copy as a blit, we want our blit source and destination formats to be
* the same (to avoid any format conversions), so we choose a canonical
* format that matches the destination image bpp.
*/
VkFormat upload_format;
switch (buffer_bpp) {
case 16:
format = VK_FORMAT_R32G32B32A32_UINT;
assert(copy_aspect == VK_IMAGE_ASPECT_COLOR_BIT);
upload_format = VK_FORMAT_R32G32B32A32_UINT;
break;
case 8:
format = VK_FORMAT_R16G16B16A16_UINT;
assert(copy_aspect == VK_IMAGE_ASPECT_COLOR_BIT);
upload_format = VK_FORMAT_R16G16B16A16_UINT;
break;
case 4:
format = VK_FORMAT_R8G8B8A8_UINT;
switch (copy_aspect) {
case VK_IMAGE_ASPECT_COLOR_BIT:
upload_format = VK_FORMAT_R8G8B8A8_UINT;
break;
case VK_IMAGE_ASPECT_DEPTH_BIT:
assert(image->vk_format == VK_FORMAT_D32_SFLOAT ||
image->vk_format == VK_FORMAT_D24_UNORM_S8_UINT ||
image->vk_format == VK_FORMAT_X8_D24_UNORM_PACK32);
if (!vk_format_has_stencil(image->vk_format))
upload_format = image->vk_format;
else
upload_format = VK_FORMAT_X8_D24_UNORM_PACK32;
break;
case VK_IMAGE_ASPECT_STENCIL_BIT:
/* Since we don't support separate stencil this is always a stencil
* copy to a combined depth/stencil image.
*
* Because we don't support separate stencil images, our copy/blit
* functions don't support them either, so to handle this case we
* upload the buffer to a compatible R8UI color image and then we
* emit a "blit stencil aspect from R8UI to S8D24" which the driver
* will recognize as a stencil blit and will handle properly as a
* special case.
*/
assert(copy_aspect == VK_IMAGE_ASPECT_STENCIL_BIT);
assert(image->vk_format == VK_FORMAT_D24_UNORM_S8_UINT);
upload_aspect = VK_IMAGE_ASPECT_COLOR_BIT;
upload_format = VK_FORMAT_R8_UINT;
buffer_bpp = 1;
break;
default:
unreachable("Unsupported aspect");
};
break;
case 2:
format = VK_FORMAT_R16_UINT;
upload_format = (copy_aspect == VK_IMAGE_ASPECT_COLOR_BIT) ?
VK_FORMAT_R16_UINT : image->vk_format;
break;
case 1:
format = VK_FORMAT_R8_UINT;
assert(copy_aspect == VK_IMAGE_ASPECT_COLOR_BIT);
upload_format = VK_FORMAT_R8_UINT;
break;
default:
unreachable("unsupported bpp");
@@ -1891,7 +1941,7 @@ copy_buffer_to_image_blit(struct v3dv_cmd_buffer *cmd_buffer,
VkImageCreateInfo image_info = {
.sType = VK_STRUCTURE_TYPE_IMAGE_CREATE_INFO,
.imageType = VK_IMAGE_TYPE_2D,
.format = format,
.format = upload_format,
.extent = { buf_width, buf_height, 1 },
.mipLevels = 1,
.arrayLayers = 1,
@@ -1937,13 +1987,13 @@ copy_buffer_to_image_blit(struct v3dv_cmd_buffer *cmd_buffer,
/* Upload buffer contents for the selected layer */
VkDeviceSize buffer_offset =
region->bufferOffset + i * buf_height * buf_width * image->cpp;
region->bufferOffset + i * buf_height * buf_width * buffer_bpp;
const VkBufferImageCopy buffer_image_copy = {
.bufferOffset = buffer_offset,
.bufferRowLength = region->bufferRowLength,
.bufferImageHeight = region->bufferImageHeight,
.imageSubresource = {
.aspectMask = region->imageSubresource.aspectMask,
.aspectMask = upload_aspect,
.mipLevel = 0,
.baseArrayLayer = 0,
.layerCount = 1,
@@ -1959,10 +2009,16 @@ copy_buffer_to_image_blit(struct v3dv_cmd_buffer *cmd_buffer,
/* Blit-copy the requested image extent from the buffer image to the
* destination image.
*
* Since we are copying, the blit must use the same format on the
* destination and source images to avoid format conversions. The
* only exception is copying stencil, which we upload to a R8UI source
* image, but that we need to blit to a S8D24 destination (the only
* stencil format we support).
*/
const VkImageBlit blit_region = {
.srcSubresource = {
.aspectMask = region->imageSubresource.aspectMask,
.aspectMask = copy_aspect,
.mipLevel = 0,
.baseArrayLayer = 0,
.layerCount = 1,
@@ -1985,9 +2041,18 @@ copy_buffer_to_image_blit(struct v3dv_cmd_buffer *cmd_buffer,
},
},
};
VkFormat src_format = upload_format;
VkFormat dst_format;
if (copy_aspect == VK_IMAGE_ASPECT_STENCIL_BIT) {
assert(image->vk_format == VK_FORMAT_D24_UNORM_S8_UINT);
dst_format = image->vk_format;
} else {
dst_format = src_format;
}
bool ok = blit_shader(cmd_buffer,
image, format,
v3dv_image_from_handle(buffer_image), format,
image, dst_format,
v3dv_image_from_handle(buffer_image), src_format,
&blit_region, VK_FILTER_NEAREST);
if (!ok)
return false;
@@ -2830,6 +2895,51 @@ create_blit_pipeline(struct v3dv_device *device,
pipeline);
}
/* The only stencil format that we support is S8D24, which is compatible with
* RGBA8UI, so we implement stencil blits by reinterpreting the operation
* as a color blit to a RGBA8UI render target where we map stencil to the R
* channel and depth to the GBA channels.
*/
static void
rewrite_stencil_blit_spec(VkFormat *dst_format,
VkFormat *src_format,
VkImageAspectFlags *aspects,
VkColorComponentFlags *cmask)
{
if (!(*aspects & VK_IMAGE_ASPECT_STENCIL_BIT))
return;
/* If we are blitting stencil, then we must be blitting from S8D24 to
* S8D24 (in which case we might be blitting depth too) or, as a special
* case, R8UI to S8D24 (in which case we are blitting only stencil). The
* latter is a special case that we use when are copying stencil from a
* buffer to a S8D24 image.
*/
assert(*dst_format == VK_FORMAT_D24_UNORM_S8_UINT);
assert(*src_format == VK_FORMAT_D24_UNORM_S8_UINT ||
(*src_format == VK_FORMAT_R8_UINT &&
*aspects == VK_IMAGE_ASPECT_STENCIL_BIT));
*dst_format = VK_FORMAT_R8G8B8A8_UINT;
if (*src_format == VK_FORMAT_D24_UNORM_S8_UINT)
*src_format = VK_FORMAT_R8G8B8A8_UINT;
/* If we are only copying stencil we want to make sure we only write to the
* R channel, otherwise we would stomp the depth aspect. We only need this
* information to create the blit pipeline.
*/
if (cmask) {
*cmask = VK_COLOR_COMPONENT_R_BIT;
if (*aspects & VK_IMAGE_ASPECT_DEPTH_BIT)
*cmask |= VK_COLOR_COMPONENT_G_BIT |
VK_COLOR_COMPONENT_B_BIT |
VK_COLOR_COMPONENT_A_BIT;
}
*aspects = VK_IMAGE_ASPECT_COLOR_BIT;
}
/**
* Return a pipeline suitable for blitting the requested aspect given the
* destination and source formats.
@@ -2868,16 +2978,7 @@ get_blit_pipeline(struct v3dv_device *device,
if (entry) {
mtx_unlock(&device->meta.mtx);
*pipeline = entry->data;
/* We implement stencil aspect (and stencil+depth) blits with a
* color pipeline.
*/
if (*aspects & VK_IMAGE_ASPECT_STENCIL_BIT) {
*dst_format = VK_FORMAT_R8G8B8A8_UINT;
*src_format = VK_FORMAT_R8G8B8A8_UINT;
*aspects = VK_IMAGE_ASPECT_COLOR_BIT;
}
rewrite_stencil_blit_spec(dst_format, src_format, aspects, NULL);
return true;
}
@@ -2887,20 +2988,11 @@ get_blit_pipeline(struct v3dv_device *device,
if (*pipeline == NULL)
goto fail;
/* We implement stencil aspect (and stencil+depth) blits with a
* color pipeline.
*/
VkColorComponentFlags cmask = VK_COLOR_COMPONENT_R_BIT |
VK_COLOR_COMPONENT_G_BIT |
VK_COLOR_COMPONENT_B_BIT |
VK_COLOR_COMPONENT_A_BIT;
if (*aspects & VK_IMAGE_ASPECT_STENCIL_BIT) {
*dst_format = VK_FORMAT_R8G8B8A8_UINT;
*src_format = VK_FORMAT_R8G8B8A8_UINT;
if (!(*aspects & VK_IMAGE_ASPECT_DEPTH_BIT))
cmask = VK_COLOR_COMPONENT_R_BIT;
*aspects = VK_IMAGE_ASPECT_COLOR_BIT;
}
rewrite_stencil_blit_spec(dst_format, src_format, aspects, &cmask);
ok = create_blit_render_pass(device, *aspects, *dst_format, *src_format,
&(*pipeline)->pass);