wined3d: Hold an internal reference on pixel and vertex shaders.

This commit is contained in:
Stefan Dösinger 2007-08-20 18:56:10 +02:00 committed by Alexandre Julliard
parent c52a190a88
commit 36aef3dc54
4 changed files with 53 additions and 29 deletions

View file

@ -522,6 +522,12 @@ static HRESULT WINAPI IWineD3DDeviceImpl_CreateStateBlock(IWineD3DDevice* iface,
if(object->pIndexData) {
IWineD3DIndexBuffer_AddRef(object->pIndexData);
}
if(object->vertexShader) {
IWineD3DVertexShader_AddRef(object->vertexShader);
}
if(object->pixelShader) {
IWineD3DPixelShader_AddRef(object->pixelShader);
}
} else if (Type == WINED3DSBT_PIXELSTATE) {
@ -568,6 +574,9 @@ static HRESULT WINAPI IWineD3DDeviceImpl_CreateStateBlock(IWineD3DDevice* iface,
object->num_contained_sampler_states++;
}
}
if(object->pixelShader) {
IWineD3DPixelShader_AddRef(object->pixelShader);
}
/* Pixel state blocks do not contain vertex buffers. Set them to NULL to avoid wrong refcounting
* on them. This makes releasing the buffer easier
@ -576,6 +585,7 @@ static HRESULT WINAPI IWineD3DDeviceImpl_CreateStateBlock(IWineD3DDevice* iface,
object->streamSource[i] = NULL;
}
object->pIndexData = NULL;
object->vertexShader = NULL;
} else if (Type == WINED3DSBT_VERTEXSTATE) {
@ -636,7 +646,11 @@ static HRESULT WINAPI IWineD3DDeviceImpl_CreateStateBlock(IWineD3DDevice* iface,
IWineD3DVertexBuffer_AddRef(object->streamSource[i]);
}
}
if(object->vertexShader) {
IWineD3DVertexShader_AddRef(object->vertexShader);
}
object->pIndexData = NULL;
object->pixelShader = NULL;
} else {
FIXME("Unrecognized state block type %d\n", Type);
}
@ -3091,6 +3105,8 @@ static HRESULT WINAPI IWineD3DDeviceImpl_SetVertexShader(IWineD3DDevice *iface,
This->updateStateBlock->changed.vertexShader = TRUE;
if (This->isRecordingState) {
if(pShader) IWineD3DVertexShader_AddRef(pShader);
if(oldShader) IWineD3DVertexShader_Release(oldShader);
TRACE("Recording... not performing anything\n");
return WINED3D_OK;
} else if(oldShader == pShader) {
@ -3100,6 +3116,8 @@ static HRESULT WINAPI IWineD3DDeviceImpl_SetVertexShader(IWineD3DDevice *iface,
}
TRACE("(%p) : setting pShader(%p)\n", This, pShader);
if(pShader) IWineD3DVertexShader_AddRef(pShader);
if(oldShader) IWineD3DVertexShader_Release(oldShader);
IWineD3DDeviceImpl_MarkStateDirty(This, STATE_VSHADER);
@ -3478,6 +3496,8 @@ static HRESULT WINAPI IWineD3DDeviceImpl_SetPixelShader(IWineD3DDevice *iface, I
if (This->isRecordingState) {
TRACE("Recording... not performing anything\n");
if(pShader) IWineD3DPixelShader_AddRef(pShader);
if(oldShader) IWineD3DPixelShader_Release(oldShader);
return WINED3D_OK;
}
@ -3486,6 +3506,9 @@ static HRESULT WINAPI IWineD3DDeviceImpl_SetPixelShader(IWineD3DDevice *iface, I
return WINED3D_OK;
}
if(pShader) IWineD3DPixelShader_AddRef(pShader);
if(oldShader) IWineD3DPixelShader_Release(oldShader);
TRACE("(%p) : setting pShader(%p)\n", This, pShader);
IWineD3DDeviceImpl_MarkStateDirty(This, STATE_PIXELSHADER);

View file

@ -73,18 +73,6 @@ static ULONG WINAPI IWineD3DPixelShaderImpl_Release(IWineD3DPixelShader *iface)
TRACE("(%p) : Releasing from %d\n", This, This->ref);
ref = InterlockedDecrement(&This->ref);
if (ref == 0) {
/* SetPixelShader does not AddRef. If the bound pixel shader is destroyed, the pointer in the stateblock remains
* unchanged. Drawing again will most likely crash, even on windows. A problem can occur if the application creates
* a new pixel shader which resides at the same address. Then SetPixelShader will think it is a NOP change, and won't
* dirtify the state.
*
* Do NOT call GetPixelShader here. This will addRef and cause a recursion. And do NOT set the pixel shader to NULL,
* Windows does not do that(Although no test exists since they'd crash randomly)
*/
if(iface == ((IWineD3DDeviceImpl *) This->baseShader.device)->stateBlock->pixelShader) {
IWineD3DDeviceImpl_MarkStateDirty((IWineD3DDeviceImpl *) This->baseShader.device, STATE_PIXELSHADER);
}
if (This->baseShader.shader_mode == SHADER_GLSL && This->baseShader.prgId != 0) {
struct list *linked_programs = &This->baseShader.linked_programs;

View file

@ -272,6 +272,8 @@ static ULONG WINAPI IWineD3DStateBlockImpl_Release(IWineD3DStateBlock *iface) {
}
}
if(This->pIndexData) IWineD3DIndexBuffer_Release(This->pIndexData);
if(This->vertexShader) IWineD3DVertexShader_Release(This->vertexShader);
if(This->pixelShader) IWineD3DPixelShader_Release(This->pixelShader);
for(counter = 0; counter < LIGHTMAP_SIZE; counter++) {
struct list *e1, *e2;
@ -386,9 +388,11 @@ static HRESULT WINAPI IWineD3DStateBlockImpl_Capture(IWineD3DStateBlock *iface)
if (This->blockType == WINED3DSBT_RECORDED) {
/* Recorded => Only update 'changed' values */
if (This->vertexShader != targetStateBlock->vertexShader) {
if (This->changed.vertexShader && This->vertexShader != targetStateBlock->vertexShader) {
TRACE("Updating vertex shader from %p to %p\n", This->vertexShader, targetStateBlock->vertexShader);
if(targetStateBlock->vertexShader) IWineD3DVertexShader_AddRef(targetStateBlock->vertexShader);
if(This->vertexShader) IWineD3DVertexShader_Release(This->vertexShader);
This->vertexShader = targetStateBlock->vertexShader;
}
@ -431,13 +435,6 @@ static HRESULT WINAPI IWineD3DStateBlockImpl_Capture(IWineD3DStateBlock *iface)
This->vertexShaderConstantB[i] = targetStateBlock->vertexShaderConstantB[i];
}
/* Recorded => Only update 'changed' values */
if (This->pixelShader != targetStateBlock->pixelShader) {
TRACE("Updating pixel shader from %p to %p\n", This->pixelShader, targetStateBlock->pixelShader);
This->pixelShader = targetStateBlock->pixelShader;
}
/* Pixel Shader Float Constants */
for (j = 0; j < This->num_contained_ps_consts_f; ++j) {
i = This->contained_ps_consts_f[j];
@ -594,11 +591,15 @@ static HRESULT WINAPI IWineD3DStateBlockImpl_Capture(IWineD3DStateBlock *iface)
This->samplerState[stage][state]);
This->samplerState[stage][state] = targetStateBlock->samplerState[stage][state];
}
if(This->changed.pixelShader && This->pixelShader != targetStateBlock->pixelShader) {
if(targetStateBlock->pixelShader) IWineD3DPixelShader_AddRef(targetStateBlock->pixelShader);
if(This->pixelShader) IWineD3DPixelShader_Release(This->pixelShader);
This->pixelShader = targetStateBlock->pixelShader;
}
record_lights(This, targetStateBlock);
} else if(This->blockType == WINED3DSBT_ALL) {
This->vertexDecl = targetStateBlock->vertexDecl;
This->vertexShader = targetStateBlock->vertexShader;
memcpy(This->vertexShaderConstantB, targetStateBlock->vertexShaderConstantB, sizeof(This->vertexShaderConstantI));
memcpy(This->vertexShaderConstantI, targetStateBlock->vertexShaderConstantI, sizeof(This->vertexShaderConstantF));
memcpy(This->vertexShaderConstantF, targetStateBlock->vertexShaderConstantF, sizeof(float) * GL_LIMITS(vshader_constantsF) * 4);
@ -613,7 +614,6 @@ static HRESULT WINAPI IWineD3DStateBlockImpl_Capture(IWineD3DStateBlock *iface)
This->clip_status = targetStateBlock->clip_status;
This->viewport = targetStateBlock->viewport;
This->material = targetStateBlock->material;
This->pixelShader = targetStateBlock->pixelShader;
memcpy(This->pixelShaderConstantB, targetStateBlock->pixelShaderConstantB, sizeof(This->pixelShaderConstantI));
memcpy(This->pixelShaderConstantI, targetStateBlock->pixelShaderConstantI, sizeof(This->pixelShaderConstantF));
memcpy(This->pixelShaderConstantF, targetStateBlock->pixelShaderConstantF, sizeof(float) * GL_LIMITS(pshader_constantsF) * 4);
@ -636,8 +636,17 @@ static HRESULT WINAPI IWineD3DStateBlockImpl_Capture(IWineD3DStateBlock *iface)
This->streamSource[i] = targetStateBlock->streamSource[i];
}
}
if(This->vertexShader != targetStateBlock->vertexShader) {
if(targetStateBlock->vertexShader) IWineD3DVertexShader_AddRef(targetStateBlock->vertexShader);
if(This->vertexShader) IWineD3DVertexShader_Release(This->vertexShader);
This->vertexShader = targetStateBlock->vertexShader;
}
if(This->pixelShader != targetStateBlock->pixelShader) {
if(targetStateBlock->pixelShader) IWineD3DPixelShader_AddRef(targetStateBlock->pixelShader);
if(This->pixelShader) IWineD3DPixelShader_Release(This->pixelShader);
This->pixelShader = targetStateBlock->pixelShader;
}
} else if(This->blockType == WINED3DSBT_VERTEXSTATE) {
This->vertexShader = targetStateBlock->vertexShader;
memcpy(This->vertexShaderConstantB, targetStateBlock->vertexShaderConstantB, sizeof(This->vertexShaderConstantI));
memcpy(This->vertexShaderConstantI, targetStateBlock->vertexShaderConstantI, sizeof(This->vertexShaderConstantF));
memcpy(This->vertexShaderConstantF, targetStateBlock->vertexShaderConstantF, sizeof(float) * GL_LIMITS(vshader_constantsF) * 4);
@ -662,8 +671,12 @@ static HRESULT WINAPI IWineD3DStateBlockImpl_Capture(IWineD3DStateBlock *iface)
This->streamSource[i] = targetStateBlock->streamSource[i];
}
}
if(This->vertexShader != targetStateBlock->vertexShader) {
if(targetStateBlock->vertexShader) IWineD3DVertexShader_AddRef(targetStateBlock->vertexShader);
if(This->vertexShader) IWineD3DVertexShader_Release(This->vertexShader);
This->vertexShader = targetStateBlock->vertexShader;
}
} else if(This->blockType == WINED3DSBT_PIXELSTATE) {
This->pixelShader = targetStateBlock->pixelShader;
memcpy(This->pixelShaderConstantB, targetStateBlock->pixelShaderConstantB, sizeof(This->pixelShaderConstantI));
memcpy(This->pixelShaderConstantI, targetStateBlock->pixelShaderConstantI, sizeof(This->pixelShaderConstantF));
memcpy(This->pixelShaderConstantF, targetStateBlock->pixelShaderConstantF, sizeof(float) * GL_LIMITS(pshader_constantsF) * 4);
@ -680,6 +693,11 @@ static HRESULT WINAPI IWineD3DStateBlockImpl_Capture(IWineD3DStateBlock *iface)
This->textureState[j][SavedPixelStates_R[i]] = targetStateBlock->textureState[j][SavedPixelStates_R[i]];
}
}
if(This->pixelShader != targetStateBlock->pixelShader) {
if(targetStateBlock->pixelShader) IWineD3DPixelShader_AddRef(targetStateBlock->pixelShader);
if(This->pixelShader) IWineD3DPixelShader_Release(This->pixelShader);
This->pixelShader = targetStateBlock->pixelShader;
}
}
TRACE("(%p) : Updated state block %p ------------------^\n", targetStateBlock, This);

View file

@ -460,11 +460,6 @@ static ULONG WINAPI IWineD3DVertexShaderImpl_Release(IWineD3DVertexShader *iface
TRACE("(%p) : Releasing from %d\n", This, This->ref);
ref = InterlockedDecrement(&This->ref);
if (ref == 0) {
if(iface == ((IWineD3DDeviceImpl *) This->baseShader.device)->stateBlock->vertexShader) {
/* See comment in PixelShader::Release */
IWineD3DDeviceImpl_MarkStateDirty((IWineD3DDeviceImpl *) This->baseShader.device, STATE_VSHADER);
}
if (This->baseShader.shader_mode == SHADER_GLSL && This->baseShader.prgId != 0) {
struct list *linked_programs = &This->baseShader.linked_programs;