wined3d: Use gl_Color and gl_SecondaryColor to support more varyings in SM3.0 shaders.
authorH. Verbeet <hverbeet@gmail.com>
Wed, 18 Jun 2008 22:36:35 +0000 (00:36 +0200)
committerAlexandre Julliard <julliard@winehq.org>
Thu, 19 Jun 2008 09:47:52 +0000 (11:47 +0200)
SM3.0 requires 10 4 component float varyings for passing stuff between
vertex and pixel shaders. GF7 and earlier report 8 generic varyings +
gl_Color and gl_SecondaryColor in GLSL. This patch allows us to use
gl_Color and gl_SecondaryColor to get 2 extra varyings, which some
games, like C&C3 with highest gfx settings, require.

dlls/wined3d/glsl_shader.c
dlls/wined3d/pixelshader.c
dlls/wined3d/wined3d_private.h

index 8aec21d0c0a1e61fdd29eb775834b7bf6228f958..672997780a541b9e7f0b55e19b7d40c3a5ffb27f 100644 (file)
@@ -39,12 +39,12 @@ WINE_DECLARE_DEBUG_CHANNEL(d3d_caps);
 #define GLINFO_LOCATION      (*gl_info)
 
 typedef struct {
-    char reg_name[50];
+    char reg_name[150];
     char mask_str[6];
 } glsl_dst_param_t;
 
 typedef struct {
-    char reg_name[50];
+    char reg_name[150];
     char param_str[100];
 } glsl_src_param_t;
 
@@ -836,7 +836,7 @@ static void shader_glsl_get_register_name(
     WineD3D_GL_Info* gl_info = &deviceImpl->adapter->gl_info;
 
     char pshader = shader_is_pshader_version(This->baseShader.hex_version);
-    char tmpStr[50];
+    char tmpStr[150];
 
     *is_color = FALSE;   
  
@@ -848,6 +848,8 @@ static void shader_glsl_get_register_name(
         if (pshader) {
             /* Pixel shaders >= 3.0 */
             if (WINED3DSHADER_VERSION_MAJOR(This->baseShader.hex_version) >= 3) {
+                DWORD in_count = GL_LIMITS(glsl_varyings) / 4;
+
                 if (param & WINED3DSHADER_ADDRMODE_RELATIVE) {
                     glsl_src_param_t rel_param;
                     shader_glsl_add_src_param(arg, addr_token, 0, WINED3DSP_WRITEMASK_0, &rel_param);
@@ -856,14 +858,33 @@ static void shader_glsl_get_register_name(
                      * operation there
                      */
                     if(((IWineD3DPixelShaderImpl *) This)->input_reg_map[reg]) {
-                        sprintf(tmpStr, "IN[%s + %u]", rel_param.param_str,
-                                ((IWineD3DPixelShaderImpl *) This)->input_reg_map[reg]);
+                        if (((IWineD3DPixelShaderImpl *)This)->declared_in_count > in_count) {
+                            sprintf(tmpStr, "((%s + %u) > %d ? (%s + %u) > %d ? gl_SecondaryColor : gl_Color : IN[%s + %u])",
+                                    rel_param.param_str, ((IWineD3DPixelShaderImpl *)This)->input_reg_map[reg], in_count - 1,
+                                    rel_param.param_str, ((IWineD3DPixelShaderImpl *)This)->input_reg_map[reg], in_count,
+                                    rel_param.param_str, ((IWineD3DPixelShaderImpl *)This)->input_reg_map[reg]);
+                        } else {
+                            sprintf(tmpStr, "IN[%s + %u]", rel_param.param_str, ((IWineD3DPixelShaderImpl *)This)->input_reg_map[reg]);
+                        }
                     } else {
-                        sprintf(tmpStr, "IN[%s]", rel_param.param_str);
+                        if (((IWineD3DPixelShaderImpl *)This)->declared_in_count > in_count) {
+                            sprintf(tmpStr, "((%s) > %d ? (%s) > %d ? gl_SecondaryColor : gl_Color : IN[%s])",
+                                    rel_param.param_str, in_count - 1,
+                                    rel_param.param_str, in_count,
+                                    rel_param.param_str);
+                        } else {
+                            sprintf(tmpStr, "IN[%s]", rel_param.param_str);
+                        }
                     }
                 } else {
-                    sprintf(tmpStr, "IN[%u]",
-                            ((IWineD3DPixelShaderImpl *) This)->input_reg_map[reg]);
+                    DWORD idx = ((IWineD3DPixelShaderImpl *) This)->input_reg_map[reg];
+                    if (idx == in_count) {
+                        sprintf(tmpStr, "gl_Color");
+                    } else if (idx == in_count + 1) {
+                        sprintf(tmpStr, "gl_SecondaryColor");
+                    } else {
+                        sprintf(tmpStr, "IN[%u]", idx);
+                    }
                 }
             } else {
                 if (reg==0)
@@ -2804,20 +2825,40 @@ static void handle_ps3_input(SHADER_BUFFER *buffer, semantic *semantics_in, sema
     DWORD register_token, register_token_out;
     DWORD usage, usage_idx, usage_out, usage_idx_out;
     DWORD *set;
+    DWORD in_idx;
+    DWORD in_count = GL_LIMITS(glsl_varyings) / 4;
     char reg_mask[6], reg_mask_out[6];
+    char destination[50];
+
+    set = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*set) * (in_count + 2));
 
-    set = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*set) * (GL_LIMITS(glsl_varyings) / 4));
+    if (!semantics_out) {
+        /* Save gl_FrontColor & gl_FrontSecondaryColor before overwriting them. */
+        shader_addline(buffer, "vec4 front_color = gl_FrontColor;");
+        shader_addline(buffer, "vec4 front_secondary_color = gl_FrontSecondaryColor;");
+    }
 
     for(i = 0; i < MAX_REG_INPUT; i++) {
         usage_token = semantics_in[i].usage;
         if (!usage_token) continue;
-        if(map[i] >= (GL_LIMITS(glsl_varyings) / 4)) {
+
+        in_idx = map[i];
+        if (in_idx >= (in_count + 2)) {
             FIXME("More input varyings declared than supported, expect issues\n");
             continue;
         } else if(map[i] == -1) {
             /* Declared, but not read register */
             continue;
         }
+
+        if (in_idx == in_count) {
+            sprintf(destination, "gl_FrontColor");
+        } else if (in_idx == in_count + 1) {
+            sprintf(destination, "gl_FrontSecondaryColor");
+        } else {
+            sprintf(destination, "IN[%u]", in_idx);
+        }
+
         register_token = semantics_in[i].reg;
 
         usage = (usage_token & WINED3DSP_DCL_USAGE_MASK) >> WINED3DSP_DCL_USAGE_SHIFT;
@@ -2828,34 +2869,34 @@ static void handle_ps3_input(SHADER_BUFFER *buffer, semantic *semantics_in, sema
             switch(usage) {
                 case WINED3DDECLUSAGE_COLOR:
                     if (usage_idx == 0)
-                        shader_addline(buffer, "IN[%u]%s = gl_FrontColor%s;\n",
-                                       map[i], reg_mask, reg_mask);
+                        shader_addline(buffer, "%s%s = front_color%s;\n",
+                                       destination, reg_mask, reg_mask);
                     else if (usage_idx == 1)
-                        shader_addline(buffer, "IN[%u]%s = gl_FrontSecondaryColor%s;\n",
-                                       map[i], reg_mask, reg_mask);
+                        shader_addline(buffer, "%s%s = front_secondary_color%s;\n",
+                                       destination, reg_mask, reg_mask);
                     else
-                        shader_addline(buffer, "IN[%u]%s = vec4(0.0, 0.0, 0.0, 0.0)%s;\n",
-                                       map[i], reg_mask, reg_mask);
+                        shader_addline(buffer, "%s%s = vec4(0.0, 0.0, 0.0, 0.0)%s;\n",
+                                       destination, reg_mask, reg_mask);
                     break;
 
                 case WINED3DDECLUSAGE_TEXCOORD:
                     if (usage_idx < 8) {
-                        shader_addline(buffer, "IN[%u]%s = gl_TexCoord[%u]%s;\n",
-                                       map[i], reg_mask, usage_idx, reg_mask);
+                        shader_addline(buffer, "%s%s = gl_TexCoord[%u]%s;\n",
+                                       destination, reg_mask, usage_idx, reg_mask);
                     } else {
-                        shader_addline(buffer, "IN[%u]%s = vec4(0.0, 0.0, 0.0, 0.0)%s;\n",
-                                       map[i], reg_mask, reg_mask);
+                        shader_addline(buffer, "%s%s = vec4(0.0, 0.0, 0.0, 0.0)%s;\n",
+                                       destination, reg_mask, reg_mask);
                     }
                     break;
 
                 case WINED3DDECLUSAGE_FOG:
-                    shader_addline(buffer, "IN[%u]%s = vec4(gl_FogFragCoord, 0.0, 0.0, 0.0)%s;\n",
-                                   map[i], reg_mask, reg_mask);
+                    shader_addline(buffer, "%s%s = vec4(gl_FogFragCoord, 0.0, 0.0, 0.0)%s;\n",
+                                   destination, reg_mask, reg_mask);
                     break;
 
                 default:
-                    shader_addline(buffer, "IN[%u]%s = vec4(0.0, 0.0, 0.0, 0.0)%s;\n",
-                                   map[i], reg_mask, reg_mask);
+                    shader_addline(buffer, "%s%s = vec4(0.0, 0.0, 0.0, 0.0)%s;\n",
+                                   destination, reg_mask, reg_mask);
             }
         } else {
             BOOL found = FALSE;
@@ -2870,14 +2911,14 @@ static void handle_ps3_input(SHADER_BUFFER *buffer, semantic *semantics_in, sema
 
                 if(usage == usage_out &&
                    usage_idx == usage_idx_out) {
-                    shader_addline(buffer, "IN[%u]%s = OUT[%u]%s;\n",
-                                   map[i], reg_mask, j, reg_mask);
+                    shader_addline(buffer, "%s%s = OUT[%u]%s;\n",
+                                   destination, reg_mask, j, reg_mask);
                     found = TRUE;
                 }
             }
             if(!found) {
-                shader_addline(buffer, "IN[%u]%s = vec4(0.0, 0.0, 0.0, 0.0)%s;\n",
-                               map[i], reg_mask, reg_mask);
+                shader_addline(buffer, "%s%s = vec4(0.0, 0.0, 0.0, 0.0)%s;\n",
+                               destination, reg_mask, reg_mask);
             }
         }
     }
@@ -2886,7 +2927,7 @@ static void handle_ps3_input(SHADER_BUFFER *buffer, semantic *semantics_in, sema
      * varyings. It shouldn't result in any real code executed on the GPU, since all read
      * input varyings are assigned above, if the optimizer works properly.
      */
-    for(i = 0; i < GL_LIMITS(glsl_varyings) / 4; i++) {
+    for(i = 0; i < in_count + 2; i++) {
         if(set[i] != WINED3DSP_WRITEMASK_ALL) {
             unsigned int size = 0;
             memset(reg_mask, 0, sizeof(reg_mask));
@@ -2906,19 +2947,19 @@ static void handle_ps3_input(SHADER_BUFFER *buffer, semantic *semantics_in, sema
                 reg_mask[size] = 'w';
                 size++;
             }
-            switch(size) {
-                case 1:
-                    shader_addline(buffer, "IN[%u].%s = 0.0;\n", i, reg_mask);
-                    break;
-                case 2:
-                    shader_addline(buffer, "IN[%u].%s = vec2(0.0, 0.0);\n", i, reg_mask);
-                    break;
-                case 3:
-                    shader_addline(buffer, "IN[%u].%s = vec3(0.0, 0.0, 0.0);\n", i, reg_mask);
-                    break;
-                case 4:
-                    shader_addline(buffer, "IN[%u].%s = vec4(0.0, 0.0, 0.0, 0.0);\n", i, reg_mask);
-                    break;
+
+            if (i == in_count) {
+                sprintf(destination, "gl_FrontColor");
+            } else if (i == in_count + 1) {
+                sprintf(destination, "gl_FrontSecondaryColor");
+            } else {
+                sprintf(destination, "IN[%u]", i);
+            }
+
+            if (size == 1) {
+                shader_addline(buffer, "%s.%s = 0.0;\n", destination, reg_mask);
+            } else {
+                shader_addline(buffer, "%s.%s = vec%u(0.0);\n", destination, reg_mask, size);
             }
         }
     }
@@ -3224,6 +3265,14 @@ static void set_glsl_shader_program(IWineD3DDevice *iface, BOOL use_ps, BOOL use
     entry->ycorrection_location = GL_EXTCALL(glGetUniformLocationARB(programId, "ycorrection"));
     checkGLcall("Find glsl program uniform locations");
 
+    if (pshader && WINED3DSHADER_VERSION_MAJOR(((IWineD3DPixelShaderImpl *)pshader)->baseShader.hex_version) >= 3
+            && ((IWineD3DPixelShaderImpl *)pshader)->declared_in_count > GL_LIMITS(glsl_varyings) / 4) {
+        TRACE("Shader %d needs vertex color clamping disabled\n", programId);
+        entry->vertex_color_clamp = GL_FALSE;
+    } else {
+        entry->vertex_color_clamp = GL_FIXED_ONLY_ARB;
+    }
+
     /* Set the shader to allow uniform loading on it */
     GL_EXTCALL(glUseProgramObjectARB(programId));
     checkGLcall("glUseProgramObjectARB(programId)");
@@ -3305,10 +3354,24 @@ static void shader_glsl_select(IWineD3DDevice *iface, BOOL usePS, BOOL useVS) {
     IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
     WineD3D_GL_Info *gl_info = &This->adapter->gl_info;
     GLhandleARB program_id = 0;
+    GLenum old_vertex_color_clamp, current_vertex_color_clamp;
+
+    old_vertex_color_clamp = This->stateBlock->glsl_program ? This->stateBlock->glsl_program->vertex_color_clamp : GL_FIXED_ONLY_ARB;
 
     if (useVS || usePS) set_glsl_shader_program(iface, usePS, useVS);
     else This->stateBlock->glsl_program = NULL;
 
+    current_vertex_color_clamp = This->stateBlock->glsl_program ? This->stateBlock->glsl_program->vertex_color_clamp : GL_FIXED_ONLY_ARB;
+
+    if (old_vertex_color_clamp != current_vertex_color_clamp) {
+        if (GL_SUPPORT(ARB_COLOR_BUFFER_FLOAT)) {
+            GL_EXTCALL(glClampColorARB(GL_CLAMP_VERTEX_COLOR_ARB, current_vertex_color_clamp));
+            checkGLcall("glClampColorARB");
+        } else {
+            FIXME("vertex color clamp needs to be changed, but extension not supported.\n");
+        }
+    }
+
     program_id = This->stateBlock->glsl_program ? This->stateBlock->glsl_program->programId : 0;
     if (program_id) TRACE("Using GLSL program %u\n", program_id);
     GL_EXTCALL(glUseProgramObjectARB(program_id));
index c9a77577e5a92836c70a5cf417c1b71c8939438c..3a55df770e02d832713e9b5726dc99cc6cc3d01c 100644 (file)
@@ -359,6 +359,7 @@ static HRESULT WINAPI IWineD3DPixelShaderImpl_SetFunction(IWineD3DPixelShader *i
             for(i = 0; i < MAX_REG_INPUT; i++) {
                 This->input_reg_map[i] = i;
             }
+            This->declared_in_count = highest_reg_used + 1;
         } else {
             j = 0;
             for(i = 0; i < MAX_REG_INPUT; i++) {
@@ -369,6 +370,7 @@ static HRESULT WINAPI IWineD3DPixelShaderImpl_SetFunction(IWineD3DPixelShader *i
                     This->input_reg_map[i] = -1;
                 }
             }
+            This->declared_in_count = j;
         }
     }
     This->baseShader.load_local_constsF = FALSE;
index 26952be1f91be1523e2b6d06b06911d4dc85b64a..880f93d4a2a4fc8441568d710f7fa0de57791e6c 100644 (file)
@@ -1830,6 +1830,7 @@ struct glsl_shader_prog_link {
     GLhandleARB             srgb_comparison_location;
     GLhandleARB             srgb_mul_low_location;
     GLhandleARB             ycorrection_location;
+    GLenum                  vertex_color_clamp;
     GLhandleARB             vshader;
     GLhandleARB             pshader;
 };
@@ -2343,6 +2344,7 @@ typedef struct IWineD3DPixelShaderImpl {
     semantic semantics_in [MAX_REG_INPUT];
     DWORD                 input_reg_map[MAX_REG_INPUT];
     BOOL                  input_reg_used[MAX_REG_INPUT];
+    int                         declared_in_count;
 
     /* run time data */
     PSHADERDATA                *data;