From 6bc3cbf1c57d59368af6930aa25243fc074f4345 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Stefan=20D=C3=B6singer?= Date: Mon, 26 Aug 2013 02:01:29 +0200 Subject: [PATCH] wined3d: Implement sRGB for volumes. --- dlls/wined3d/texture.c | 54 ++++++----------- dlls/wined3d/utils.c | 1 + dlls/wined3d/volume.c | 104 ++++++++++++++++++++++++++------- dlls/wined3d/wined3d_private.h | 4 +- 4 files changed, 105 insertions(+), 58 deletions(-) diff --git a/dlls/wined3d/texture.c b/dlls/wined3d/texture.c index f9185402fdb..9b8b16ef86b 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; + srgb_mode = texture_srgb_mode(texture, srgb); + gl_tex = wined3d_texture_get_gl_texture(texture, gl_info, srgb_mode); - if (srgb_was_toggled) - { - if (sampler_srgb) - texture->flags |= WINED3D_TEXTURE_IS_SRGB; - else - texture->flags &= ~WINED3D_TEXTURE_IS_SRGB; - } - } - - /* 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 f81b653c718..492ff704ca0 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 1813a316c45..9f49f87b51b 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: @@ -165,6 +169,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_RGB); + 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); + } } /* 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 4db76000789..2e113efd070 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;