Commit c585b4de authored by Stefan Dösinger's avatar Stefan Dösinger Committed by Alexandre Julliard

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.
parent 2803516d
......@@ -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];
}
}
......@@ -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);
......
......@@ -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);
......
......@@ -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)) {
......
......@@ -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;
}
TRACE("(%p) : setting texture name %u\n", This, new_name);
if (!This->glDescription.textureName && 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);
if(!device->isInDraw) ActivateContext(device, device->lastActiveRenderTarget, CTXUSAGE_RESOURCELOAD);
surface_bind_and_dirtify(This);
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);
/* 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");
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);
}
}
/* Otherwise: System memory copy must be most up to date */
if(!device->isInDraw) ActivateContext(device, device->lastActiveRenderTarget, CTXUSAGE_RESOURCELOAD);
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);
......
......@@ -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;
}
......
......@@ -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);
......
......@@ -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");
......
......@@ -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) {
......
......@@ -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);
......
......@@ -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(
);
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment