From 5ab5202e0f991cf94b2be5b197af864ff5188f65 Mon Sep 17 00:00:00 2001 From: =?utf8?q?Stefan=20D=C3=B6singer?= Date: Tue, 18 Mar 2008 19:39:26 +0100 Subject: [PATCH] wined3d: Set shader specific caps in the shader backend. The whole control structures in directx.c get terribly confusing with the various codepaths for texturing and different shader implementations. It is also hard to reflect the shader model decisions this way too. This patch moves the shader specific parts of the caps code into the shader backend where we can set our caps dependent of the shader model decisions and without complex caps flag checks. --- dlls/wined3d/arb_program_shader.c | 5 + dlls/wined3d/baseshader.c | 199 ++++++++++++++++++++++++++++++++ dlls/wined3d/directx.c | 236 ++++++-------------------------------- dlls/wined3d/glsl_shader.c | 5 + dlls/wined3d/wined3d_private.h | 26 +++++ 5 files changed, 269 insertions(+), 202 deletions(-) diff --git a/dlls/wined3d/arb_program_shader.c b/dlls/wined3d/arb_program_shader.c index d5db0787607..33b4adfc58d 100644 --- a/dlls/wined3d/arb_program_shader.c +++ b/dlls/wined3d/arb_program_shader.c @@ -2042,6 +2042,10 @@ static void shader_arb_generate_vshader(IWineD3DVertexShader *iface, SHADER_BUFF } } +static void shader_arb_get_caps(WINED3DDEVTYPE devtype, WineD3D_GL_Info *gl_info, struct shader_caps *caps) { + none_shader_backend.shader_get_caps(devtype, gl_info, caps); +} + const shader_backend_t arb_program_shader_backend = { &shader_arb_select, &shader_arb_select_depth_blt, @@ -2055,5 +2059,6 @@ const shader_backend_t arb_program_shader_backend = { &shader_arb_dirty_const, &shader_arb_generate_pshader, &shader_arb_generate_vshader, + &shader_arb_get_caps, FFPStateTable }; diff --git a/dlls/wined3d/baseshader.c b/dlls/wined3d/baseshader.c index 979546e5fa9..cbbd061d606 100644 --- a/dlls/wined3d/baseshader.c +++ b/dlls/wined3d/baseshader.c @@ -28,6 +28,7 @@ #include "wined3d_private.h" WINE_DEFAULT_DEBUG_CHANNEL(d3d_shader); +WINE_DECLARE_DEBUG_CHANNEL(d3d_caps); #define GLNAME_REQUIRE_GLSL ((const char *)1) @@ -1105,6 +1106,203 @@ static void shader_none_generate_vshader(IWineD3DVertexShader *iface, SHADER_BUF FIXME("NONE shader backend asked to generate a vertex shader\n"); } +#define GLINFO_LOCATION (*gl_info) +static void shader_none_get_caps(WINED3DDEVTYPE devtype, WineD3D_GL_Info *gl_info, struct shader_caps *pCaps) { + int ps_selected_mode, vs_selected_mode; + + pCaps->TextureOpCaps = WINED3DTEXOPCAPS_ADD | + WINED3DTEXOPCAPS_ADDSIGNED | + WINED3DTEXOPCAPS_ADDSIGNED2X | + WINED3DTEXOPCAPS_MODULATE | + WINED3DTEXOPCAPS_MODULATE2X | + WINED3DTEXOPCAPS_MODULATE4X | + WINED3DTEXOPCAPS_SELECTARG1 | + WINED3DTEXOPCAPS_SELECTARG2 | + WINED3DTEXOPCAPS_DISABLE; + + if (GL_SUPPORT(ARB_TEXTURE_ENV_COMBINE) || + GL_SUPPORT(EXT_TEXTURE_ENV_COMBINE) || + GL_SUPPORT(NV_TEXTURE_ENV_COMBINE4)) { + pCaps->TextureOpCaps |= WINED3DTEXOPCAPS_BLENDDIFFUSEALPHA | + WINED3DTEXOPCAPS_BLENDTEXTUREALPHA | + WINED3DTEXOPCAPS_BLENDFACTORALPHA | + WINED3DTEXOPCAPS_BLENDCURRENTALPHA | + WINED3DTEXOPCAPS_LERP | + WINED3DTEXOPCAPS_SUBTRACT; + } + if (GL_SUPPORT(ATI_TEXTURE_ENV_COMBINE3) || + GL_SUPPORT(NV_TEXTURE_ENV_COMBINE4)) { + pCaps->TextureOpCaps |= WINED3DTEXOPCAPS_ADDSMOOTH | + WINED3DTEXOPCAPS_MULTIPLYADD | + WINED3DTEXOPCAPS_MODULATEALPHA_ADDCOLOR | + WINED3DTEXOPCAPS_MODULATECOLOR_ADDALPHA | + WINED3DTEXOPCAPS_BLENDTEXTUREALPHAPM; + } + if (GL_SUPPORT(ARB_TEXTURE_ENV_DOT3)) + pCaps->TextureOpCaps |= WINED3DTEXOPCAPS_DOTPRODUCT3; + + if (GL_SUPPORT(NV_REGISTER_COMBINERS)) { + pCaps->TextureOpCaps |= WINED3DTEXOPCAPS_MODULATEINVALPHA_ADDCOLOR | + WINED3DTEXOPCAPS_MODULATEINVCOLOR_ADDALPHA; + } + + if(GL_SUPPORT(ATI_ENVMAP_BUMPMAP)) { + pCaps->TextureOpCaps |= WINED3DTEXOPCAPS_BUMPENVMAP; + } else if(GL_SUPPORT(NV_TEXTURE_SHADER2)) { + /* Bump mapping is supported already in NV_TEXTURE_SHADER, but that extension does + * not support 3D textures. This asks for trouble if an app uses both bump mapping + * and 3D textures. It also allows us to keep the code simpler by having texture + * shaders constantly enabled. + */ + pCaps->TextureOpCaps |= WINED3DTEXOPCAPS_BUMPENVMAP; + /* TODO: Luminance bump map? */ + } + +#if 0 + /* FIXME: Add + pCaps->TextureOpCaps |= WINED3DTEXOPCAPS_BUMPENVMAPLUMINANCE + WINED3DTEXOPCAPS_PREMODULATE */ +#endif + + pCaps->MaxTextureBlendStages = GL_LIMITS(texture_stages); + pCaps->MaxSimultaneousTextures = GL_LIMITS(textures); + + /* FIXME: This doesn't belong here. Its just here to make the initial shader model caps selection + * a NOP + */ + select_shader_mode(&GLINFO_LOCATION, devtype, &ps_selected_mode, &vs_selected_mode); + + if (vs_selected_mode == SHADER_GLSL) { + /* Nvidia Geforce6/7 or Ati R4xx/R5xx cards with GLSL support, support VS 3.0 but older Nvidia/Ati + * models with GLSL support only support 2.0. In case of nvidia we can detect VS 2.0 support using + * vs_nv_version which is based on NV_vertex_program. + * For Ati cards there's no way using glsl (it abstracts the lowlevel info away) and also not + * using ARB_vertex_program. It is safe to assume that when a card supports pixel shader 2.0 it + * supports vertex shader 2.0 too and the way around. We can detect ps2.0 using the maximum number + * of native instructions, so use that here. For more info see the pixel shader versioning code below. */ + if((GLINFO_LOCATION.vs_nv_version == VS_VERSION_20) || (GLINFO_LOCATION.ps_arb_max_instructions <= 512)) + pCaps->VertexShaderVersion = WINED3DVS_VERSION(2,0); + else + pCaps->VertexShaderVersion = WINED3DVS_VERSION(3,0); + TRACE_(d3d_caps)("Hardware vertex shader version %d.%d enabled (GLSL)\n", (pCaps->VertexShaderVersion >> 8) & 0xff, pCaps->VertexShaderVersion & 0xff); + } else if (vs_selected_mode == SHADER_ARB) { + pCaps->VertexShaderVersion = WINED3DVS_VERSION(1,1); + TRACE_(d3d_caps)("Hardware vertex shader version 1.1 enabled (ARB_PROGRAM)\n"); + } else { + pCaps->VertexShaderVersion = 0; + TRACE_(d3d_caps)("Vertex shader functionality not available\n"); + } + + pCaps->MaxVertexShaderConst = GL_LIMITS(vshader_constantsF); + + if (ps_selected_mode == SHADER_GLSL) { + /* Older DX9-class videocards (GeforceFX / Radeon >9500/X*00) only support pixel shader 2.0/2.0a/2.0b. + * In OpenGL the extensions related to GLSL abstract lowlevel GL info away which is needed + * to distinguish between 2.0 and 3.0 (and 2.0a/2.0b). In case of Nvidia we use their fragment + * program extensions. On other hardware including ATI GL_ARB_fragment_program offers the info + * in max native instructions. Intel and others also offer the info in this extension but they + * don't support GLSL (at least on Windows). + * + * PS2.0 requires at least 96 instructions, 2.0a/2.0b go up to 512. Assume that if the number + * of instructions is 512 or less we have to do with ps2.0 hardware. + * NOTE: ps3.0 hardware requires 512 or more instructions but ati and nvidia offer 'enough' (1024 vs 4096) on their most basic ps3.0 hardware. + */ + if((GLINFO_LOCATION.ps_nv_version == PS_VERSION_20) || (GLINFO_LOCATION.ps_arb_max_instructions <= 512)) + pCaps->PixelShaderVersion = WINED3DPS_VERSION(2,0); + else + pCaps->PixelShaderVersion = WINED3DPS_VERSION(3,0); + /* FIXME: The following line is card dependent. -8.0 to 8.0 is the + * Direct3D minimum requirement. + * + * Both GL_ARB_fragment_program and GLSL require a "maximum representable magnitude" + * of colors to be 2^10, and 2^32 for other floats. Should we use 1024 here? + * + * The problem is that the refrast clamps temporary results in the shader to + * [-MaxValue;+MaxValue]. If the card's max value is bigger than the one we advertize here, + * then applications may miss the clamping behavior. On the other hand, if it is smaller, + * the shader will generate incorrect results too. Unfortunately, GL deliberately doesn't + * offer a way to query this. + */ + pCaps->PixelShader1xMaxValue = 8.0; + TRACE_(d3d_caps)("Hardware pixel shader version %d.%d enabled (GLSL)\n", (pCaps->PixelShaderVersion >> 8) & 0xff, pCaps->PixelShaderVersion & 0xff); + } else if (ps_selected_mode == SHADER_ARB) { + pCaps->PixelShaderVersion = WINED3DPS_VERSION(1,4); + pCaps->PixelShader1xMaxValue = 8.0; + TRACE_(d3d_caps)("Hardware pixel shader version 1.4 enabled (ARB_PROGRAM)\n"); + } else { + pCaps->PixelShaderVersion = 0; + pCaps->PixelShader1xMaxValue = 0.0; + TRACE_(d3d_caps)("Pixel shader functionality not available\n"); + } + + if(pCaps->VertexShaderVersion == WINED3DVS_VERSION(3,0)) { + /* Where possible set the caps based on OpenGL extensions and if they aren't set (in case of software rendering) + use the VS 3.0 from MSDN or else if there's OpenGL spec use a hardcoded value minimum VS3.0 value. */ + pCaps->VS20Caps.Caps = WINED3DVS20CAPS_PREDICATION; + pCaps->VS20Caps.DynamicFlowControlDepth = WINED3DVS20_MAX_DYNAMICFLOWCONTROLDEPTH; /* VS 3.0 requires MAX_DYNAMICFLOWCONTROLDEPTH (24) */ + pCaps->VS20Caps.NumTemps = max(32, GLINFO_LOCATION.vs_arb_max_temps); + pCaps->VS20Caps.StaticFlowControlDepth = WINED3DVS20_MAX_STATICFLOWCONTROLDEPTH ; /* level of nesting in loops / if-statements; VS 3.0 requires MAX (4) */ + + pCaps->MaxVShaderInstructionsExecuted = 65535; /* VS 3.0 needs at least 65535, some cards even use 2^32-1 */ + pCaps->MaxVertexShader30InstructionSlots = max(512, GLINFO_LOCATION.vs_arb_max_instructions); + } else if(pCaps->VertexShaderVersion == WINED3DVS_VERSION(2,0)) { + pCaps->VS20Caps.Caps = 0; + pCaps->VS20Caps.DynamicFlowControlDepth = WINED3DVS20_MIN_DYNAMICFLOWCONTROLDEPTH; + pCaps->VS20Caps.NumTemps = max(12, GLINFO_LOCATION.vs_arb_max_temps); + pCaps->VS20Caps.StaticFlowControlDepth = 1; + + pCaps->MaxVShaderInstructionsExecuted = 65535; + pCaps->MaxVertexShader30InstructionSlots = 0; + } else { /* VS 1.x */ + pCaps->VS20Caps.Caps = 0; + pCaps->VS20Caps.DynamicFlowControlDepth = 0; + pCaps->VS20Caps.NumTemps = 0; + pCaps->VS20Caps.StaticFlowControlDepth = 0; + + pCaps->MaxVShaderInstructionsExecuted = 0; + pCaps->MaxVertexShader30InstructionSlots = 0; + } + + if(pCaps->PixelShaderVersion == WINED3DPS_VERSION(3,0)) { + /* Where possible set the caps based on OpenGL extensions and if they aren't set (in case of software rendering) + use the PS 3.0 from MSDN or else if there's OpenGL spec use a hardcoded value minimum PS 3.0 value. */ + + /* Caps is more or less undocumented on MSDN but it appears to be used for PS20Caps based on results from R9600/FX5900/Geforce6800 cards from Windows */ + pCaps->PS20Caps.Caps = WINED3DPS20CAPS_ARBITRARYSWIZZLE | + WINED3DPS20CAPS_GRADIENTINSTRUCTIONS | + WINED3DPS20CAPS_PREDICATION | + WINED3DPS20CAPS_NODEPENDENTREADLIMIT | + WINED3DPS20CAPS_NOTEXINSTRUCTIONLIMIT; + pCaps->PS20Caps.DynamicFlowControlDepth = WINED3DPS20_MAX_DYNAMICFLOWCONTROLDEPTH; /* PS 3.0 requires MAX_DYNAMICFLOWCONTROLDEPTH (24) */ + pCaps->PS20Caps.NumTemps = max(32, GLINFO_LOCATION.ps_arb_max_temps); + pCaps->PS20Caps.StaticFlowControlDepth = WINED3DPS20_MAX_STATICFLOWCONTROLDEPTH; /* PS 3.0 requires MAX_STATICFLOWCONTROLDEPTH (4) */ + pCaps->PS20Caps.NumInstructionSlots = WINED3DPS20_MAX_NUMINSTRUCTIONSLOTS; /* PS 3.0 requires MAX_NUMINSTRUCTIONSLOTS (512) */ + + pCaps->MaxPShaderInstructionsExecuted = 65535; + pCaps->MaxPixelShader30InstructionSlots = max(WINED3DMIN30SHADERINSTRUCTIONS, GLINFO_LOCATION.ps_arb_max_instructions); + } else if(pCaps->PixelShaderVersion == WINED3DPS_VERSION(2,0)) { + /* Below we assume PS2.0 specs, not extended 2.0a(GeforceFX)/2.0b(Radeon R3xx) ones */ + pCaps->PS20Caps.Caps = 0; + pCaps->PS20Caps.DynamicFlowControlDepth = 0; /* WINED3DVS20_MIN_DYNAMICFLOWCONTROLDEPTH = 0 */ + pCaps->PS20Caps.NumTemps = max(12, GLINFO_LOCATION.ps_arb_max_temps); + pCaps->PS20Caps.StaticFlowControlDepth = WINED3DPS20_MIN_STATICFLOWCONTROLDEPTH; /* Minimum: 1 */ + pCaps->PS20Caps.NumInstructionSlots = WINED3DPS20_MIN_NUMINSTRUCTIONSLOTS; /* Minimum number (64 ALU + 32 Texture), a GeforceFX uses 512 */ + + pCaps->MaxPShaderInstructionsExecuted = 512; /* Minimum value, a GeforceFX uses 1024 */ + pCaps->MaxPixelShader30InstructionSlots = 0; + } else { /* PS 1.x */ + pCaps->PS20Caps.Caps = 0; + pCaps->PS20Caps.DynamicFlowControlDepth = 0; + pCaps->PS20Caps.NumTemps = 0; + pCaps->PS20Caps.StaticFlowControlDepth = 0; + pCaps->PS20Caps.NumInstructionSlots = 0; + + pCaps->MaxPShaderInstructionsExecuted = 0; + pCaps->MaxPixelShader30InstructionSlots = 0; + } +} +#undef GLINFO_LOCATION + const shader_backend_t none_shader_backend = { &shader_none_select, &shader_none_select_depth_blt, @@ -1118,6 +1316,7 @@ const shader_backend_t none_shader_backend = { &shader_none_dirty_const, &shader_none_generate_pshader, &shader_none_generate_vshader, + &shader_none_get_caps, FFPStateTable }; diff --git a/dlls/wined3d/directx.c b/dlls/wined3d/directx.c index cb22d3c049d..addf1dbde1d 100644 --- a/dlls/wined3d/directx.c +++ b/dlls/wined3d/directx.c @@ -348,7 +348,7 @@ static ULONG WINAPI IWineD3DImpl_Release(IWineD3D *iface) { /* 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( +void select_shader_mode( WineD3D_GL_Info *gl_info, WINED3DDEVTYPE DeviceType, int* ps_selected, @@ -2662,6 +2662,8 @@ static HRESULT WINAPI IWineD3DImpl_GetDeviceCaps(IWineD3D *iface, UINT Adapter, IWineD3DImpl *This = (IWineD3DImpl *)iface; int vs_selected_mode; int ps_selected_mode; + struct shader_caps shader_caps; + const shader_backend_t *shader_backend; TRACE_(d3d_caps)("(%p)->(Adptr:%d, DevType: %x, pCaps: %p)\n", This, Adapter, DeviceType, pCaps); @@ -2984,61 +2986,6 @@ static HRESULT WINAPI IWineD3DImpl_GetDeviceCaps(IWineD3D *iface, UINT Adapter, pCaps->FVFCaps = WINED3DFVFCAPS_PSIZE | 0x0008; /* 8 texture coords */ - pCaps->TextureOpCaps = WINED3DTEXOPCAPS_ADD | - WINED3DTEXOPCAPS_ADDSIGNED | - WINED3DTEXOPCAPS_ADDSIGNED2X | - WINED3DTEXOPCAPS_MODULATE | - WINED3DTEXOPCAPS_MODULATE2X | - WINED3DTEXOPCAPS_MODULATE4X | - WINED3DTEXOPCAPS_SELECTARG1 | - WINED3DTEXOPCAPS_SELECTARG2 | - WINED3DTEXOPCAPS_DISABLE; - - if (GL_SUPPORT(ARB_TEXTURE_ENV_COMBINE) || - GL_SUPPORT(EXT_TEXTURE_ENV_COMBINE) || - GL_SUPPORT(NV_TEXTURE_ENV_COMBINE4)) { - pCaps->TextureOpCaps |= WINED3DTEXOPCAPS_BLENDDIFFUSEALPHA | - WINED3DTEXOPCAPS_BLENDTEXTUREALPHA | - WINED3DTEXOPCAPS_BLENDFACTORALPHA | - WINED3DTEXOPCAPS_BLENDCURRENTALPHA | - WINED3DTEXOPCAPS_LERP | - WINED3DTEXOPCAPS_SUBTRACT; - } - if (GL_SUPPORT(ATI_TEXTURE_ENV_COMBINE3) || - GL_SUPPORT(NV_TEXTURE_ENV_COMBINE4)) { - pCaps->TextureOpCaps |= WINED3DTEXOPCAPS_ADDSMOOTH | - WINED3DTEXOPCAPS_MULTIPLYADD | - WINED3DTEXOPCAPS_MODULATEALPHA_ADDCOLOR | - WINED3DTEXOPCAPS_MODULATECOLOR_ADDALPHA | - WINED3DTEXOPCAPS_BLENDTEXTUREALPHAPM; - } - if (GL_SUPPORT(ARB_TEXTURE_ENV_DOT3)) - pCaps->TextureOpCaps |= WINED3DTEXOPCAPS_DOTPRODUCT3; - - if (GL_SUPPORT(NV_REGISTER_COMBINERS)) { - pCaps->TextureOpCaps |= WINED3DTEXOPCAPS_MODULATEINVALPHA_ADDCOLOR | - WINED3DTEXOPCAPS_MODULATEINVCOLOR_ADDALPHA; - } - - if(GL_SUPPORT(ATI_ENVMAP_BUMPMAP)) { - pCaps->TextureOpCaps |= WINED3DTEXOPCAPS_BUMPENVMAP; - } else if(GL_SUPPORT(NV_TEXTURE_SHADER2)) { - /* Bump mapping is supported already in NV_TEXTURE_SHADER, but that extension does - * not support 3D textures. This asks for trouble if an app uses both bump mapping - * and 3D textures. It also allows us to keep the code simpler by having texture - * shaders constantly enabled. - */ - pCaps->TextureOpCaps |= WINED3DTEXOPCAPS_BUMPENVMAP; - /* TODO: Luminance bump map? */ - } -#if 0 - /* FIXME: Add - pCaps->TextureOpCaps |= WINED3DTEXOPCAPS_BUMPENVMAPLUMINANCE - WINED3DTEXOPCAPS_PREMODULATE */ -#endif - - pCaps->MaxTextureBlendStages = GL_LIMITS(texture_stages); - pCaps->MaxSimultaneousTextures = GL_LIMITS(textures); pCaps->MaxUserClipPlanes = GL_LIMITS(clipplanes); pCaps->MaxActiveLights = GL_LIMITS(lights); @@ -3063,72 +3010,6 @@ static HRESULT WINAPI IWineD3DImpl_GetDeviceCaps(IWineD3D *iface, UINT Adapter, pCaps->MaxStreams = MAX_STREAMS; pCaps->MaxStreamStride = 1024; - if (vs_selected_mode == SHADER_GLSL) { - /* Nvidia Geforce6/7 or Ati R4xx/R5xx cards with GLSL support, support VS 3.0 but older Nvidia/Ati - * models with GLSL support only support 2.0. In case of nvidia we can detect VS 2.0 support using - * vs_nv_version which is based on NV_vertex_program. - * For Ati cards there's no way using glsl (it abstracts the lowlevel info away) and also not - * using ARB_vertex_program. It is safe to assume that when a card supports pixel shader 2.0 it - * supports vertex shader 2.0 too and the way around. We can detect ps2.0 using the maximum number - * of native instructions, so use that here. For more info see the pixel shader versioning code below. */ - if((GLINFO_LOCATION.vs_nv_version == VS_VERSION_20) || (GLINFO_LOCATION.ps_arb_max_instructions <= 512)) - pCaps->VertexShaderVersion = WINED3DVS_VERSION(2,0); - else - pCaps->VertexShaderVersion = WINED3DVS_VERSION(3,0); - TRACE_(d3d_caps)("Hardware vertex shader version %d.%d enabled (GLSL)\n", (pCaps->VertexShaderVersion >> 8) & 0xff, pCaps->VertexShaderVersion & 0xff); - } else if (vs_selected_mode == SHADER_ARB) { - pCaps->VertexShaderVersion = WINED3DVS_VERSION(1,1); - TRACE_(d3d_caps)("Hardware vertex shader version 1.1 enabled (ARB_PROGRAM)\n"); - } else { - pCaps->VertexShaderVersion = 0; - TRACE_(d3d_caps)("Vertex shader functionality not available\n"); - } - - pCaps->MaxVertexShaderConst = GL_LIMITS(vshader_constantsF); - - if (ps_selected_mode == SHADER_GLSL) { - /* Older DX9-class videocards (GeforceFX / Radeon >9500/X*00) only support pixel shader 2.0/2.0a/2.0b. - * In OpenGL the extensions related to GLSL abstract lowlevel GL info away which is needed - * to distinguish between 2.0 and 3.0 (and 2.0a/2.0b). In case of Nvidia we use their fragment - * program extensions. On other hardware including ATI GL_ARB_fragment_program offers the info - * in max native instructions. Intel and others also offer the info in this extension but they - * don't support GLSL (at least on Windows). - * - * PS2.0 requires at least 96 instructions, 2.0a/2.0b go up to 512. Assume that if the number - * of instructions is 512 or less we have to do with ps2.0 hardware. - * NOTE: ps3.0 hardware requires 512 or more instructions but ati and nvidia offer 'enough' (1024 vs 4096) on their most basic ps3.0 hardware. - */ - if((GLINFO_LOCATION.ps_nv_version == PS_VERSION_20) || (GLINFO_LOCATION.ps_arb_max_instructions <= 512)) - pCaps->PixelShaderVersion = WINED3DPS_VERSION(2,0); - else - pCaps->PixelShaderVersion = WINED3DPS_VERSION(3,0); - /* FIXME: The following line is card dependent. -8.0 to 8.0 is the - * Direct3D minimum requirement. - * - * Both GL_ARB_fragment_program and GLSL require a "maximum representable magnitude" - * of colors to be 2^10, and 2^32 for other floats. Should we use 1024 here? - * - * The problem is that the refrast clamps temporary results in the shader to - * [-MaxValue;+MaxValue]. If the card's max value is bigger than the one we advertize here, - * then applications may miss the clamping behavior. On the other hand, if it is smaller, - * the shader will generate incorrect results too. Unfortunately, GL deliberately doesn't - * offer a way to query this. - */ - pCaps->PixelShader1xMaxValue = 8.0; - TRACE_(d3d_caps)("Hardware pixel shader version %d.%d enabled (GLSL)\n", (pCaps->PixelShaderVersion >> 8) & 0xff, pCaps->PixelShaderVersion & 0xff); - } else if (ps_selected_mode == SHADER_ARB) { - pCaps->PixelShaderVersion = WINED3DPS_VERSION(1,4); - pCaps->PixelShader1xMaxValue = 8.0; - TRACE_(d3d_caps)("Hardware pixel shader version 1.4 enabled (ARB_PROGRAM)\n"); - } else { - pCaps->PixelShaderVersion = 0; - pCaps->PixelShader1xMaxValue = 0.0; - TRACE_(d3d_caps)("Pixel shader functionality not available\n"); - } - - /* ------------------------------------------------ - The following fields apply to d3d9 only - ------------------------------------------------ */ /* d3d9.dll sets D3DDEVCAPS2_CAN_STRETCHRECT_FROM_TEXTURES here because StretchRects is implemented in d3d9 */ pCaps->DevCaps2 = WINED3DDEVCAPS2_STREAMOFFSET; /* TODO: VS3.0 needs at least D3DDEVCAPS2_VERTEXELEMENTSCANSHARESTREAMOFFSET */ @@ -3137,6 +3018,32 @@ static HRESULT WINAPI IWineD3DImpl_GetDeviceCaps(IWineD3D *iface, UINT Adapter, pCaps->AdapterOrdinalInGroup = 0; pCaps->NumberOfAdaptersInGroup = 1; + pCaps->NumSimultaneousRTs = GL_LIMITS(buffers); + + pCaps->StretchRectFilterCaps = WINED3DPTFILTERCAPS_MINFPOINT | + WINED3DPTFILTERCAPS_MAGFPOINT | + WINED3DPTFILTERCAPS_MINFLINEAR | + WINED3DPTFILTERCAPS_MAGFLINEAR; + pCaps->VertexTextureFilterCaps = 0; + + memset(&shader_caps, 0, sizeof(shader_caps)); + shader_backend = select_shader_backend(Adapter, DeviceType); + shader_backend->shader_get_caps(DeviceType, &GLINFO_LOCATION, &shader_caps); + + pCaps->TextureOpCaps = shader_caps.TextureOpCaps; + pCaps->MaxTextureBlendStages = shader_caps.MaxTextureBlendStages; + pCaps->MaxSimultaneousTextures = shader_caps.MaxSimultaneousTextures; + pCaps->VertexShaderVersion = shader_caps.VertexShaderVersion; + pCaps->MaxVertexShaderConst = shader_caps.MaxVertexShaderConst; + pCaps->PixelShaderVersion = shader_caps.PixelShaderVersion; + pCaps->PixelShader1xMaxValue = shader_caps.PixelShader1xMaxValue; + pCaps->VS20Caps = shader_caps.VS20Caps; + pCaps->MaxVShaderInstructionsExecuted = shader_caps.MaxVShaderInstructionsExecuted; + pCaps->MaxVertexShader30InstructionSlots= shader_caps.MaxVertexShader30InstructionSlots; + pCaps->PS20Caps = shader_caps.PS20Caps; + pCaps->MaxPShaderInstructionsExecuted = shader_caps.MaxPShaderInstructionsExecuted; + pCaps->MaxPixelShader30InstructionSlots = shader_caps.MaxPixelShader30InstructionSlots; + if(pCaps->VertexShaderVersion >= WINED3DVS_VERSION(2,0)) { /* OpenGL supports all the formats below, perhaps not always * without conversion, but it supports them. @@ -3146,91 +3053,16 @@ static HRESULT WINAPI IWineD3DImpl_GetDeviceCaps(IWineD3D *iface, UINT Adapter, * support it. * TODO: WINED3DDTCAPS_USHORT2N, WINED3DDTCAPS_USHORT4N, WINED3DDTCAPS_UDEC3, WINED3DDTCAPS_DEC3N */ pCaps->DeclTypes = WINED3DDTCAPS_UBYTE4 | - WINED3DDTCAPS_UBYTE4N | - WINED3DDTCAPS_SHORT2N | - WINED3DDTCAPS_SHORT4N; + WINED3DDTCAPS_UBYTE4N | + WINED3DDTCAPS_SHORT2N | + WINED3DDTCAPS_SHORT4N; if (GL_SUPPORT(NV_HALF_FLOAT)) { - pCaps->DeclTypes |= - WINED3DDTCAPS_FLOAT16_2 | - WINED3DDTCAPS_FLOAT16_4; + pCaps->DeclTypes |= WINED3DDTCAPS_FLOAT16_2 | + WINED3DDTCAPS_FLOAT16_4; } } else pCaps->DeclTypes = 0; - pCaps->NumSimultaneousRTs = GL_LIMITS(buffers); - - pCaps->StretchRectFilterCaps = WINED3DPTFILTERCAPS_MINFPOINT | - WINED3DPTFILTERCAPS_MAGFPOINT | - WINED3DPTFILTERCAPS_MINFLINEAR | - WINED3DPTFILTERCAPS_MAGFLINEAR; - pCaps->VertexTextureFilterCaps = 0; - - if(pCaps->VertexShaderVersion == WINED3DVS_VERSION(3,0)) { - /* Where possible set the caps based on OpenGL extensions and if they aren't set (in case of software rendering) - use the VS 3.0 from MSDN or else if there's OpenGL spec use a hardcoded value minimum VS3.0 value. */ - pCaps->VS20Caps.Caps = WINED3DVS20CAPS_PREDICATION; - pCaps->VS20Caps.DynamicFlowControlDepth = WINED3DVS20_MAX_DYNAMICFLOWCONTROLDEPTH; /* VS 3.0 requires MAX_DYNAMICFLOWCONTROLDEPTH (24) */ - pCaps->VS20Caps.NumTemps = max(32, GLINFO_LOCATION.vs_arb_max_temps); - pCaps->VS20Caps.StaticFlowControlDepth = WINED3DVS20_MAX_STATICFLOWCONTROLDEPTH ; /* level of nesting in loops / if-statements; VS 3.0 requires MAX (4) */ - - pCaps->MaxVShaderInstructionsExecuted = 65535; /* VS 3.0 needs at least 65535, some cards even use 2^32-1 */ - pCaps->MaxVertexShader30InstructionSlots = max(512, GLINFO_LOCATION.vs_arb_max_instructions); - } else if(pCaps->VertexShaderVersion == WINED3DVS_VERSION(2,0)) { - pCaps->VS20Caps.Caps = 0; - pCaps->VS20Caps.DynamicFlowControlDepth = WINED3DVS20_MIN_DYNAMICFLOWCONTROLDEPTH; - pCaps->VS20Caps.NumTemps = max(12, GLINFO_LOCATION.vs_arb_max_temps); - pCaps->VS20Caps.StaticFlowControlDepth = 1; - - pCaps->MaxVShaderInstructionsExecuted = 65535; - pCaps->MaxVertexShader30InstructionSlots = 0; - } else { /* VS 1.x */ - pCaps->VS20Caps.Caps = 0; - pCaps->VS20Caps.DynamicFlowControlDepth = 0; - pCaps->VS20Caps.NumTemps = 0; - pCaps->VS20Caps.StaticFlowControlDepth = 0; - - pCaps->MaxVShaderInstructionsExecuted = 0; - pCaps->MaxVertexShader30InstructionSlots = 0; - } - - if(pCaps->PixelShaderVersion == WINED3DPS_VERSION(3,0)) { - /* Where possible set the caps based on OpenGL extensions and if they aren't set (in case of software rendering) - use the PS 3.0 from MSDN or else if there's OpenGL spec use a hardcoded value minimum PS 3.0 value. */ - - /* Caps is more or less undocumented on MSDN but it appears to be used for PS20Caps based on results from R9600/FX5900/Geforce6800 cards from Windows */ - pCaps->PS20Caps.Caps = WINED3DPS20CAPS_ARBITRARYSWIZZLE | - WINED3DPS20CAPS_GRADIENTINSTRUCTIONS | - WINED3DPS20CAPS_PREDICATION | - WINED3DPS20CAPS_NODEPENDENTREADLIMIT | - WINED3DPS20CAPS_NOTEXINSTRUCTIONLIMIT; - pCaps->PS20Caps.DynamicFlowControlDepth = WINED3DPS20_MAX_DYNAMICFLOWCONTROLDEPTH; /* PS 3.0 requires MAX_DYNAMICFLOWCONTROLDEPTH (24) */ - pCaps->PS20Caps.NumTemps = max(32, GLINFO_LOCATION.ps_arb_max_temps); - pCaps->PS20Caps.StaticFlowControlDepth = WINED3DPS20_MAX_STATICFLOWCONTROLDEPTH; /* PS 3.0 requires MAX_STATICFLOWCONTROLDEPTH (4) */ - pCaps->PS20Caps.NumInstructionSlots = WINED3DPS20_MAX_NUMINSTRUCTIONSLOTS; /* PS 3.0 requires MAX_NUMINSTRUCTIONSLOTS (512) */ - - pCaps->MaxPShaderInstructionsExecuted = 65535; - pCaps->MaxPixelShader30InstructionSlots = max(WINED3DMIN30SHADERINSTRUCTIONS, GLINFO_LOCATION.ps_arb_max_instructions); - } else if(pCaps->PixelShaderVersion == WINED3DPS_VERSION(2,0)) { - /* Below we assume PS2.0 specs, not extended 2.0a(GeforceFX)/2.0b(Radeon R3xx) ones */ - pCaps->PS20Caps.Caps = 0; - pCaps->PS20Caps.DynamicFlowControlDepth = 0; /* WINED3DVS20_MIN_DYNAMICFLOWCONTROLDEPTH = 0 */ - pCaps->PS20Caps.NumTemps = max(12, GLINFO_LOCATION.ps_arb_max_temps); - pCaps->PS20Caps.StaticFlowControlDepth = WINED3DPS20_MIN_STATICFLOWCONTROLDEPTH; /* Minimum: 1 */ - pCaps->PS20Caps.NumInstructionSlots = WINED3DPS20_MIN_NUMINSTRUCTIONSLOTS; /* Minimum number (64 ALU + 32 Texture), a GeforceFX uses 512 */ - - pCaps->MaxPShaderInstructionsExecuted = 512; /* Minimum value, a GeforceFX uses 1024 */ - pCaps->MaxPixelShader30InstructionSlots = 0; - } else { /* PS 1.x */ - pCaps->PS20Caps.Caps = 0; - pCaps->PS20Caps.DynamicFlowControlDepth = 0; - pCaps->PS20Caps.NumTemps = 0; - pCaps->PS20Caps.StaticFlowControlDepth = 0; - pCaps->PS20Caps.NumInstructionSlots = 0; - - pCaps->MaxPShaderInstructionsExecuted = 0; - pCaps->MaxPixelShader30InstructionSlots = 0; - } - return WINED3D_OK; } diff --git a/dlls/wined3d/glsl_shader.c b/dlls/wined3d/glsl_shader.c index d7b609dc94c..7a1169baf3a 100644 --- a/dlls/wined3d/glsl_shader.c +++ b/dlls/wined3d/glsl_shader.c @@ -3525,6 +3525,10 @@ static void shader_glsl_generate_vshader(IWineD3DVertexShader *iface, SHADER_BUF This->baseShader.prgId = shader_obj; } +static void shader_glsl_get_caps(WINED3DDEVTYPE devtype, WineD3D_GL_Info *gl_info, struct shader_caps *caps) { + none_shader_backend.shader_get_caps(devtype, gl_info, caps); +} + const shader_backend_t glsl_shader_backend = { &shader_glsl_select, &shader_glsl_select_depth_blt, @@ -3538,5 +3542,6 @@ const shader_backend_t glsl_shader_backend = { &shader_glsl_dirty_const, &shader_glsl_generate_pshader, &shader_glsl_generate_vshader, + &shader_glsl_get_caps, FFPStateTable }; diff --git a/dlls/wined3d/wined3d_private.h b/dlls/wined3d/wined3d_private.h index ccafd8647d4..09ac9aea5dc 100644 --- a/dlls/wined3d/wined3d_private.h +++ b/dlls/wined3d/wined3d_private.h @@ -257,6 +257,26 @@ typedef struct SHADER_BUFFER { BOOL newline; } SHADER_BUFFER; +struct shader_caps { + DWORD TextureOpCaps; + DWORD MaxTextureBlendStages; + DWORD MaxSimultaneousTextures; + + DWORD VertexShaderVersion; + DWORD MaxVertexShaderConst; + + DWORD PixelShaderVersion; + float PixelShader1xMaxValue; + + WINED3DVSHADERCAPS2_0 VS20Caps; + WINED3DPSHADERCAPS2_0 PS20Caps; + + DWORD MaxVShaderInstructionsExecuted; + DWORD MaxPShaderInstructionsExecuted; + DWORD MaxVertexShader30InstructionSlots; + DWORD MaxPixelShader30InstructionSlots; +}; + typedef struct { void (*shader_select)(IWineD3DDevice *iface, BOOL usePS, BOOL useVS); void (*shader_select_depth_blt)(IWineD3DDevice *iface); @@ -270,6 +290,7 @@ typedef struct { BOOL (*shader_dirtifyable_constants)(IWineD3DDevice *iface); void (*shader_generate_pshader)(IWineD3DPixelShader *iface, SHADER_BUFFER *buffer); void (*shader_generate_vshader)(IWineD3DVertexShader *iface, SHADER_BUFFER *buffer); + void (*shader_get_caps)(WINED3DDEVTYPE devtype, WineD3D_GL_Info *gl_info, struct shader_caps *caps); const struct StateEntry *StateTable; } shader_backend_t; @@ -2359,4 +2380,9 @@ static inline BOOL use_ps(IWineD3DDeviceImpl *device) { void stretch_rect_fbo(IWineD3DDevice *iface, IWineD3DSurface *src_surface, WINED3DRECT *src_rect, IWineD3DSurface *dst_surface, WINED3DRECT *dst_rect, const WINED3DTEXTUREFILTERTYPE filter, BOOL flip); +void select_shader_mode( + WineD3D_GL_Info *gl_info, + WINED3DDEVTYPE DeviceType, + int* ps_selected, + int* vs_selected); #endif -- 2.11.4.GIT