[PATCH v2 5/6] wined3d: Handle typeless resolve in the Vulkan blitter.

Jan Sikorski jsikorski at codeweavers.com
Tue Mar 9 03:26:12 CST 2021


Signed-off-by: Jan Sikorski <jsikorski at codeweavers.com>
---
 dlls/wined3d/texture.c | 274 +++++++++++++++++++++++++++++++++++++----
 1 file changed, 248 insertions(+), 26 deletions(-)

diff --git a/dlls/wined3d/texture.c b/dlls/wined3d/texture.c
index 7d85413fc5d..fa78cddc69b 100644
--- a/dlls/wined3d/texture.c
+++ b/dlls/wined3d/texture.c
@@ -6500,7 +6500,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, enum wined3d_format_id format_id)
 {
     const struct wined3d_format *src_format = src_resource->format;
     const struct wined3d_format *dst_format = dst_resource->format;
@@ -6532,7 +6532,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))
+                        || (format_id == WINED3DFMT_UNKNOWN)))
         {
             TRACE("Format conversion not supported.\n");
             return false;
@@ -6564,6 +6566,74 @@ static bool vk_blitter_blit_supported(enum wined3d_blit_op op, const struct wine
     return true;
 }
 
+static VkResult create_staging_image_for_resolve(struct wined3d_context_vk *context_vk,
+        VkImageType vk_image_type, VkFormat vk_format, unsigned width, unsigned height, unsigned depth,
+        unsigned sample_count, VkImage *image)
+{
+    struct wined3d_adapter_vk *adapter_vk = wined3d_adapter_vk(context_vk->c.device->adapter);
+    struct wined3d_device_vk *device_vk = wined3d_device_vk(context_vk->c.device);
+    const struct wined3d_vk_info *vk_info = context_vk->vk_info;
+    VkMemoryAllocateInfo allocate_info = {0};
+    VkMemoryRequirements memory_requirements;
+    VkImageCreateInfo create_info;
+    VkDeviceMemory device_memory;
+    VkResult vr;
+
+    create_info.sType = VK_STRUCTURE_TYPE_IMAGE_CREATE_INFO;
+    create_info.pNext = NULL;
+    create_info.flags = 0;
+    create_info.imageType = vk_image_type;
+    create_info.format = vk_format;
+    create_info.extent.width = width;
+    create_info.extent.height = height;
+    create_info.extent.depth = depth;
+    create_info.mipLevels = 1;
+    create_info.arrayLayers = 1;
+    create_info.samples = sample_count;
+    create_info.tiling = VK_IMAGE_TILING_OPTIMAL;
+    create_info.usage = VK_IMAGE_USAGE_TRANSFER_SRC_BIT
+            | VK_IMAGE_USAGE_TRANSFER_DST_BIT
+            | VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT;
+    create_info.sharingMode = VK_SHARING_MODE_EXCLUSIVE;
+    create_info.queueFamilyIndexCount = 0;
+    create_info.pQueueFamilyIndices = NULL;
+    create_info.initialLayout = VK_IMAGE_LAYOUT_UNDEFINED;
+
+    vr = VK_CALL(vkCreateImage(device_vk->vk_device, &create_info, NULL, image));
+    if (vr != VK_SUCCESS)
+    {
+        ERR("Failed to create image, vr %#x.\n", vr);
+        return vr;
+    }
+
+    wined3d_context_vk_destroy_image(context_vk, *image, context_vk->current_command_buffer.id);
+
+    VK_CALL(vkGetImageMemoryRequirements(device_vk->vk_device, *image, &memory_requirements));
+
+    allocate_info.sType = VK_STRUCTURE_TYPE_MEMORY_ALLOCATE_INFO;
+    allocate_info.allocationSize = memory_requirements.size;
+    allocate_info.memoryTypeIndex = wined3d_adapter_vk_get_memory_type_index(adapter_vk,
+            memory_requirements.memoryTypeBits, VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT);
+
+    vr = VK_CALL(vkAllocateMemory(device_vk->vk_device, &allocate_info, NULL, &device_memory));
+    if (vr != VK_SUCCESS)
+    {
+        ERR("Failed to allocate memory, vr %#x.\n", vr);
+        return vr;
+    }
+
+    wined3d_context_vk_destroy_memory(context_vk, device_memory, context_vk->current_command_buffer.id);
+
+    vr = VK_CALL(vkBindImageMemory(device_vk->vk_device, *image, device_memory, 0));
+    if (vr != VK_SUCCESS)
+    {
+        ERR("Failed to bind image memory, vr %#x.\n", vr);
+        return vr;
+    }
+
+    return VK_SUCCESS;
+}
+
 static DWORD vk_blitter_blit(struct wined3d_blitter *blitter, enum wined3d_blit_op op,
         struct wined3d_context *context, struct wined3d_texture *src_texture, unsigned int src_sub_resource_idx,
         DWORD src_location, const RECT *src_rect, struct wined3d_texture *dst_texture,
@@ -6578,21 +6648,23 @@ static DWORD vk_blitter_blit(struct wined3d_blitter *blitter, enum wined3d_blit_
     VkImageAspectFlags src_aspect, dst_aspect;
     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, src_rect %s, "
-            "dst_texture %p, dst_sub_resource_idx %u, dst_location %s, dst_rect %s, colour_key %p, filter %s.\n",
+            "dst_texture %p, dst_sub_resource_idx %u, dst_location %s, dst_rect %s, colour_key %p, filter %s, format_id %s.\n",
             blitter, op, context, src_texture, src_sub_resource_idx, wined3d_debug_location(src_location),
             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));
+            wine_dbgstr_rect(dst_rect), colour_key, debug_d3dtexturefiltertype(filter), debug_d3dformat(format_id));
 
-    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, format_id))
         goto next;
 
     src_aspect = vk_aspect_mask_from_format(src_texture_vk->t.resource.format);
     dst_aspect = vk_aspect_mask_from_format(dst_texture_vk->t.resource.format);
 
-    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;
 
     src_level = src_sub_resource_idx % src_texture->level_count;
@@ -6642,30 +6714,180 @@ static DWORD vk_blitter_blit(struct wined3d_blitter *blitter, enum wined3d_blit_
             dst_texture_vk->layout, VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL,
             dst_texture_vk->vk_image, dst_aspect);
 
+
     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 struct wined3d_format_vk *resolve_format_vk;
+        VkImage src_vk_image, dst_vk_image;
+        VkImageResolve resolve_region;
+        VkImageType vk_image_type;
+        VkImageCopy copy_region;
+        VkFormat vk_format;
+        VkResult vr;
 
-        region.srcSubresource.aspectMask = src_aspect;
-        region.srcSubresource.mipLevel = src_level;
-        region.srcSubresource.baseArrayLayer = src_layer;
-        region.srcSubresource.layerCount = 1;
-        region.srcOffset.x = src_rect->left;
-        region.srcOffset.y = src_rect->top;
-        region.srcOffset.z = 0;
-        region.dstSubresource.aspectMask = dst_aspect;
-        region.dstSubresource.mipLevel = dst_level;
-        region.dstSubresource.baseArrayLayer = dst_layer;
-        region.dstSubresource.layerCount = 1;
-        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;
+        resolve_format_vk = wined3d_format_vk(wined3d_get_format(context->device->adapter, format_id, 0));
 
-        VK_CALL(vkCmdResolveImage(vk_command_buffer, src_texture_vk->vk_image, VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL,
-                dst_texture_vk->vk_image, VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, 1, &region));
+        if (!wined3d_format_is_typeless(&src_format_vk->f))
+        {
+            vk_format = src_format_vk->vk_format;
+        }
+        else if (!wined3d_format_is_typeless(&dst_format_vk->f))
+        {
+            vk_format = dst_format_vk->vk_format;
+        }
+        else
+        {
+            vk_format = resolve_format_vk->vk_format;
+        }
+
+        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 next;
+        }
+
+        resolve_region.dstSubresource.aspectMask = dst_aspect;
+        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)
+        {
+            vr = create_staging_image_for_resolve(context_vk, vk_image_type, vk_format,
+                    resolve_region.extent.width, resolve_region.extent.height, 1, src_sample_count, &src_vk_image);
+            if (vr != VK_SUCCESS)
+                goto next;
+
+            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, src_aspect);
+
+            copy_region.srcSubresource.aspectMask = src_aspect;
+            copy_region.srcSubresource.mipLevel = src_level;
+            copy_region.srcSubresource.baseArrayLayer = src_layer;
+            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 = src_aspect;
+            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->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, src_aspect);
+
+            resolve_region.srcSubresource.aspectMask = src_aspect;
+            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->vk_image;
+
+            resolve_region.srcSubresource.aspectMask = src_aspect;
+            resolve_region.srcSubresource.mipLevel = src_level;
+            resolve_region.srcSubresource.baseArrayLayer = src_layer;
+            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)
+        {
+            vr = create_staging_image_for_resolve(context_vk, vk_image_type, vk_format,
+                    resolve_region.extent.width, resolve_region.extent.height, 1, VK_SAMPLE_COUNT_1_BIT, &dst_vk_image);
+            if (vr != VK_SUCCESS)
+                goto next;
+
+            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, dst_aspect);
+
+            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->vk_image;
+
+            resolve_region.dstSubresource.mipLevel = dst_level;
+            resolve_region.dstSubresource.baseArrayLayer = dst_layer;
+            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->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, dst_aspect);
+
+            copy_region.srcSubresource.aspectMask = dst_aspect;
+            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 = dst_aspect;
+            copy_region.dstSubresource.mipLevel = dst_level;
+            copy_region.dstSubresource.baseArrayLayer = dst_layer;
+            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->vk_image, VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, 1, &copy_region));
+        }
     }
     else
     {
-- 
2.30.1




More information about the wine-devel mailing list