[PATCH] wined3d: Implement automatic mip-map generation for the Vulkan adapter.

Henri Verbeet hverbeet at codeweavers.com
Fri Mar 12 10:59:06 CST 2021


Signed-off-by: Henri Verbeet <hverbeet at codeweavers.com>
---
 dlls/wined3d/adapter_gl.c      |   9 ++
 dlls/wined3d/adapter_vk.c      |   9 ++
 dlls/wined3d/cs.c              |   6 +-
 dlls/wined3d/utils.c           |   3 +
 dlls/wined3d/view.c            | 153 ++++++++++++++++++++++++++++++---
 dlls/wined3d/wined3d_private.h |   6 +-
 6 files changed, 172 insertions(+), 14 deletions(-)

diff --git a/dlls/wined3d/adapter_gl.c b/dlls/wined3d/adapter_gl.c
index 93f0e385e41..c3ce959a14f 100644
--- a/dlls/wined3d/adapter_gl.c
+++ b/dlls/wined3d/adapter_gl.c
@@ -5028,6 +5028,14 @@ static void adapter_gl_clear_uav(struct wined3d_context *context,
             clear_value, wined3d_context_gl(context));
 }
 
+static void adapter_gl_generate_mipmap(struct wined3d_context *context, struct wined3d_shader_resource_view *view)
+{
+    TRACE("context %p, view %p.\n", context, view);
+
+    wined3d_shader_resource_view_gl_generate_mipmap(wined3d_shader_resource_view_gl(view),
+            wined3d_context_gl(context));
+}
+
 static const struct wined3d_adapter_ops wined3d_adapter_gl_ops =
 {
     .adapter_destroy = adapter_gl_destroy,
@@ -5062,6 +5070,7 @@ static const struct wined3d_adapter_ops wined3d_adapter_gl_ops =
     .adapter_draw_primitive = draw_primitive,
     .adapter_dispatch_compute = dispatch_compute,
     .adapter_clear_uav = adapter_gl_clear_uav,
+    .adapter_generate_mipmap = adapter_gl_generate_mipmap,
 };
 
 static void wined3d_adapter_gl_init_d3d_info(struct wined3d_adapter_gl *adapter_gl, uint32_t wined3d_creation_flags)
diff --git a/dlls/wined3d/adapter_vk.c b/dlls/wined3d/adapter_vk.c
index 7360ad33e40..973aebac9fa 100644
--- a/dlls/wined3d/adapter_vk.c
+++ b/dlls/wined3d/adapter_vk.c
@@ -1759,6 +1759,14 @@ static void adapter_vk_clear_uav(struct wined3d_context *context,
             clear_value, wined3d_context_vk(context));
 }
 
+static void adapter_vk_generate_mipmap(struct wined3d_context *context, struct wined3d_shader_resource_view *view)
+{
+    TRACE("context %p, view %p.\n", context, view);
+
+    wined3d_shader_resource_view_vk_generate_mipmap(wined3d_shader_resource_view_vk(view),
+            wined3d_context_vk(context));
+}
+
 static const struct wined3d_adapter_ops wined3d_adapter_vk_ops =
 {
     .adapter_destroy = adapter_vk_destroy,
@@ -1793,6 +1801,7 @@ static const struct wined3d_adapter_ops wined3d_adapter_vk_ops =
     .adapter_draw_primitive = adapter_vk_draw_primitive,
     .adapter_dispatch_compute = adapter_vk_dispatch_compute,
     .adapter_clear_uav = adapter_vk_clear_uav,
+    .adapter_generate_mipmap = adapter_vk_generate_mipmap,
 };
 
 static unsigned int wined3d_get_wine_vk_version(void)
diff --git a/dlls/wined3d/cs.c b/dlls/wined3d/cs.c
index 2aaeeab95a6..6bb628b5d13 100644
--- a/dlls/wined3d/cs.c
+++ b/dlls/wined3d/cs.c
@@ -2596,8 +2596,12 @@ static void wined3d_cs_exec_generate_mipmaps(struct wined3d_cs *cs, const void *
 {
     const struct wined3d_cs_generate_mipmaps *op = data;
     struct wined3d_shader_resource_view *view = op->view;
+    struct wined3d_context *context;
+
+    context = context_acquire(cs->c.device, NULL, 0);
+    cs->c.device->adapter->adapter_ops->adapter_generate_mipmap(context, view);
+    context_release(context);
 
-    shader_resource_view_generate_mipmaps(view);
     wined3d_resource_release(view->resource);
 }
 
diff --git a/dlls/wined3d/utils.c b/dlls/wined3d/utils.c
index 66caf8249f5..11284d19811 100644
--- a/dlls/wined3d/utils.c
+++ b/dlls/wined3d/utils.c
@@ -4225,6 +4225,9 @@ static void init_vulkan_format_info(struct wined3d_format_vk *format,
         flags |= WINED3DFMT_FLAG_UNORDERED_ACCESS;
     }
 
+    if (!(~flags & (WINED3DFMT_FLAG_RENDERTARGET | WINED3DFMT_FLAG_FILTERING)))
+        flags |= WINED3DFMT_FLAG_GEN_MIPMAP;
+
     format->f.flags[WINED3D_GL_RES_TYPE_TEX_1D] |= flags;
     format->f.flags[WINED3D_GL_RES_TYPE_TEX_2D] |= flags;
     format->f.flags[WINED3D_GL_RES_TYPE_TEX_3D] |= flags;
diff --git a/dlls/wined3d/view.c b/dlls/wined3d/view.c
index 9650f6c08e3..74a100405aa 100644
--- a/dlls/wined3d/view.c
+++ b/dlls/wined3d/view.c
@@ -1194,23 +1194,18 @@ static void shader_resource_view_gl_bind_and_dirtify(struct wined3d_shader_resou
     wined3d_context_gl_bind_texture(context_gl, view_gl->gl_view.target, view_gl->gl_view.name);
 }
 
-void shader_resource_view_generate_mipmaps(struct wined3d_shader_resource_view *view)
+void wined3d_shader_resource_view_gl_generate_mipmap(struct wined3d_shader_resource_view_gl *view_gl,
+        struct wined3d_context_gl *context_gl)
 {
-    struct wined3d_shader_resource_view_gl *view_gl = wined3d_shader_resource_view_gl(view);
     unsigned int i, j, layer_count, level_count, base_level, max_level;
-    const struct wined3d_gl_info *gl_info;
+    const struct wined3d_gl_info *gl_info = context_gl->gl_info;
     struct wined3d_texture_gl *texture_gl;
-    struct wined3d_context_gl *context_gl;
-    struct wined3d_context *context;
     struct gl_texture *gl_tex;
     DWORD location;
     BOOL srgb;
 
-    TRACE("view %p.\n", view);
+    TRACE("view_gl %p.\n", view_gl);
 
-    context = context_acquire(view_gl->v.resource->device, NULL, 0);
-    context_gl = wined3d_context_gl(context);
-    gl_info = context_gl->gl_info;
     layer_count = view_gl->v.desc.u.texture.layer_count;
     level_count = view_gl->v.desc.u.texture.level_count;
     base_level = view_gl->v.desc.u.texture.level_idx;
@@ -1220,7 +1215,9 @@ void shader_resource_view_generate_mipmaps(struct wined3d_shader_resource_view *
     srgb = !!(texture_gl->t.flags & WINED3D_TEXTURE_IS_SRGB);
     location = srgb ? WINED3D_LOCATION_TEXTURE_SRGB : WINED3D_LOCATION_TEXTURE_RGB;
     for (i = 0; i < layer_count; ++i)
-        wined3d_texture_load_location(&texture_gl->t, i * level_count + base_level, context, location);
+    {
+        wined3d_texture_load_location(&texture_gl->t, i * level_count + base_level, &context_gl->c, location);
+    }
 
     if (view_gl->gl_view.name)
     {
@@ -1236,7 +1233,7 @@ void shader_resource_view_generate_mipmaps(struct wined3d_shader_resource_view *
     if (gl_info->supported[ARB_SAMPLER_OBJECTS])
         GL_EXTCALL(glBindSampler(context_gl->active_texture, 0));
     gl_tex = wined3d_texture_gl_get_gl_texture(texture_gl, srgb);
-    if (context->d3d_info->wined3d_creation_flags & WINED3D_SRGB_READ_WRITE_CONTROL)
+    if (context_gl->c.d3d_info->wined3d_creation_flags & WINED3D_SRGB_READ_WRITE_CONTROL)
     {
         gl_info->gl_ops.gl.p_glTexParameteri(texture_gl->target,
                 GL_TEXTURE_SRGB_DECODE_EXT, GL_SKIP_DECODE_EXT);
@@ -1261,8 +1258,140 @@ void shader_resource_view_generate_mipmaps(struct wined3d_shader_resource_view *
         gl_info->gl_ops.gl.p_glTexParameteri(texture_gl->target,
                 GL_TEXTURE_MAX_LEVEL, texture_gl->t.level_count - 1);
     }
+}
 
-    context_release(context);
+void wined3d_shader_resource_view_vk_generate_mipmap(struct wined3d_shader_resource_view_vk *srv_vk,
+        struct wined3d_context_vk *context_vk)
+{
+    unsigned int i, j, layer_count, level_count, base_level, base_layer;
+    const struct wined3d_vk_info *vk_info = context_vk->vk_info;
+    VkImageSubresourceRange vk_src_range, vk_dst_range;
+    struct wined3d_texture_vk *texture_vk;
+    VkCommandBuffer vk_command_buffer;
+    VkImageBlit region;
+
+    TRACE("srv_vk %p.\n", srv_vk);
+
+    layer_count = srv_vk->v.desc.u.texture.layer_count;
+    level_count = srv_vk->v.desc.u.texture.level_count;
+    base_level = srv_vk->v.desc.u.texture.level_idx;
+    base_layer = srv_vk->v.desc.u.texture.layer_idx;
+
+    texture_vk = wined3d_texture_vk(texture_from_resource(srv_vk->v.resource));
+    for (i = 0; i < layer_count; ++i)
+    {
+        if (!wined3d_texture_load_location(&texture_vk->t,
+                (base_layer + i) * level_count + base_level, &context_vk->c, WINED3D_LOCATION_TEXTURE_RGB))
+            ERR("Failed to load source layer %u.\n", base_layer + i);
+    }
+
+    if (context_vk->c.d3d_info->wined3d_creation_flags & WINED3D_SRGB_READ_WRITE_CONTROL)
+        FIXME("Unhandled sRGB read/write control.\n");
+
+    if (wined3d_format_vk(srv_vk->v.format)->vk_format != wined3d_format_vk(texture_vk->t.resource.format)->vk_format)
+        FIXME("Ignoring view format %s.\n", debug_d3dformat(srv_vk->v.format->id));
+
+    if (wined3d_resource_get_sample_count(&texture_vk->t.resource) > 1)
+        FIXME("Unhandled multi-sampled resource.\n");
+
+    if (!(vk_command_buffer = wined3d_context_vk_get_command_buffer(context_vk)))
+    {
+        ERR("Failed to get command buffer.\n");
+        return;
+    }
+
+    vk_src_range.aspectMask = vk_aspect_mask_from_format(texture_vk->t.resource.format);
+    vk_src_range.baseMipLevel = base_level;
+    vk_src_range.levelCount = 1;
+    vk_src_range.baseArrayLayer = base_layer;
+    vk_src_range.layerCount = layer_count;
+
+    vk_dst_range = vk_src_range;
+    ++vk_dst_range.baseMipLevel;
+
+    wined3d_context_vk_image_barrier(context_vk, vk_command_buffer,
+            VK_PIPELINE_STAGE_ALL_COMMANDS_BIT, VK_PIPELINE_STAGE_TRANSFER_BIT,
+            vk_access_mask_from_bind_flags(texture_vk->t.resource.bind_flags),
+            VK_ACCESS_TRANSFER_READ_BIT,
+            texture_vk->layout, VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL,
+            texture_vk->vk_image, &vk_src_range);
+    wined3d_context_vk_image_barrier(context_vk, vk_command_buffer,
+            VK_PIPELINE_STAGE_ALL_COMMANDS_BIT, VK_PIPELINE_STAGE_TRANSFER_BIT,
+            vk_access_mask_from_bind_flags(texture_vk->t.resource.bind_flags),
+            VK_ACCESS_TRANSFER_WRITE_BIT,
+            texture_vk->layout, VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL,
+            texture_vk->vk_image, &vk_dst_range);
+
+    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.srcOffsets[0].x = 0;
+    region.srcOffsets[0].y = 0;
+    region.srcOffsets[0].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.dstOffsets[0].x = 0;
+    region.dstOffsets[0].y = 0;
+    region.dstOffsets[0].z = 0;
+
+    for (i = 1; i < level_count; ++i)
+    {
+        region.srcOffsets[1].x = wined3d_texture_get_level_width(&texture_vk->t, vk_src_range.baseMipLevel);
+        region.srcOffsets[1].y = wined3d_texture_get_level_height(&texture_vk->t, vk_src_range.baseMipLevel);
+        region.srcOffsets[1].z = wined3d_texture_get_level_depth(&texture_vk->t, vk_src_range.baseMipLevel);
+
+        region.dstOffsets[1].x = wined3d_texture_get_level_width(&texture_vk->t, vk_dst_range.baseMipLevel);
+        region.dstOffsets[1].y = wined3d_texture_get_level_height(&texture_vk->t, vk_dst_range.baseMipLevel);
+        region.dstOffsets[1].z = wined3d_texture_get_level_depth(&texture_vk->t, vk_dst_range.baseMipLevel);
+
+        VK_CALL(vkCmdBlitImage(vk_command_buffer, texture_vk->vk_image, VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL,
+                texture_vk->vk_image, VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, 1, &region, VK_FILTER_LINEAR));
+
+        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(texture_vk->t.resource.bind_flags),
+                VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL, texture_vk->layout,
+                texture_vk->vk_image, &vk_src_range);
+
+        if (i == level_count - 1)
+        {
+            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(texture_vk->t.resource.bind_flags),
+                    VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, texture_vk->layout,
+                    texture_vk->vk_image, &vk_dst_range);
+        }
+        else
+        {
+            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,
+                    texture_vk->vk_image, &vk_dst_range);
+
+            region.srcSubresource.mipLevel = ++vk_src_range.baseMipLevel;
+            region.dstSubresource.mipLevel = ++vk_dst_range.baseMipLevel;
+        }
+    }
+
+    for (i = 0; i < layer_count; ++i)
+    {
+        for (j = 1; j < level_count; ++j)
+        {
+            wined3d_texture_validate_location(&texture_vk->t,
+                    (base_layer + i) * level_count + base_level + j, WINED3D_LOCATION_TEXTURE_RGB);
+            wined3d_texture_invalidate_location(&texture_vk->t,
+                    (base_layer + i) * level_count + base_level + j, ~WINED3D_LOCATION_TEXTURE_RGB);
+        }
+    }
+
+    wined3d_context_vk_reference_texture(context_vk, texture_vk);
 }
 
 void CDECL wined3d_shader_resource_view_generate_mipmaps(struct wined3d_shader_resource_view *view)
diff --git a/dlls/wined3d/wined3d_private.h b/dlls/wined3d/wined3d_private.h
index d4f1e4a9173..86d8061d005 100644
--- a/dlls/wined3d/wined3d_private.h
+++ b/dlls/wined3d/wined3d_private.h
@@ -3344,6 +3344,7 @@ struct wined3d_adapter_ops
             const struct wined3d_dispatch_parameters *parameters);
     void (*adapter_clear_uav)(struct wined3d_context *context,
             struct wined3d_unordered_access_view *view, const struct wined3d_uvec4 *clear_value);
+    void (*adapter_generate_mipmap)(struct wined3d_context *context, struct wined3d_shader_resource_view *view);
 };
 
 struct wined3d_output
@@ -5051,7 +5052,6 @@ struct wined3d_shader_resource_view
 };
 
 void wined3d_shader_resource_view_cleanup(struct wined3d_shader_resource_view *view) DECLSPEC_HIDDEN;
-void shader_resource_view_generate_mipmaps(struct wined3d_shader_resource_view *view) DECLSPEC_HIDDEN;
 
 struct wined3d_shader_resource_view_gl
 {
@@ -5068,6 +5068,8 @@ static inline struct wined3d_shader_resource_view_gl *wined3d_shader_resource_vi
 
 void wined3d_shader_resource_view_gl_bind(struct wined3d_shader_resource_view_gl *view_gl, unsigned int unit,
         struct wined3d_sampler_gl *sampler_gl, struct wined3d_context_gl *context_gl) DECLSPEC_HIDDEN;
+void wined3d_shader_resource_view_gl_generate_mipmap(struct wined3d_shader_resource_view_gl *srv_gl,
+        struct wined3d_context_gl *context_gl) DECLSPEC_HIDDEN;
 HRESULT wined3d_shader_resource_view_gl_init(struct wined3d_shader_resource_view_gl *view_gl,
         const struct wined3d_view_desc *desc, struct wined3d_resource *resource,
         void *parent, const struct wined3d_parent_ops *parent_ops) DECLSPEC_HIDDEN;
@@ -5103,6 +5105,8 @@ static inline void wined3d_shader_resource_view_vk_barrier(struct wined3d_shader
     wined3d_resource_vk_barrier(srv_vk->v.resource, context_vk, bind_mask);
 }
 
+void wined3d_shader_resource_view_vk_generate_mipmap(struct wined3d_shader_resource_view_vk *srv_vk,
+        struct wined3d_context_vk *context_vk) DECLSPEC_HIDDEN;
 HRESULT wined3d_shader_resource_view_vk_init(struct wined3d_shader_resource_view_vk *view_vk,
         const struct wined3d_view_desc *desc, struct wined3d_resource *resource,
         void *parent, const struct wined3d_parent_ops *parent_ops) DECLSPEC_HIDDEN;
-- 
2.20.1




More information about the wine-devel mailing list