[PATCH 4/7] wined3d: Implement sRGB for volumes

Stefan Dösinger stefan at codeweavers.com
Sun Aug 25 19:01:29 CDT 2013


---
 dlls/wined3d/texture.c         |  54 ++++++++--------------
 dlls/wined3d/utils.c           |   1 +
 dlls/wined3d/volume.c          | 102 +++++++++++++++++++++++++++++++++--------
 dlls/wined3d/wined3d_private.h |   4 +-
 4 files changed, 104 insertions(+), 57 deletions(-)

diff --git a/dlls/wined3d/texture.c b/dlls/wined3d/texture.c
index f918540..9b8b16e 100644
--- a/dlls/wined3d/texture.c
+++ b/dlls/wined3d/texture.c
@@ -1056,57 +1056,39 @@ static HRESULT texture3d_bind(struct wined3d_texture *texture,
 /* Do not call while under the GL lock. */
 static void texture3d_preload(struct wined3d_texture *texture, enum WINED3DSRGB srgb)
 {
+    UINT sub_count = texture->level_count * texture->layer_count;
     struct wined3d_device *device = texture->resource.device;
-    struct wined3d_context *context;
-    BOOL srgb_was_toggled = FALSE;
-    unsigned int i;
+    const struct wined3d_gl_info *gl_info = &device->adapter->gl_info;
+    struct wined3d_context *context = NULL;
+    struct gl_texture *gl_tex;
+    BOOL srgb_mode;
+    UINT i;
 
     TRACE("texture %p, srgb %#x.\n", texture, srgb);
 
-    /* TODO: Use already acquired context when possible. */
-    context = context_acquire(device, NULL);
-    if (texture->resource.bind_count > 0)
-    {
-        BOOL texture_srgb = texture->flags & WINED3D_TEXTURE_IS_SRGB;
-        BOOL sampler_srgb = texture_srgb_mode(texture, srgb);
-        srgb_was_toggled = !texture_srgb != !sampler_srgb;
-
-        if (srgb_was_toggled)
-        {
-            if (sampler_srgb)
-                texture->flags |= WINED3D_TEXTURE_IS_SRGB;
-            else
-                texture->flags &= ~WINED3D_TEXTURE_IS_SRGB;
-        }
-    }
+    srgb_mode = texture_srgb_mode(texture, srgb);
+    gl_tex = wined3d_texture_get_gl_texture(texture, gl_info, srgb_mode);
 
-    /* If the texture is marked dirty or the sRGB sampler setting has changed
-     * since the last load then reload the volumes. */
-    if (texture->texture_rgb.dirty)
+    if (gl_tex->dirty)
     {
-        for (i = 0; i < texture->level_count; ++i)
+        context = context_acquire(device, NULL);
+
+        /* Reload the surfaces if the texture is marked dirty. */
+        for (i = 0; i < sub_count; ++i)
         {
             wined3d_volume_load(volume_from_resource(texture->sub_resources[i]), context,
-                    texture->flags & WINED3D_TEXTURE_IS_SRGB);
-        }
-    }
-    else if (srgb_was_toggled)
-    {
-        for (i = 0; i < texture->level_count; ++i)
-        {
-            struct wined3d_volume *volume = volume_from_resource(texture->sub_resources[i]);
-            wined3d_volume_load(volume, context, texture->flags & WINED3D_TEXTURE_IS_SRGB);
+                    srgb_mode);
         }
+
+        context_release(context);
     }
     else
     {
         TRACE("Texture %p not dirty, nothing to do.\n", texture);
     }
 
-    context_release(context);
-
-    /* No longer dirty */
-    texture->texture_rgb.dirty = FALSE;
+    /* No longer dirty. */
+    gl_tex->dirty = FALSE;
 }
 
 static void texture3d_sub_resource_add_dirty_region(struct wined3d_resource *sub_resource,
diff --git a/dlls/wined3d/utils.c b/dlls/wined3d/utils.c
index f81b653..492ff70 100644
--- a/dlls/wined3d/utils.c
+++ b/dlls/wined3d/utils.c
@@ -3722,6 +3722,7 @@ const char *wined3d_debug_location(DWORD location)
     LOCATION_TO_STR(WINED3D_LOCATION_SYSMEM);
     LOCATION_TO_STR(WINED3D_LOCATION_BUFFER);
     LOCATION_TO_STR(WINED3D_LOCATION_TEXTURE_RGB);
+    LOCATION_TO_STR(WINED3D_LOCATION_TEXTURE_SRGB);
 #undef LOCATION_TO_STR
     if (location) FIXME("Unrecognized location flag(s) %#x.\n", location);
 
diff --git a/dlls/wined3d/volume.c b/dlls/wined3d/volume.c
index fc12bfb..f940ae3 100644
--- a/dlls/wined3d/volume.c
+++ b/dlls/wined3d/volume.c
@@ -25,9 +25,11 @@
 #include "wined3d_private.h"
 
 WINE_DEFAULT_DEBUG_CHANNEL(d3d_surface);
+WINE_DECLARE_DEBUG_CHANNEL(d3d_perf);
 
 /* Context activation is done by the caller. */
-static void volume_bind_and_dirtify(const struct wined3d_volume *volume, struct wined3d_context *context)
+static void volume_bind_and_dirtify(const struct wined3d_volume *volume,
+        struct wined3d_context *context, BOOL srgb)
 {
     struct wined3d_texture *container = volume->container;
     DWORD active_sampler;
@@ -45,7 +47,7 @@ static void volume_bind_and_dirtify(const struct wined3d_volume *volume, struct
     if (active_sampler != WINED3D_UNMAPPED_STAGE)
         device_invalidate_state(volume->resource.device, STATE_SAMPLER(active_sampler));
 
-    container->texture_ops->texture_bind(container, context, FALSE);
+    container->texture_ops->texture_bind(container, context, srgb);
 }
 
 void volume_set_container(struct wined3d_volume *volume, struct wined3d_texture *container)
@@ -57,12 +59,13 @@ void volume_set_container(struct wined3d_volume *volume, struct wined3d_texture
 
 /* Context activation is done by the caller. */
 static void wined3d_volume_allocate_texture(const struct wined3d_volume *volume,
-        const struct wined3d_context *context)
+        const struct wined3d_context *context, BOOL srgb)
 {
     const struct wined3d_gl_info *gl_info = context->gl_info;
     const struct wined3d_format *format = volume->resource.format;
 
-    GL_EXTCALL(glTexImage3DEXT(GL_TEXTURE_3D, volume->texture_level, format->glInternal,
+    GL_EXTCALL(glTexImage3DEXT(GL_TEXTURE_3D, volume->texture_level,
+            srgb ? format->glGammaInternal : format->glInternal,
             volume->resource.width, volume->resource.height, volume->resource.depth,
             0, format->glFormat, format->glType, NULL));
     checkGLcall("glTexImage3D");
@@ -157,6 +160,7 @@ static DWORD volume_access_from_location(DWORD location)
 
         case WINED3D_LOCATION_BUFFER:
         case WINED3D_LOCATION_TEXTURE_RGB:
+        case WINED3D_LOCATION_TEXTURE_SRGB:
             return WINED3D_RESOURCE_ACCESS_GPU;
 
         default:
@@ -166,6 +170,32 @@ static DWORD volume_access_from_location(DWORD location)
 }
 
 /* Context activation is done by the caller. */
+static void wined3d_volume_srgb_transfer(struct wined3d_volume *volume,
+        struct wined3d_context *context, BOOL dest_is_srgb)
+{
+    struct wined3d_bo_address data;
+    /* Optimizations are possible, but the effort should be put into either
+     * implementing EXT_SRGB_DECODE in the driver or finding out why we
+     * picked the wrong copy for the original upload and fixing that.
+     *
+     * Also keep in mind that we want to avoid using resource.allocatedMemory
+     * for DEFAULT pool surfaces. */
+
+    WARN_(d3d_perf)("Performing slow rgb/srgb volume transfer.\n");
+    data.buffer_object = 0;
+    data.addr = HeapAlloc(GetProcessHeap(), 0, volume->resource.size);
+    if (!data.addr)
+        return;
+
+    volume_bind_and_dirtify(volume, context, !dest_is_srgb);
+    wined3d_volume_download_data(volume, context, &data);
+    volume_bind_and_dirtify(volume, context, dest_is_srgb);
+    wined3d_volume_upload_data(volume, context, &data);
+
+    HeapFree(GetProcessHeap(), 0, data.addr);
+}
+
+/* Context activation is done by the caller. */
 static void wined3d_volume_load_location(struct wined3d_volume *volume,
         struct wined3d_context *context, DWORD location)
 {
@@ -190,11 +220,12 @@ static void wined3d_volume_load_location(struct wined3d_volume *volume,
     switch (location)
     {
         case WINED3D_LOCATION_TEXTURE_RGB:
-            if (!(volume->flags & WINED3D_VFLAG_ALLOCATED))
-            {
-                ERR("Trying to load RGB texture without prior allocation.\n");
-                return;
-            }
+        case WINED3D_LOCATION_TEXTURE_SRGB:
+            if ((location == WINED3D_LOCATION_TEXTURE_RGB
+                    && !(volume->flags & WINED3D_VFLAG_ALLOCATED))
+                    || (location == WINED3D_LOCATION_TEXTURE_SRGB
+                    && !(volume->flags & WINED3D_VFLAG_SRGB_ALLOCATED)))
+                ERR("Trying to load (s)RGB texture without prior allocation.\n");
 
             if (volume->locations & WINED3D_LOCATION_DISCARDED)
             {
@@ -211,12 +242,20 @@ static void wined3d_volume_load_location(struct wined3d_volume *volume,
                 struct wined3d_bo_address data = {volume->pbo, NULL};
                 wined3d_volume_upload_data(volume, context, &data);
             }
+            else if (volume->locations & WINED3D_LOCATION_TEXTURE_RGB)
+            {
+                wined3d_volume_srgb_transfer(volume, context, TRUE);
+            }
+            else if (volume->locations & WINED3D_LOCATION_TEXTURE_SRGB)
+            {
+                wined3d_volume_srgb_transfer(volume, context, FALSE);
+            }
             else
             {
                 FIXME("Implement texture loading from %s.\n", wined3d_debug_location(volume->locations));
                 return;
             }
-            wined3d_volume_validate_location(volume, WINED3D_LOCATION_TEXTURE_RGB);
+            wined3d_volume_validate_location(volume, location);
 
             if (volume->resource.pool == WINED3D_POOL_MANAGED && volume->download_count < 10)
                 wined3d_volume_evict_sysmem(volume);
@@ -235,10 +274,15 @@ static void wined3d_volume_load_location(struct wined3d_volume *volume,
                 TRACE("Volume previously discarded, nothing to do.\n");
                 wined3d_volume_invalidate_location(volume, WINED3D_LOCATION_DISCARDED);
             }
-            else if (volume->locations & WINED3D_LOCATION_TEXTURE_RGB)
+            else if (volume->locations & (WINED3D_LOCATION_TEXTURE_RGB | WINED3D_LOCATION_TEXTURE_SRGB))
             {
                 struct wined3d_bo_address data = {0, volume->resource.allocatedMemory};
-                volume_bind_and_dirtify(volume, context);
+
+                if (volume->locations & WINED3D_LOCATION_TEXTURE_RGB)
+                    volume_bind_and_dirtify(volume, context, FALSE);
+                else
+                    volume_bind_and_dirtify(volume, context, TRUE);
+
                 volume->download_count++;
                 wined3d_volume_download_data(volume, context, &data);
             }
@@ -260,10 +304,15 @@ static void wined3d_volume_load_location(struct wined3d_volume *volume,
                 TRACE("Volume previously discarded, nothing to do.\n");
                 wined3d_volume_invalidate_location(volume, WINED3D_LOCATION_DISCARDED);
             }
-            else if (volume->locations & WINED3D_LOCATION_TEXTURE_RGB)
+            else if (volume->locations & (WINED3D_LOCATION_TEXTURE_RGB | WINED3D_LOCATION_TEXTURE_SRGB))
             {
                 struct wined3d_bo_address data = {volume->pbo, NULL};
-                volume_bind_and_dirtify(volume, context);
+
+                if (volume->locations & WINED3D_LOCATION_TEXTURE_RGB)
+                    volume_bind_and_dirtify(volume, context, FALSE);
+                else
+                    volume_bind_and_dirtify(volume, context, TRUE);
+
                 wined3d_volume_download_data(volume, context, &data);
             }
             else
@@ -284,15 +333,28 @@ static void wined3d_volume_load_location(struct wined3d_volume *volume,
 /* Context activation is done by the caller. */
 void wined3d_volume_load(struct wined3d_volume *volume, struct wined3d_context *context, BOOL srgb_mode)
 {
-    volume_bind_and_dirtify(volume, context);
+    volume_bind_and_dirtify(volume, context, srgb_mode);
 
-    if (!(volume->flags & WINED3D_VFLAG_ALLOCATED))
+    if (srgb_mode)
     {
-        wined3d_volume_allocate_texture(volume, context);
-        volume->flags |= WINED3D_VFLAG_ALLOCATED;
+        if (!(volume->flags & WINED3D_VFLAG_SRGB_ALLOCATED))
+        {
+            wined3d_volume_allocate_texture(volume, context, TRUE);
+            volume->flags |= WINED3D_VFLAG_SRGB_ALLOCATED;
+        }
+
+        wined3d_volume_load_location(volume, context, WINED3D_LOCATION_TEXTURE_SRGB);
     }
+    else
+    {
+        if (!(volume->flags & WINED3D_VFLAG_ALLOCATED))
+        {
+            wined3d_volume_allocate_texture(volume, context, FALSE);
+            volume->flags |= WINED3D_VFLAG_ALLOCATED;
+        }
 
-    wined3d_volume_load_location(volume, context, WINED3D_LOCATION_TEXTURE_RGB);
+        wined3d_volume_load_location(volume, context, WINED3D_LOCATION_TEXTURE_RGB);
+    }
 }
 
 /* Context activation is done by the caller. */
@@ -372,7 +434,7 @@ static void volume_unload(struct wined3d_resource *resource)
     }
 
     /* The texture name is managed by the container. */
-    volume->flags &= ~WINED3D_VFLAG_ALLOCATED;
+    volume->flags &= ~(WINED3D_VFLAG_ALLOCATED | WINED3D_VFLAG_SRGB_ALLOCATED);
 
     resource_unload(resource);
 }
diff --git a/dlls/wined3d/wined3d_private.h b/dlls/wined3d/wined3d_private.h
index 6f38703..09b18b2 100644
--- a/dlls/wined3d/wined3d_private.h
+++ b/dlls/wined3d/wined3d_private.h
@@ -2056,12 +2056,14 @@ void wined3d_texture_set_dirty(struct wined3d_texture *texture, BOOL dirty) DECL
 
 #define WINED3D_VFLAG_LOCKED            0x00000001
 #define WINED3D_VFLAG_ALLOCATED         0x00000002
-#define WINED3D_VFLAG_PBO               0x00000004
+#define WINED3D_VFLAG_SRGB_ALLOCATED    0x00000004
+#define WINED3D_VFLAG_PBO               0x00000008
 
 #define WINED3D_LOCATION_DISCARDED      0x00000001
 #define WINED3D_LOCATION_SYSMEM         0x00000002
 #define WINED3D_LOCATION_BUFFER         0x00000004
 #define WINED3D_LOCATION_TEXTURE_RGB    0x00000008
+#define WINED3D_LOCATION_TEXTURE_SRGB   0x00000010
 
 const char *wined3d_debug_location(DWORD location) DECLSPEC_HIDDEN;
 
-- 
1.8.1.5




More information about the wine-patches mailing list