From c585b4de9949ec3cb583de4a3a49768835e4103c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Stefan=20D=C3=B6singer?= Date: Fri, 16 Jan 2009 16:22:09 +0100 Subject: [PATCH] wined3d: Duplicate GL textures for srgb switching. This reduces the number of srgb switching reloads quite a lot. The only situation in which a reload is needed is if the rgb copy is modified on the GL side and the srgb copy is needed. --- dlls/wined3d/basetexture.c | 125 ++++++++++++++++----------- dlls/wined3d/cubetexture.c | 48 ++++------- dlls/wined3d/device.c | 2 +- dlls/wined3d/state.c | 4 +- dlls/wined3d/surface.c | 149 ++++++++++++++++++++------------- dlls/wined3d/surface_base.c | 2 +- dlls/wined3d/texture.c | 40 ++++----- dlls/wined3d/volume.c | 2 +- dlls/wined3d/volumetexture.c | 10 +-- dlls/wined3d/wined3d_private.h | 43 +++++----- include/wine/wined3d.idl | 4 +- 11 files changed, 236 insertions(+), 193 deletions(-) diff --git a/dlls/wined3d/basetexture.c b/dlls/wined3d/basetexture.c index f6189b6a1df..834906482bb 100644 --- a/dlls/wined3d/basetexture.c +++ b/dlls/wined3d/basetexture.c @@ -33,8 +33,8 @@ void basetexture_init(struct IWineD3DBaseTextureClass *texture, UINT levels, DWO texture->filterType = (usage & WINED3DUSAGE_AUTOGENMIPMAP) ? WINED3DTEXF_LINEAR : WINED3DTEXF_NONE; texture->LOD = 0; texture->dirty = TRUE; + texture->srgbDirty = TRUE; texture->is_srgb = FALSE; - texture->srgb_mode_change_count = 0; } void basetexture_cleanup(IWineD3DBaseTexture *iface) @@ -48,6 +48,7 @@ void basetexture_cleanup(IWineD3DBaseTexture *iface) ENTER_GL(); TRACE("(%p) : Deleting texture %d\n", This, This->baseTexture.textureName); glDeleteTextures(1, &This->baseTexture.textureName); + glDeleteTextures(1, &This->baseTexture.srgbTextureName); LEAVE_GL(); } @@ -63,10 +64,13 @@ void basetexture_unload(IWineD3DBaseTexture *iface) ActivateContext(device, device->lastActiveRenderTarget, CTXUSAGE_RESOURCELOAD); ENTER_GL(); glDeleteTextures(1, &This->baseTexture.textureName); + glDeleteTextures(1, &This->baseTexture.srgbTextureName); This->baseTexture.textureName = 0; + This->baseTexture.srgbTextureName = 0; LEAVE_GL(); } This->baseTexture.dirty = TRUE; + This->baseTexture.srgbDirty = TRUE; } /* There is no OpenGL equivalent of setLOD, getLOD. All they do anyway is prioritize texture loading @@ -173,54 +177,67 @@ BOOL basetexture_set_dirty(IWineD3DBaseTexture *iface, BOOL dirty) { BOOL old; IWineD3DBaseTextureImpl *This = (IWineD3DBaseTextureImpl *)iface; - old = This->baseTexture.dirty; + old = This->baseTexture.dirty || This->baseTexture.srgbDirty; This->baseTexture.dirty = dirty; + This->baseTexture.srgbDirty = dirty; return old; } BOOL basetexture_get_dirty(IWineD3DBaseTexture *iface) { IWineD3DBaseTextureImpl *This = (IWineD3DBaseTextureImpl *)iface; - return This->baseTexture.dirty; + return This->baseTexture.dirty || This->baseTexture.srgbDirty; } -HRESULT basetexture_bind(IWineD3DBaseTexture *iface) +HRESULT basetexture_bind(IWineD3DBaseTexture *iface, BOOL srgb, BOOL *set_surface_desc) { IWineD3DBaseTextureImpl *This = (IWineD3DBaseTextureImpl *)iface; HRESULT hr = WINED3D_OK; UINT textureDimensions; BOOL isNewTexture = FALSE; + GLuint *texture; + DWORD *states; TRACE("(%p) : About to bind texture\n", This); + This->baseTexture.is_srgb = srgb; /* SRGB mode cache for PreLoad calls outside drawprim */ + if(srgb) { + texture = &This->baseTexture.srgbTextureName; + states = This->baseTexture.srgbstates; + } else { + texture = &This->baseTexture.textureName; + states = This->baseTexture.states; + } + textureDimensions = IWineD3DBaseTexture_GetTextureDimensions(iface); ENTER_GL(); /* Generate a texture name if we don't already have one */ - if (This->baseTexture.textureName == 0) { - glGenTextures(1, &This->baseTexture.textureName); + if (*texture == 0) { + *set_surface_desc = TRUE; + glGenTextures(1, texture); checkGLcall("glGenTextures"); - TRACE("Generated texture %d\n", This->baseTexture.textureName); + TRACE("Generated texture %d\n", *texture); if (This->resource.pool == WINED3DPOOL_DEFAULT) { /* Tell opengl to try and keep this texture in video ram (well mostly) */ GLclampf tmp; tmp = 0.9f; - glPrioritizeTextures(1, &This->baseTexture.textureName, &tmp); + glPrioritizeTextures(1, texture, &tmp); } /* Initialise the state of the texture object to the openGL defaults, not the directx defaults */ - This->baseTexture.states[WINED3DTEXSTA_ADDRESSU] = WINED3DTADDRESS_WRAP; - This->baseTexture.states[WINED3DTEXSTA_ADDRESSV] = WINED3DTADDRESS_WRAP; - This->baseTexture.states[WINED3DTEXSTA_ADDRESSW] = WINED3DTADDRESS_WRAP; - This->baseTexture.states[WINED3DTEXSTA_BORDERCOLOR] = 0; - This->baseTexture.states[WINED3DTEXSTA_MAGFILTER] = WINED3DTEXF_LINEAR; - This->baseTexture.states[WINED3DTEXSTA_MINFILTER] = WINED3DTEXF_POINT; /* GL_NEAREST_MIPMAP_LINEAR */ - This->baseTexture.states[WINED3DTEXSTA_MIPFILTER] = WINED3DTEXF_LINEAR; /* GL_NEAREST_MIPMAP_LINEAR */ - This->baseTexture.states[WINED3DTEXSTA_MAXMIPLEVEL] = 0; - This->baseTexture.states[WINED3DTEXSTA_MAXANISOTROPY] = 0; - This->baseTexture.states[WINED3DTEXSTA_SRGBTEXTURE] = 0; - This->baseTexture.states[WINED3DTEXSTA_ELEMENTINDEX] = 0; - This->baseTexture.states[WINED3DTEXSTA_DMAPOFFSET] = 0; - This->baseTexture.states[WINED3DTEXSTA_TSSADDRESSW] = WINED3DTADDRESS_WRAP; + states[WINED3DTEXSTA_ADDRESSU] = WINED3DTADDRESS_WRAP; + states[WINED3DTEXSTA_ADDRESSV] = WINED3DTADDRESS_WRAP; + states[WINED3DTEXSTA_ADDRESSW] = WINED3DTADDRESS_WRAP; + states[WINED3DTEXSTA_BORDERCOLOR] = 0; + states[WINED3DTEXSTA_MAGFILTER] = WINED3DTEXF_LINEAR; + states[WINED3DTEXSTA_MINFILTER] = WINED3DTEXF_POINT; /* GL_NEAREST_MIPMAP_LINEAR */ + states[WINED3DTEXSTA_MIPFILTER] = WINED3DTEXF_LINEAR; /* GL_NEAREST_MIPMAP_LINEAR */ + states[WINED3DTEXSTA_MAXMIPLEVEL] = 0; + states[WINED3DTEXSTA_MAXANISOTROPY] = 0; + states[WINED3DTEXSTA_SRGBTEXTURE] = 0; + states[WINED3DTEXSTA_ELEMENTINDEX] = 0; + states[WINED3DTEXSTA_DMAPOFFSET] = 0; + states[WINED3DTEXSTA_TSSADDRESSW] = WINED3DTADDRESS_WRAP; IWineD3DBaseTexture_SetDirty(iface, TRUE); isNewTexture = TRUE; @@ -228,16 +245,18 @@ HRESULT basetexture_bind(IWineD3DBaseTexture *iface) /* This means double binding the texture at creation, but keeps the code simpler all * in all, and the run-time path free from additional checks */ - glBindTexture(textureDimensions, This->baseTexture.textureName); + glBindTexture(textureDimensions, *texture); checkGLcall("glBindTexture"); glTexParameteri(textureDimensions, GL_GENERATE_MIPMAP_SGIS, GL_TRUE); checkGLcall("glTexParameteri(textureDimensions, GL_GENERATE_MIPMAP_SGIS, GL_TRUE)"); } + } else { + *set_surface_desc = FALSE; } /* Bind the texture */ - if (This->baseTexture.textureName != 0) { - glBindTexture(textureDimensions, This->baseTexture.textureName); + if (*texture != 0) { + glBindTexture(textureDimensions, *texture); checkGLcall("glBindTexture"); if (isNewTexture) { /* For a new texture we have to set the textures levels after binding the texture. @@ -298,31 +317,37 @@ void basetexture_apply_state_changes(IWineD3DBaseTexture *iface, const DWORD samplerStates[WINED3D_HIGHEST_SAMPLER_STATE + 1]) { IWineD3DBaseTextureImpl *This = (IWineD3DBaseTextureImpl *)iface; - DWORD state; + DWORD state, *states; GLint textureDimensions = IWineD3DBaseTexture_GetTextureDimensions(iface); BOOL cond_np2 = IWineD3DBaseTexture_IsCondNP2(iface); + if(This->baseTexture.is_srgb) { + states = This->baseTexture.srgbstates; + } else { + states = This->baseTexture.states; + } + /* ApplyStateChanges relies on the correct texture being bound and loaded. */ - if(samplerStates[WINED3DSAMP_ADDRESSU] != This->baseTexture.states[WINED3DTEXSTA_ADDRESSU]) { + if(samplerStates[WINED3DSAMP_ADDRESSU] != states[WINED3DTEXSTA_ADDRESSU]) { state = samplerStates[WINED3DSAMP_ADDRESSU]; apply_wrap(textureDimensions, state, GL_TEXTURE_WRAP_S, cond_np2); - This->baseTexture.states[WINED3DTEXSTA_ADDRESSU] = state; + states[WINED3DTEXSTA_ADDRESSU] = state; } - if(samplerStates[WINED3DSAMP_ADDRESSV] != This->baseTexture.states[WINED3DTEXSTA_ADDRESSV]) { + if(samplerStates[WINED3DSAMP_ADDRESSV] != states[WINED3DTEXSTA_ADDRESSV]) { state = samplerStates[WINED3DSAMP_ADDRESSV]; apply_wrap(textureDimensions, state, GL_TEXTURE_WRAP_T, cond_np2); - This->baseTexture.states[WINED3DTEXSTA_ADDRESSV] = state; + states[WINED3DTEXSTA_ADDRESSV] = state; } - if(samplerStates[WINED3DSAMP_ADDRESSW] != This->baseTexture.states[WINED3DTEXSTA_ADDRESSW]) { + if(samplerStates[WINED3DSAMP_ADDRESSW] != states[WINED3DTEXSTA_ADDRESSW]) { state = samplerStates[WINED3DSAMP_ADDRESSW]; apply_wrap(textureDimensions, state, GL_TEXTURE_WRAP_R, cond_np2); - This->baseTexture.states[WINED3DTEXSTA_ADDRESSW] = state; + states[WINED3DTEXSTA_ADDRESSW] = state; } - if(samplerStates[WINED3DSAMP_BORDERCOLOR] != This->baseTexture.states[WINED3DTEXSTA_BORDERCOLOR]) { + if(samplerStates[WINED3DSAMP_BORDERCOLOR] != states[WINED3DTEXSTA_BORDERCOLOR]) { float col[4]; state = samplerStates[WINED3DSAMP_BORDERCOLOR]; @@ -330,10 +355,10 @@ void basetexture_apply_state_changes(IWineD3DBaseTexture *iface, TRACE("Setting border color for %u to %x\n", textureDimensions, state); glTexParameterfv(textureDimensions, GL_TEXTURE_BORDER_COLOR, &col[0]); checkGLcall("glTexParameteri(..., GL_TEXTURE_BORDER_COLOR, ...)"); - This->baseTexture.states[WINED3DTEXSTA_BORDERCOLOR] = state; + states[WINED3DTEXSTA_BORDERCOLOR] = state; } - if(samplerStates[WINED3DSAMP_MAGFILTER] != This->baseTexture.states[WINED3DTEXSTA_MAGFILTER]) { + if(samplerStates[WINED3DSAMP_MAGFILTER] != states[WINED3DTEXSTA_MAGFILTER]) { GLint glValue; state = samplerStates[WINED3DSAMP_MAGFILTER]; if (state > WINED3DTEXF_ANISOTROPIC) { @@ -347,26 +372,26 @@ void basetexture_apply_state_changes(IWineD3DBaseTexture *iface, !cond_np2) { glTexParameteri(textureDimensions, GL_TEXTURE_MAX_ANISOTROPY_EXT, samplerStates[WINED3DSAMP_MAXANISOTROPY]); } - This->baseTexture.states[WINED3DTEXSTA_MAGFILTER] = state; + states[WINED3DTEXSTA_MAGFILTER] = state; } } - if((samplerStates[WINED3DSAMP_MINFILTER] != This->baseTexture.states[WINED3DTEXSTA_MINFILTER] || - samplerStates[WINED3DSAMP_MIPFILTER] != This->baseTexture.states[WINED3DTEXSTA_MIPFILTER] || - samplerStates[WINED3DSAMP_MAXMIPLEVEL] != This->baseTexture.states[WINED3DTEXSTA_MAXMIPLEVEL])) { + if((samplerStates[WINED3DSAMP_MINFILTER] != states[WINED3DTEXSTA_MINFILTER] || + samplerStates[WINED3DSAMP_MIPFILTER] != states[WINED3DTEXSTA_MIPFILTER] || + samplerStates[WINED3DSAMP_MAXMIPLEVEL] != states[WINED3DTEXSTA_MAXMIPLEVEL])) { GLint glValue; - This->baseTexture.states[WINED3DTEXSTA_MIPFILTER] = samplerStates[WINED3DSAMP_MIPFILTER]; - This->baseTexture.states[WINED3DTEXSTA_MINFILTER] = samplerStates[WINED3DSAMP_MINFILTER]; - This->baseTexture.states[WINED3DTEXSTA_MAXMIPLEVEL] = samplerStates[WINED3DSAMP_MAXMIPLEVEL]; + states[WINED3DTEXSTA_MIPFILTER] = samplerStates[WINED3DSAMP_MIPFILTER]; + states[WINED3DTEXSTA_MINFILTER] = samplerStates[WINED3DSAMP_MINFILTER]; + states[WINED3DTEXSTA_MAXMIPLEVEL] = samplerStates[WINED3DSAMP_MAXMIPLEVEL]; - if (This->baseTexture.states[WINED3DTEXSTA_MINFILTER] > WINED3DTEXF_ANISOTROPIC || - This->baseTexture.states[WINED3DTEXSTA_MIPFILTER] > WINED3DTEXF_LINEAR) + if (states[WINED3DTEXSTA_MINFILTER] > WINED3DTEXF_ANISOTROPIC || + states[WINED3DTEXSTA_MIPFILTER] > WINED3DTEXF_LINEAR) { FIXME("Unrecognized or unsupported D3DSAMP_MINFILTER value %d D3DSAMP_MIPFILTER value %d\n", - This->baseTexture.states[WINED3DTEXSTA_MINFILTER], - This->baseTexture.states[WINED3DTEXSTA_MIPFILTER]); + states[WINED3DTEXSTA_MINFILTER], + states[WINED3DTEXSTA_MIPFILTER]); } glValue = This->baseTexture.minMipLookup [min(max(samplerStates[WINED3DSAMP_MINFILTER],WINED3DTEXF_NONE), WINED3DTEXF_ANISOTROPIC)] @@ -379,24 +404,24 @@ void basetexture_apply_state_changes(IWineD3DBaseTexture *iface, checkGLcall("glTexParameter GL_TEXTURE_MIN_FILTER, ..."); if(!cond_np2) { - if(This->baseTexture.states[WINED3DTEXSTA_MIPFILTER] == WINED3DTEXF_NONE) { + if(states[WINED3DTEXSTA_MIPFILTER] == WINED3DTEXF_NONE) { glValue = 0; - } else if(This->baseTexture.states[WINED3DTEXSTA_MAXMIPLEVEL] >= This->baseTexture.levels) { + } else if(states[WINED3DTEXSTA_MAXMIPLEVEL] >= This->baseTexture.levels) { glValue = This->baseTexture.levels - 1; } else { - glValue = This->baseTexture.states[WINED3DTEXSTA_MAXMIPLEVEL]; + glValue = states[WINED3DTEXSTA_MAXMIPLEVEL]; } glTexParameteri(textureDimensions, GL_TEXTURE_BASE_LEVEL, glValue); } } - if(samplerStates[WINED3DSAMP_MAXANISOTROPY] != This->baseTexture.states[WINED3DTEXSTA_MAXANISOTROPY]) { + if(samplerStates[WINED3DSAMP_MAXANISOTROPY] != states[WINED3DTEXSTA_MAXANISOTROPY]) { if (GL_SUPPORT(EXT_TEXTURE_FILTER_ANISOTROPIC) && !cond_np2) { glTexParameteri(textureDimensions, GL_TEXTURE_MAX_ANISOTROPY_EXT, samplerStates[WINED3DSAMP_MAXANISOTROPY]); checkGLcall("glTexParameteri GL_TEXTURE_MAX_ANISOTROPY_EXT ..."); } else { WARN("Unsupported in local OpenGL implementation: glTexParameteri GL_TEXTURE_MAX_ANISOTROPY_EXT\n"); } - This->baseTexture.states[WINED3DTEXSTA_MAXANISOTROPY] = samplerStates[WINED3DSAMP_MAXANISOTROPY]; + states[WINED3DTEXSTA_MAXANISOTROPY] = samplerStates[WINED3DSAMP_MAXANISOTROPY]; } } diff --git a/dlls/wined3d/cubetexture.c b/dlls/wined3d/cubetexture.c index c7de212b778..30fc5499efe 100644 --- a/dlls/wined3d/cubetexture.c +++ b/dlls/wined3d/cubetexture.c @@ -97,9 +97,9 @@ static void WINAPI IWineD3DCubeTextureImpl_PreLoad(IWineD3DCubeTexture *iface) { IWineD3DCubeTextureImpl *This = (IWineD3DCubeTextureImpl *)iface; IWineD3DDeviceImpl *device = This->resource.wineD3DDevice; BOOL srgb_mode = This->baseTexture.is_srgb; - BOOL srgb_was_toggled = FALSE; + BOOL *dirty = srgb_mode ? &This->baseTexture.srgbDirty : &This->baseTexture.dirty; - TRACE("(%p) : About to load texture: dirtified(%d)\n", This, This->baseTexture.dirty); + TRACE("(%p) : About to load texture: dirtified(%d)\n", This, *dirty); /* We only have to activate a context for gl when we're not drawing. In most cases PreLoad will be called during draw * and a context was activated at the beginning of drawPrimitive @@ -109,10 +109,6 @@ static void WINAPI IWineD3DCubeTextureImpl_PreLoad(IWineD3DCubeTexture *iface) { * offscreen render targets into their texture */ ActivateContext(device, device->lastActiveRenderTarget, CTXUSAGE_RESOURCELOAD); - } else if (GL_SUPPORT(EXT_TEXTURE_SRGB) && This->baseTexture.bindCount > 0) { - srgb_mode = device->stateBlock->samplerState[This->baseTexture.sampler][WINED3DSAMP_SRGBTEXTURE]; - srgb_was_toggled = (This->baseTexture.is_srgb != srgb_mode); - This->baseTexture.is_srgb = srgb_mode; } if (This->resource.format == WINED3DFMT_P8 || This->resource.format == WINED3DFMT_A8P8) { @@ -129,34 +125,19 @@ static void WINAPI IWineD3DCubeTextureImpl_PreLoad(IWineD3DCubeTexture *iface) { } } /* If the texture is marked dirty or the srgb sampler setting has changed since the last load then reload the surfaces */ - if (This->baseTexture.dirty) { + if (*dirty) { for (i = 0; i < This->baseTexture.levels; i++) { for (j = WINED3DCUBEMAP_FACE_POSITIVE_X; j <= WINED3DCUBEMAP_FACE_NEGATIVE_Z ; j++) { IWineD3DSurface_LoadTexture(This->surfaces[j][i], srgb_mode); } } - } else if (srgb_was_toggled) { - /* Loop is repeated in the else block with the extra surface_add_dirty_rect() line to avoid the - * alternative of checking srgb_was_toggled in every iteration, even when the texture is just dirty */ - if (This->baseTexture.srgb_mode_change_count < 20) - ++This->baseTexture.srgb_mode_change_count; - else - FIXME("Cubetexture (%p) has been reloaded at least 20 times due to WINED3DSAMP_SRGBTEXTURE changes on it\'s sampler\n", This); - - for (i = 0; i < This->baseTexture.levels; i++) { - for (j = WINED3DCUBEMAP_FACE_POSITIVE_X; j <= WINED3DCUBEMAP_FACE_NEGATIVE_Z ; j++) { - surface_add_dirty_rect(This->surfaces[j][i], NULL); - surface_force_reload(This->surfaces[j][i]); - IWineD3DSurface_LoadTexture(This->surfaces[j][i], srgb_mode); - } - } } else { TRACE("(%p) Texture not dirty, nothing to do\n" , iface); } /* No longer dirty */ - This->baseTexture.dirty = FALSE; - return ; + *dirty = FALSE; + return; } static void WINAPI IWineD3DCubeTextureImpl_UnLoad(IWineD3DCubeTexture *iface) { @@ -171,7 +152,8 @@ static void WINAPI IWineD3DCubeTextureImpl_UnLoad(IWineD3DCubeTexture *iface) { for (i = 0; i < This->baseTexture.levels; i++) { for (j = WINED3DCUBEMAP_FACE_POSITIVE_X; j <= WINED3DCUBEMAP_FACE_NEGATIVE_Z ; j++) { IWineD3DSurface_UnLoad(This->surfaces[j][i]); - surface_set_texture_name(This->surfaces[j][i], 0); + surface_set_texture_name(This->surfaces[j][i], 0, TRUE); + surface_set_texture_name(This->surfaces[j][i], 0, FALSE); } } @@ -223,19 +205,23 @@ static BOOL WINAPI IWineD3DCubeTextureImpl_GetDirty(IWineD3DCubeTexture *iface) return basetexture_get_dirty((IWineD3DBaseTexture *)iface); } -static HRESULT WINAPI IWineD3DCubeTextureImpl_BindTexture(IWineD3DCubeTexture *iface) { +static HRESULT WINAPI IWineD3DCubeTextureImpl_BindTexture(IWineD3DCubeTexture *iface, BOOL srgb) { IWineD3DCubeTextureImpl *This = (IWineD3DCubeTextureImpl *)iface; - BOOL set_gl_texture_desc = This->baseTexture.textureName == 0; + BOOL set_gl_texture_desc; HRESULT hr; TRACE("(%p) : relay to BaseTexture\n", This); - hr = basetexture_bind((IWineD3DBaseTexture *)iface); + hr = basetexture_bind((IWineD3DBaseTexture *)iface, srgb, &set_gl_texture_desc); if (set_gl_texture_desc && SUCCEEDED(hr)) { UINT i, j; for (i = 0; i < This->baseTexture.levels; ++i) { for (j = WINED3DCUBEMAP_FACE_POSITIVE_X; j <= WINED3DCUBEMAP_FACE_NEGATIVE_Z; ++j) { - surface_set_texture_name(This->surfaces[j][i], This->baseTexture.textureName); + if(This->baseTexture.is_srgb) { + surface_set_texture_name(This->surfaces[j][i], This->baseTexture.textureName, TRUE); + } else { + surface_set_texture_name(This->surfaces[j][i], This->baseTexture.srgbTextureName, FALSE); + } } } } @@ -277,7 +263,8 @@ static void WINAPI IWineD3DCubeTextureImpl_Destroy(IWineD3DCubeTexture *iface, D if (This->surfaces[j][i] != NULL) { IWineD3DSurface *surface = This->surfaces[j][i]; /* Clean out the texture name we gave to the surface so that the surface doesn't try and release it */ - surface_set_texture_name(surface, 0); + surface_set_texture_name(surface, 0, TRUE); + surface_set_texture_name(surface, 0, FALSE); surface_set_texture_target(surface, 0); /* Cleanup the container */ IWineD3DSurface_SetContainer(This->surfaces[j][i], 0); @@ -357,6 +344,7 @@ static HRESULT WINAPI IWineD3DCubeTextureImpl_AddDirtyRect(IWineD3DCubeTexture HRESULT hr = WINED3DERR_INVALIDCALL; IWineD3DCubeTextureImpl *This = (IWineD3DCubeTextureImpl *)iface; This->baseTexture.dirty = TRUE; + This->baseTexture.srgbDirty = TRUE; TRACE("(%p) : dirtyfication of faceType(%d) Level (0)\n", This, FaceType); if (FaceType <= WINED3DCUBEMAP_FACE_NEGATIVE_Z) { surface_add_dirty_rect(This->surfaces[FaceType][0], pDirtyRect); diff --git a/dlls/wined3d/device.c b/dlls/wined3d/device.c index 71e69e30298..1fd37e21e9a 100644 --- a/dlls/wined3d/device.c +++ b/dlls/wined3d/device.c @@ -5922,7 +5922,7 @@ static HRESULT WINAPI IWineD3DDeviceImpl_UpdateSurface(IWineD3DDevice *iface, /* Make sure the surface is loaded and up to date */ IWineD3DSurface_PreLoad(pDestinationSurface); - IWineD3DSurface_BindTexture(pDestinationSurface); + IWineD3DSurface_BindTexture(pDestinationSurface, FALSE); IWineD3DSurface_GetGlDesc(pDestinationSurface, &glDescription); diff --git a/dlls/wined3d/state.c b/dlls/wined3d/state.c index e1aeeab6985..30c7e127efa 100644 --- a/dlls/wined3d/state.c +++ b/dlls/wined3d/state.c @@ -3344,8 +3344,10 @@ static void sampler(DWORD state, IWineD3DStateBlockImpl *stateblock, WineD3DCont checkGLcall("glActiveTextureARB"); if(stateblock->textures[sampler]) { + BOOL srgb = stateblock->samplerState[sampler][WINED3DSAMP_SRGBTEXTURE]; + basetexture_setsrgbcache(stateblock->textures[sampler], srgb); IWineD3DBaseTexture_PreLoad(stateblock->textures[sampler]); - IWineD3DBaseTexture_BindTexture(stateblock->textures[sampler]); + IWineD3DBaseTexture_BindTexture(stateblock->textures[sampler], srgb); IWineD3DBaseTexture_ApplyStateChanges(stateblock->textures[sampler], stateblock->textureState[sampler], stateblock->samplerState[sampler]); if (GL_SUPPORT(EXT_TEXTURE_LOD_BIAS)) { diff --git a/dlls/wined3d/surface.c b/dlls/wined3d/surface.c index c3d56ee40e5..2998bd14362 100644 --- a/dlls/wined3d/surface.c +++ b/dlls/wined3d/surface.c @@ -42,25 +42,38 @@ void surface_force_reload(IWineD3DSurface *iface) { IWineD3DSurfaceImpl *This = (IWineD3DSurfaceImpl *)iface; - This->Flags &= ~SFLAG_ALLOCATED; + This->Flags &= ~(SFLAG_ALLOCATED | SFLAG_SRGBALLOCATED); } -void surface_set_texture_name(IWineD3DSurface *iface, GLuint name) +void surface_set_texture_name(IWineD3DSurface *iface, GLuint new_name, BOOL srgb) { IWineD3DSurfaceImpl *This = (IWineD3DSurfaceImpl *)iface; + GLuint *name; + DWORD flag; - TRACE("(%p) : setting texture name %u\n", This, name); + if(srgb) + { + name = &This->glDescription.srgbTextureName; + flag = SFLAG_INSRGBTEX; + } + else + { + name = &This->glDescription.textureName; + flag = SFLAG_INTEXTURE; + } - if (!This->glDescription.textureName && name) + TRACE("(%p) : setting texture name %u\n", This, new_name); + + if (!*name && new_name) { /* FIXME: We shouldn't need to remove SFLAG_INTEXTURE if the * surface has no texture name yet. See if we can get rid of this. */ - if (This->Flags & SFLAG_INTEXTURE) + if (This->Flags & flag) ERR("Surface has SFLAG_INTEXTURE set, but no texture name\n"); - IWineD3DSurface_ModifyLocation(iface, SFLAG_INTEXTURE, FALSE); + IWineD3DSurface_ModifyLocation(iface, flag, FALSE); } - This->glDescription.textureName = name; + *name = new_name; surface_force_reload(iface); } @@ -85,7 +98,7 @@ void surface_set_texture_target(IWineD3DSurface *iface, GLenum target) surface_force_reload(iface); } -static void surface_bind_and_dirtify(IWineD3DSurfaceImpl *This) { +static void surface_bind_and_dirtify(IWineD3DSurfaceImpl *This, BOOL srgb) { int active_sampler; /* We don't need a specific texture unit, but after binding the texture the current unit is dirty. @@ -108,7 +121,7 @@ static void surface_bind_and_dirtify(IWineD3DSurfaceImpl *This) { if (active_sampler != -1) { IWineD3DDeviceImpl_MarkStateDirty(This->resource.wineD3DDevice, STATE_SAMPLER(active_sampler)); } - IWineD3DSurface_BindTexture((IWineD3DSurface *)This); + IWineD3DSurface_BindTexture((IWineD3DSurface *)This, srgb); } /* This function checks if the primary render target uses the 8bit paletted format. */ @@ -125,11 +138,6 @@ static BOOL primary_render_target_is_p8(IWineD3DDeviceImpl *device) /* This call just downloads data, the caller is responsible for activating the * right context and binding the correct texture. */ static void surface_download_data(IWineD3DSurfaceImpl *This) { - if (0 == This->glDescription.textureName) { - ERR("Surface does not have a texture, but SFLAG_INTEXTURE is set\n"); - return; - } - /* Only support read back of converted P8 surfaces */ if(This->Flags & SFLAG_CONVERTED && (This->resource.format != WINED3DFMT_P8)) { FIXME("Read back converted textures unsupported, format=%s\n", debug_d3dformat(This->resource.format)); @@ -404,8 +412,6 @@ static void surface_allocate_surface(IWineD3DSurfaceImpl *This, GLenum internal, checkGLcall("glPixelStorei(GL_UNPACK_CLIENT_STORAGE_APPLE, GL_TRUE)"); } LEAVE_GL(); - - This->Flags |= SFLAG_ALLOCATED; } /* In D3D the depth stencil dimensions have to be greater than or equal to the @@ -669,7 +675,7 @@ static void WINAPI IWineD3DSurfaceImpl_UnLoad(IWineD3DSurface *iface) { IWineD3DSurface_ModifyLocation(iface, SFLAG_INDRAWABLE, FALSE); } IWineD3DSurface_ModifyLocation(iface, SFLAG_INTEXTURE, FALSE); - This->Flags &= ~SFLAG_ALLOCATED; + This->Flags &= ~(SFLAG_ALLOCATED | SFLAG_SRGBALLOCATED); /* Destroy PBOs, but load them into real sysmem before */ if(This->Flags & SFLAG_PBO) { @@ -956,7 +962,7 @@ static void read_from_framebuffer(IWineD3DSurfaceImpl *This, CONST RECT *rect, v } /* Read the framebuffer contents into a texture */ -static void read_from_framebuffer_texture(IWineD3DSurfaceImpl *This) +static void read_from_framebuffer_texture(IWineD3DSurfaceImpl *This, BOOL srgb) { IWineD3DDeviceImpl *device = This->resource.wineD3DDevice; IWineD3DSwapChainImpl *swapchain; @@ -964,15 +970,16 @@ static void read_from_framebuffer_texture(IWineD3DSurfaceImpl *This) GLenum format, internal, type; CONVERT_TYPES convert; GLint prevRead; + BOOL alloc_flag = srgb ? SFLAG_SRGBALLOCATED : SFLAG_ALLOCATED; - d3dfmt_get_conv(This, TRUE /* We need color keying */, TRUE /* We will use textures */, &format, &internal, &type, &convert, &bpp, This->srgb); + d3dfmt_get_conv(This, TRUE /* We need color keying */, TRUE /* We will use textures */, &format, &internal, &type, &convert, &bpp, srgb); /* Activate the surface to read from. In some situations it isn't the currently active target(e.g. backbuffer * locking during offscreen rendering). RESOURCELOAD is ok because glCopyTexSubImage2D isn't affected by any * states in the stateblock, and no driver was found yet that had bugs in that regard. */ ActivateContext(device, (IWineD3DSurface *) This, CTXUSAGE_RESOURCELOAD); - surface_bind_and_dirtify(This); + surface_bind_and_dirtify(This, srgb); ENTER_GL(); glGetIntegerv(GL_READ_BUFFER, &prevRead); @@ -1004,9 +1011,10 @@ static void read_from_framebuffer_texture(IWineD3DSurfaceImpl *This) LEAVE_GL(); } - if(!(This->Flags & SFLAG_ALLOCATED)) { + if(!(This->Flags & alloc_flag)) { surface_allocate_surface(This, internal, This->pow2Width, This->pow2Height, format, type); + This->Flags |= alloc_flag; } ENTER_GL(); @@ -2274,8 +2282,9 @@ BOOL palette9_changed(IWineD3DSurfaceImpl *This) { static HRESULT WINAPI IWineD3DSurfaceImpl_LoadTexture(IWineD3DSurface *iface, BOOL srgb_mode) { IWineD3DSurfaceImpl *This = (IWineD3DSurfaceImpl *)iface; + DWORD flag = srgb_mode ? SFLAG_INSRGBTEX : SFLAG_INTEXTURE; - if (!(This->Flags & SFLAG_INTEXTURE)) { + if (!(This->Flags & flag)) { TRACE("Reloading because surface is dirty\n"); } else if(/* Reload: gl texture has ck, now no ckey is set OR */ ((This->Flags & SFLAG_GLCKEY) && (!(This->CKeyFlags & WINEDDSD_CKSRCBLT))) || @@ -2310,8 +2319,7 @@ static HRESULT WINAPI IWineD3DSurfaceImpl_LoadTexture(IWineD3DSurface *iface, BO return WINED3DERR_INVALIDCALL; } - This->srgb = srgb_mode; - IWineD3DSurface_LoadLocation(iface, SFLAG_INTEXTURE, NULL /* no partial locking for textures yet */); + IWineD3DSurface_LoadLocation(iface, flag, NULL /* no partial locking for textures yet */); #if 0 { @@ -2342,7 +2350,7 @@ static HRESULT WINAPI IWineD3DSurfaceImpl_LoadTexture(IWineD3DSurface *iface, BO return WINED3D_OK; } -static void WINAPI IWineD3DSurfaceImpl_BindTexture(IWineD3DSurface *iface) { +static void WINAPI IWineD3DSurfaceImpl_BindTexture(IWineD3DSurface *iface, BOOL srgb) { /* TODO: check for locks */ IWineD3DSurfaceImpl *This = (IWineD3DSurfaceImpl *)iface; IWineD3DBaseTexture *baseTexture = NULL; @@ -2351,11 +2359,13 @@ static void WINAPI IWineD3DSurfaceImpl_BindTexture(IWineD3DSurface *iface) { TRACE("(%p)Checking to see if the container is a base texture\n", This); if (IWineD3DSurface_GetContainer(iface, &IID_IWineD3DBaseTexture, (void **)&baseTexture) == WINED3D_OK) { TRACE("Passing to container\n"); - IWineD3DBaseTexture_BindTexture(baseTexture); + IWineD3DBaseTexture_BindTexture(baseTexture, srgb); IWineD3DBaseTexture_Release(baseTexture); } else { + GLuint *name; TRACE("(%p) : Binding surface\n", This); + name = srgb ? &This->glDescription.srgbTextureName : &This->glDescription.textureName; if(!device->isInDraw) { ActivateContext(device, device->lastActiveRenderTarget, CTXUSAGE_RESOURCELOAD); } @@ -2363,12 +2373,12 @@ static void WINAPI IWineD3DSurfaceImpl_BindTexture(IWineD3DSurface *iface) { ENTER_GL(); if (!This->glDescription.level) { - if (!This->glDescription.textureName) { - glGenTextures(1, &This->glDescription.textureName); + if (!*name) { + glGenTextures(1, name); checkGLcall("glGenTextures"); - TRACE("Surface %p given name %d\n", This, This->glDescription.textureName); + TRACE("Surface %p given name %d\n", This, *name); - glBindTexture(This->glDescription.target, This->glDescription.textureName); + glBindTexture(This->glDescription.target, *name); checkGLcall("glBindTexture"); glTexParameteri(This->glDescription.target, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); checkGLcall("glTexParameteri(dimension, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE)"); @@ -2382,7 +2392,7 @@ static void WINAPI IWineD3DSurfaceImpl_BindTexture(IWineD3DSurface *iface) { checkGLcall("glTexParameteri(dimension, GL_TEXTURE_MAG_FILTER, GL_NEAREST)"); } /* This is where we should be reducing the amount of GLMemoryUsed */ - } else if (This->glDescription.textureName) { + } else if (*name) { /* Mipmap surfaces should have a base texture container */ ERR("Mipmap surface has a glTexture bound to it!\n"); } @@ -2466,7 +2476,7 @@ static HRESULT WINAPI IWineD3DSurfaceImpl_SaveSnapshot(IWineD3DSurface *iface, c } else { /* bind the real texture, and make sure it up to date */ IWineD3DSurface_PreLoad(iface); - surface_bind_and_dirtify(This); + surface_bind_and_dirtify(This, FALSE); } allocatedMemory = HeapAlloc(GetProcessHeap(), 0, width * height * 4); ENTER_GL(); @@ -2554,7 +2564,7 @@ static HRESULT WINAPI IWineD3DSurfaceImpl_SetFormat(IWineD3DSurface *iface, WINE This->glDescription.glFormatInternal = glDesc->glInternal; This->glDescription.glType = glDesc->glType; - This->Flags &= ~SFLAG_ALLOCATED; + This->Flags &= ~(SFLAG_ALLOCATED | SFLAG_SRGBALLOCATED); TRACE("(%p) : glFormat %d, glFotmatInternal %d, glType %d\n", This, This->glDescription.glFormat, This->glDescription.glFormatInternal, This->glDescription.glType); } @@ -2598,7 +2608,7 @@ static HRESULT WINAPI IWineD3DSurfaceImpl_SetMem(IWineD3DSurface *iface, void *M /* For client textures opengl has to be notified */ if(This->Flags & SFLAG_CLIENT) { - This->Flags &= ~SFLAG_ALLOCATED; + This->Flags &= ~(SFLAG_ALLOCATED | SFLAG_SRGBALLOCATED); IWineD3DSurface_PreLoad(iface); /* And hope that the app behaves correctly and did not free the old surface memory before setting a new pointer */ } @@ -2613,7 +2623,7 @@ static HRESULT WINAPI IWineD3DSurfaceImpl_SetMem(IWineD3DSurface *iface, void *M This->Flags &= ~SFLAG_USERPTR; if(This->Flags & SFLAG_CLIENT) { - This->Flags &= ~SFLAG_ALLOCATED; + This->Flags &= ~(SFLAG_ALLOCATED | SFLAG_SRGBALLOCATED); /* This respecifies an empty texture and opengl knows that the old memory is gone */ IWineD3DSurface_PreLoad(iface); } @@ -3776,7 +3786,7 @@ static HRESULT WINAPI IWineD3DSurfaceImpl_RealizePalette(IWineD3DSurface *iface) BOOL use_texture = (wined3d_settings.rendertargetlock_mode == RTL_READTEX || wined3d_settings.rendertargetlock_mode == RTL_TEXTEX); /* Check if we have hardware palette conversion if we have convert is set to NO_CONVERSION */ - d3dfmt_get_conv(This, TRUE, use_texture, &format, &internal, &type, &convert, &bpp, This->srgb); + d3dfmt_get_conv(This, TRUE, use_texture, &format, &internal, &type, &convert, &bpp, FALSE); if((This->resource.usage & WINED3DUSAGE_RENDERTARGET) && (convert == NO_CONVERSION)) { @@ -4205,7 +4215,8 @@ static void WINAPI IWineD3DSurfaceImpl_ModifyLocation(IWineD3DSurface *iface, DW } if(persistent) { - if((This->Flags & SFLAG_INTEXTURE) && !(flag & SFLAG_INTEXTURE)) { + if(((This->Flags & SFLAG_INTEXTURE) && !(flag & SFLAG_INTEXTURE)) || + ((This->Flags & SFLAG_INSRGBTEX) && !(flag & SFLAG_INSRGBTEX))) { if (IWineD3DSurface_GetContainer(iface, &IID_IWineD3DBaseTexture, (void **)&texture) == WINED3D_OK) { TRACE("Passing to container\n"); IWineD3DBaseTexture_SetDirty(texture, TRUE); @@ -4222,7 +4233,7 @@ static void WINAPI IWineD3DSurfaceImpl_ModifyLocation(IWineD3DSurface *iface, DW } } } else { - if((This->Flags & SFLAG_INTEXTURE) && (flag & SFLAG_INTEXTURE)) { + if((This->Flags & (SFLAG_INTEXTURE | SFLAG_INSRGBTEX)) && (flag & (SFLAG_INTEXTURE | SFLAG_INSRGBTEX))) { if (IWineD3DSurface_GetContainer(iface, &IID_IWineD3DBaseTexture, (void **)&texture) == WINED3D_OK) { TRACE("Passing to container\n"); IWineD3DBaseTexture_SetDirty(texture, TRUE); @@ -4231,6 +4242,10 @@ static void WINAPI IWineD3DSurfaceImpl_ModifyLocation(IWineD3DSurface *iface, DW } This->Flags &= ~flag; } + + if(!(This->Flags & SFLAG_LOCATIONS)) { + ERR("%p: Surface does not have any up to date location\n", This); + } } struct coords { @@ -4451,6 +4466,7 @@ static HRESULT WINAPI IWineD3DSurfaceImpl_LoadLocation(IWineD3DSurface *iface, D int bpp; int width, pitch, outpitch; BYTE *mem; + BOOL drawable_read_ok = TRUE; if (wined3d_settings.offscreen_rendering_mode == ORM_FBO) { if (SUCCEEDED(IWineD3DSurface_GetContainer(iface, &IID_IWineD3DSwapChain, (void **)&swapchain))) { @@ -4461,6 +4477,7 @@ static HRESULT WINAPI IWineD3DSurfaceImpl_LoadLocation(IWineD3DSurface *iface, D /* With ORM_FBO, SFLAG_INTEXTURE and SFLAG_INDRAWABLE are the same for offscreen targets. * Prefer SFLAG_INTEXTURE. */ if (flag == SFLAG_INDRAWABLE) flag = SFLAG_INTEXTURE; + drawable_read_ok = FALSE; } } @@ -4477,7 +4494,7 @@ static HRESULT WINAPI IWineD3DSurfaceImpl_LoadLocation(IWineD3DSurface *iface, D } if(!(This->Flags & SFLAG_LOCATIONS)) { - ERR("Surface does not have any up to date location\n"); + ERR("%p: Surface does not have any up to date location\n", This); This->Flags |= SFLAG_LOST; return WINED3DERR_DEVICELOST; } @@ -4486,9 +4503,9 @@ static HRESULT WINAPI IWineD3DSurfaceImpl_LoadLocation(IWineD3DSurface *iface, D surface_prepare_system_memory(This); /* Download the surface to system memory */ - if(This->Flags & SFLAG_INTEXTURE) { + if(This->Flags & (SFLAG_INTEXTURE | SFLAG_INSRGBTEX)) { if(!device->isInDraw) ActivateContext(device, device->lastActiveRenderTarget, CTXUSAGE_RESOURCELOAD); - surface_bind_and_dirtify(This); + surface_bind_and_dirtify(This, !(This->Flags & SFLAG_INTEXTURE)); surface_download_data(This); } else { @@ -4500,7 +4517,15 @@ static HRESULT WINAPI IWineD3DSurfaceImpl_LoadLocation(IWineD3DSurface *iface, D if(This->Flags & SFLAG_INTEXTURE) { surface_blt_to_drawable(This, rect); } else { - d3dfmt_get_conv(This, TRUE /* We need color keying */, FALSE /* We won't use textures */, &format, &internal, &type, &convert, &bpp, This->srgb); + if((This->Flags & SFLAG_LOCATIONS) == SFLAG_INSRGBTEX) { + /* This needs a shader to convert the srgb data sampled from the GL texture into RGB + * values, otherwise we get incorrect values in the target. For now go the slow way + * via a system memory copy + */ + IWineD3DSurfaceImpl_LoadLocation(iface, SFLAG_INSYSMEM, rect); + } + + d3dfmt_get_conv(This, TRUE /* We need color keying */, FALSE /* We won't use textures */, &format, &internal, &type, &convert, &bpp, FALSE); /* The width is in 'length' not in bytes */ width = This->currentDesc.Width; @@ -4539,22 +4564,30 @@ static HRESULT WINAPI IWineD3DSurfaceImpl_LoadLocation(IWineD3DSurface *iface, D if((mem != This->resource.allocatedMemory) && !(This->Flags & SFLAG_PBO)) HeapFree(GetProcessHeap(), 0, mem); } - } else /* if(flag == SFLAG_INTEXTURE) */ { - if (This->Flags & SFLAG_INDRAWABLE) { - read_from_framebuffer_texture(This); + } else /* if(flag & (SFLAG_INTEXTURE | SFLAG_INSRGBTEX)) */ { + if (drawable_read_ok && (This->Flags & SFLAG_INDRAWABLE)) { + read_from_framebuffer_texture(This, flag == SFLAG_INSRGBTEX); } else { /* Upload from system memory */ - d3dfmt_get_conv(This, TRUE /* We need color keying */, TRUE /* We will use textures */, &format, &internal, &type, &convert, &bpp, This->srgb); + BOOL srgb = flag == SFLAG_INSRGBTEX; + DWORD alloc_flag = srgb ? SFLAG_SRGBALLOCATED : SFLAG_ALLOCATED; + d3dfmt_get_conv(This, TRUE /* We need color keying */, TRUE /* We will use textures */, &format, &internal, &type, &convert, &bpp, srgb); + + if(srgb) { + if((This->Flags & (SFLAG_INTEXTURE | SFLAG_INSYSMEM)) == SFLAG_INTEXTURE) { + /* Performance warning ... */ + FIXME("Downloading srgb texture to reload it as rgb\n"); + IWineD3DSurfaceImpl_LoadLocation(iface, SFLAG_INSYSMEM, rect); + } + } else { + if((This->Flags & SFLAG_LOCATIONS) == SFLAG_INSRGBTEX) { + /* Performance warning ... */ + FIXME("Downloading srgb texture to reload it as srgb\n"); + IWineD3DSurfaceImpl_LoadLocation(iface, SFLAG_INSYSMEM, rect); + } + } if(!device->isInDraw) ActivateContext(device, device->lastActiveRenderTarget, CTXUSAGE_RESOURCELOAD); - surface_bind_and_dirtify(This); - - /* The only place where LoadTexture() might get called when isInDraw=1 - * is ActivateContext where lastActiveRenderTarget is preloaded. - */ - if(iface == device->lastActiveRenderTarget && device->isInDraw) - ERR("Reading back render target but SFLAG_INDRAWABLE not set\n"); - - /* Otherwise: System memory copy must be most up to date */ + surface_bind_and_dirtify(This, srgb); if(This->CKeyFlags & WINEDDSD_CKSRCBLT) { This->Flags |= SFLAG_GLCKEY; @@ -4604,8 +4637,9 @@ static HRESULT WINAPI IWineD3DSurfaceImpl_LoadLocation(IWineD3DSurface *iface, D if ((This->Flags & SFLAG_NONPOW2) && !(This->Flags & SFLAG_OVERSIZE)) { TRACE("non power of two support\n"); - if(!(This->Flags & SFLAG_ALLOCATED)) { + if(!(This->Flags & alloc_flag)) { surface_allocate_surface(This, internal, This->pow2Width, This->pow2Height, format, type); + This->Flags |= alloc_flag; } if (mem || (This->Flags & SFLAG_PBO)) { surface_upload_data(This, internal, This->currentDesc.Width, This->currentDesc.Height, format, type, mem); @@ -4614,8 +4648,9 @@ static HRESULT WINAPI IWineD3DSurfaceImpl_LoadLocation(IWineD3DSurface *iface, D /* When making the realloc conditional, keep in mind that GL_APPLE_client_storage may be in use, and This->resource.allocatedMemory * changed. So also keep track of memory changes. In this case the texture has to be reallocated */ - if(!(This->Flags & SFLAG_ALLOCATED)) { + if(!(This->Flags & alloc_flag)) { surface_allocate_surface(This, internal, This->glRect.right - This->glRect.left, This->glRect.bottom - This->glRect.top, format, type); + This->Flags |= alloc_flag; } if (mem || (This->Flags & SFLAG_PBO)) { surface_upload_data(This, internal, This->glRect.right - This->glRect.left, This->glRect.bottom - This->glRect.top, format, type, mem); diff --git a/dlls/wined3d/surface_base.c b/dlls/wined3d/surface_base.c index 12917019cb8..d4ce220ad71 100644 --- a/dlls/wined3d/surface_base.c +++ b/dlls/wined3d/surface_base.c @@ -1862,7 +1862,7 @@ HRESULT WINAPI IWineD3DBaseSurfaceImpl_LockRect(IWineD3DSurface *iface, WINED3DL return WINED3D_OK; } -void WINAPI IWineD3DBaseSurfaceImpl_BindTexture(IWineD3DSurface *iface) { +void WINAPI IWineD3DBaseSurfaceImpl_BindTexture(IWineD3DSurface *iface, BOOL srgb) { ERR("Should not be called on base texture\n"); return; } diff --git a/dlls/wined3d/texture.c b/dlls/wined3d/texture.c index e83d869c29a..2ae6694608a 100644 --- a/dlls/wined3d/texture.c +++ b/dlls/wined3d/texture.c @@ -99,7 +99,7 @@ static void WINAPI IWineD3DTextureImpl_PreLoad(IWineD3DTexture *iface) { IWineD3DTextureImpl *This = (IWineD3DTextureImpl *)iface; IWineD3DDeviceImpl *device = This->resource.wineD3DDevice; BOOL srgb_mode = This->baseTexture.is_srgb; - BOOL srgb_was_toggled = FALSE; + BOOL *dirty = srgb_mode ? &This->baseTexture.srgbDirty : &This->baseTexture.dirty; TRACE("(%p) : About to load texture\n", This); @@ -108,10 +108,6 @@ static void WINAPI IWineD3DTextureImpl_PreLoad(IWineD3DTexture *iface) { * recursive calls */ ActivateContext(device, device->lastActiveRenderTarget, CTXUSAGE_RESOURCELOAD); - } else if (GL_SUPPORT(EXT_TEXTURE_SRGB) && This->baseTexture.bindCount > 0) { - srgb_mode = device->stateBlock->samplerState[This->baseTexture.sampler][WINED3DSAMP_SRGBTEXTURE]; - srgb_was_toggled = This->baseTexture.is_srgb != srgb_mode; - This->baseTexture.is_srgb = srgb_mode; } if (This->resource.format == WINED3DFMT_P8 || This->resource.format == WINED3DFMT_A8P8) { @@ -126,27 +122,16 @@ static void WINAPI IWineD3DTextureImpl_PreLoad(IWineD3DTexture *iface) { } } /* If the texture is marked dirty or the srgb sampler setting has changed since the last load then reload the surfaces */ - if (This->baseTexture.dirty) { + if (*dirty) { for (i = 0; i < This->baseTexture.levels; i++) { IWineD3DSurface_LoadTexture(This->surfaces[i], srgb_mode); } - } else if (srgb_was_toggled) { - if (This->baseTexture.srgb_mode_change_count < 20) - ++This->baseTexture.srgb_mode_change_count; - else - FIXME("Texture (%p) has been reloaded at least 20 times due to WINED3DSAMP_SRGBTEXTURE changes on it\'s sampler\n", This); - - for (i = 0; i < This->baseTexture.levels; i++) { - surface_add_dirty_rect(This->surfaces[i], NULL); - surface_force_reload(This->surfaces[i]); - IWineD3DSurface_LoadTexture(This->surfaces[i], srgb_mode); - } } else { TRACE("(%p) Texture not dirty, nothing to do\n" , iface); } /* No longer dirty */ - This->baseTexture.dirty = FALSE; + *dirty = FALSE; return ; } @@ -162,7 +147,8 @@ static void WINAPI IWineD3DTextureImpl_UnLoad(IWineD3DTexture *iface) { */ for (i = 0; i < This->baseTexture.levels; i++) { IWineD3DSurface_UnLoad(This->surfaces[i]); - surface_set_texture_name(This->surfaces[i], 0); + surface_set_texture_name(This->surfaces[i], 0, FALSE); /* Delete rgb name */ + surface_set_texture_name(This->surfaces[i], 0, TRUE); /* delete srgb name */ } basetexture_unload((IWineD3DBaseTexture *)iface); @@ -212,18 +198,22 @@ static BOOL WINAPI IWineD3DTextureImpl_GetDirty(IWineD3DTexture *iface) { return basetexture_get_dirty((IWineD3DBaseTexture *)iface); } -static HRESULT WINAPI IWineD3DTextureImpl_BindTexture(IWineD3DTexture *iface) { +static HRESULT WINAPI IWineD3DTextureImpl_BindTexture(IWineD3DTexture *iface, BOOL srgb) { IWineD3DTextureImpl *This = (IWineD3DTextureImpl *)iface; - BOOL set_gl_texture_desc = This->baseTexture.textureName == 0; + BOOL set_gl_texture_desc; HRESULT hr; TRACE("(%p) : relay to BaseTexture\n", This); - hr = basetexture_bind((IWineD3DBaseTexture *)iface); + hr = basetexture_bind((IWineD3DBaseTexture *)iface, srgb, &set_gl_texture_desc); if (set_gl_texture_desc && SUCCEEDED(hr)) { UINT i; for (i = 0; i < This->baseTexture.levels; ++i) { - surface_set_texture_name(This->surfaces[i], This->baseTexture.textureName); + if(This->baseTexture.is_srgb) { + surface_set_texture_name(This->surfaces[i], This->baseTexture.srgbTextureName, TRUE); + } else { + surface_set_texture_name(This->surfaces[i], This->baseTexture.textureName, FALSE); + } } /* Conditinal non power of two textures use a different clamping default. If we're using the GL_WINE_normalized_texrect * partial driver emulation, we're dealing with a GL_TEXTURE_2D texture which has the address mode set to repeat - something @@ -284,7 +274,8 @@ static void WINAPI IWineD3DTextureImpl_Destroy(IWineD3DTexture *iface, D3DCB_DES for (i = 0; i < This->baseTexture.levels; i++) { if (This->surfaces[i] != NULL) { /* Clean out the texture name we gave to the surface so that the surface doesn't try and release it */ - surface_set_texture_name(This->surfaces[i], 0); + surface_set_texture_name(This->surfaces[i], 0, TRUE); + surface_set_texture_name(This->surfaces[i], 0, FALSE); surface_set_texture_target(This->surfaces[i], 0); IWineD3DSurface_SetContainer(This->surfaces[i], 0); D3DCB_DestroySurface(This->surfaces[i]); @@ -359,6 +350,7 @@ static HRESULT WINAPI IWineD3DTextureImpl_UnlockRect(IWineD3DTexture *iface, UIN static HRESULT WINAPI IWineD3DTextureImpl_AddDirtyRect(IWineD3DTexture *iface, CONST RECT* pDirtyRect) { IWineD3DTextureImpl *This = (IWineD3DTextureImpl *)iface; This->baseTexture.dirty = TRUE; + This->baseTexture.srgbDirty = TRUE; TRACE("(%p) : dirtyfication of surface Level (0)\n", This); surface_add_dirty_rect(This->surfaces[0], pDirtyRect); diff --git a/dlls/wined3d/volume.c b/dlls/wined3d/volume.c index ceffae73d66..4bae1cb8c26 100644 --- a/dlls/wined3d/volume.c +++ b/dlls/wined3d/volume.c @@ -57,7 +57,7 @@ static void volume_bind_and_dirtify(IWineD3DVolume *iface) { } if (SUCCEEDED(IWineD3DSurface_GetContainer(iface, &IID_IWineD3DVolumeTexture, (void **)&texture))) { - IWineD3DVolumeTexture_BindTexture(texture); + IWineD3DVolumeTexture_BindTexture(texture, FALSE); IWineD3DVolumeTexture_Release(texture); } else { ERR("Volume should be part of a volume texture\n"); diff --git a/dlls/wined3d/volumetexture.c b/dlls/wined3d/volumetexture.c index ea8c07370d7..29f81f7c7dd 100644 --- a/dlls/wined3d/volumetexture.c +++ b/dlls/wined3d/volumetexture.c @@ -113,11 +113,6 @@ static void WINAPI IWineD3DVolumeTextureImpl_PreLoad(IWineD3DVolumeTexture *ifac for (i = 0; i < This->baseTexture.levels; i++) IWineD3DVolume_LoadTexture(This->volumes[i], i, srgb_mode); } else if (srgb_was_toggled) { - if (This->baseTexture.srgb_mode_change_count < 20) - ++This->baseTexture.srgb_mode_change_count; - else - FIXME("Volumetexture (%p) has been reloaded at least 20 times due to WINED3DSAMP_SRGBTEXTURE changes on it\'s sampler\n", This); - for (i = 0; i < This->baseTexture.levels; i++) { volume_add_dirty_box(This->volumes[i], NULL); IWineD3DVolume_LoadTexture(This->volumes[i], i, srgb_mode); @@ -192,10 +187,11 @@ static BOOL WINAPI IWineD3DVolumeTextureImpl_GetDirty(IWineD3DVolumeTexture *ifa return basetexture_get_dirty((IWineD3DBaseTexture *)iface); } -static HRESULT WINAPI IWineD3DVolumeTextureImpl_BindTexture(IWineD3DVolumeTexture *iface) { +static HRESULT WINAPI IWineD3DVolumeTextureImpl_BindTexture(IWineD3DVolumeTexture *iface, BOOL srgb) { IWineD3DVolumeTextureImpl *This = (IWineD3DVolumeTextureImpl *)iface; + BOOL dummy; TRACE("(%p) : relay to BaseTexture\n", This); - return basetexture_bind((IWineD3DBaseTexture *)iface); + return basetexture_bind((IWineD3DBaseTexture *)iface, srgb, &dummy); } static UINT WINAPI IWineD3DVolumeTextureImpl_GetTextureDimensions(IWineD3DVolumeTexture *iface) { diff --git a/dlls/wined3d/wined3d_private.h b/dlls/wined3d/wined3d_private.h index d76988d04f6..c9f9187e157 100644 --- a/dlls/wined3d/wined3d_private.h +++ b/dlls/wined3d/wined3d_private.h @@ -1357,16 +1357,16 @@ typedef enum winetexturestates { typedef struct IWineD3DBaseTextureClass { DWORD states[MAX_WINETEXTURESTATES]; + DWORD srgbstates[MAX_WINETEXTURESTATES]; UINT levels; - BOOL dirty; - UINT textureName; + BOOL dirty, srgbDirty; + UINT textureName, srgbTextureName; float pow2Matrix[16]; UINT LOD; WINED3DTEXTUREFILTERTYPE filterType; LONG bindCount; DWORD sampler; BOOL is_srgb; - UINT srgb_mode_change_count; const struct min_lookup *minMipLookup; const GLenum *magLookup; struct color_fixup_desc shader_color_fixup; @@ -1384,7 +1384,7 @@ typedef struct IWineD3DBaseTextureImpl void basetexture_apply_state_changes(IWineD3DBaseTexture *iface, const DWORD texture_states[WINED3D_HIGHEST_TEXTURE_STATE + 1], const DWORD sampler_states[WINED3D_HIGHEST_SAMPLER_STATE + 1]); -HRESULT basetexture_bind(IWineD3DBaseTexture *iface); +HRESULT basetexture_bind(IWineD3DBaseTexture *iface, BOOL srgb, BOOL *set_surface_desc); void basetexture_cleanup(IWineD3DBaseTexture *iface); void basetexture_generate_mipmaps(IWineD3DBaseTexture *iface); WINED3DTEXTUREFILTERTYPE basetexture_get_autogen_filter_type(IWineD3DBaseTexture *iface); @@ -1396,6 +1396,10 @@ HRESULT basetexture_set_autogen_filter_type(IWineD3DBaseTexture *iface, WINED3DT BOOL basetexture_set_dirty(IWineD3DBaseTexture *iface, BOOL dirty); DWORD basetexture_set_lod(IWineD3DBaseTexture *iface, DWORD new_lod); void basetexture_unload(IWineD3DBaseTexture *iface); +static inline void basetexture_setsrgbcache(IWineD3DBaseTexture *iface, BOOL srgb) { + IWineD3DBaseTextureImpl *This = (IWineD3DBaseTextureImpl *)iface; + This->baseTexture.is_srgb = srgb; +} /***************************************************************************** * IWineD3DTexture implementation structure (extends IWineD3DBaseTextureImpl) @@ -1572,7 +1576,6 @@ struct IWineD3DSurfaceImpl #define MAXLOCKCOUNT 50 /* After this amount of locks do not free the sysmem copy */ glDescriptor glDescription; - BOOL srgb; /* For GetDC */ wineD3DSurface_DIB dib; @@ -1641,7 +1644,7 @@ HRESULT WINAPI IWineD3DBaseSurfaceImpl_Blt(IWineD3DSurface *iface, const RECT *D HRESULT WINAPI IWineD3DBaseSurfaceImpl_BltFast(IWineD3DSurface *iface, DWORD dstx, DWORD dsty, IWineD3DSurface *Source, const RECT *rsrc, DWORD trans); HRESULT WINAPI IWineD3DBaseSurfaceImpl_LockRect(IWineD3DSurface *iface, WINED3DLOCKED_RECT* pLockedRect, CONST RECT* pRect, DWORD Flags); -void WINAPI IWineD3DBaseSurfaceImpl_BindTexture(IWineD3DSurface *iface); +void WINAPI IWineD3DBaseSurfaceImpl_BindTexture(IWineD3DSurface *iface, BOOL srgb); const void *WINAPI IWineD3DBaseSurfaceImpl_GetData(IWineD3DSurface *iface); void get_drawable_size_swapchain(IWineD3DSurfaceImpl *This, UINT *width, UINT *height); @@ -1659,22 +1662,23 @@ void flip_surface(IWineD3DSurfaceImpl *front, IWineD3DSurfaceImpl *back); #define SFLAG_DISCARD 0x00000010 /* ??? */ #define SFLAG_LOCKED 0x00000020 /* Surface is locked atm */ #define SFLAG_INTEXTURE 0x00000040 /* The GL texture contains the newest surface content */ -#define SFLAG_INDRAWABLE 0x00000080 /* The gl drawable contains the most up to date data */ -#define SFLAG_INSYSMEM 0x00000100 /* The system memory copy is most up to date */ -#define SFLAG_NONPOW2 0x00000200 /* Surface sizes are not a power of 2 */ -#define SFLAG_DYNLOCK 0x00000400 /* Surface is often locked by the app */ -#define SFLAG_DYNCHANGE 0x00000C00 /* Surface contents are changed very often, implies DYNLOCK */ +#define SFLAG_INSRGBTEX 0x00000080 /* The GL srgb texture contains the newest surface content */ +#define SFLAG_INDRAWABLE 0x00000100 /* The gl drawable contains the most up to date data */ +#define SFLAG_INSYSMEM 0x00000200 /* The system memory copy is most up to date */ +#define SFLAG_NONPOW2 0x00000400 /* Surface sizes are not a power of 2 */ +#define SFLAG_DYNLOCK 0x00000800 /* Surface is often locked by the app */ #define SFLAG_DCINUSE 0x00001000 /* Set between GetDC and ReleaseDC calls */ #define SFLAG_LOST 0x00002000 /* Surface lost flag for DDraw */ #define SFLAG_USERPTR 0x00004000 /* The application allocated the memory for this surface */ #define SFLAG_GLCKEY 0x00008000 /* The gl texture was created with a color key */ #define SFLAG_CLIENT 0x00010000 /* GL_APPLE_client_storage is used on that texture */ #define SFLAG_ALLOCATED 0x00020000 /* A gl texture is allocated for this surface */ -#define SFLAG_PBO 0x00040000 /* Has a PBO attached for speeding up data transfers for dynamically locked surfaces */ -#define SFLAG_NORMCOORD 0x00080000 /* Set if the GL texture coords are normalized(non-texture rectangle) */ -#define SFLAG_DS_ONSCREEN 0x00100000 /* Is a depth stencil, last modified onscreen */ -#define SFLAG_DS_OFFSCREEN 0x00200000 /* Is a depth stencil, last modified offscreen */ -#define SFLAG_INOVERLAYDRAW 0x00400000 /* Overlay drawing is in progress. Recursion prevention */ +#define SFLAG_SRGBALLOCATED 0x00040000 /* A srgb gl texture is allocated for this surface */ +#define SFLAG_PBO 0x00080000 /* Has a PBO attached for speeding up data transfers for dynamically locked surfaces */ +#define SFLAG_NORMCOORD 0x00100000 /* Set if the GL texture coords are normalized(non-texture rectangle) */ +#define SFLAG_DS_ONSCREEN 0x00200000 /* Is a depth stencil, last modified onscreen */ +#define SFLAG_DS_OFFSCREEN 0x00400000 /* Is a depth stencil, last modified offscreen */ +#define SFLAG_INOVERLAYDRAW 0x00800000 /* Overlay drawing is in progress. Recursion prevention */ /* In some conditions the surface memory must not be freed: * SFLAG_OVERSIZE: Not all data can be kept in GL @@ -1682,7 +1686,6 @@ void flip_surface(IWineD3DSurfaceImpl *front, IWineD3DSurfaceImpl *back); * SFLAG_DIBSECTION: The dib code manages the memory * SFLAG_LOCKED: The app requires access to the surface data * SFLAG_DYNLOCK: Avoid freeing the data for performance - * SFLAG_DYNCHANGE: Same reason as DYNLOCK * SFLAG_PBO: PBOs don't use 'normal' memory. It is either allocated by the driver or must be NULL. * SFLAG_CLIENT: OpenGL uses our memory as backup */ @@ -1691,14 +1694,14 @@ void flip_surface(IWineD3DSurfaceImpl *front, IWineD3DSurfaceImpl *back); SFLAG_DIBSECTION | \ SFLAG_LOCKED | \ SFLAG_DYNLOCK | \ - SFLAG_DYNCHANGE | \ SFLAG_USERPTR | \ SFLAG_PBO | \ SFLAG_CLIENT) #define SFLAG_LOCATIONS (SFLAG_INSYSMEM | \ SFLAG_INTEXTURE | \ - SFLAG_INDRAWABLE) + SFLAG_INDRAWABLE | \ + SFLAG_INSRGBTEX) #define SFLAG_DS_LOCATIONS (SFLAG_DS_ONSCREEN | \ SFLAG_DS_OFFSCREEN) @@ -2056,7 +2059,7 @@ GLenum surface_get_gl_buffer(IWineD3DSurface *iface, IWineD3DSwapChain *swapchai void surface_load_ds_location(IWineD3DSurface *iface, DWORD location); void surface_modify_ds_location(IWineD3DSurface *iface, DWORD location); void surface_set_compatible_renderbuffer(IWineD3DSurface *iface, unsigned int width, unsigned int height); -void surface_set_texture_name(IWineD3DSurface *iface, GLuint name); +void surface_set_texture_name(IWineD3DSurface *iface, GLuint name, BOOL srgb_name); void surface_set_texture_target(IWineD3DSurface *iface, GLenum target); BOOL getColorBits(WINED3DFORMAT fmt, short *redSize, short *greenSize, short *blueSize, short *alphaSize, short *totalSize); diff --git a/include/wine/wined3d.idl b/include/wine/wined3d.idl index 2307f5d6091..f896420b516 100644 --- a/include/wine/wined3d.idl +++ b/include/wine/wined3d.idl @@ -1830,7 +1830,7 @@ typedef struct _WINED3DINDEXBUFFER_DESC typedef struct glDescriptor { - UINT textureName; + UINT textureName, srgbTextureName; int level; int /*GLenum*/ target; int /*GLenum*/ glFormat; @@ -2501,6 +2501,7 @@ interface IWineD3DSurface : IWineD3DResource [in] BOOL srgb_mode ); void BindTexture( + [in] BOOL srgb ); HRESULT SaveSnapshot( [in] const char *filename @@ -2589,6 +2590,7 @@ interface IWineD3DBaseTexture : IWineD3DResource BOOL GetDirty( ); HRESULT BindTexture( + [in] BOOL srgb ); UINT GetTextureDimensions( );