diff --git a/dlls/wined3d/device.c b/dlls/wined3d/device.c index 833c84b36d8..1bc25c2a92b 100644 --- a/dlls/wined3d/device.c +++ b/dlls/wined3d/device.c @@ -3690,37 +3690,18 @@ static HRESULT WINAPI IWineD3DDeviceImpl_SetPixelShader(IWineD3DDevice *iface, I if (NULL != pShader) { IWineD3DPixelShader_AddRef(pShader); - if(oldShader == NULL) { - /* Fixed function color ops deactivate the texture dimensions from the first stage which has colorop = disable - * Pixel shaders require that this is enabled, so dirtify all samplers, they will enable the dimensions. - * do not dirtify the colorop - it won't do anything when a ashader is bound - * This is temporary until pixel shaders are handled by the state table too - */ - int i; - for(i = 0; i < MAX_SAMPLERS; i++) { - IWineD3DDeviceImpl_MarkStateDirty(This, STATE_SAMPLER(i)); - } - } } if (NULL != oldShader) { IWineD3DPixelShader_Release(oldShader); - if(pShader == NULL) { - /* Fixed function pipeline color args conflict with pixel shader setup, so we do not apply them when a pshader is - * bound. Due to that we have to reapply all color ops when disabling pixel shaders. - * When pixel shaders are handled by the state table too, the pshader function will take care for that, and this - * will also handle draw -> SetPixelShader(NULL) -> SetPixelShader(!= NULL) -> draw cases better - */ - int i; - for(i = 0; i < MAX_TEXTURES; i++) { - IWineD3DDeviceImpl_MarkStateDirty(This, STATE_TEXTURESTAGE(i, WINED3DTSS_COLOROP)); - } - } + } + + if (This->isRecordingState) { + TRACE("Recording... not performing anything\n"); + return WINED3D_OK; } TRACE("(%p) : setting pShader(%p)\n", This, pShader); - /** - * TODO: merge HAL shaders context switching from prototype - */ + IWineD3DDeviceImpl_MarkStateDirty(This, STATE_PIXELSHADER); return WINED3D_OK; } diff --git a/dlls/wined3d/drawprim.c b/dlls/wined3d/drawprim.c index c550d044cb2..a050bb248b1 100644 --- a/dlls/wined3d/drawprim.c +++ b/dlls/wined3d/drawprim.c @@ -1781,14 +1781,6 @@ inline static void drawPrimitiveDrawStrided( useDrawStridedSlow = TRUE; } - if(usePixelShaderFunction) { - /* We compile the shader here because it depends on the texture stage state - * setup of the bound textures. If the shader is already compiled and the texture stage - * state setup matches the program this function will do nothing - */ - IWineD3DPixelShader_CompileShader(This->stateBlock->pixelShader); - } - /* Make any shaders active */ This->shader_backend->shader_select(iface, usePixelShaderFunction, useVertexShaderFunction); diff --git a/dlls/wined3d/state.c b/dlls/wined3d/state.c index 89e2e2babeb..16057c446c2 100644 --- a/dlls/wined3d/state.c +++ b/dlls/wined3d/state.c @@ -1707,6 +1707,60 @@ static void sampler(DWORD state, IWineD3DStateBlockImpl *stateblock) { } } +static void pixelshader(DWORD state, IWineD3DStateBlockImpl *stateblock) { + int i; + + if(stateblock->pixelShader && ((IWineD3DPixelShaderImpl *) stateblock->pixelShader)->baseShader.function != NULL) { + if(!stateblock->wineD3DDevice->last_was_pshader) { + /* Former draw without a pixel shader, some samplers + * may be disabled because of WINED3DTSS_COLOROP = WINED3DTOP_DISABLE + * make sure to enable them + */ + for(i=0; i < MAX_SAMPLERS; i++) { + if(!isStateDirty(stateblock->wineD3DDevice, STATE_SAMPLER(i))) { + sampler(STATE_SAMPLER(i), stateblock); + } + } + } else { + /* Otherwise all samplers were activated by the code above in earlier draws, or by sampler() + * if a different texture was bound. I don't have to do anything. + */ + } + + /* Compile and bind the shader */ + IWineD3DPixelShader_CompileShader(stateblock->pixelShader); + +#if 0 + /* Can't do that here right now, because glsl shaders depend on having both pixel and vertex shader + * setup at the same time. The shader_select call will be done by drawprim until vertex shaders are + * moved to the state table too + */ + stateblock->wineD3DDevice->shader_backend->shader_select( + (IWineD3DDevice *) stateblock->wineD3DDevice, + TRUE, + !stateblock->vertexShader ? FALSE : ((IWineD3DVertexShaderImpl *) stateblock->vertexShader)->baseShader.function != NULL); +#endif + stateblock->wineD3DDevice->last_was_pshader = TRUE; + } else { + /* Disabled the pixel shader - color ops weren't applied + * while it was enabled, so re-apply them. + */ + for(i=0; i < MAX_TEXTURES; i++) { + if(!isStateDirty(stateblock->wineD3DDevice, STATE_TEXTURESTAGE(i, WINED3DTSS_COLOROP))) { + tex_colorop(STATE_TEXTURESTAGE(i, WINED3DTSS_COLOROP), stateblock); + } + } + stateblock->wineD3DDevice->last_was_pshader = FALSE; + +#if 0 + stateblock->wineD3DDevice->shader_backend->shader_select( + (IWineD3DDevice *) stateblock->wineD3DDevice, + FALSE, + !stateblock->vertexShader ? FALSE : ((IWineD3DVertexShaderImpl *) stateblock->vertexShader)->baseShader.function != NULL); +#endif + } +} + const struct StateEntry StateTable[] = { /* State name representative, apply function */ @@ -2204,4 +2258,6 @@ const struct StateEntry StateTable[] = { /*13, Sampler 13 */ STATE_SAMPLER(13), sampler }, { /*14, Sampler 14 */ STATE_SAMPLER(14), sampler }, { /*15, Sampler 15 */ STATE_SAMPLER(15), sampler }, + /* Pixel shader */ + { /* , Pixel Shader */ STATE_PIXELSHADER, pixelshader }, }; diff --git a/dlls/wined3d/wined3d_private.h b/dlls/wined3d/wined3d_private.h index 360ed7b8034..1df81bbd2fc 100644 --- a/dlls/wined3d/wined3d_private.h +++ b/dlls/wined3d/wined3d_private.h @@ -420,7 +420,10 @@ typedef void (*APPLYSTATEFUNC)(DWORD state, IWineD3DStateBlockImpl *stateblock); #define STATE_SAMPLER(num) (STATE_TEXTURESTAGE(MAX_TEXTURES - 1, WINED3D_HIGHEST_TEXTURE_STATE) + 1 + (num)) #define STATE_IS_SAMPLER(num) ((num) >= STATE_SAMPLER(0) && (num) <= STATE_SAMPLER(MAX_SAMPLERS - 1)) -#define STATE_HIGHEST (STATE_SAMPLER(MAX_SAMPLERS - 1)) +#define STATE_PIXELSHADER (STATE_SAMPLER(MAX_SAMPLERS - 1) + 1) +#define STATE_IS_PIXELSHADER(a) ((a) == STATE_PIXELSHADER) + +#define STATE_HIGHEST (STATE_PIXELSHADER) struct StateEntry { @@ -564,6 +567,7 @@ typedef struct IWineD3DDeviceImpl BOOL texture_shader_active; /* TODO: Confirm use is correct */ BOOL last_was_notclipped; BOOL untransformed; + BOOL last_was_pshader; /* State block related */ BOOL isRecordingState;