From 36aef3dc546adfe0e8a45895e5e8cbd234f7736b Mon Sep 17 00:00:00 2001 From: =?utf8?q?Stefan=20D=C3=B6singer?= Date: Mon, 20 Aug 2007 18:56:10 +0200 Subject: [PATCH] wined3d: Hold an internal reference on pixel and vertex shaders. --- dlls/wined3d/device.c | 23 +++++++++++++++++++++++ dlls/wined3d/pixelshader.c | 12 ------------ dlls/wined3d/stateblock.c | 42 ++++++++++++++++++++++++++++++------------ dlls/wined3d/vertexshader.c | 5 ----- 4 files changed, 53 insertions(+), 29 deletions(-) diff --git a/dlls/wined3d/device.c b/dlls/wined3d/device.c index 93e825ab285..d14ad303a63 100644 --- a/dlls/wined3d/device.c +++ b/dlls/wined3d/device.c @@ -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); diff --git a/dlls/wined3d/pixelshader.c b/dlls/wined3d/pixelshader.c index 163453bcc14..55e9bf95cc1 100644 --- a/dlls/wined3d/pixelshader.c +++ b/dlls/wined3d/pixelshader.c @@ -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; diff --git a/dlls/wined3d/stateblock.c b/dlls/wined3d/stateblock.c index 5b50e0fd97e..758606afaff 100644 --- a/dlls/wined3d/stateblock.c +++ b/dlls/wined3d/stateblock.c @@ -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); diff --git a/dlls/wined3d/vertexshader.c b/dlls/wined3d/vertexshader.c index 1c95d65c155..8f4f1fd87a6 100644 --- a/dlls/wined3d/vertexshader.c +++ b/dlls/wined3d/vertexshader.c @@ -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; -- 2.11.4.GIT