wined3d: Make the number of floating point shader constants dynamic

Jason Green jave27 at gmail.com
Fri Jun 30 01:25:53 CDT 2006


The size of the floating point constant array is different for every
card.  This patch uses the GL limits for both ARB and GLSL shaders to
dynamically allocate the number of float constants available.

- Makes the register_maps struct allocate the memory dynamically
- Makes the stateblock allocate the space for the constants and the
set/changed flags dynamically
- Removes the hack for MESA drivers
- Declare the number supported in the shader programs as (gl_max -
number of locally defined constants by DEF, DEFI, and DEFB [ - number
of other uniforms which may be present in GLSL shaders])
-------------- next part --------------
diff --git a/dlls/wined3d/arb_program_shader.c b/dlls/wined3d/arb_program_shader.c
index ec6cb14..be35861 100644
--- a/dlls/wined3d/arb_program_shader.c
+++ b/dlls/wined3d/arb_program_shader.c
@@ -88,13 +88,13 @@ void shader_arb_load_constants(
         if (NULL != vertexDeclaration && NULL != vertexDeclaration->constants) {
             /* Load DirectX 8 float constants for vertex shader */
             shader_arb_load_constantsF(gl_info, GL_VERTEX_PROGRAM_ARB,
-                                       WINED3D_VSHADER_MAX_CONSTANTS,
+                                       GL_LIMITS(vshader_constantsF),
                                        vertexDeclaration->constants, NULL);
         }
 
         /* Load DirectX 9 float constants for vertex shader */
         shader_arb_load_constantsF(gl_info, GL_VERTEX_PROGRAM_ARB,
-                                   WINED3D_VSHADER_MAX_CONSTANTS,
+                                   GL_LIMITS(vshader_constantsF),
                                    stateBlock->vertexShaderConstantF,
                                    stateBlock->set.vertexShaderConstantsF);
     }
@@ -102,7 +102,7 @@ void shader_arb_load_constants(
     if (usePixelShader) {
 
         /* Load DirectX 9 float constants for pixel shader */
-        shader_arb_load_constantsF(gl_info, GL_FRAGMENT_PROGRAM_ARB, WINED3D_PSHADER_MAX_CONSTANTS,
+        shader_arb_load_constantsF(gl_info, GL_FRAGMENT_PROGRAM_ARB, GL_LIMITS(pshader_constantsF),
                                    stateBlock->pixelShaderConstantF,
                                    stateBlock->set.pixelShaderConstantsF);
     }
@@ -140,8 +140,8 @@ void shader_generate_arb_declarations(
 
     /* Need to PARAM the environment parameters (constants) so we can use relative addressing */
     shader_addline(buffer, "PARAM C[%d] = { program.env[0..%d] };\n",
-                   This->baseShader.limits.constant_float,
-                   This->baseShader.limits.constant_float - 1);
+                   This->baseShader.limits.constant_float - reg_maps->num_local_constants,
+                   This->baseShader.limits.constant_float - reg_maps->num_local_constants - 1);
 }
 
 /** Process the D3DSIO_DEF opcode into an ARB string - creates a local vec4
diff --git a/dlls/wined3d/baseshader.c b/dlls/wined3d/baseshader.c
index e9e3097..5342a31 100644
--- a/dlls/wined3d/baseshader.c
+++ b/dlls/wined3d/baseshader.c
@@ -360,8 +360,11 @@ void shader_get_registers_used(
                 reg_maps->samplers[regnum] = usage;
 
         /* Skip definitions (for now) */
-        } else if (D3DSIO_DEF == curOpcode->opcode) {
+        } else if (D3DSIO_DEF == curOpcode->opcode
+                || D3DSIO_DEFI == curOpcode->opcode
+                || D3DSIO_DEFB == curOpcode->opcode) {
             pToken += curOpcode->num_params;
+            reg_maps->num_local_constants++;
 
         /* If there's a loop in the shader */
         } else if (D3DSIO_LOOP == curOpcode->opcode) {
diff --git a/dlls/wined3d/device.c b/dlls/wined3d/device.c
index 087ba92..eedce59 100644
--- a/dlls/wined3d/device.c
+++ b/dlls/wined3d/device.c
@@ -416,6 +416,33 @@ static void delete_glsl_shader_list(IWin
     }
 }
 
+/** Allocates the correct amount of space for pixel and vertex shader constants, 
+ * along with their set/changed flags on the given stateblock object
+ */
+static HRESULT allocate_shader_constants(IWineD3DDevice* iface, IWineD3DStateBlockImpl* object) {
+    
+    IWineD3DDeviceImpl     *This = (IWineD3DDeviceImpl *)iface;
+
+#define WINED3D_MEMCHECK(_object) if (NULL == _object) { FIXME("Out of memory!\n"); return E_OUTOFMEMORY; }
+
+    /* Allocate space for floating point constants */
+    object->pixelShaderConstantF = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(float) * GL_LIMITS(pshader_constantsF) * 4);
+    WINED3D_MEMCHECK(object->pixelShaderConstantF);
+    object->set.pixelShaderConstantsF = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(BOOL) * GL_LIMITS(pshader_constantsF) );
+    WINED3D_MEMCHECK(object->set.pixelShaderConstantsF);
+    object->changed.pixelShaderConstantsF = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(BOOL) * GL_LIMITS(pshader_constantsF));
+    WINED3D_MEMCHECK(object->changed.pixelShaderConstantsF);
+    object->vertexShaderConstantF = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(float) * GL_LIMITS(vshader_constantsF) * 4);
+    WINED3D_MEMCHECK(object->vertexShaderConstantF);
+    object->set.vertexShaderConstantsF = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(BOOL) * GL_LIMITS(vshader_constantsF));
+    WINED3D_MEMCHECK(object->set.vertexShaderConstantsF);
+    object->changed.vertexShaderConstantsF = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(BOOL) * GL_LIMITS(vshader_constantsF));
+    WINED3D_MEMCHECK(object->changed.vertexShaderConstantsF);
+
+#undef WINED3D_MEMCHECK
+
+    return WINED3D_OK;
+}
 
 /* Apply the current values to the specified texture stage */
 static void WINAPI IWineD3DDeviceImpl_SetupTextureStates(IWineD3DDevice *iface, DWORD Sampler, DWORD texture_idx, DWORD Flags) {
@@ -782,10 +809,15 @@ static HRESULT WINAPI IWineD3DDeviceImpl
     IWineD3DDeviceImpl     *This = (IWineD3DDeviceImpl *)iface;
     IWineD3DStateBlockImpl *object;
     int i, j;
+    HRESULT temp_result;
 
     D3DCREATEOBJECTINSTANCE(object, StateBlock)
     object->blockType     = Type;
 
+    temp_result = allocate_shader_constants(iface, object);
+    if (WINED3D_OK != temp_result)
+        return temp_result;
+
     /* Special case - Used during initialization to produce a placeholder stateblock
           so other functions called can update a state block                         */
     if (Type == WINED3DSBT_INIT) {
@@ -820,11 +852,13 @@ static HRESULT WINAPI IWineD3DDeviceImpl
         object->changed.pixelShader = TRUE;
 
         /* Pixel Shader Constants */
-        for (i = 0; i < MAX_PSHADER_CONSTANTS; ++i) {
+        for (i = 0; i < GL_LIMITS(pshader_constantsF); ++i)
             object->changed.pixelShaderConstantsF[i] = TRUE;
+        for (i = 0; i < MAX_CONST_B; ++i)
             object->changed.pixelShaderConstantsB[i] = TRUE;
+        for (i = 0; i < MAX_CONST_I; ++i)
             object->changed.pixelShaderConstantsI[i] = TRUE;
-        }
+        
         for (i = 0; i < NUM_SAVEDPIXELSTATES_R; i++) {
             object->changed.renderState[SavedPixelStates_R[i]] = TRUE;
         }
@@ -848,11 +882,13 @@ static HRESULT WINAPI IWineD3DDeviceImpl
         object->changed.vertexShader = TRUE;
 
         /* Vertex Shader Constants */
-        for (i = 0; i < MAX_VSHADER_CONSTANTS; ++i) {
+        for (i = 0; i < GL_LIMITS(vshader_constantsF); ++i)
             object->changed.vertexShaderConstantsF[i] = TRUE;
+        for (i = 0; i < MAX_CONST_B; ++i)
             object->changed.vertexShaderConstantsB[i] = TRUE;
+        for (i = 0; i < MAX_CONST_I; ++i)
             object->changed.vertexShaderConstantsI[i] = TRUE;
-        }
+ 
         for (i = 0; i < NUM_SAVEDVERTEXSTATES_R; i++) {
             object->changed.renderState[SavedVertexStates_R[i]] = TRUE;
         }
@@ -4672,7 +4708,7 @@ static HRESULT WINAPI IWineD3DDeviceImpl
     UINT count) {
 
     IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
-    int i, cnt = min(count, MAX_VSHADER_CONSTANTS - (start + 1));
+    int i, cnt = min(count, MAX_CONST_B - (start + 1));
 
     TRACE("(iface %p, srcData %p, start %d, count %d)\n",
             iface, srcData, start, count);
@@ -4697,7 +4733,7 @@ static HRESULT WINAPI IWineD3DDeviceImpl
     UINT count) {
 
     IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
-    int cnt = min(count, MAX_VSHADER_CONSTANTS - (start + 1));
+    int cnt = min(count, MAX_CONST_B - (start + 1));
 
     TRACE("(iface %p, dstData %p, start %d, count %d)\n",
             iface, dstData, start, count);
@@ -4716,7 +4752,7 @@ static HRESULT WINAPI IWineD3DDeviceImpl
     UINT count) {
 
     IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
-    int i, cnt = min(count, MAX_VSHADER_CONSTANTS - (start + 1));
+    int i, cnt = min(count, MAX_CONST_I - (start + 1));
 
     TRACE("(iface %p, srcData %p, start %d, count %d)\n",
             iface, srcData, start, count);
@@ -4741,7 +4777,7 @@ static HRESULT WINAPI IWineD3DDeviceImpl
     UINT count) {
 
     IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
-    int cnt = min(count, MAX_VSHADER_CONSTANTS - (start + 1));
+    int cnt = min(count, MAX_CONST_I - (start + 1));
 
     TRACE("(iface %p, dstData %p, start %d, count %d)\n",
             iface, dstData, start, count);
@@ -4760,7 +4796,7 @@ static HRESULT WINAPI IWineD3DDeviceImpl
     UINT count) {
 
     IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
-    int i, cnt = min(count, MAX_VSHADER_CONSTANTS - (start + 1));
+    int i, cnt = min(count, GL_LIMITS(vshader_constantsF) - (start + 1));
 
     TRACE("(iface %p, srcData %p, start %d, count %d)\n",
             iface, srcData, start, count);
@@ -4785,7 +4821,7 @@ static HRESULT WINAPI IWineD3DDeviceImpl
     UINT count) {
 
     IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
-    int cnt = min(count, MAX_VSHADER_CONSTANTS - (start + 1));
+    int cnt = min(count, GL_LIMITS(vshader_constantsF) - (start + 1));
 
     TRACE("(iface %p, dstData %p, start %d, count %d)\n",
             iface, dstData, start, count);
@@ -4846,7 +4882,7 @@ static HRESULT WINAPI IWineD3DDeviceImpl
     UINT count) {
 
     IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
-    int i, cnt = min(count, MAX_PSHADER_CONSTANTS - (start + 1));
+    int i, cnt = min(count, MAX_CONST_B - (start + 1));
 
     TRACE("(iface %p, srcData %p, start %d, count %d)\n",
             iface, srcData, start, count);
@@ -4871,7 +4907,7 @@ static HRESULT WINAPI IWineD3DDeviceImpl
     UINT count) {
 
     IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
-    int cnt = min(count, MAX_PSHADER_CONSTANTS - (start + 1));
+    int cnt = min(count, MAX_CONST_B - (start + 1));
 
     TRACE("(iface %p, dstData %p, start %d, count %d)\n",
             iface, dstData, start, count);
@@ -4890,7 +4926,7 @@ static HRESULT WINAPI IWineD3DDeviceImpl
     UINT count) {
 
     IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
-    int i, cnt = min(count, MAX_PSHADER_CONSTANTS - (start + 1));
+    int i, cnt = min(count, MAX_CONST_I - (start + 1));
 
     TRACE("(iface %p, srcData %p, start %d, count %d)\n",
             iface, srcData, start, count);
@@ -4915,7 +4951,7 @@ static HRESULT WINAPI IWineD3DDeviceImpl
     UINT count) {
 
     IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
-    int cnt = min(count, MAX_PSHADER_CONSTANTS - (start + 1));
+    int cnt = min(count, MAX_CONST_I - (start + 1));
 
     TRACE("(iface %p, dstData %p, start %d, count %d)\n",
             iface, dstData, start, count);
@@ -4934,7 +4970,7 @@ static HRESULT WINAPI IWineD3DDeviceImpl
     UINT count) {
 
     IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
-    int i, cnt = min(count, MAX_PSHADER_CONSTANTS - (start + 1));
+    int i, cnt = min(count, GL_LIMITS(pshader_constantsF) - (start + 1));
 
     TRACE("(iface %p, srcData %p, start %d, count %d)\n",
             iface, srcData, start, count);
@@ -4959,7 +4995,7 @@ static HRESULT WINAPI IWineD3DDeviceImpl
     UINT count) {
 
     IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
-    int cnt = min(count, MAX_PSHADER_CONSTANTS - (start + 1));
+    int cnt = min(count, GL_LIMITS(pshader_constantsF) - (start + 1));
 
     TRACE("(iface %p, dstData %p, start %d, count %d)\n",
             iface, dstData, start, count);
@@ -5796,6 +5832,8 @@ static HRESULT WINAPI IWineD3DDeviceImpl
 static HRESULT WINAPI IWineD3DDeviceImpl_BeginStateBlock(IWineD3DDevice *iface) {
     IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
     IWineD3DStateBlockImpl *object;
+    HRESULT temp_result;
+    
     TRACE("(%p)", This);
     
     if (This->isRecordingState) {
@@ -5807,7 +5845,12 @@ static HRESULT WINAPI IWineD3DDeviceImpl
         FIXME("(%p)Error allocating memory for stateblock\n", This);
         return E_OUTOFMEMORY;
     }
-    TRACE("(%p) creted object %p\n", This, object);
+   
+    temp_result = allocate_shader_constants(iface, object);
+    if (WINED3D_OK != temp_result)
+        return temp_result;
+
+    TRACE("(%p) created object %p\n", This, object);
     object->wineD3DDevice= This;
     /** FIXME: object->parent       = parent; **/
     object->parent       = NULL;
diff --git a/dlls/wined3d/directx.c b/dlls/wined3d/directx.c
index e7d225b..91383e1 100644
--- a/dlls/wined3d/directx.c
+++ b/dlls/wined3d/directx.c
@@ -762,6 +762,9 @@ #undef USE_GL_FUNC
     else
         wined3d_settings.shader_mode = SHADER_SW;
 
+    /* Maximum float constants allowed in the shaders */
+    gl_info->max_vshader_constantsF = vshader_get_max_constantsF();
+    gl_info->max_pshader_constantsF = pshader_get_max_constantsF();
 
     /* If we created a dummy context, throw it away */
     if (NULL != fake_ctx) WineD3D_ReleaseFakeGLContext(fake_ctx);
@@ -1736,11 +1739,7 @@ #endif
         TRACE_(d3d_caps)("Vertex shader functionality not available\n");
     }
 
-    if (This->gl_info.gl_vendor == VENDOR_MESA || This->gl_info.gl_vendor == VENDOR_WINE) {
-        *pCaps->MaxVertexShaderConst = 95;
-    } else {
-        *pCaps->MaxVertexShaderConst = WINED3D_VSHADER_MAX_CONSTANTS;
-    }
+    *pCaps->MaxVertexShaderConst = GL_LIMITS(vshader_constantsF);
 
     if (wined3d_settings.ps_mode == PS_HW && wined3d_settings.shader_mode == SHADER_GLSL
         && DeviceType != WINED3DDEVTYPE_REF) {
@@ -1849,6 +1848,11 @@ static HRESULT  WINAPI IWineD3DImpl_Crea
     object->adapterNo                    = Adapter;
     object->devType                      = DeviceType;
 
+    /* Setup some defaults for creating the implicit swapchain */
+    ENTER_GL();
+    IWineD3DImpl_FillGLCaps(&This->gl_info, IWineD3DImpl_GetAdapterDisplay(iface, Adapter));
+    LEAVE_GL();
+
     TRACE("(%p) : Creating stateblock\n", This);
     /* Creating the startup stateBlock - Note Special Case: 0 => Don't fill in yet! */
     if (WINED3D_OK != IWineD3DDevice_CreateStateBlock((IWineD3DDevice *)object,
@@ -1861,13 +1865,6 @@ static HRESULT  WINAPI IWineD3DImpl_Crea
     TRACE("(%p) : Created stateblock (%p)\n", This, object->stateBlock);
     object->updateStateBlock = object->stateBlock;
     IWineD3DStateBlock_AddRef((IWineD3DStateBlock*)object->updateStateBlock);
-    /* Setup surfaces for the backbuffer, frontbuffer and depthstencil buffer */
-
-    /* Setup some defaults for creating the implicit swapchain */
-    ENTER_GL();
-    IWineD3DImpl_FillGLCaps(&This->gl_info, IWineD3DImpl_GetAdapterDisplay(iface, Adapter));
-    LEAVE_GL();
-
     /* set the state of the device to valid */
     object->state = WINED3D_OK;
 
diff --git a/dlls/wined3d/glsl_shader.c b/dlls/wined3d/glsl_shader.c
index 94871c0..c3604f9 100644
--- a/dlls/wined3d/glsl_shader.c
+++ b/dlls/wined3d/glsl_shader.c
@@ -207,12 +207,12 @@ void shader_glsl_load_constants(
 
         if (NULL != vertexDeclaration && NULL != vertexDeclaration->constants) {
             /* Load DirectX 8 float constants/uniforms for vertex shader */
-            shader_glsl_load_constantsF(gl_info, programId, WINED3D_VSHADER_MAX_CONSTANTS,
+            shader_glsl_load_constantsF(gl_info, programId, GL_LIMITS(vshader_constantsF),
                                         vertexDeclaration->constants, NULL, 0);
         }
 
         /* Load DirectX 9 float constants/uniforms for vertex shader */
-        shader_glsl_load_constantsF(gl_info, programId, WINED3D_VSHADER_MAX_CONSTANTS,
+        shader_glsl_load_constantsF(gl_info, programId, GL_LIMITS(vshader_constantsF),
                                     stateBlock->vertexShaderConstantF, 
                                     stateBlock->set.vertexShaderConstantsF, 0);
 
@@ -233,7 +233,7 @@ void shader_glsl_load_constants(
         shader_glsl_load_psamplers(gl_info, iface);
 
         /* Load DirectX 9 float constants/uniforms for pixel shader */
-        shader_glsl_load_constantsF(gl_info, programId, WINED3D_PSHADER_MAX_CONSTANTS,
+        shader_glsl_load_constantsF(gl_info, programId, GL_LIMITS(pshader_constantsF),
                                     stateBlock->pixelShaderConstantF,
                                     stateBlock->set.pixelShaderConstantsF, 1);
 
@@ -264,7 +264,8 @@ void shader_generate_glsl_declarations(
 
     /* Declare the constants (aka uniforms) */
     if (This->baseShader.limits.constant_float > 0)
-        shader_addline(buffer, "uniform vec4 %cC[%u];\n", prefix, This->baseShader.limits.constant_float);
+        shader_addline(buffer, "uniform vec4 %cC[%u];\n", prefix, 
+                This->baseShader.limits.constant_float - reg_maps->num_local_constants);
 
     if (This->baseShader.limits.constant_int > 0)
         shader_addline(buffer, "uniform ivec4 %cI[%u];\n", prefix, This->baseShader.limits.constant_int);
diff --git a/dlls/wined3d/pixelshader.c b/dlls/wined3d/pixelshader.c
index 532be0b..84c7bba 100644
--- a/dlls/wined3d/pixelshader.c
+++ b/dlls/wined3d/pixelshader.c
@@ -32,6 +32,26 @@ WINE_DEFAULT_DEBUG_CHANNEL(d3d_shader);
 
 #define GLINFO_LOCATION ((IWineD3DImpl *)(((IWineD3DDeviceImpl *)This->wineD3DDevice)->wineD3D))->gl_info
 
+/** Returns the maximum allowable pixel shader constants/uniforms based on GL Maximums */
+int pshader_get_max_constantsF() {
+
+    int gl_max;
+    
+    if (wined3d_settings.shader_mode == SHADER_GLSL) {
+        glGetIntegerv(GL_MAX_FRAGMENT_UNIFORM_COMPONENTS_ARB, &gl_max);
+        checkGLcall("glGetIntegerv");
+
+    } else if (wined3d_settings.shader_mode == SHADER_ARB) {
+        glGetProgramivARB(GL_FRAGMENT_PROGRAM_ARB, GL_MAX_PROGRAM_ENV_PARAMETERS_ARB, &gl_max);
+        checkGLcall("glGetProgramivARB");
+        
+    } else {
+        /* TODO: Fixup software shaders */
+        gl_max = 96;
+    }
+    return gl_max;
+}
+
 #if 0 /* Must not be 1 in cvs version */
 # define PSTRACE(A) TRACE A
 # define TRACE_VSVECTOR(name) TRACE( #name "=(%f, %f, %f, %f)\n", name.x, name.y, name.z, name.w)
@@ -1313,6 +1333,7 @@ inline static VOID IWineD3DPixelShaderIm
 
     memset(&reg_maps, 0, sizeof(shader_reg_maps));
     memset(semantics_in, 0, WINED3DSHADERDECLUSAGE_MAX_USAGE * sizeof(DWORD));
+    reg_maps.constantsF = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, GL_LIMITS(pshader_constantsF));
     reg_maps.semantics_in = semantics_in;
     reg_maps.semantics_out = NULL;
     shader_get_registers_used((IWineD3DBaseShader*) This, &reg_maps, pFunction);
@@ -1404,6 +1425,8 @@ #endif
         }
     }
 
+    HeapFree(GetProcessHeap(), 0, reg_maps.constantsF);
+    
 #if 1 /* if were using the data buffer of device then we don't need to free it */
   HeapFree(GetProcessHeap(), 0, buffer.buffer);
 #endif
diff --git a/dlls/wined3d/stateblock.c b/dlls/wined3d/stateblock.c
index 5d26682..4f614af 100644
--- a/dlls/wined3d/stateblock.c
+++ b/dlls/wined3d/stateblock.c
@@ -88,7 +88,14 @@ static ULONG  WINAPI IWineD3DStateBlockI
             if (NULL != This->vertexDecl) {
                 IWineD3DVertexDeclaration_Release(This->vertexDecl);
             }
-
+            
+            HeapFree(GetProcessHeap(), 0, This->vertexShaderConstantF);
+            HeapFree(GetProcessHeap(), 0, This->set.vertexShaderConstantsF);
+            HeapFree(GetProcessHeap(), 0, This->changed.vertexShaderConstantsF);
+            HeapFree(GetProcessHeap(), 0, This->pixelShaderConstantF);
+            HeapFree(GetProcessHeap(), 0, This->set.pixelShaderConstantsF);
+            HeapFree(GetProcessHeap(), 0, This->changed.pixelShaderConstantsF);
+ 
             /* NOTE: according to MSDN: The application is responsible for making sure the texture references are cleared down */
             for (counter = 0; counter < GL_LIMITS(sampler_stages); counter++) {
                 if (This->textures[counter]) {
@@ -166,9 +173,8 @@ static HRESULT  WINAPI IWineD3DStateBloc
             This->vertexShader = targetStateBlock->vertexShader;
         }
 
-        /* Vertex Shader Constants */
-        for (i = 0; i < MAX_VSHADER_CONSTANTS; ++i) {
-
+        /* Vertex Shader Float Constants */
+        for (i = 0; i < GL_LIMITS(vshader_constantsF); ++i) {
             if (This->set.vertexShaderConstantsF[i]) {
                 TRACE("Setting %p from %p %d to { %f, %f, %f, %f }\n", This, targetStateBlock, i,
                     targetStateBlock->vertexShaderConstantF[i * 4],
@@ -181,7 +187,10 @@ static HRESULT  WINAPI IWineD3DStateBloc
                 This->vertexShaderConstantF[i * 4 + 2]  = targetStateBlock->vertexShaderConstantF[i * 4 + 2];
                 This->vertexShaderConstantF[i * 4 + 3]  = targetStateBlock->vertexShaderConstantF[i * 4 + 3];
             }
-
+        }
+        
+        /* Vertex Shader Integer Constants */
+        for (i = 0; i < MAX_CONST_I; ++i) {
             if (This->set.vertexShaderConstantsI[i]) {
                 TRACE("Setting %p from %p %d to { %d, %d, %d, %d }\n", This, targetStateBlock, i,
                     targetStateBlock->vertexShaderConstantI[i * 4],
@@ -194,7 +203,10 @@ static HRESULT  WINAPI IWineD3DStateBloc
                 This->vertexShaderConstantI[i * 4 + 2]  = targetStateBlock->vertexShaderConstantI[i * 4 + 2];
                 This->vertexShaderConstantI[i * 4 + 3]  = targetStateBlock->vertexShaderConstantI[i * 4 + 3];
             }
-
+        }
+        
+        /* Vertex Shader Boolean Constants */
+        for (i = 0; i < MAX_CONST_B; ++i) {
             if (This->set.vertexShaderConstantsB[i]) {
                 TRACE("Setting %p from %p %d to %s\n", This, targetStateBlock, i,
                     targetStateBlock->vertexShaderConstantB[i]? "TRUE":"FALSE");
@@ -202,7 +214,7 @@ static HRESULT  WINAPI IWineD3DStateBloc
                 This->vertexShaderConstantB[i] =  targetStateBlock->vertexShaderConstantB[i];
             }
         }
-
+        
         /* Lights... For a recorded state block, we just had a chain of actions to perform,
              so we need to walk that chain and update any actions which differ */
         src = This->lights;
@@ -249,8 +261,8 @@ static HRESULT  WINAPI IWineD3DStateBloc
             This->pixelShader = targetStateBlock->pixelShader;
         }
 
-        for (i = 0; i < MAX_PSHADER_CONSTANTS; ++i) {
-
+        /* Pixel Shader Float Constants */
+        for (i = 0; i < GL_LIMITS(pshader_constantsF); ++i) {
             if (This->set.pixelShaderConstantsF[i]) {
                 TRACE("Setting %p from %p %d to { %f, %f, %f, %f }\n", This, targetStateBlock, i,
                     targetStateBlock->pixelShaderConstantF[i * 4],
@@ -263,7 +275,10 @@ static HRESULT  WINAPI IWineD3DStateBloc
                 This->pixelShaderConstantF[i * 4 + 2]  = targetStateBlock->pixelShaderConstantF[i * 4 + 2];
                 This->pixelShaderConstantF[i * 4 + 3]  = targetStateBlock->pixelShaderConstantF[i * 4 + 3];
             }
-
+        }
+        
+        /* Pixel Shader Integer Constants */
+        for (i = 0; i < MAX_CONST_I; ++i) {
             if (This->set.pixelShaderConstantsI[i]) {
                 TRACE("Setting %p from %p %d to { %d, %d, %d, %d }\n", This, targetStateBlock, i,
                     targetStateBlock->pixelShaderConstantI[i * 4],
@@ -276,7 +291,10 @@ static HRESULT  WINAPI IWineD3DStateBloc
                 This->pixelShaderConstantI[i * 4 + 2]  = targetStateBlock->pixelShaderConstantI[i * 4 + 2];
                 This->pixelShaderConstantI[i * 4 + 3]  = targetStateBlock->pixelShaderConstantI[i * 4 + 3];
             }
-
+        }
+        
+        /* Pixel Shader Boolean Constants */
+        for (i = 0; i < MAX_CONST_B; ++i) {
             if (This->set.pixelShaderConstantsB[i]) {
                 TRACE("Setting %p from %p %d to %s\n", This, targetStateBlock, i,
                     targetStateBlock->pixelShaderConstantB[i]? "TRUE":"FALSE");
@@ -442,16 +460,17 @@ should really perform a delta so that on
         }
 
         /* Vertex Shader Constants */
-        for (i = 0; i < MAX_VSHADER_CONSTANTS; ++i) {
+        for (i = 0; i < GL_LIMITS(vshader_constantsF); ++i)
             if (This->set.vertexShaderConstantsF[i] && This->changed.vertexShaderConstantsF[i])
                 IWineD3DDevice_SetVertexShaderConstantF(pDevice, i, This->vertexShaderConstantF + i * 4, 1);
 
+        for (i = 0; i < MAX_CONST_I; i++)
             if (This->set.vertexShaderConstantsI[i] && This->changed.vertexShaderConstantsI[i])
                 IWineD3DDevice_SetVertexShaderConstantI(pDevice, i, This->vertexShaderConstantI + i * 4, 1);
 
+        for (i = 0; i < MAX_CONST_B; i++)
             if (This->set.vertexShaderConstantsB[i] && This->changed.vertexShaderConstantsB[i])
                 IWineD3DDevice_SetVertexShaderConstantB(pDevice, i, This->vertexShaderConstantB + i, 1);
-        }
     }
 
     if (/*TODO: 'magic' statetype, replace with BOOL This->blockType == D3DSBT_RECORDED || */ This->blockType == D3DSBT_ALL || This->blockType == D3DSBT_PIXELSTATE) {
@@ -462,13 +481,17 @@ should really perform a delta so that on
         }
 
         /* Pixel Shader Constants */
-        for (i = 0; i < MAX_PSHADER_CONSTANTS; ++i) {
+        for (i = 0; i < GL_LIMITS(vshader_constantsF); ++i) {
             if (This->set.pixelShaderConstantsF[i] && This->changed.pixelShaderConstantsF[i])
                 IWineD3DDevice_SetPixelShaderConstantF(pDevice, i, This->pixelShaderConstantF + i * 4, 1);
+        }
 
+        for (i = 0; i < MAX_CONST_I; i++) {
             if (This->set.pixelShaderConstantsI[i] && This->changed.pixelShaderConstantsI[i])
                 IWineD3DDevice_SetPixelShaderConstantI(pDevice, i, This->pixelShaderConstantI + i * 4, 1);
-
+        }
+        
+        for (i = 0; i < MAX_CONST_B; i++) {
             if (This->set.pixelShaderConstantsB[i] && This->changed.pixelShaderConstantsB[i])
                 IWineD3DDevice_SetPixelShaderConstantB(pDevice, i, This->pixelShaderConstantB + i, 1);
         }
diff --git a/dlls/wined3d/vertexdeclaration.c b/dlls/wined3d/vertexdeclaration.c
index 5cd014f..c6c6a49 100644
--- a/dlls/wined3d/vertexdeclaration.c
+++ b/dlls/wined3d/vertexdeclaration.c
@@ -307,7 +307,8 @@ #define MAKE_LOOKUP(_reg,_usage,_usagein
             DWORD count        = ((token & D3DVSD_CONSTCOUNTMASK)   >> D3DVSD_CONSTCOUNTSHIFT);
             DWORD constaddress = ((token & D3DVSD_CONSTADDRESSMASK) >> D3DVSD_CONSTADDRESSSHIFT);
             if (This->constants == NULL ) {
-                This->constants = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, MAX_VSHADER_CONSTANTS * 4 * sizeof(float));
+                This->constants = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, 
+                        vshader_get_max_constantsF() * 4 * sizeof(float));
             }
             TRACE(" 0x%08lx CONST(%lu, %lu)\n", token, constaddress, count);
             for (i = 0; i < count; ++i) {
diff --git a/dlls/wined3d/vertexshader.c b/dlls/wined3d/vertexshader.c
index 86eff1f..0649413 100644
--- a/dlls/wined3d/vertexshader.c
+++ b/dlls/wined3d/vertexshader.c
@@ -32,6 +32,33 @@ WINE_DEFAULT_DEBUG_CHANNEL(d3d_shader);
 
 #define GLINFO_LOCATION ((IWineD3DImpl *)(((IWineD3DDeviceImpl *)This->wineD3DDevice)->wineD3D))->gl_info
 
+/** Returns the maximum float constants/uniforms that a vertex shader can have */
+int vshader_get_max_constantsF() {
+
+    int gl_max;
+    
+    if (wined3d_settings.shader_mode == SHADER_GLSL) {
+        glGetIntegerv(GL_MAX_VERTEX_UNIFORM_COMPONENTS_ARB, &gl_max);
+        checkGLcall("glGetIntegerv");
+        /* FIXME:
+         * GL has a maximum number of Uniforms allowed in a single linked program.
+         * To abide by this, we need to subtract the sum of all the other uniforms
+         * that we may be using.  If apps need to use the full 256 constants for shaders 3.0,
+         * and the hardware won't support that many uniforms, this will pose a problem.
+         */
+        gl_max = gl_max - MAX_CONST_B - MAX_CONST_I - MAX_SAMPLERS;
+
+    } else if (wined3d_settings.shader_mode == SHADER_ARB) {
+        glGetProgramivARB(GL_VERTEX_PROGRAM_ARB, GL_MAX_PROGRAM_ENV_PARAMETERS_ARB, &gl_max);
+        checkGLcall("glGetProgramivARB");
+
+    } else {
+        /* TODO: Fixup software shaders */
+        gl_max = 96;
+    }
+    return gl_max;
+}
+
 /* Shader debugging - Change the following line to enable debugging of software
       vertex shaders                                                             */
 #if 0 /* Musxt not be 1 in cvs version */
@@ -715,7 +742,7 @@ static void vshader_set_limits(
       This->baseShader.limits.packed_input = 0;
 
       /* Must match D3DCAPS9.MaxVertexShaderConst: at least 256 for vs_2_0 */
-      This->baseShader.limits.constant_float = WINED3D_VSHADER_MAX_CONSTANTS;
+      This->baseShader.limits.constant_float = GL_LIMITS(vshader_constantsF);
 
       switch (This->baseShader.hex_version) {
           case D3DVS_VERSION(1,0):
@@ -846,6 +873,7 @@ inline static VOID IWineD3DVertexShaderI
 
     memset(&reg_maps, 0, sizeof(shader_reg_maps));
     memset(semantics_out, 0, WINED3DSHADERDECLUSAGE_MAX_USAGE * sizeof(DWORD));
+    reg_maps.constantsF = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, GL_LIMITS(vshader_constantsF));
     reg_maps.semantics_in = This->arrayUsageMap;
     reg_maps.semantics_out = semantics_out;
     shader_get_registers_used((IWineD3DBaseShader*) This, &reg_maps, pFunction);
@@ -896,11 +924,6 @@ #endif
         /*  Create the hw ARB shader */
         shader_addline(&buffer, "!!ARBvp1.0\n");
 
-        /* Mesa supports only 95 constants */
-        if (GL_VEND(MESA) || GL_VEND(WINE))
-            This->baseShader.limits.constant_float = 
-                min(95, This->baseShader.limits.constant_float);
-
         /* Base Declarations */
         shader_generate_arb_declarations( (IWineD3DBaseShader*) This, &reg_maps, &buffer);
 
@@ -929,6 +952,8 @@ #endif
         }
     }
 
+    HeapFree(GetProcessHeap(), 0, reg_maps.constantsF);
+    
 #if 1 /* if were using the data buffer of device then we don't need to free it */
   HeapFree(GetProcessHeap(), 0, buffer.buffer);
 #endif
diff --git a/dlls/wined3d/wined3d_private.h b/dlls/wined3d/wined3d_private.h
index 53dee67..ecb38a5 100644
--- a/dlls/wined3d/wined3d_private.h
+++ b/dlls/wined3d/wined3d_private.h
@@ -53,8 +53,8 @@ #define MAX_ACTIVE_LIGHTS 8
 #define MAX_CLIPPLANES    D3DMAXUSERCLIPPLANES
 #define MAX_LEVELS        256
 
-#define MAX_VSHADER_CONSTANTS 96
-#define MAX_PSHADER_CONSTANTS 32
+#define MAX_CONST_I 16
+#define MAX_CONST_B 16
 
 /* Used for CreateStateBlock */
 #define NUM_SAVEDPIXELSTATES_R     35
@@ -1012,13 +1012,13 @@ typedef struct SAVEDSTATES {
         BOOL                      clipplane[MAX_CLIPPLANES];
         BOOL                      vertexDecl;
         BOOL                      pixelShader;
-        BOOL                      pixelShaderConstantsB[MAX_PSHADER_CONSTANTS];
-        BOOL                      pixelShaderConstantsI[MAX_PSHADER_CONSTANTS];
-        BOOL                      pixelShaderConstantsF[MAX_PSHADER_CONSTANTS];
+        BOOL                      pixelShaderConstantsB[MAX_CONST_B];
+        BOOL                      pixelShaderConstantsI[MAX_CONST_I];
+        BOOL                     *pixelShaderConstantsF;
         BOOL                      vertexShader;
-        BOOL                      vertexShaderConstantsB[MAX_VSHADER_CONSTANTS];
-        BOOL                      vertexShaderConstantsI[MAX_VSHADER_CONSTANTS];
-        BOOL                      vertexShaderConstantsF[MAX_VSHADER_CONSTANTS];
+        BOOL                      vertexShaderConstantsB[MAX_CONST_B];
+        BOOL                      vertexShaderConstantsI[MAX_CONST_I];
+        BOOL                     *vertexShaderConstantsF;
 } SAVEDSTATES;
 
 struct IWineD3DStateBlockImpl
@@ -1044,9 +1044,9 @@ struct IWineD3DStateBlockImpl
     IWineD3DVertexShader      *vertexShader;
 
     /* Vertex Shader Constants */
-    BOOL                       vertexShaderConstantB[MAX_VSHADER_CONSTANTS];
-    INT                        vertexShaderConstantI[MAX_VSHADER_CONSTANTS * 4];
-    float                      vertexShaderConstantF[MAX_VSHADER_CONSTANTS * 4];
+    BOOL                       vertexShaderConstantB[MAX_CONST_B];
+    INT                        vertexShaderConstantI[MAX_CONST_I * 4];
+    float                     *vertexShaderConstantF;
 
     /* Stream Source */
     BOOL                      streamIsUP;
@@ -1080,9 +1080,9 @@ struct IWineD3DStateBlockImpl
     IWineD3DPixelShader      *pixelShader;
 
     /* Pixel Shader Constants */
-    BOOL                       pixelShaderConstantB[MAX_PSHADER_CONSTANTS];
-    INT                        pixelShaderConstantI[MAX_PSHADER_CONSTANTS * 4];
-    float                      pixelShaderConstantF[MAX_PSHADER_CONSTANTS * 4];
+    BOOL                       pixelShaderConstantB[MAX_CONST_B];
+    INT                        pixelShaderConstantI[MAX_CONST_I * 4];
+    float                     *pixelShaderConstantF;
 
     /* Indexed Vertex Blending */
     D3DVERTEXBLENDFLAGS       vertex_blend;
@@ -1277,9 +1277,6 @@ #define MAX_REG_TEXCRD 8
 #define MAX_REG_INPUT 12
 #define MAX_REG_OUTPUT 12
 #define MAX_ATTRIBS 16
-#define MAX_CONST_F 256
-#define MAX_CONST_I 16
-#define MAX_CONST_B 16
 
 typedef struct shader_reg_maps {
 
@@ -1290,10 +1287,12 @@ typedef struct shader_reg_maps {
     char packed_output[MAX_REG_OUTPUT];     /* vertex >= 3.0 */
     char attributes[MAX_ATTRIBS];           /* vertex */
 
-    char constantsF[MAX_CONST_F];           /* pixel, vertex */
+    char *constantsF;                       /* pixel, vertex */
     char constantsI[MAX_CONST_I];           /* pixel & vertex >= 2.0 */
     char constantsB[MAX_CONST_B];           /* pixel & vertex >= 2.0 */
-    
+   
+    int  num_local_constants;               /* pixel, vertex */
+
     /* Semantics maps (semantic -> reg_token)
      * Use 0 as default (bit 31 is always 1 on a valid token) */
     DWORD* semantics_in;                    /* vertex, pixel */
@@ -1370,6 +1369,9 @@ extern const SHADER_OPCODE* shader_get_o
     IWineD3DBaseShader *iface, 
     const DWORD code);
 
+extern int vshader_get_max_constantsF();
+extern int pshader_get_max_constantsF();
+
 /* ARB_[vertex/fragment]_program helper functions */
 extern void shader_arb_load_constants(
     IWineD3DStateBlock* iface,
diff --git a/include/wine/wined3d_gl.h b/include/wine/wined3d_gl.h
index 038cbaf..0636d06 100644
--- a/include/wine/wined3d_gl.h
+++ b/include/wine/wined3d_gl.h
@@ -1679,6 +1679,9 @@ typedef struct _WineD3D_GL_Info {
   UINT   max_blends;
   UINT   max_anisotropy;
 
+  unsigned max_vshader_constantsF;
+  unsigned max_pshader_constantsF;
+
   GL_PSVersion ps_arb_version;
   GL_PSVersion ps_nv_version;
 







More information about the wine-patches mailing list