diff --git a/dlls/wined3d/arb_program_shader.c b/dlls/wined3d/arb_program_shader.c index e01240456f7..8c08771e0ed 100644 --- a/dlls/wined3d/arb_program_shader.c +++ b/dlls/wined3d/arb_program_shader.c @@ -40,10 +40,20 @@ WINE_DECLARE_DEBUG_CHANNEL(d3d); #define GLINFO_LOCATION (*gl_info) +/* We have to subtract any other PARAMs that we might use in our shader programs. + * ATI seems to count 2 implicit PARAMs when we use fog and NVIDIA counts 1, + * and we reference one row of the PROJECTION matrix which counts as 1 PARAM. */ +#define ARB_SHADER_RESERVED_VS_CONSTS 3 + +/* The arb shader only loads the bump mapping environment matrix into the shader if it finds + * a free constant to do that, so only reduce the number of available constants by 2 for the fog states. + */ +#define ARB_SHADER_RESERVED_PS_CONSTS 2 + /* Internally used shader constants. Applications can use constants 0 to GL_LIMITS(vshader_constantsF) - 1, * so upload them above that */ -#define ARB_SHADER_PRIVCONST_BASE GL_LIMITS(vshader_constantsF) +#define ARB_SHADER_PRIVCONST_BASE (GL_LIMITS(vshader_constantsF) - ARB_SHADER_RESERVED_VS_CONSTS) #define ARB_SHADER_PRIVCONST_POS ARB_SHADER_PRIVCONST_BASE + 0 /* ARB_program_shader private data */ @@ -258,7 +268,8 @@ static void shader_generate_arb_declarations(IWineD3DBaseShader *iface, const sh DWORD i, cur; char pshader = shader_is_pshader_version(reg_maps->shader_version); unsigned max_constantsF = min(This->baseShader.limits.constant_float, - (pshader ? GL_LIMITS(pshader_constantsF) : GL_LIMITS(vshader_constantsF))); + (pshader ? GL_LIMITS(pshader_constantsF) - ARB_SHADER_RESERVED_PS_CONSTS : + GL_LIMITS(vshader_constantsF) - ARB_SHADER_RESERVED_VS_CONSTS)); UINT extra_constants_needed = 0; const local_constant *lconst; @@ -300,13 +311,13 @@ static void shader_generate_arb_declarations(IWineD3DBaseShader *iface, const sh * the stateblock into the shader. If no constant is available don't load, texbem will then just sample the texture without applying * bump mapping. */ - if(max_constantsF + extra_constants_needed < GL_LIMITS(pshader_constantsF)) { + if(max_constantsF + extra_constants_needed < GL_LIMITS(pshader_constantsF) - ARB_SHADER_RESERVED_PS_CONSTS) { ps->bumpenvmatconst[cur].const_num = max_constantsF + extra_constants_needed; shader_addline(buffer, "PARAM bumpenvmat%d = program.env[%d];\n", i, ps->bumpenvmatconst[cur].const_num); extra_constants_needed++; - if(reg_maps->luminanceparams && max_constantsF + extra_constants_needed < GL_LIMITS(pshader_constantsF)) { + if(reg_maps->luminanceparams && max_constantsF + extra_constants_needed < GL_LIMITS(pshader_constantsF) - ARB_SHADER_RESERVED_PS_CONSTS) { ((IWineD3DPixelShaderImpl *)This)->luminanceconst[cur].const_num = max_constantsF + extra_constants_needed; shader_addline(buffer, "PARAM luminance%d = program.env[%d];\n", i, ps->luminanceconst[cur].const_num); @@ -2170,13 +2181,14 @@ static void shader_arb_get_caps(WINED3DDEVTYPE devtype, const WineD3D_GL_Info *g if(GL_SUPPORT(ARB_VERTEX_PROGRAM)) { pCaps->VertexShaderVersion = WINED3DVS_VERSION(1,1); TRACE_(d3d_caps)("Hardware vertex shader version 1.1 enabled (ARB_PROGRAM)\n"); - pCaps->MaxVertexShaderConst = GL_LIMITS(vshader_constantsF); + pCaps->MaxVertexShaderConst = GL_LIMITS(vshader_constantsF) - ARB_SHADER_RESERVED_VS_CONSTS; } if(GL_SUPPORT(ARB_FRAGMENT_PROGRAM)) { pCaps->PixelShaderVersion = WINED3DPS_VERSION(1,4); pCaps->PixelShader1xMaxValue = 8.0; TRACE_(d3d_caps)("Hardware pixel shader version 1.4 enabled (ARB_PROGRAM)\n"); + pCaps->MaxPixelShaderConst = GL_LIMITS(pshader_constantsF) - ARB_SHADER_RESERVED_PS_CONSTS; } } diff --git a/dlls/wined3d/device.c b/dlls/wined3d/device.c index bf38d263c3a..1099872ba3b 100644 --- a/dlls/wined3d/device.c +++ b/dlls/wined3d/device.c @@ -4070,7 +4070,7 @@ static HRESULT WINAPI IWineD3DDeviceImpl_SetVertexShaderConstantF( iface, srcData, start, count); /* Specifically test start > limit to catch MAX_UINT overflows when adding start + count */ - if (srcData == NULL || start + count > GL_LIMITS(vshader_constantsF) || start > GL_LIMITS(vshader_constantsF)) + if (srcData == NULL || start + count > This->d3d_vshader_constantF || start > This->d3d_vshader_constantF) return WINED3DERR_INVALIDCALL; memcpy(&This->updateStateBlock->vertexShaderConstantF[start * 4], srcData, count * sizeof(float) * 4); @@ -4099,7 +4099,7 @@ static HRESULT WINAPI IWineD3DDeviceImpl_GetVertexShaderConstantF( UINT count) { IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface; - int cnt = min(count, GL_LIMITS(vshader_constantsF) - start); + int cnt = min(count, This->d3d_vshader_constantF - start); TRACE("(iface %p, dstData %p, start %d, count %d)\n", iface, dstData, start, count); @@ -4462,7 +4462,7 @@ static HRESULT WINAPI IWineD3DDeviceImpl_SetPixelShaderConstantF( iface, srcData, start, count); /* Specifically test start > limit to catch MAX_UINT overflows when adding start + count */ - if (srcData == NULL || start + count > GL_LIMITS(pshader_constantsF) || start > GL_LIMITS(pshader_constantsF)) + if (srcData == NULL || start + count > This->d3d_pshader_constantF || start > This->d3d_pshader_constantF) return WINED3DERR_INVALIDCALL; memcpy(&This->updateStateBlock->pixelShaderConstantF[start * 4], srcData, count * sizeof(float) * 4); @@ -4491,7 +4491,7 @@ static HRESULT WINAPI IWineD3DDeviceImpl_GetPixelShaderConstantF( UINT count) { IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface; - int cnt = min(count, GL_LIMITS(pshader_constantsF) - start); + int cnt = min(count, This->d3d_pshader_constantF - start); TRACE("(iface %p, dstData %p, start %d, count %d)\n", iface, dstData, start, count); diff --git a/dlls/wined3d/directx.c b/dlls/wined3d/directx.c index 30763dbd8e8..99d37625520 100644 --- a/dlls/wined3d/directx.c +++ b/dlls/wined3d/directx.c @@ -424,14 +424,10 @@ static void select_shader_max_constants( switch (vs_selected_mode) { case SHADER_GLSL: - /* Subtract the other potential uniforms from the max available (bools, ints, and 1 row of projection matrix) */ - gl_info->max_vshader_constantsF = gl_info->vs_glsl_constantsF - (MAX_CONST_B / 4) - MAX_CONST_I - 1; + gl_info->max_vshader_constantsF = gl_info->vs_glsl_constantsF; break; case SHADER_ARB: - /* We have to subtract any other PARAMs that we might use in our shader programs. - * ATI seems to count 2 implicit PARAMs when we use fog and NVIDIA counts 1, - * and we reference one row of the PROJECTION matrix which counts as 1 PARAM. */ - gl_info->max_vshader_constantsF = gl_info->vs_arb_constantsF - 3; + gl_info->max_vshader_constantsF = gl_info->vs_arb_constantsF; break; default: gl_info->max_vshader_constantsF = 0; @@ -440,18 +436,10 @@ static void select_shader_max_constants( switch (ps_selected_mode) { case SHADER_GLSL: - /* Subtract the other potential uniforms from the max available (bools & ints), and 2 states for fog. - * In theory the texbem instruction may need one more shader constant too. But lets assume - * that a sm <= 1.3 shader does not need all the uniforms provided by a glsl-capable card, - * and lets not take away a uniform needlessly from all other shaders. - */ - gl_info->max_pshader_constantsF = gl_info->ps_glsl_constantsF - (MAX_CONST_B / 4) - MAX_CONST_I - 2; + gl_info->max_pshader_constantsF = gl_info->ps_glsl_constantsF; break; case SHADER_ARB: - /* The arb shader only loads the bump mapping environment matrix into the shader if it finds - * a free constant to do that, so only reduce the number of available constants by 2 for the fog states. - */ - gl_info->max_pshader_constantsF = gl_info->ps_arb_constantsF - 2; + gl_info->max_pshader_constantsF = gl_info->ps_arb_constantsF; break; default: gl_info->max_pshader_constantsF = 0; @@ -3734,6 +3722,7 @@ static HRESULT WINAPI IWineD3DImpl_CreateDevice(IWineD3D *iface, UINT Adapter, const struct fragment_pipeline *frag_pipeline = NULL; int i; struct fragment_caps ffp_caps; + struct shader_caps shader_caps; HRESULT hr; /* Validate the adapter number. If no adapters are available(no GL), ignore the adapter @@ -3789,6 +3778,11 @@ static HRESULT WINAPI IWineD3DImpl_CreateDevice(IWineD3D *iface, UINT Adapter, &object->ps_selected_mode, &object->vs_selected_mode); object->shader_backend = select_shader_backend(adapter, DeviceType); + memset(&shader_caps, 0, sizeof(shader_caps)); + object->shader_backend->shader_get_caps(DeviceType, &adapter->gl_info, &shader_caps); + object->d3d_vshader_constantF = shader_caps.MaxVertexShaderConst; + object->d3d_pshader_constantF = shader_caps.MaxPixelShaderConst; + memset(&ffp_caps, 0, sizeof(ffp_caps)); frag_pipeline = select_fragment_implementation(adapter, DeviceType); object->frag_pipe = frag_pipeline; diff --git a/dlls/wined3d/glsl_shader.c b/dlls/wined3d/glsl_shader.c index 6a01ed78c63..1ed2161cbde 100644 --- a/dlls/wined3d/glsl_shader.c +++ b/dlls/wined3d/glsl_shader.c @@ -698,8 +698,15 @@ static void shader_generate_glsl_declarations(IWineD3DBaseShader *iface, const s /* Declare the constants (aka uniforms) */ if (This->baseShader.limits.constant_float > 0) { - unsigned max_constantsF = min(This->baseShader.limits.constant_float, - (pshader ? GL_LIMITS(pshader_constantsF) : GL_LIMITS(vshader_constantsF))); + unsigned max_constantsF; + if(pshader) { + max_constantsF = GL_LIMITS(pshader_constantsF) - (MAX_CONST_B / 4) - MAX_CONST_I - 2; + max_constantsF = min(This->baseShader.limits.constant_float, max_constantsF); + } else { + /* Subtract the other potential uniforms from the max available (bools, ints, and 1 row of projection matrix) */ + max_constantsF = GL_LIMITS(vshader_constantsF) - (MAX_CONST_B / 4) - MAX_CONST_I - 1; + max_constantsF = min(This->baseShader.limits.constant_float, max_constantsF); + } shader_addline(buffer, "uniform vec4 %cC[%u];\n", prefix, max_constantsF); } @@ -4118,7 +4125,8 @@ static void shader_glsl_get_caps(WINED3DDEVTYPE devtype, const WineD3D_GL_Info * 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); - pCaps->MaxVertexShaderConst = GL_LIMITS(vshader_constantsF); + /* Subtract the other potential uniforms from the max available (bools, ints, and 1 row of projection matrix) */ + pCaps->MaxVertexShaderConst = GL_LIMITS(vshader_constantsF) - (MAX_CONST_B / 4) - MAX_CONST_I - 1; /* 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 @@ -4136,6 +4144,13 @@ static void shader_glsl_get_caps(WINED3DDEVTYPE devtype, const WineD3D_GL_Info * else pCaps->PixelShaderVersion = WINED3DPS_VERSION(3,0); + /* Subtract the other potential uniforms from the max available (bools & ints), and 2 states for fog. + * In theory the texbem instruction may need one more shader constant too. But lets assume + * that a sm <= 1.3 shader does not need all the uniforms provided by a glsl-capable card, + * and lets not take away a uniform needlessly from all other shaders. + */ + pCaps->MaxPixelShaderConst = GL_LIMITS(pshader_constantsF) - (MAX_CONST_B / 4) - MAX_CONST_I - 2; + /* FIXME: The following line is card dependent. -8.0 to 8.0 is the * Direct3D minimum requirement. * diff --git a/dlls/wined3d/wined3d_private.h b/dlls/wined3d/wined3d_private.h index 82afe3b700f..ebc75613732 100644 --- a/dlls/wined3d/wined3d_private.h +++ b/dlls/wined3d/wined3d_private.h @@ -487,6 +487,7 @@ struct shader_caps { DWORD PixelShaderVersion; float PixelShader1xMaxValue; + DWORD MaxPixelShaderConst; WINED3DVSHADERCAPS2_0 VS20Caps; WINED3DPSHADERCAPS2_0 PS20Caps; @@ -1216,6 +1217,7 @@ struct IWineD3DDeviceImpl const struct blit_shader *blitter; unsigned int max_ffp_textures, max_ffp_texture_stages; + DWORD d3d_vshader_constantF, d3d_pshader_constantF; /* Advertised d3d caps, not GL ones */ WORD view_ident : 1; /* true iff view matrix is identity */ WORD untransformed : 1;