[PATCH 1/6] wined3d: Unify vertex shader output handling between shader models.

Henri Verbeet hverbeet at codeweavers.com
Thu Jul 29 05:56:53 CDT 2010


---
 dlls/wined3d/glsl_shader.c |  170 +++++++++-----------------------------------
 dlls/wined3d/shader.c      |   83 ++++++++++++++++++++--
 2 files changed, 111 insertions(+), 142 deletions(-)

diff --git a/dlls/wined3d/glsl_shader.c b/dlls/wined3d/glsl_shader.c
index 8ddbae0..42e4311 100644
--- a/dlls/wined3d/glsl_shader.c
+++ b/dlls/wined3d/glsl_shader.c
@@ -981,25 +981,13 @@ static void shader_generate_glsl_declarations(const struct wined3d_context *cont
     if (This->baseShader.limits.constant_bool > 0 && This->baseShader.reg_maps.boolean_constants)
         shader_addline(buffer, "uniform bool %cB[%u];\n", prefix, This->baseShader.limits.constant_bool);
 
-    if(!pshader) {
+    if (!pshader)
+    {
         shader_addline(buffer, "uniform vec4 posFixup;\n");
-        /* Predeclaration; This function is added at link time based on the pixel shader.
-         * VS 3.0 shaders have an array OUT[] the shader writes to, earlier versions don't have
-         * that. We know the input to the reorder function at vertex shader compile time, so
-         * we can deal with that. The reorder function for a 1.x and 2.x vertex shader can just
-         * read gl_FrontColor. The output depends on the pixel shader. The reorder function for a
-         * 1.x and 2.x pshader or for fixed function will write gl_FrontColor, and for a 3.0 shader
-         * it will write to the varying array. Here we depend on the shader optimizer on sorting that
-         * out. The nvidia driver only does that if the parameter is inout instead of out, hence the
-         * inout.
-         */
-        if (reg_maps->shader_version.major >= 3)
-        {
-            shader_addline(buffer, "void order_ps_input(in vec4[%u]);\n", MAX_REG_OUTPUT);
-        } else {
-            shader_addline(buffer, "void order_ps_input();\n");
-        }
-    } else {
+        shader_addline(buffer, "void order_ps_input(in vec4[%u]);\n", MAX_REG_OUTPUT);
+    }
+    else
+    {
         for (i = 0, map = reg_maps->bumpmat; map; map >>= 1, ++i)
         {
             if (!(map & 1)) continue;
@@ -1302,7 +1290,7 @@ static void shader_glsl_get_register_name(const struct wined3d_shader_register *
         char *register_name, BOOL *is_color, const struct wined3d_shader_instruction *ins)
 {
     /* oPos, oFog and oPts in D3D */
-    static const char * const hwrastout_reg_names[] = { "gl_Position", "gl_FogFragCoord", "gl_PointSize" };
+    static const char * const hwrastout_reg_names[] = {"OUT[10]", "OUT[11].x", "OUT[11].y"};
 
     IWineD3DBaseShaderImpl *This = (IWineD3DBaseShaderImpl *)ins->ctx->shader;
     const struct wined3d_gl_info *gl_info = ins->ctx->gl_info;
@@ -1445,14 +1433,13 @@ static void shader_glsl_get_register_name(const struct wined3d_shader_register *
             break;
 
         case WINED3DSPR_ATTROUT:
-            if (reg->idx == 0) sprintf(register_name, "gl_FrontColor");
-            else sprintf(register_name, "gl_FrontSecondaryColor");
+            if (reg->idx == 0) sprintf(register_name, "OUT[8]");
+            else sprintf(register_name, "OUT[9]");
             break;
 
         case WINED3DSPR_TEXCRDOUT:
             /* Vertex shaders >= 3.0: WINED3DSPR_OUTPUT */
-            if (This->baseShader.reg_maps.shader_version.major >= 3) sprintf(register_name, "OUT[%u]", reg->idx);
-            else sprintf(register_name, "gl_TexCoord[%u]", reg->idx);
+            sprintf(register_name, "OUT[%u]", reg->idx);
             break;
 
         case WINED3DSPR_MISCTYPE:
@@ -3745,13 +3732,6 @@ static void handle_ps3_input(struct wined3d_shader_buffer *buffer, const struct
 
     set = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*set) * (in_count + 2));
 
-    if (!output_signature)
-    {
-        /* Save gl_FrontColor & gl_FrontSecondaryColor before overwriting them. */
-        shader_addline(buffer, "vec4 front_color = gl_FrontColor;\n");
-        shader_addline(buffer, "vec4 front_secondary_color = gl_FrontSecondaryColor;\n");
-    }
-
     input_map = reg_maps_in->input_registers;
     for (i = 0; input_map; input_map >>= 1, ++i)
     {
@@ -3778,66 +3758,22 @@ static void handle_ps3_input(struct wined3d_shader_buffer *buffer, const struct
         semantic_idx_in = input_signature[i].semantic_idx;
         set[in_idx] = ~0U;
 
-        if (!output_signature)
+        output_map = reg_maps_out->output_registers;
+        for (j = 0; output_map; output_map >>= 1, ++j)
         {
-            shader_glsl_write_mask_to_str(input_signature[i].mask, reg_mask);
-            set[in_idx] = input_signature[i].mask;
+            DWORD mask;
 
-            if (shader_match_semantic(semantic_name_in, WINED3DDECLUSAGE_COLOR))
-            {
-                if (semantic_idx_in == 0)
-                    shader_addline(buffer, "%s%s = front_color%s;\n",
-                            destination, reg_mask, reg_mask);
-                else if (semantic_idx_in == 1)
-                    shader_addline(buffer, "%s%s = front_secondary_color%s;\n",
-                            destination, reg_mask, reg_mask);
-                else
-                    shader_addline(buffer, "%s%s = vec4(0.0, 0.0, 0.0, 0.0)%s;\n",
-                            destination, reg_mask, reg_mask);
-            }
-            else if (shader_match_semantic(semantic_name_in, WINED3DDECLUSAGE_TEXCOORD))
-            {
-                if (semantic_idx_in < 8)
-                {
-                    shader_addline(buffer, "%s%s = gl_TexCoord[%u]%s;\n",
-                            destination, reg_mask, semantic_idx_in, reg_mask);
-                }
-                else
-                {
-                    shader_addline(buffer, "%s%s = vec4(0.0, 0.0, 0.0, 0.0)%s;\n",
-                            destination, reg_mask, reg_mask);
-                }
-            }
-            else if (shader_match_semantic(semantic_name_in, WINED3DDECLUSAGE_FOG))
-            {
-                shader_addline(buffer, "%s%s = vec4(gl_FogFragCoord, 0.0, 0.0, 0.0)%s;\n",
-                        destination, reg_mask, reg_mask);
-            }
-            else
-            {
-                shader_addline(buffer, "%s%s = vec4(0.0, 0.0, 0.0, 0.0)%s;\n",
-                        destination, reg_mask, reg_mask);
-            }
-        }
-        else
-        {
-            output_map = reg_maps_out->output_registers;
-            for (j = 0; output_map; output_map >>= 1, ++j)
-            {
-                DWORD mask;
-
-                if (!(output_map & 1)
-                        || semantic_idx_in != output_signature[j].semantic_idx
-                        || strcmp(semantic_name_in, output_signature[j].semantic_name)
-                        || !(mask = input_signature[i].mask & output_signature[j].mask))
-                    continue;
+            if (!(output_map & 1)
+                    || semantic_idx_in != output_signature[j].semantic_idx
+                    || strcmp(semantic_name_in, output_signature[j].semantic_name)
+                    || !(mask = input_signature[i].mask & output_signature[j].mask))
+                continue;
 
-                set[in_idx] = mask;
-                shader_glsl_write_mask_to_str(mask, reg_mask);
+            set[in_idx] = mask;
+            shader_glsl_write_mask_to_str(mask, reg_mask);
 
-                shader_addline(buffer, "%s%s = OUT[%u]%s;\n",
-                        destination, reg_mask, j, reg_mask);
-            }
+            shader_addline(buffer, "%s%s = OUT[%u]%s;\n",
+                    destination, reg_mask, j, reg_mask);
         }
     }
 
@@ -3875,45 +3811,22 @@ static GLhandleARB generate_param_reorder_function(struct wined3d_shader_buffer
     GLhandleARB ret = 0;
     IWineD3DVertexShaderImpl *vs = (IWineD3DVertexShaderImpl *) vertexshader;
     IWineD3DPixelShaderImpl *ps = (IWineD3DPixelShaderImpl *) pixelshader;
-    IWineD3DDeviceImpl *device;
-    DWORD vs_major = vs->baseShader.reg_maps.shader_version.major;
     DWORD ps_major = ps ? ps->baseShader.reg_maps.shader_version.major : 0;
     unsigned int i;
     const char *semantic_name;
     UINT semantic_idx;
     char reg_mask[6];
-    const struct wined3d_shader_signature_element *output_signature;
+    const struct wined3d_shader_signature_element *output_signature = vs->baseShader.output_signature;
+    WORD map = vs->baseShader.reg_maps.output_registers;
 
     shader_buffer_clear(buffer);
 
     shader_addline(buffer, "#version 120\n");
 
-    if(vs_major < 3 && ps_major < 3) {
-        /* That one is easy: The vertex shader writes to the builtin varyings, the pixel shader reads from them.
-         * Take care about the texcoord .w fixup though if we're using the fixed function fragment pipeline
-         */
-        device = (IWineD3DDeviceImpl *) vs->baseShader.device;
-        if ((gl_info->quirks & WINED3D_QUIRK_SET_TEXCOORD_W)
-                && ps_major == 0 && vs_major > 0 && !device->frag_pipe->ffp_proj_control)
-        {
-            shader_addline(buffer, "void order_ps_input() {\n");
-            for(i = 0; i < min(8, MAX_REG_TEXCRD); i++) {
-                if(vs->baseShader.reg_maps.texcoord_mask[i] != 0 &&
-                   vs->baseShader.reg_maps.texcoord_mask[i] != WINED3DSP_WRITEMASK_ALL) {
-                    shader_addline(buffer, "gl_TexCoord[%u].w = 1.0;\n", i);
-                }
-            }
-            shader_addline(buffer, "}\n");
-        } else {
-            shader_addline(buffer, "void order_ps_input() { /* do nothing */ }\n");
-        }
-    } else if(ps_major < 3 && vs_major >= 3) {
-        WORD map = vs->baseShader.reg_maps.output_registers;
-
-        /* The vertex shader writes to its own varyings, the pixel shader needs them in the builtin ones */
-        output_signature = vs->baseShader.output_signature;
-
+    if (ps_major < 3)
+    {
         shader_addline(buffer, "void order_ps_input(in vec4 OUT[%u]) {\n", MAX_REG_OUTPUT);
+
         for (i = 0; map; map >>= 1, ++i)
         {
             DWORD write_mask;
@@ -3951,7 +3864,7 @@ static GLhandleARB generate_param_reorder_function(struct wined3d_shader_buffer
             }
             else if (shader_match_semantic(semantic_name, WINED3DDECLUSAGE_PSIZE))
             {
-                shader_addline(buffer, "gl_PointSize = OUT[%u].x;\n", i);
+                shader_addline(buffer, "gl_PointSize = OUT[%u].%c;\n", i, reg_mask[1]);
             }
             else if (shader_match_semantic(semantic_name, WINED3DDECLUSAGE_FOG))
             {
@@ -3960,11 +3873,9 @@ static GLhandleARB generate_param_reorder_function(struct wined3d_shader_buffer
         }
         shader_addline(buffer, "}\n");
 
-    } else if(ps_major >= 3 && vs_major >= 3) {
-        WORD map = vs->baseShader.reg_maps.output_registers;
-
-        output_signature = vs->baseShader.output_signature;
-
+    }
+    else
+    {
         /* This one is tricky: a 3.0 pixel shader reads from a 3.0 vertex shader */
         shader_addline(buffer, "varying vec4 IN[%u];\n", vec4_varyings(3, gl_info));
         shader_addline(buffer, "void order_ps_input(in vec4 OUT[%u]) {\n", MAX_REG_OUTPUT);
@@ -3983,7 +3894,7 @@ static GLhandleARB generate_param_reorder_function(struct wined3d_shader_buffer
             }
             else if (shader_match_semantic(semantic_name, WINED3DDECLUSAGE_PSIZE))
             {
-                shader_addline(buffer, "gl_PointSize = OUT[%u].x;\n", i);
+                shader_addline(buffer, "gl_PointSize = OUT[%u].%c;\n", i, reg_mask[1]);
             }
         }
 
@@ -3992,18 +3903,6 @@ static GLhandleARB generate_param_reorder_function(struct wined3d_shader_buffer
                 &ps->baseShader.reg_maps, output_signature, &vs->baseShader.reg_maps);
 
         shader_addline(buffer, "}\n");
-    } else if(ps_major >= 3 && vs_major < 3) {
-        shader_addline(buffer, "varying vec4 IN[%u];\n", vec4_varyings(3, gl_info));
-        shader_addline(buffer, "void order_ps_input() {\n");
-        /* The vertex shader wrote to the builtin varyings. There is no need to figure out position and
-         * point size, but we depend on the optimizers kindness to find out that the pixel shader doesn't
-         * read gl_TexCoord and gl_ColorX, otherwise we'll run out of varyings
-         */
-        handle_ps3_input(buffer, gl_info, ps->input_reg_map, ps->baseShader.input_signature,
-                &ps->baseShader.reg_maps, NULL, NULL);
-        shader_addline(buffer, "}\n");
-    } else {
-        ERR("Unexpected vertex and pixel shader version condition: vs: %d, ps: %d\n", vs_major, ps_major);
     }
 
     ret = GL_EXTCALL(glCreateShaderObjectARB(GL_VERTEX_SHADER_ARB));
@@ -4169,9 +4068,8 @@ static GLuint shader_glsl_generate_vshader(const struct wined3d_context *context
     /* Base Shader Body */
     shader_generate_main((IWineD3DBaseShader*)This, buffer, reg_maps, function, &priv_ctx);
 
-    /* Unpack 3.0 outputs */
-    if (reg_maps->shader_version.major >= 3) shader_addline(buffer, "order_ps_input(OUT);\n");
-    else shader_addline(buffer, "order_ps_input();\n");
+    /* Unpack outputs */
+    shader_addline(buffer, "order_ps_input(OUT);\n");
 
     /* The D3DRS_FOGTABLEMODE render state defines if the shader-generated fog coord is used
      * or if the fragment depth is used. If the fragment depth is used(FOGTABLEMODE != NONE),
diff --git a/dlls/wined3d/shader.c b/dlls/wined3d/shader.c
index 209bae4..b656601 100644
--- a/dlls/wined3d/shader.c
+++ b/dlls/wined3d/shader.c
@@ -182,6 +182,17 @@ static void shader_signature_from_semantic(struct wined3d_shader_signature_eleme
     e->mask = s->reg.write_mask;
 }
 
+static void shader_signature_from_usage(struct wined3d_shader_signature_element *e,
+        WINED3DDECLUSAGE usage, UINT usage_idx, UINT reg_idx, DWORD write_mask)
+{
+    e->semantic_name = shader_semantic_name_from_usage(usage);
+    e->semantic_idx = usage_idx;
+    e->sysval_semantic = 0;
+    e->component_type = 0;
+    e->register_idx = reg_idx;
+    e->mask = write_mask;
+}
+
 static const struct wined3d_shader_frontend *shader_select_frontend(DWORD version_token)
 {
     switch (version_token >> 16)
@@ -640,10 +651,70 @@ static HRESULT shader_get_registers_used(IWineD3DBaseShader *iface, const struct
                 /* WINED3DSPR_TEXCRDOUT is the same as WINED3DSPR_OUTPUT. _OUTPUT can be > MAX_REG_TEXCRD and
                  * is used in >= 3.0 shaders. Filter 3.0 shaders to prevent overflows, and also filter pixel
                  * shaders because TECRDOUT isn't used in them, but future register types might cause issues */
-                if (shader_version.type == WINED3D_SHADER_TYPE_VERTEX && shader_version.major < 3
-                        && dst_param.reg.type == WINED3DSPR_TEXCRDOUT)
+                if (shader_version.type == WINED3D_SHADER_TYPE_VERTEX && shader_version.major < 3)
                 {
-                    reg_maps->texcoord_mask[dst_param.reg.idx] |= dst_param.write_mask;
+                    UINT idx = dst_param.reg.idx;
+
+                    switch (dst_param.reg.type)
+                    {
+                        case WINED3DSPR_RASTOUT:
+                            switch (idx)
+                            {
+                                case 0: /* oPos */
+                                    reg_maps->output_registers |= 1 << 10;
+                                    shader_signature_from_usage(&output_signature[10],
+                                            WINED3DDECLUSAGE_POSITION, 0, 10, WINED3DSP_WRITEMASK_ALL);
+                                    break;
+
+                                case 1: /* oFog */
+                                    reg_maps->output_registers |= 1 << 11;
+                                    shader_signature_from_usage(&output_signature[11],
+                                            WINED3DDECLUSAGE_FOG, 0, 11, WINED3DSP_WRITEMASK_0);
+                                    break;
+
+                                case 2: /* oPts */
+                                    reg_maps->output_registers |= 1 << 11;
+                                    shader_signature_from_usage(&output_signature[11],
+                                            WINED3DDECLUSAGE_PSIZE, 0, 11, WINED3DSP_WRITEMASK_1);
+                                    break;
+                            }
+                            break;
+
+                        case WINED3DSPR_ATTROUT:
+                            if (idx < 2)
+                            {
+                                idx += 8;
+                                if (reg_maps->output_registers & (1 << idx))
+                                {
+                                    output_signature[idx].mask |= dst_param.write_mask;
+                                }
+                                else
+                                {
+                                    reg_maps->output_registers |= 1 << idx;
+                                    shader_signature_from_usage(&output_signature[idx],
+                                            WINED3DDECLUSAGE_COLOR, idx - 8, idx, dst_param.write_mask);
+                                }
+                            }
+                            break;
+
+                        case WINED3DSPR_TEXCRDOUT:
+
+                            reg_maps->texcoord_mask[idx] |= dst_param.write_mask;
+                            if (reg_maps->output_registers & (1 << idx))
+                            {
+                                output_signature[idx].mask |= dst_param.write_mask;
+                            }
+                            else
+                            {
+                                reg_maps->output_registers |= 1 << idx;
+                                shader_signature_from_usage(&output_signature[idx],
+                                        WINED3DDECLUSAGE_TEXCOORD, idx, idx, dst_param.write_mask);
+                            }
+                            break;
+
+                        default:
+                            break;
+                    }
                 }
 
                 if (shader_version.type == WINED3D_SHADER_TYPE_PIXEL)
@@ -1700,7 +1771,7 @@ static void vertexshader_set_limits(IWineD3DVertexShaderImpl *shader)
             shader->baseShader.limits.constant_bool = 0;
             shader->baseShader.limits.constant_int = 0;
             shader->baseShader.limits.address = 1;
-            shader->baseShader.limits.packed_output = 0;
+            shader->baseShader.limits.packed_output = 12;
             shader->baseShader.limits.sampler = 0;
             shader->baseShader.limits.label = 0;
             /* TODO: vs_1_1 has a minimum of 96 constants. What happens when
@@ -1715,7 +1786,7 @@ static void vertexshader_set_limits(IWineD3DVertexShaderImpl *shader)
             shader->baseShader.limits.constant_bool = 16;
             shader->baseShader.limits.constant_int = 16;
             shader->baseShader.limits.address = 1;
-            shader->baseShader.limits.packed_output = 0;
+            shader->baseShader.limits.packed_output = 12;
             shader->baseShader.limits.sampler = 0;
             shader->baseShader.limits.label = 16;
             shader->baseShader.limits.constant_float = min(256, device->d3d_vshader_constantF);
@@ -1746,7 +1817,7 @@ static void vertexshader_set_limits(IWineD3DVertexShaderImpl *shader)
             shader->baseShader.limits.constant_bool = 16;
             shader->baseShader.limits.constant_int = 16;
             shader->baseShader.limits.address = 1;
-            shader->baseShader.limits.packed_output = 0;
+            shader->baseShader.limits.packed_output = 12;
             shader->baseShader.limits.sampler = 0;
             shader->baseShader.limits.label = 16;
             shader->baseShader.limits.constant_float = min(256, device->d3d_vshader_constantF);
-- 
1.7.1




More information about the wine-patches mailing list