wined3d: Handle typeless resolve in the Vulkan blitter.

Signed-off-by: Jan Sikorski <jsikorski@codeweavers.com>
Signed-off-by: Henri Verbeet <hverbeet@codeweavers.com>
Signed-off-by: Alexandre Julliard <julliard@winehq.org>
This commit is contained in:
Jan Sikorski 2021-04-19 11:16:58 +02:00 committed by Alexandre Julliard
parent 9e04985a60
commit 73c2466179
1 changed files with 211 additions and 24 deletions

View File

@ -6354,7 +6354,7 @@ static void vk_blitter_clear(struct wined3d_blitter *blitter, struct wined3d_dev
static bool vk_blitter_blit_supported(enum wined3d_blit_op op, const struct wined3d_context *context,
const struct wined3d_resource *src_resource, const RECT *src_rect,
const struct wined3d_resource *dst_resource, const RECT *dst_rect)
const struct wined3d_resource *dst_resource, const RECT *dst_rect, const struct wined3d_format *resolve_format)
{
const struct wined3d_format *src_format = src_resource->format;
const struct wined3d_format *dst_format = dst_resource->format;
@ -6386,7 +6386,9 @@ static bool vk_blitter_blit_supported(enum wined3d_blit_op op, const struct wine
}
if (op != WINED3D_BLIT_OP_RAW_BLIT
&& wined3d_format_vk(src_format)->vk_format != wined3d_format_vk(dst_format)->vk_format)
&& wined3d_format_vk(src_format)->vk_format != wined3d_format_vk(dst_format)->vk_format
&& ((!wined3d_format_is_typeless(src_format) && !wined3d_format_is_typeless(dst_format))
|| !resolve_format))
{
TRACE("Format conversion not supported.\n");
return false;
@ -6432,6 +6434,7 @@ static DWORD vk_blitter_blit(struct wined3d_blitter *blitter, enum wined3d_blit_
VkImageSubresourceRange vk_src_range, vk_dst_range;
VkCommandBuffer vk_command_buffer;
struct wined3d_blitter *next;
unsigned src_sample_count;
bool resolve = false;
TRACE("blitter %p, op %#x, context %p, src_texture %p, src_sub_resource_idx %u, src_location %s, "
@ -6441,10 +6444,12 @@ static DWORD vk_blitter_blit(struct wined3d_blitter *blitter, enum wined3d_blit_
wine_dbgstr_rect(src_rect), dst_texture, dst_sub_resource_idx, wined3d_debug_location(dst_location),
wine_dbgstr_rect(dst_rect), colour_key, debug_d3dtexturefiltertype(filter), resolve_format);
if (!vk_blitter_blit_supported(op, context, &src_texture->resource, src_rect, &dst_texture->resource, dst_rect))
if (!vk_blitter_blit_supported(op, context, &src_texture->resource, src_rect, &dst_texture->resource, dst_rect,
resolve_format))
goto next;
if (wined3d_resource_get_sample_count(&src_texture_vk->t.resource) > 1)
src_sample_count = wined3d_resource_get_sample_count(&src_texture_vk->t.resource);
if (src_sample_count > 1)
resolve = true;
vk_src_range.aspectMask = vk_aspect_mask_from_format(src_texture_vk->t.resource.format);
@ -6502,28 +6507,196 @@ static DWORD vk_blitter_blit(struct wined3d_blitter *blitter, enum wined3d_blit_
if (resolve)
{
VkImageResolve region;
const struct wined3d_format_vk *src_format_vk = wined3d_format_vk(src_texture->resource.format);
const struct wined3d_format_vk *dst_format_vk = wined3d_format_vk(dst_texture->resource.format);
const unsigned int usage = VK_IMAGE_USAGE_TRANSFER_SRC_BIT
| VK_IMAGE_USAGE_TRANSFER_DST_BIT | VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT;
VkImage src_vk_image, dst_vk_image;
VkImageSubresourceRange vk_range;
VkImageResolve resolve_region;
VkImageType vk_image_type;
VkImageCopy copy_region;
VkFormat vk_format;
region.srcSubresource.aspectMask = vk_src_range.aspectMask;
region.srcSubresource.mipLevel = vk_src_range.baseMipLevel;
region.srcSubresource.baseArrayLayer = vk_src_range.baseArrayLayer;
region.srcSubresource.layerCount = vk_src_range.layerCount;
region.srcOffset.x = src_rect->left;
region.srcOffset.y = src_rect->top;
region.srcOffset.z = 0;
region.dstSubresource.aspectMask = vk_dst_range.aspectMask;
region.dstSubresource.mipLevel = vk_dst_range.baseMipLevel;
region.dstSubresource.baseArrayLayer = vk_dst_range.baseArrayLayer;
region.dstSubresource.layerCount = vk_dst_range.layerCount;
region.dstOffset.x = dst_rect->left;
region.dstOffset.y = dst_rect->top;
region.dstOffset.z = 0;
region.extent.width = src_rect->right - src_rect->left;
region.extent.height = src_rect->bottom - src_rect->top;
region.extent.depth = 1;
if (resolve_format)
{
vk_format = wined3d_format_vk(resolve_format)->vk_format;
}
else if (!wined3d_format_is_typeless(src_texture->resource.format))
{
vk_format = src_format_vk->vk_format;
}
else
{
vk_format = dst_format_vk->vk_format;
}
VK_CALL(vkCmdResolveImage(vk_command_buffer, src_texture_vk->image.vk_image, VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL,
dst_texture_vk->image.vk_image, VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, 1, &region));
switch (src_texture->resource.type)
{
case WINED3D_RTYPE_TEXTURE_1D:
vk_image_type = VK_IMAGE_TYPE_1D;
break;
case WINED3D_RTYPE_TEXTURE_2D:
vk_image_type = VK_IMAGE_TYPE_2D;
break;
case WINED3D_RTYPE_TEXTURE_3D:
vk_image_type = VK_IMAGE_TYPE_3D;
break;
default:
ERR("Unexpected resource type: %s\n", debug_d3dresourcetype(src_texture->resource.type));
goto barrier_next;
}
vk_range.baseMipLevel = 0;
vk_range.levelCount = 1;
vk_range.baseArrayLayer = 0;
vk_range.layerCount = 1;
resolve_region.srcSubresource.aspectMask = vk_src_range.aspectMask;
resolve_region.dstSubresource.aspectMask = vk_dst_range.aspectMask;
resolve_region.extent.width = src_rect->right - src_rect->left;
resolve_region.extent.height = src_rect->bottom - src_rect->top;
resolve_region.extent.depth = 1;
/* In case of typeless resolve the texture type may not match the resolve type.
* To handle that, allocate intermediate texture(s) to resolve from/to.
* A possible performance improvement would be to resolve using a shader instead. */
if (src_format_vk->vk_format != vk_format)
{
struct wined3d_image_vk src_image;
if (!wined3d_context_vk_create_image(context_vk, vk_image_type, usage, vk_format,
resolve_region.extent.width, resolve_region.extent.height, 1,
src_sample_count, 1, 1, 0, &src_image))
goto barrier_next;
wined3d_context_vk_reference_image(context_vk, &src_image);
src_vk_image = src_image.vk_image;
wined3d_context_vk_destroy_image(context_vk, &src_image);
vk_range.aspectMask = vk_src_range.aspectMask;
wined3d_context_vk_image_barrier(context_vk, vk_command_buffer,
VK_PIPELINE_STAGE_TOP_OF_PIPE_BIT, VK_PIPELINE_STAGE_TRANSFER_BIT,
0, VK_ACCESS_TRANSFER_WRITE_BIT, VK_IMAGE_LAYOUT_UNDEFINED,
VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, src_vk_image, &vk_range);
copy_region.srcSubresource.aspectMask = vk_src_range.aspectMask;
copy_region.srcSubresource.mipLevel = vk_src_range.baseMipLevel;
copy_region.srcSubresource.baseArrayLayer = vk_src_range.baseArrayLayer;
copy_region.srcSubresource.layerCount = 1;
copy_region.srcOffset.x = src_rect->left;
copy_region.srcOffset.y = src_rect->top;
copy_region.srcOffset.z = 0;
copy_region.dstSubresource.aspectMask = vk_src_range.aspectMask;
copy_region.dstSubresource.mipLevel = 0;
copy_region.dstSubresource.baseArrayLayer = 0;
copy_region.dstSubresource.layerCount = 1;
copy_region.dstOffset.x = 0;
copy_region.dstOffset.y = 0;
copy_region.dstOffset.z = 0;
copy_region.extent.width = resolve_region.extent.width;
copy_region.extent.height = resolve_region.extent.height;
copy_region.extent.depth = 1;
VK_CALL(vkCmdCopyImage(vk_command_buffer, src_texture_vk->image.vk_image,
VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL, src_vk_image, VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL,
1, &copy_region));
wined3d_context_vk_image_barrier(context_vk, vk_command_buffer,
VK_PIPELINE_STAGE_TRANSFER_BIT, VK_PIPELINE_STAGE_TRANSFER_BIT,
VK_ACCESS_TRANSFER_WRITE_BIT, VK_ACCESS_TRANSFER_READ_BIT,
VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL,
src_vk_image, &vk_range);
resolve_region.srcSubresource.mipLevel = 0;
resolve_region.srcSubresource.baseArrayLayer = 0;
resolve_region.srcSubresource.layerCount = 1;
resolve_region.srcOffset.x = 0;
resolve_region.srcOffset.y = 0;
resolve_region.srcOffset.z = 0;
}
else
{
src_vk_image = src_texture_vk->image.vk_image;
resolve_region.srcSubresource.mipLevel = vk_src_range.baseMipLevel;
resolve_region.srcSubresource.baseArrayLayer = vk_src_range.baseArrayLayer;
resolve_region.srcSubresource.layerCount = 1;
resolve_region.srcOffset.x = src_rect->left;
resolve_region.srcOffset.y = src_rect->top;
resolve_region.srcOffset.z = 0;
}
if (dst_format_vk->vk_format != vk_format)
{
struct wined3d_image_vk dst_image;
if (!wined3d_context_vk_create_image(context_vk, vk_image_type, usage, vk_format,
resolve_region.extent.width, resolve_region.extent.height, 1,
VK_SAMPLE_COUNT_1_BIT, 1, 1, 0, &dst_image))
goto barrier_next;
wined3d_context_vk_reference_image(context_vk, &dst_image);
dst_vk_image = dst_image.vk_image;
wined3d_context_vk_destroy_image(context_vk, &dst_image);
vk_range.aspectMask = vk_dst_range.aspectMask;
wined3d_context_vk_image_barrier(context_vk, vk_command_buffer,
VK_PIPELINE_STAGE_TOP_OF_PIPE_BIT, VK_PIPELINE_STAGE_TRANSFER_BIT, 0, VK_ACCESS_TRANSFER_WRITE_BIT,
VK_IMAGE_LAYOUT_UNDEFINED, VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, dst_vk_image, &vk_range);
resolve_region.dstSubresource.mipLevel = 0;
resolve_region.dstSubresource.baseArrayLayer = 0;
resolve_region.dstSubresource.layerCount = 1;
resolve_region.dstOffset.x = 0;
resolve_region.dstOffset.y = 0;
resolve_region.dstOffset.z = 0;
}
else
{
dst_vk_image = dst_texture_vk->image.vk_image;
resolve_region.dstSubresource.mipLevel = vk_dst_range.baseMipLevel;
resolve_region.dstSubresource.baseArrayLayer = vk_dst_range.baseArrayLayer;
resolve_region.dstSubresource.layerCount = 1;
resolve_region.dstOffset.x = dst_rect->left;
resolve_region.dstOffset.y = dst_rect->top;
resolve_region.dstOffset.z = 0;
}
VK_CALL(vkCmdResolveImage(vk_command_buffer, src_vk_image, VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL,
dst_vk_image, VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, 1, &resolve_region));
if (dst_vk_image != dst_texture_vk->image.vk_image)
{
wined3d_context_vk_image_barrier(context_vk, vk_command_buffer,
VK_PIPELINE_STAGE_TRANSFER_BIT, VK_PIPELINE_STAGE_TRANSFER_BIT,
VK_ACCESS_TRANSFER_WRITE_BIT, VK_ACCESS_TRANSFER_READ_BIT,
VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL,
dst_vk_image, &vk_range);
copy_region.srcSubresource.aspectMask = vk_dst_range.aspectMask;
copy_region.srcSubresource.mipLevel = 0;
copy_region.srcSubresource.baseArrayLayer = 0;
copy_region.srcSubresource.layerCount = 1;
copy_region.srcOffset.x = 0;
copy_region.srcOffset.y = 0;
copy_region.srcOffset.z = 0;
copy_region.dstSubresource.aspectMask = vk_dst_range.aspectMask;
copy_region.dstSubresource.mipLevel = vk_dst_range.baseMipLevel;
copy_region.dstSubresource.baseArrayLayer = vk_dst_range.baseArrayLayer;
copy_region.dstSubresource.layerCount = 1;
copy_region.dstOffset.x = dst_rect->left;
copy_region.dstOffset.y = dst_rect->top;
copy_region.dstOffset.z = 0;
copy_region.extent.width = resolve_region.extent.width;
copy_region.extent.height = resolve_region.extent.height;
copy_region.extent.depth = 1;
VK_CALL(vkCmdCopyImage(vk_command_buffer, dst_vk_image, VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL,
dst_texture_vk->image.vk_image, VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, 1, &copy_region));
}
}
else
{
@ -6574,6 +6747,20 @@ static DWORD vk_blitter_blit(struct wined3d_blitter *blitter, enum wined3d_blit_
return dst_location | WINED3D_LOCATION_TEXTURE_RGB;
barrier_next:
wined3d_context_vk_image_barrier(context_vk, vk_command_buffer,
VK_PIPELINE_STAGE_TRANSFER_BIT, VK_PIPELINE_STAGE_ALL_COMMANDS_BIT,
VK_ACCESS_TRANSFER_WRITE_BIT,
vk_access_mask_from_bind_flags(dst_texture_vk->t.resource.bind_flags),
VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, dst_texture_vk->layout,
dst_texture_vk->image.vk_image, &vk_dst_range);
wined3d_context_vk_image_barrier(context_vk, vk_command_buffer,
VK_PIPELINE_STAGE_TRANSFER_BIT, VK_PIPELINE_STAGE_ALL_COMMANDS_BIT,
VK_ACCESS_TRANSFER_READ_BIT,
vk_access_mask_from_bind_flags(src_texture_vk->t.resource.bind_flags),
VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL, src_texture_vk->layout,
src_texture_vk->image.vk_image, &vk_src_range);
next:
if (!(next = blitter->next))
{