Signed-off-by: Jan Sikorski jsikorski@codeweavers.com -- v5: Handle NULL resolve format, added image barriers in the failure case, whitespace fix --- dlls/wined3d/texture.c | 235 ++++++++++++++++++++++++++++++++++++----- 1 file changed, 211 insertions(+), 24 deletions(-)
diff --git a/dlls/wined3d/texture.c b/dlls/wined3d/texture.c index 333002ebfd5..43920944544 100644 --- a/dlls/wined3d/texture.c +++ b/dlls/wined3d/texture.c @@ -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; + + 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; + }
- 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; + 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_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, ®ion)); + 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, ©_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, ©_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)) {