diff --git a/dlls/wined3d/baseshader.c b/dlls/wined3d/baseshader.c index a1b987f48e..a0ea4381bc 100644 --- a/dlls/wined3d/baseshader.c +++ b/dlls/wined3d/baseshader.c @@ -747,9 +747,14 @@ void shader_generate_main( /* Read opcode */ opcode_token = *pToken++; curOpcode = shader_get_opcode(iface, opcode_token); - hw_fct = (curOpcode == NULL)? NULL: - (wined3d_settings.shader_mode == SHADER_GLSL)? - curOpcode->hw_glsl_fct : curOpcode->hw_fct; + + /* Select handler */ + if (curOpcode == NULL) + hw_fct = NULL; + else if (This->baseShader.shader_mode == SHADER_GLSL) + hw_fct = curOpcode->hw_glsl_fct; + else if (This->baseShader.shader_mode == SHADER_ARB) + hw_fct = curOpcode->hw_fct; /* Unknown opcode and its parameters */ if (NULL == curOpcode) { @@ -802,7 +807,7 @@ void shader_generate_main( hw_fct(&hw_arg); /* Process instruction modifiers for GLSL apps ( _sat, etc. ) */ - if (wined3d_settings.shader_mode == SHADER_GLSL) + if (This->baseShader.shader_mode == SHADER_GLSL) shader_glsl_add_instruction_modifiers(&hw_arg); /* Unhandled opcode */ diff --git a/dlls/wined3d/device.c b/dlls/wined3d/device.c index 6b2ae6ed57..2d6a1f3441 100644 --- a/dlls/wined3d/device.c +++ b/dlls/wined3d/device.c @@ -567,9 +567,9 @@ static ULONG WINAPI IWineD3DDeviceImpl_Release(IWineD3DDevice *iface) { ** ***************************/ /* Delete any GLSL shader programs that may exist */ - if (wined3d_settings.shader_mode == SHADER_GLSL) { + if (wined3d_settings.vs_selected_mode == SHADER_GLSL || + wined3d_settings.ps_selected_mode == SHADER_GLSL) delete_glsl_shader_list(iface); - } /* Release the update stateblock */ if(IWineD3DStateBlock_Release((IWineD3DStateBlock *)This->updateStateBlock) > 0){ diff --git a/dlls/wined3d/directx.c b/dlls/wined3d/directx.c index e7d225b642..ae0ea82b56 100644 --- a/dlls/wined3d/directx.c +++ b/dlls/wined3d/directx.c @@ -199,6 +199,43 @@ static ULONG WINAPI IWineD3DImpl_Release(IWineD3D *iface) { return ref; } +/* Set the shader type for this device, depending on the given capabilities, + * the device type, and the user preferences in wined3d_settings */ + +static void select_shader_mode( + WineD3D_GL_Info *gl_info, + WINED3DDEVTYPE DeviceType, + int* ps_selected, + int* vs_selected) { + + /* Give priority to user disable/emulation request. + * Then respect REF device for software. + * Then check capabilities for hardware, and fallback to software */ + + if (wined3d_settings.vs_mode == VS_NONE) + *vs_selected = SHADER_NONE; + else if (DeviceType == WINED3DDEVTYPE_REF || wined3d_settings.vs_mode == VS_SW) + *vs_selected = SHADER_SW; + else if (gl_info->supported[ARB_SHADING_LANGUAGE_100] && wined3d_settings.glslRequested) + *vs_selected = SHADER_GLSL; + else if (gl_info->supported[ARB_VERTEX_PROGRAM]) + *vs_selected = SHADER_ARB; + else + *vs_selected = SHADER_SW; + + /* Fallback to SHADER_NONE where software pixel shaders should be used */ + if (wined3d_settings.ps_mode == PS_NONE) + *ps_selected = SHADER_NONE; + else if (DeviceType == WINED3DDEVTYPE_REF) + *ps_selected = SHADER_NONE; + else if (gl_info->supported[ARB_SHADING_LANGUAGE_100] && wined3d_settings.glslRequested) + *ps_selected = SHADER_GLSL; + else if (gl_info->supported[ARB_FRAGMENT_PROGRAM]) + *ps_selected = SHADER_ARB; + else + *ps_selected = SHADER_NONE; +} + /********************************************************** * IWineD3D parts follows **********************************************************/ @@ -752,17 +789,6 @@ BOOL IWineD3DImpl_FillGLCaps(WineD3D_GL_Info *gl_info, Display* display) { GLX_EXT_FUNCS_GEN; #undef USE_GL_FUNC - /* Determine shader mode to use based on GL caps */ - if (gl_info->supported[ARB_SHADING_LANGUAGE_100] && wined3d_settings.glslRequested - && (wined3d_settings.vs_mode == VS_HW || wined3d_settings.ps_mode == PS_HW)) - wined3d_settings.shader_mode = SHADER_GLSL; - else if ((gl_info->supported[ARB_VERTEX_PROGRAM] && wined3d_settings.vs_mode == VS_HW) || - (gl_info->supported[ARB_FRAGMENT_PROGRAM] && wined3d_settings.ps_mode == PS_HW)) - wined3d_settings.shader_mode = SHADER_ARB; - else - wined3d_settings.shader_mode = SHADER_SW; - - /* If we created a dummy context, throw it away */ if (NULL != fake_ctx) WineD3D_ReleaseFakeGLContext(fake_ctx); @@ -1467,6 +1493,8 @@ static HRESULT WINAPI IWineD3DImpl_GetDeviceCaps(IWineD3D *iface, UINT Adapter, return WINED3DERR_INVALIDCALL; } + /* FIXME: both the gl_info and the shader_mode should be made per adapter */ + /* If we don't know the device settings, go query them now */ if (This->isGLInfoValid == FALSE) { /* use the desktop window to fill gl caps */ @@ -1474,8 +1502,9 @@ static HRESULT WINAPI IWineD3DImpl_GetDeviceCaps(IWineD3D *iface, UINT Adapter, /* We are running off a real context, save the values */ if (rc) This->isGLInfoValid = TRUE; - } + select_shader_mode(&This->gl_info, DeviceType, + &wined3d_settings.ps_selected_mode, &wined3d_settings.vs_selected_mode); /* ------------------------------------------------ The following fields apply to both d3d8 and d3d9 @@ -1718,19 +1747,16 @@ static HRESULT WINAPI IWineD3DImpl_GetDeviceCaps(IWineD3D *iface, UINT Adapter, *pCaps->MaxStreams = MAX_STREAMS; *pCaps->MaxStreamStride = 1024; - if (wined3d_settings.vs_mode == VS_HW && wined3d_settings.shader_mode == SHADER_GLSL - && DeviceType != WINED3DDEVTYPE_REF) { + /* FIXME: the shader mode should be per adapter */ + if (wined3d_settings.vs_selected_mode == SHADER_GLSL) { *pCaps->VertexShaderVersion = D3DVS_VERSION(3,0); - TRACE_(d3d_caps)("Hardware vertex shader versions 2.0+ enabled\n"); - } else if (wined3d_settings.vs_mode == VS_HW - && wined3d_settings.shader_mode == SHADER_ARB - && DeviceType != WINED3DDEVTYPE_REF) { + TRACE_(d3d_caps)("Hardware vertex shader version 3.0 enabled (GLSL)\n"); + } else if (wined3d_settings.vs_selected_mode == SHADER_ARB) { *pCaps->VertexShaderVersion = D3DVS_VERSION(1,1); - TRACE_(d3d_caps)("Hardware vertex shader version 1.1 enabled\n"); - } else if (wined3d_settings.vs_mode == VS_SW || DeviceType == WINED3DDEVTYPE_REF) { - /* FIXME: Change the following line (when needed) to reflect the reported software vertex shader version implemented */ - *pCaps->VertexShaderVersion = D3DVS_VERSION(1,1); - TRACE_(d3d_caps)("Software vertex shader version 1.1 enabled\n"); + TRACE_(d3d_caps)("Hardware vertex shader version 1.1 enabled (ARB_PROGRAM)\n"); + } else if (wined3d_settings.vs_selected_mode == SHADER_SW) { + *pCaps->VertexShaderVersion = D3DVS_VERSION(3,0); + TRACE_(d3d_caps)("Software vertex shader version 3.0 enabled\n"); } else { *pCaps->VertexShaderVersion = 0; TRACE_(d3d_caps)("Vertex shader functionality not available\n"); @@ -1742,23 +1768,21 @@ static HRESULT WINAPI IWineD3DImpl_GetDeviceCaps(IWineD3D *iface, UINT Adapter, *pCaps->MaxVertexShaderConst = WINED3D_VSHADER_MAX_CONSTANTS; } - if (wined3d_settings.ps_mode == PS_HW && wined3d_settings.shader_mode == SHADER_GLSL - && DeviceType != WINED3DDEVTYPE_REF) { + /* FIXME: the shader ode should be per adapter */ + if (wined3d_settings.ps_selected_mode == SHADER_GLSL) { *pCaps->PixelShaderVersion = D3DPS_VERSION(3,0); /* FIXME: The following line is card dependent. -1.0 to 1.0 is a safe default clamp range for now */ *pCaps->PixelShader1xMaxValue = 1.0; - TRACE_(d3d_caps)("Hardware pixel shader versions 2.0+ enabled\n"); - } else if (wined3d_settings.ps_mode == PS_HW - && wined3d_settings.shader_mode == SHADER_ARB - && DeviceType != WINED3DDEVTYPE_REF) { + TRACE_(d3d_caps)("Hardware pixel shader version 3.0 enabled (GLSL)\n"); + } else if (wined3d_settings.ps_selected_mode == SHADER_ARB) { *pCaps->PixelShaderVersion = D3DPS_VERSION(1,4); *pCaps->PixelShader1xMaxValue = 1.0; - TRACE_(d3d_caps)("Hardware pixel shader version 1.4 enabled\n"); - /* FIXME: Uncomment this when there is support for software Pixel Shader 1.4 and PS_SW is defined - } else if (wined3d_settings.ps_mode == PS_SW || DeviceType == WINED3DDEVTYPE_REF) { - *pCaps->PixelShaderVersion = D3DPS_VERSION(1,4); + TRACE_(d3d_caps)("Hardware pixel shader version 1.4 enabled (ARB_PROGRAM)\n"); + /* FIXME: Uncomment this when there is support for software Pixel Shader 3.0 and PS_SW is defined + } else if (wined3d_settings.ps_selected_mode = SHADER_SW) { + *pCaps->PixelShaderVersion = D3DPS_VERSION(3,0); *pCaps->PixelShader1xMaxValue = 1.0; - TRACE_(d3d_caps)("Software pixel shader version 1.4 enabled\n"); */ + TRACE_(d3d_caps)("Software pixel shader version 3.0 enabled\n"); */ } else { *pCaps->PixelShaderVersion = 0; *pCaps->PixelShader1xMaxValue = 0.0; @@ -1865,8 +1889,11 @@ static HRESULT WINAPI IWineD3DImpl_CreateDevice(IWineD3D *iface, UINT Adapter, /* Setup some defaults for creating the implicit swapchain */ ENTER_GL(); + /* FIXME: both of those should be made per adapter */ IWineD3DImpl_FillGLCaps(&This->gl_info, IWineD3DImpl_GetAdapterDisplay(iface, Adapter)); LEAVE_GL(); + select_shader_mode(&This->gl_info, DeviceType, + &wined3d_settings.ps_selected_mode, &wined3d_settings.vs_selected_mode); /* set the state of the device to valid */ object->state = WINED3D_OK; diff --git a/dlls/wined3d/drawprim.c b/dlls/wined3d/drawprim.c index 616e0427a5..95ccc77009 100644 --- a/dlls/wined3d/drawprim.c +++ b/dlls/wined3d/drawprim.c @@ -1962,7 +1962,9 @@ UINT numberOfvertices, UINT numberOfIndicies, GLenum glPrimType, const void *idx TRACE("Loaded arrays\n"); /* Bind the correct GLSL shader program based on the currently set vertex & pixel shaders. */ - if (wined3d_settings.shader_mode == SHADER_GLSL) { + if (wined3d_settings.vs_selected_mode == SHADER_GLSL || + wined3d_settings.ps_selected_mode == SHADER_GLSL) { + set_glsl_shader_program(iface); /* Start using this program ID (if it's 0, there is no shader program to use, so * glUseProgramObjectARB(0) will disable the use of any shaders) */ @@ -1977,7 +1979,7 @@ UINT numberOfvertices, UINT numberOfIndicies, GLenum glPrimType, const void *idx TRACE("Using vertex shader\n"); - if (wined3d_settings.shader_mode == SHADER_ARB) { + if (wined3d_settings.vs_selected_mode == SHADER_ARB) { /* Bind the vertex program */ GL_EXTCALL(glBindProgramARB(GL_VERTEX_PROGRAM_ARB, ((IWineD3DVertexShaderImpl *)This->stateBlock->vertexShader)->baseShader.prgId)); @@ -1995,7 +1997,7 @@ UINT numberOfvertices, UINT numberOfIndicies, GLenum glPrimType, const void *idx TRACE("Using pixel shader\n"); - if (wined3d_settings.shader_mode == SHADER_ARB) { + if (wined3d_settings.ps_selected_mode == SHADER_ARB) { /* Bind the fragment program */ GL_EXTCALL(glBindProgramARB(GL_FRAGMENT_PROGRAM_ARB, ((IWineD3DPixelShaderImpl *)This->stateBlock->pixelShader)->baseShader.prgId)); @@ -2008,12 +2010,12 @@ UINT numberOfvertices, UINT numberOfIndicies, GLenum glPrimType, const void *idx This, ((IWineD3DPixelShaderImpl *)This->stateBlock->pixelShader)->baseShader.prgId); } } - + /* Load any global constants/uniforms that may have been set by the application */ - if (wined3d_settings.shader_mode == SHADER_GLSL) - shader_glsl_load_constants((IWineD3DStateBlock*)This->stateBlock, usePixelShaderFunction, useVertexShaderFunction); - else if (wined3d_settings.shader_mode == SHADER_ARB) - shader_arb_load_constants((IWineD3DStateBlock*)This->stateBlock, usePixelShaderFunction, useVertexShaderFunction); + if (wined3d_settings.vs_selected_mode == SHADER_GLSL || wined3d_settings.ps_selected_mode == SHADER_GLSL) + shader_glsl_load_constants((IWineD3DStateBlock*)This->stateBlock, usePixelShaderFunction, useVertexShaderFunction); + else if (wined3d_settings.vs_selected_mode== SHADER_ARB || wined3d_settings.ps_selected_mode == SHADER_ARB) + shader_arb_load_constants((IWineD3DStateBlock*)This->stateBlock, usePixelShaderFunction, useVertexShaderFunction); /* DirectX colours are in a different format to opengl colours @@ -2046,12 +2048,12 @@ UINT numberOfvertices, UINT numberOfIndicies, GLenum glPrimType, const void *idx checkGLcall("glDisableVertexAttribArrayARB(reg);"); } - if (wined3d_settings.shader_mode == SHADER_ARB) + if (wined3d_settings.vs_selected_mode == SHADER_ARB) glDisable(GL_VERTEX_PROGRAM_ARB); } /* Cleanup fragment program */ - if (usePixelShaderFunction && wined3d_settings.shader_mode == SHADER_ARB) { + if (usePixelShaderFunction && wined3d_settings.ps_selected_mode == SHADER_ARB) { glDisable(GL_FRAGMENT_PROGRAM_ARB); } } @@ -2278,19 +2280,15 @@ void drawPrimitive(IWineD3DDevice *iface, int useHW = FALSE, i; BOOL fixup = FALSE; - if (This->stateBlock->vertexShader != NULL && wined3d_settings.vs_mode != VS_NONE - &&((IWineD3DVertexShaderImpl *)This->stateBlock->vertexShader)->baseShader.function != NULL - && GL_SUPPORT(ARB_VERTEX_PROGRAM)) { + /* Shaders can be implemented using ARB_PROGRAM, GLSL, or software - + * here simply check whether a shader was set, or the user disabled shaders */ + if (wined3d_settings.vs_selected_mode != SHADER_NONE && This->stateBlock->vertexShader && + ((IWineD3DVertexShaderImpl *)This->stateBlock->vertexShader)->baseShader.function != NULL) useVertexShaderFunction = TRUE; - } else { - useVertexShaderFunction = FALSE; - } - if (wined3d_settings.ps_mode != PS_NONE && GL_SUPPORT(ARB_FRAGMENT_PROGRAM) - && This->stateBlock->pixelShader - && ((IWineD3DPixelShaderImpl *)This->stateBlock->pixelShader)->baseShader.function) { + if (wined3d_settings.ps_selected_mode != SHADER_NONE && This->stateBlock->pixelShader && + ((IWineD3DPixelShaderImpl *)This->stateBlock->pixelShader)->baseShader.function) usePixelShaderFunction = TRUE; - } if (This->stateBlock->vertexDecl == NULL) { /* Work out what the FVF should look like */ diff --git a/dlls/wined3d/pixelshader.c b/dlls/wined3d/pixelshader.c index a61fa832a6..933cfc3f4b 100644 --- a/dlls/wined3d/pixelshader.c +++ b/dlls/wined3d/pixelshader.c @@ -73,7 +73,7 @@ static ULONG WINAPI IWineD3DPixelShaderImpl_Release(IWineD3DPixelShader *iface) ref = InterlockedDecrement(&This->ref); if (ref == 0) { HeapFree(GetProcessHeap(), 0, This); - if (wined3d_settings.shader_mode == SHADER_GLSL && This->baseShader.prgId != 0) { + if (This->baseShader.shader_mode == SHADER_GLSL && This->baseShader.prgId != 0) { /* If this shader is still attached to a program, GL will perform a lazy delete */ TRACE("Deleting shader object %u\n", This->baseShader.prgId); GL_EXTCALL(glDeleteObjectARB(This->baseShader.prgId)); @@ -829,7 +829,7 @@ inline static VOID IWineD3DPixelShaderImpl_GenerateShader( buffer.bsize = 0; buffer.lineNo = 0; - if (wined3d_settings.shader_mode == SHADER_GLSL) { + if (This->baseShader.shader_mode == SHADER_GLSL) { /* Create the hw GLSL shader object and assign it as the baseShader.prgId */ GLhandleARB shader_obj = GL_EXTCALL(glCreateShaderObjectARB(GL_FRAGMENT_SHADER_ARB)); @@ -857,7 +857,7 @@ inline static VOID IWineD3DPixelShaderImpl_GenerateShader( /* Store the shader object */ This->baseShader.prgId = shader_obj; - } else if (wined3d_settings.shader_mode == SHADER_ARB) { + } else if (wined3d_settings.ps_selected_mode == SHADER_ARB) { /* Create the hw ARB shader */ shader_addline(&buffer, "!!ARBfp1.0\n"); @@ -913,7 +913,8 @@ static HRESULT WINAPI IWineD3DPixelShaderImpl_SetFunction(IWineD3DPixelShader *i pshader_set_limits(This); /* Generate HW shader in needed */ - if (NULL != pFunction && wined3d_settings.vs_mode == VS_HW) { + This->baseShader.shader_mode = wined3d_settings.ps_selected_mode; + if (NULL != pFunction && This->baseShader.shader_mode != SHADER_SW) { TRACE("(%p) : Generating hardware program\n", This); IWineD3DPixelShaderImpl_GenerateShader(iface, pFunction); } diff --git a/dlls/wined3d/vertexshader.c b/dlls/wined3d/vertexshader.c index c3c2e4fb6c..aa68081c12 100644 --- a/dlls/wined3d/vertexshader.c +++ b/dlls/wined3d/vertexshader.c @@ -644,7 +644,7 @@ inline static VOID IWineD3DVertexShaderImpl_GenerateShader( buffer.bsize = 0; buffer.lineNo = 0; - if (wined3d_settings.shader_mode == SHADER_GLSL) { + if (This->baseShader.shader_mode == SHADER_GLSL) { /* Create the hw GLSL shader program and assign it as the baseShader.prgId */ GLhandleARB shader_obj = GL_EXTCALL(glCreateShaderObjectARB(GL_VERTEX_SHADER_ARB)); @@ -669,7 +669,7 @@ inline static VOID IWineD3DVertexShaderImpl_GenerateShader( /* Store the shader object */ This->baseShader.prgId = shader_obj; - } else if (wined3d_settings.shader_mode == SHADER_ARB) { + } else if (This->baseShader.shader_mode == SHADER_ARB) { /* Create the hw ARB shader */ shader_addline(&buffer, "!!ARBvp1.0\n"); @@ -990,7 +990,7 @@ static ULONG WINAPI IWineD3DVertexShaderImpl_Release(IWineD3DVertexShader *iface ref = InterlockedDecrement(&This->ref); if (ref == 0) { if (This->vertexDeclaration) IWineD3DVertexDeclaration_Release(This->vertexDeclaration); - if (wined3d_settings.shader_mode == SHADER_GLSL && This->baseShader.prgId != 0) { + if (This->baseShader.shader_mode == SHADER_GLSL && This->baseShader.prgId != 0) { /* If this shader is still attached to a program, GL will perform a lazy delete */ TRACE("Deleting shader object %u\n", This->baseShader.prgId); GL_EXTCALL(glDeleteObjectARB(This->baseShader.prgId)); @@ -1055,7 +1055,8 @@ static HRESULT WINAPI IWineD3DVertexShaderImpl_SetFunction(IWineD3DVertexShader vshader_set_limits(This); /* Generate HW shader in needed */ - if (NULL != pFunction && wined3d_settings.vs_mode == VS_HW) + This->baseShader.shader_mode = wined3d_settings.vs_selected_mode; + if (NULL != pFunction && This->baseShader.shader_mode != SHADER_SW) IWineD3DVertexShaderImpl_GenerateShader(iface, pFunction); /* copy the function ... because it will certainly be released by application */ @@ -1065,6 +1066,7 @@ static HRESULT WINAPI IWineD3DVertexShaderImpl_SetFunction(IWineD3DVertexShader } else { This->baseShader.function = NULL; } + return WINED3D_OK; } diff --git a/dlls/wined3d/wined3d_private.h b/dlls/wined3d/wined3d_private.h index ab5eddf7ca..0f354c1e4e 100644 --- a/dlls/wined3d/wined3d_private.h +++ b/dlls/wined3d/wined3d_private.h @@ -136,6 +136,7 @@ WINED3DGLTYPE static const glTypeLookup[D3DDECLTYPE_UNUSED] = { #define SHADER_SW 0 #define SHADER_ARB 1 #define SHADER_GLSL 2 +#define SHADER_NONE 3 typedef struct wined3d_settings_s { /* vertex and pixel shader modes */ @@ -146,7 +147,8 @@ typedef struct wined3d_settings_s { we should use it. However, until it's fully implemented, we'll leave it as a registry setting for developers. */ BOOL glslRequested; - int shader_mode; + int vs_selected_mode; + int ps_selected_mode; /* nonpower 2 function */ int nonpower2_mode; } wined3d_settings_t; @@ -1460,6 +1462,10 @@ typedef struct IWineD3DBaseShaderClass CONST DWORD *function; UINT functionLength; GLuint prgId; + + /* Type of shader backend */ + int shader_mode; + } IWineD3DBaseShaderClass; typedef struct IWineD3DBaseShaderImpl {