[PATCH v2 4/6] wined3d: Handle typeless resolve in the FBO blitter.

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


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

diff --git a/dlls/wined3d/texture.c b/dlls/wined3d/texture.c
index 6969de46952..7d85413fc5d 100644
--- a/dlls/wined3d/texture.c
+++ b/dlls/wined3d/texture.c
@@ -320,9 +320,13 @@ static void texture2d_blt_fbo(struct wined3d_device *device, struct wined3d_cont
         enum wined3d_texture_filter_type filter, struct wined3d_texture *src_texture,
         unsigned int src_sub_resource_idx, DWORD src_location, const RECT *src_rect,
         struct wined3d_texture *dst_texture, unsigned int dst_sub_resource_idx, DWORD dst_location,
-        const RECT *dst_rect)
+        const RECT *dst_rect, enum wined3d_format_id resolve_format_id)
 {
+    unsigned int dst_save_sub_resource_idx = dst_sub_resource_idx;
     struct wined3d_texture *required_texture, *restore_texture;
+    struct wined3d_texture *dst_save_texture = dst_texture;
+    struct wined3d_texture *src_staging_texture = NULL;
+    struct wined3d_texture *dst_staging_texture = NULL;
     const struct wined3d_gl_info *gl_info;
     struct wined3d_context_gl *context_gl;
     unsigned int restore_idx;
@@ -332,10 +336,10 @@ static void texture2d_blt_fbo(struct wined3d_device *device, struct wined3d_cont
     RECT s, d;
 
     TRACE("device %p, context %p, filter %s, 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.\n",
+            "src_rect %s, dst_texture %p, dst_sub_resource_idx %u, dst_location %s, dst_rect %s, resolve_format_id %s.\n",
             device, context, debug_d3dtexturefiltertype(filter), 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));
+            dst_sub_resource_idx, wined3d_debug_location(dst_location), wine_dbgstr_rect(dst_rect), debug_d3dformat(resolve_format_id));
 
     scaled_resolve = wined3d_texture_gl_is_multisample_location(wined3d_texture_gl(src_texture), src_location)
             && (abs(src_rect->bottom - src_rect->top) != abs(dst_rect->bottom - dst_rect->top)
@@ -346,6 +350,124 @@ static void texture2d_blt_fbo(struct wined3d_device *device, struct wined3d_cont
     else
         gl_filter = scaled_resolve ? GL_SCALED_RESOLVE_FASTEST_EXT : GL_NEAREST;
 
+    context_gl = wined3d_context_gl(context);
+    if (!context_gl->valid)
+    {
+        context_release(context);
+        WARN("Invalid context, skipping blit.\n");
+        return;
+    }
+
+    gl_info = context_gl->gl_info;
+
+    if (resolve_format_id != WINED3DFMT_UNKNOWN)
+    {
+        const struct wined3d_format_gl *resolve_format_gl = wined3d_format_gl(wined3d_get_format(device->adapter, resolve_format_id, 0));
+        const struct wined3d_format_gl *src_format_gl = wined3d_format_gl(src_texture->resource.format);
+        const struct wined3d_format_gl *dst_format_gl = wined3d_format_gl(dst_texture->resource.format);
+        GLint src_internal, dst_internal, resolve_internal;
+
+        switch (resolve_format_id)
+        {
+            case WINED3DFMT_R8G8B8A8_UNORM_SRGB:
+            case WINED3DFMT_B8G8R8A8_UNORM_SRGB:
+            case WINED3DFMT_B8G8R8X8_UNORM_SRGB:
+                gl_info->gl_ops.gl.p_glEnable(GL_FRAMEBUFFER_SRGB);
+                context_invalidate_state(context, STATE_RENDER(WINED3D_RS_SRGBWRITEENABLE));
+                resolve_internal = resolve_format_gl->srgb_internal;
+                break;
+            default:
+                resolve_internal = resolve_format_gl->internal;
+                break;
+        }
+
+        if (src_location == WINED3D_LOCATION_TEXTURE_SRGB)
+            src_internal = src_format_gl->srgb_internal;
+        else if (src_texture->resource.bind_flags & WINED3D_BIND_RENDER_TARGET && wined3d_resource_is_offscreen(&src_texture->resource))
+            src_internal = src_format_gl->rt_internal;
+        else
+            src_internal = src_format_gl->internal;
+
+        if (dst_location == WINED3D_LOCATION_TEXTURE_SRGB)
+            dst_internal = dst_format_gl->srgb_internal;
+        else if (dst_texture->resource.bind_flags & WINED3D_BIND_RENDER_TARGET && wined3d_resource_is_offscreen(&dst_texture->resource))
+            dst_internal = dst_format_gl->rt_internal;
+        else
+            dst_internal = dst_format_gl->internal;
+
+        /* 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_internal != resolve_internal)
+        {
+            struct wined3d_resource_desc desc;
+            unsigned src_level;
+            HRESULT hr;
+
+            src_level = src_sub_resource_idx % src_texture->level_count;
+            desc.resource_type = WINED3D_RTYPE_TEXTURE_2D;
+            desc.format = resolve_format_id;
+            desc.multisample_type = src_texture->resource.multisample_type;
+            desc.multisample_quality = src_texture->resource.multisample_quality;
+            desc.usage = WINED3DUSAGE_PRIVATE;
+            desc.bind_flags = 0;
+            desc.access = WINED3D_RESOURCE_ACCESS_GPU;
+            desc.width = wined3d_texture_get_level_width(src_texture, src_level);
+            desc.height = wined3d_texture_get_level_height(src_texture, src_level);
+            desc.depth = 1;
+            desc.size = 0;
+
+            hr = wined3d_texture_create(device, &desc, 1, 1, 0, NULL, NULL, &wined3d_null_parent_ops, &src_staging_texture);
+            if (FAILED(hr))
+            {
+                ERR("Failed to create staging texture, hr %#x.\n", hr);
+                return;
+            }
+
+            device->blitter->ops->blitter_blit(device->blitter, WINED3D_BLIT_OP_RAW_BLIT, context,
+                    src_texture, src_sub_resource_idx, src_location, src_rect,
+                    src_staging_texture, 0, src_location, src_rect,
+                    NULL, WINED3D_TEXF_NONE, WINED3DFMT_UNKNOWN);
+
+            src_texture = src_staging_texture;
+            src_sub_resource_idx = 0;
+        }
+
+        if (dst_internal != resolve_internal)
+        {
+            struct wined3d_resource_desc desc;
+            unsigned dst_level;
+            HRESULT hr;
+
+            dst_level = dst_sub_resource_idx % dst_texture->level_count;
+            desc.resource_type = WINED3D_RTYPE_TEXTURE_2D;
+            desc.format = resolve_format_id;
+            desc.multisample_type = dst_texture->resource.multisample_type;
+            desc.multisample_quality = dst_texture->resource.multisample_quality;
+            desc.usage = WINED3DUSAGE_PRIVATE;
+            desc.bind_flags = 0;
+            desc.access = WINED3D_RESOURCE_ACCESS_GPU;
+            desc.width = wined3d_texture_get_level_width(dst_texture, dst_level);
+            desc.height = wined3d_texture_get_level_height(dst_texture, dst_level);
+            desc.depth = 1;
+            desc.size = 0;
+
+            hr = wined3d_texture_create(device, &desc, 1, 1, 0, NULL, NULL, &wined3d_null_parent_ops, &dst_staging_texture);
+            if (FAILED(hr))
+            {
+                ERR("Failed to create staging texture, hr %#x.\n", hr);
+                if (src_staging_texture)
+                    wined3d_texture_decref(src_staging_texture);
+                return;
+            }
+
+            wined3d_texture_load_location(dst_staging_texture, 0, context, dst_location);
+
+            dst_texture = dst_staging_texture;
+            dst_sub_resource_idx = 0;
+        }
+    }
+
     /* Make sure the locations are up-to-date. Loading the destination
      * surface isn't required if the entire surface is overwritten. (And is
      * in fact harmful if we're being called by surface_load_location() with
@@ -374,16 +496,6 @@ static void texture2d_blt_fbo(struct wined3d_device *device, struct wined3d_cont
     else
         restore_texture = NULL;
 
-    context_gl = wined3d_context_gl(context);
-    if (!context_gl->valid)
-    {
-        context_release(context);
-        WARN("Invalid context, skipping blit.\n");
-        return;
-    }
-
-    gl_info = context_gl->gl_info;
-
     if (src_location == WINED3D_LOCATION_DRAWABLE)
     {
         TRACE("Source texture %p is onscreen.\n", src_texture);
@@ -437,6 +549,18 @@ static void texture2d_blt_fbo(struct wined3d_device *device, struct wined3d_cont
     if (dst_location == WINED3D_LOCATION_DRAWABLE && dst_texture->swapchain->front_buffer == dst_texture)
         gl_info->gl_ops.gl.p_glFlush();
 
+    if (dst_staging_texture)
+    {
+        device->blitter->ops->blitter_blit(device->blitter, WINED3D_BLIT_OP_RAW_BLIT, context,
+                dst_texture, 0, dst_location, dst_rect,
+                dst_save_texture, dst_save_sub_resource_idx, dst_location, dst_rect,
+                NULL, WINED3D_TEXF_NONE, WINED3DFMT_UNKNOWN);
+        wined3d_texture_decref(dst_texture);
+    }
+
+    if (src_staging_texture)
+        wined3d_texture_decref(src_staging_texture);
+
     if (restore_texture)
         context_restore(context, restore_texture, restore_idx);
 }
@@ -2971,7 +3095,7 @@ static BOOL wined3d_texture_load_renderbuffer(struct wined3d_texture *texture,
         src_location = WINED3D_LOCATION_TEXTURE_RGB;
 
     texture2d_blt_fbo(texture->resource.device, context, WINED3D_TEXF_POINT, texture,
-            sub_resource_idx, src_location, &rect, texture, sub_resource_idx, dst_location, &rect);
+            sub_resource_idx, src_location, &rect, texture, sub_resource_idx, dst_location, &rect, WINED3DFMT_UNKNOWN);
 
     return TRUE;
 }
@@ -3018,11 +3142,11 @@ static BOOL wined3d_texture_gl_load_texture(struct wined3d_texture_gl *texture_g
         if (srgb)
             texture2d_blt_fbo(device, &context_gl->c, WINED3D_TEXF_POINT,
                     &texture_gl->t, sub_resource_idx, WINED3D_LOCATION_TEXTURE_RGB, &src_rect,
-                    &texture_gl->t, sub_resource_idx, WINED3D_LOCATION_TEXTURE_SRGB, &src_rect);
+                    &texture_gl->t, sub_resource_idx, WINED3D_LOCATION_TEXTURE_SRGB, &src_rect, WINED3DFMT_UNKNOWN);
         else
             texture2d_blt_fbo(device, &context_gl->c, WINED3D_TEXF_POINT,
                     &texture_gl->t, sub_resource_idx, WINED3D_LOCATION_TEXTURE_SRGB, &src_rect,
-                    &texture_gl->t, sub_resource_idx, WINED3D_LOCATION_TEXTURE_RGB, &src_rect);
+                    &texture_gl->t, sub_resource_idx, WINED3D_LOCATION_TEXTURE_RGB, &src_rect, WINED3DFMT_UNKNOWN);
 
         return TRUE;
     }
@@ -3039,7 +3163,7 @@ static BOOL wined3d_texture_gl_load_texture(struct wined3d_texture_gl *texture_g
         if (fbo_blitter_supported(WINED3D_BLIT_OP_COLOR_BLIT, gl_info,
                 &texture_gl->t.resource, src_location, &texture_gl->t.resource, dst_location))
             texture2d_blt_fbo(device, &context_gl->c, WINED3D_TEXF_POINT, &texture_gl->t, sub_resource_idx,
-                    src_location, &src_rect, &texture_gl->t, sub_resource_idx, dst_location, &src_rect);
+                    src_location, &src_rect, &texture_gl->t, sub_resource_idx, dst_location, &src_rect, WINED3DFMT_UNKNOWN);
 
         return TRUE;
     }
@@ -5904,7 +6028,7 @@ static DWORD fbo_blitter_blit(struct wined3d_blitter *blitter, enum wined3d_blit
     {
         TRACE("Colour blit.\n");
         texture2d_blt_fbo(device, context, filter, src_texture, src_sub_resource_idx, src_location,
-                src_rect, dst_texture, dst_sub_resource_idx, dst_location, dst_rect);
+                src_rect, dst_texture, dst_sub_resource_idx, dst_location, dst_rect, format_id);
         return dst_location;
     }
 
-- 
2.30.1




More information about the wine-devel mailing list