[PATCH 5/6] wined3d: Implement manual mipmap generation.

Matteo Bruni mbruni at codeweavers.com
Mon Dec 4 11:07:31 CST 2017


Signed-off-by: Matteo Bruni <mbruni at codeweavers.com>
---
 dlls/wined3d/cs.c              |  30 ++++++++++++
 dlls/wined3d/texture.c         |  11 -----
 dlls/wined3d/view.c            | 102 +++++++++++++++++++++++++++++++++++++++++
 dlls/wined3d/wined3d.spec      |   2 +-
 dlls/wined3d/wined3d_private.h |   2 +
 include/wine/wined3d.h         |   2 +-
 6 files changed, 136 insertions(+), 13 deletions(-)

diff --git a/dlls/wined3d/cs.c b/dlls/wined3d/cs.c
index f7c943e98e..dbe9f42beb 100644
--- a/dlls/wined3d/cs.c
+++ b/dlls/wined3d/cs.c
@@ -71,6 +71,7 @@ enum wined3d_cs_op
     WINED3D_CS_OP_ADD_DIRTY_TEXTURE_REGION,
     WINED3D_CS_OP_CLEAR_UNORDERED_ACCESS_VIEW,
     WINED3D_CS_OP_COPY_UAV_COUNTER,
+    WINED3D_CS_OP_GENERATE_MIPMAPS,
     WINED3D_CS_OP_STOP,
 };
 
@@ -421,6 +422,12 @@ struct wined3d_cs_copy_uav_counter
     struct wined3d_unordered_access_view *view;
 };
 
+struct wined3d_cs_generate_mipmaps
+{
+    enum wined3d_cs_op opcode;
+    struct wined3d_shader_resource_view *view;
+};
+
 struct wined3d_cs_stop
 {
     enum wined3d_cs_op opcode;
@@ -2336,6 +2343,28 @@ void wined3d_cs_emit_copy_uav_counter(struct wined3d_cs *cs, struct wined3d_buff
     cs->ops->submit(cs, WINED3D_CS_QUEUE_DEFAULT);
 }
 
+static void wined3d_cs_exec_generate_mipmaps(struct wined3d_cs *cs, const void *data)
+{
+    const struct wined3d_cs_generate_mipmaps *op = data;
+    struct wined3d_shader_resource_view *view = op->view;
+
+    shader_resource_view_generate_mipmaps(view);
+    wined3d_resource_release(view->resource);
+}
+
+void wined3d_cs_emit_generate_mipmaps(struct wined3d_cs *cs, struct wined3d_shader_resource_view *view)
+{
+    struct wined3d_cs_generate_mipmaps *op;
+
+    op = cs->ops->require_space(cs, sizeof(*op), WINED3D_CS_QUEUE_DEFAULT);
+    op->opcode = WINED3D_CS_OP_GENERATE_MIPMAPS;
+    op->view = view;
+
+    wined3d_resource_acquire(view->resource);
+
+    cs->ops->submit(cs, WINED3D_CS_QUEUE_DEFAULT);
+}
+
 static void wined3d_cs_emit_stop(struct wined3d_cs *cs)
 {
     struct wined3d_cs_stop *op;
@@ -2394,6 +2423,7 @@ static void (* const wined3d_cs_op_handlers[])(struct wined3d_cs *cs, const void
     /* WINED3D_CS_OP_ADD_DIRTY_TEXTURE_REGION    */ wined3d_cs_exec_add_dirty_texture_region,
     /* WINED3D_CS_OP_CLEAR_UNORDERED_ACCESS_VIEW */ wined3d_cs_exec_clear_unordered_access_view,
     /* WINED3D_CS_OP_COPY_UAV_COUNTER            */ wined3d_cs_exec_copy_uav_counter,
+    /* WINED3D_CS_OP_GENERATE_MIPMAPS            */ wined3d_cs_exec_generate_mipmaps,
 };
 
 static void *wined3d_cs_st_require_space(struct wined3d_cs *cs, size_t size, enum wined3d_cs_queue_id queue_id)
diff --git a/dlls/wined3d/texture.c b/dlls/wined3d/texture.c
index 7a8e1fb7d1..ddbe340dc8 100644
--- a/dlls/wined3d/texture.c
+++ b/dlls/wined3d/texture.c
@@ -1580,17 +1580,6 @@ BOOL wined3d_texture_prepare_location(struct wined3d_texture *texture, unsigned
     }
 }
 
-void CDECL wined3d_texture_generate_mipmaps(struct wined3d_texture *texture)
-{
-    FIXME("texture %p stub!\n", texture);
-
-    if (!(texture->flags & WINED3D_TEXTURE_GENERATE_MIPMAPS))
-    {
-        WARN("Texture without the WINED3D_TEXTURE_GENERATE_MIPMAPS flag, ignoring.\n");
-        return;
-    }
-}
-
 static struct wined3d_texture_sub_resource *wined3d_texture_get_sub_resource(struct wined3d_texture *texture,
         unsigned int sub_resource_idx)
 {
diff --git a/dlls/wined3d/view.c b/dlls/wined3d/view.c
index b35b66bfeb..4463fabb6a 100644
--- a/dlls/wined3d/view.c
+++ b/dlls/wined3d/view.c
@@ -803,6 +803,108 @@ void wined3d_shader_resource_view_bind(struct wined3d_shader_resource_view *view
     wined3d_sampler_bind(sampler, unit, texture, context);
 }
 
+/* Context activation is done by the caller. */
+static void shader_resource_view_bind_and_dirtify(struct wined3d_shader_resource_view *view,
+        struct wined3d_context *context)
+{
+    if (context->active_texture < ARRAY_SIZE(context->rev_tex_unit_map))
+    {
+        DWORD active_sampler = context->rev_tex_unit_map[context->active_texture];
+        if (active_sampler != WINED3D_UNMAPPED_STAGE)
+            context_invalidate_state(context, STATE_SAMPLER(active_sampler));
+    }
+    /* FIXME: Ideally we'd only do this when touching a binding that's used by
+     * a shader. */
+    context_invalidate_compute_state(context, STATE_COMPUTE_SHADER_RESOURCE_BINDING);
+    context_invalidate_state(context, STATE_GRAPHICS_SHADER_RESOURCE_BINDING);
+
+    context_bind_texture(context, view->gl_view.target, view->gl_view.name);
+}
+
+void shader_resource_view_generate_mipmaps(struct wined3d_shader_resource_view *view)
+{
+    struct wined3d_texture *texture = texture_from_resource(view->resource);
+    unsigned int i, j, layer_count, level_count, base_level, max_level;
+    const struct wined3d_gl_info *gl_info;
+    struct wined3d_context *context;
+    struct gl_texture *gl_tex;
+    DWORD location;
+    BOOL srgb;
+
+    TRACE("view %p.\n", view);
+
+    wined3d_from_cs(view->resource->device->cs);
+
+    context = context_acquire(view->resource->device, NULL, 0);
+    gl_info = context->gl_info;
+    layer_count = view->desc.u.texture.layer_count;
+    level_count = view->desc.u.texture.level_count;
+    base_level = view->desc.u.texture.level_idx;
+    max_level = base_level + level_count - 1;
+
+    srgb = !!(texture->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, i * level_count + base_level, context, location);
+    if (view->gl_view.name)
+        shader_resource_view_bind_and_dirtify(view, context);
+    else
+        wined3d_texture_bind_and_dirtify(texture, context, srgb);
+    if (gl_info->supported[ARB_SAMPLER_OBJECTS])
+        GL_EXTCALL(glBindSampler(context->active_texture, 0));
+    gl_info->gl_ops.gl.p_glTexParameteri(texture->target, GL_TEXTURE_BASE_LEVEL, base_level);
+    gl_info->gl_ops.gl.p_glTexParameteri(texture->target, GL_TEXTURE_MAX_LEVEL, max_level);
+    gl_tex = wined3d_texture_get_gl_texture(texture, srgb);
+    if (context->d3d_info->wined3d_creation_flags & WINED3D_SRGB_READ_WRITE_CONTROL)
+    {
+        gl_info->gl_ops.gl.p_glTexParameteri(texture->target, GL_TEXTURE_SRGB_DECODE_EXT,
+                GL_SKIP_DECODE_EXT);
+        gl_tex->sampler_desc.srgb_decode = FALSE;
+    }
+
+    gl_info->fbo_ops.glGenerateMipmap(texture->target);
+    checkGLcall("glGenerateMipMap()");
+
+    for (i = 0; i < layer_count; ++i)
+    {
+        for (j = base_level + 1; j <= max_level; ++j)
+        {
+            wined3d_texture_validate_location(texture, i * level_count + j, location);
+            wined3d_texture_invalidate_location(texture, i * level_count + j, ~location);
+        }
+    }
+
+    gl_info->gl_ops.gl.p_glTexParameteri(texture->target, GL_TEXTURE_MAX_LEVEL, level_count - 1);
+    if (srgb)
+        texture->texture_srgb.base_level = base_level;
+    else
+        texture->texture_rgb.base_level = base_level;
+
+    context_release(context);
+}
+
+void CDECL wined3d_shader_resource_view_generate_mipmaps(struct wined3d_shader_resource_view *view)
+{
+    struct wined3d_texture *texture;
+
+    TRACE("view %p.\n", view);
+
+    if (view->resource->type == WINED3D_RTYPE_BUFFER)
+    {
+        WARN("Called on buffer resource %p.\n", view->resource);
+        return;
+    }
+
+    texture = texture_from_resource(view->resource);
+    if (!(texture->flags & WINED3D_TEXTURE_GENERATE_MIPMAPS))
+    {
+        WARN("Texture without the WINED3D_TEXTURE_GENERATE_MIPMAPS flag, ignoring.\n");
+        return;
+    }
+
+    wined3d_cs_emit_generate_mipmaps(view->resource->device->cs, view);
+}
+
 ULONG CDECL wined3d_unordered_access_view_incref(struct wined3d_unordered_access_view *view)
 {
     ULONG refcount = InterlockedIncrement(&view->refcount);
diff --git a/dlls/wined3d/wined3d.spec b/dlls/wined3d/wined3d.spec
index 0825b93660..74e61eab39 100644
--- a/dlls/wined3d/wined3d.spec
+++ b/dlls/wined3d/wined3d.spec
@@ -254,6 +254,7 @@
 
 @ cdecl wined3d_shader_resource_view_create(ptr ptr ptr ptr ptr)
 @ cdecl wined3d_shader_resource_view_decref(ptr)
+@ cdecl wined3d_shader_resource_view_generate_mipmaps(ptr)
 @ cdecl wined3d_shader_resource_view_get_parent(ptr)
 @ cdecl wined3d_shader_resource_view_incref(ptr)
 
@@ -287,7 +288,6 @@
 @ cdecl wined3d_texture_create(ptr ptr long long long ptr ptr ptr ptr)
 @ cdecl wined3d_texture_decref(ptr)
 @ cdecl wined3d_texture_from_resource(ptr)
-@ cdecl wined3d_texture_generate_mipmaps(ptr)
 @ cdecl wined3d_texture_get_autogen_filter_type(ptr)
 @ cdecl wined3d_texture_get_dc(ptr long ptr)
 @ cdecl wined3d_texture_get_level_count(ptr)
diff --git a/dlls/wined3d/wined3d_private.h b/dlls/wined3d/wined3d_private.h
index da06ba159f..01f0e1695b 100644
--- a/dlls/wined3d/wined3d_private.h
+++ b/dlls/wined3d/wined3d_private.h
@@ -3508,6 +3508,7 @@ void wined3d_cs_emit_draw(struct wined3d_cs *cs, GLenum primitive_type, unsigned
 void wined3d_cs_emit_draw_indirect(struct wined3d_cs *cs, GLenum primitive_type, unsigned int patch_vertex_count,
         struct wined3d_buffer *buffer, unsigned int offset, BOOL indexed) DECLSPEC_HIDDEN;
 void wined3d_cs_emit_flush(struct wined3d_cs *cs) DECLSPEC_HIDDEN;
+void wined3d_cs_emit_generate_mipmaps(struct wined3d_cs *cs, struct wined3d_shader_resource_view *view) DECLSPEC_HIDDEN;
 void wined3d_cs_emit_preload_resource(struct wined3d_cs *cs, struct wined3d_resource *resource) DECLSPEC_HIDDEN;
 void wined3d_cs_emit_present(struct wined3d_cs *cs, struct wined3d_swapchain *swapchain,
         const RECT *src_rect, const RECT *dst_rect, HWND dst_window_override, DWORD flags) DECLSPEC_HIDDEN;
@@ -3705,6 +3706,7 @@ struct wined3d_shader_resource_view
     struct wined3d_view_desc desc;
 };
 
+void shader_resource_view_generate_mipmaps(struct wined3d_shader_resource_view *view) DECLSPEC_HIDDEN;
 void wined3d_shader_resource_view_bind(struct wined3d_shader_resource_view *view, unsigned int unit,
         struct wined3d_sampler *sampler, struct wined3d_context *context) DECLSPEC_HIDDEN;
 
diff --git a/include/wine/wined3d.h b/include/wine/wined3d.h
index ad9fd1362b..282e7338db 100644
--- a/include/wine/wined3d.h
+++ b/include/wine/wined3d.h
@@ -2609,6 +2609,7 @@ HRESULT __cdecl wined3d_shader_resource_view_create(const struct wined3d_view_de
         struct wined3d_resource *resource, void *parent, const struct wined3d_parent_ops *parent_ops,
         struct wined3d_shader_resource_view **view);
 ULONG __cdecl wined3d_shader_resource_view_decref(struct wined3d_shader_resource_view *view);
+void __cdecl wined3d_shader_resource_view_generate_mipmaps(struct wined3d_shader_resource_view *view);
 void * __cdecl wined3d_shader_resource_view_get_parent(const struct wined3d_shader_resource_view *view);
 ULONG __cdecl wined3d_shader_resource_view_incref(struct wined3d_shader_resource_view *view);
 
@@ -2661,7 +2662,6 @@ HRESULT __cdecl wined3d_texture_create(struct wined3d_device *device, const stru
         void *parent, const struct wined3d_parent_ops *parent_ops, struct wined3d_texture **texture);
 struct wined3d_texture * __cdecl wined3d_texture_from_resource(struct wined3d_resource *resource);
 ULONG __cdecl wined3d_texture_decref(struct wined3d_texture *texture);
-void __cdecl wined3d_texture_generate_mipmaps(struct wined3d_texture *texture);
 enum wined3d_texture_filter_type __cdecl wined3d_texture_get_autogen_filter_type(const struct wined3d_texture *texture);
 HRESULT __cdecl wined3d_texture_get_dc(struct wined3d_texture *texture, unsigned int sub_resource_idx, HDC *dc);
 DWORD __cdecl wined3d_texture_get_level_count(const struct wined3d_texture *texture);
-- 
2.13.6




More information about the wine-devel mailing list