[WINED3D] Clean up per version shader limits code

Ivan Gyurdiev ivg2 at cornell.edu
Mon May 8 16:09:21 CDT 2006


>
> - default case was made to match the lowest supported one
I'm not too happy with this part of the patch.
If we don't know the version we probably want higher limits, so that the 
shader will work regardless.
In particular, this shows up with NFS:MW, which uses unknown shader 
version ps_2_1.

Please use the attached patch instead, it does not decrease the default 
(unknown) case anywhere. It actually increases the number of temporaries 
available to 32, so that it matches the ps_2_0 case as it did before the 
patch.

We still need to figure out how many registers ps_2_1 is supposed to 
support - we should never fall back to the default case.



-------------- next part --------------
---

 dlls/wined3d/pixelshader.c     |  162 ++++++++++++++++++++++------------------
 dlls/wined3d/vertexshader.c    |  143 +++++++++++++++++++----------------
 dlls/wined3d/wined3d_private.h |   11 +++
 3 files changed, 178 insertions(+), 138 deletions(-)

b1130296853f0d34cbc6f586f01846b1fdca01f2
diff --git a/dlls/wined3d/pixelshader.c b/dlls/wined3d/pixelshader.c
index 2d7ab7a..89c3077 100644
--- a/dlls/wined3d/pixelshader.c
+++ b/dlls/wined3d/pixelshader.c
@@ -975,6 +975,61 @@ inline static void pshader_program_get_r
     }
 }
 
+void pshader_set_version(
+      IWineD3DPixelShaderImpl *This, 
+      DWORD version) {
+
+      DWORD major = (version >> 8) & 0x0F;
+      DWORD minor = version & 0x0F;
+
+      This->baseShader.hex_version = version;
+      This->baseShader.version = major * 10 + minor;
+      TRACE("ps_%lu_%lu\n", major, minor);
+
+      This->baseShader.limits.address = 0;
+
+      switch (This->baseShader.version) {
+          case 10:
+          case 11:
+          case 12:
+          case 13: This->baseShader.limits.temporary = 2;
+                   This->baseShader.limits.constant_float = 8;
+                   This->baseShader.limits.constant_int = 0;
+                   This->baseShader.limits.constant_bool = 0;
+                   This->baseShader.limits.texture = 4;
+                   break;
+
+          case 14: This->baseShader.limits.temporary = 6;
+                   This->baseShader.limits.constant_float = 8;
+                   This->baseShader.limits.constant_int = 0;
+                   This->baseShader.limits.constant_bool = 0;
+                   This->baseShader.limits.texture = 6;
+                   break;
+               
+          /* FIXME: temporaries must match D3DPSHADERCAPS2_0.NumTemps */ 
+          case 20: This->baseShader.limits.temporary = 32;
+                   This->baseShader.limits.constant_float = 32;
+                   This->baseShader.limits.constant_int = 16;
+                   This->baseShader.limits.constant_bool = 16;
+                   This->baseShader.limits.texture = 8;
+                   break;
+
+          case 30: This->baseShader.limits.temporary = 32;
+                   This->baseShader.limits.constant_float = 224;
+                   This->baseShader.limits.constant_int = 16;
+                   This->baseShader.limits.constant_bool = 16;
+                   This->baseShader.limits.texture = 0;
+                   break;
+
+          default: This->baseShader.limits.temporary = 32;
+                   This->baseShader.limits.constant_float = 8;
+                   This->baseShader.limits.constant_int = 0;
+                   This->baseShader.limits.constant_bool = 0;
+                   This->baseShader.limits.texture = 8;
+                   FIXME("Unrecognized pixel shader version %lu!\n", version);
+      }
+}
+
 /* NOTE: A description of how to parse tokens can be found at http://msdn.microsoft.com/library/default.asp?url=/library/en-us/graphics/hh/graphics/usermodedisplaydriver_shader_cc8e4e05-f5c3-4ec0-8853-8ce07c1551b2.xml.asp */
 inline static VOID IWineD3DPixelShaderImpl_GenerateProgramArbHW(IWineD3DPixelShader *iface, CONST DWORD *pFunction) {
     IWineD3DPixelShaderImpl *This = (IWineD3DPixelShaderImpl *)iface;
@@ -991,7 +1046,7 @@ #endif
     BOOL saturate; /* clamp to 0.0 -> 1.0*/
     int row = 0; /* not sure, something to do with macros? */
     DWORD tcw[2];
-    int version = 0; /* The version of the shader */
+    int version = This->baseShader.version; 
 
     /* Keep bitmaps of used temporary and texture registers */
     DWORD tempsUsed, texUsed;
@@ -1011,6 +1066,9 @@ #endif
     buffer.bsize = 0;
     buffer.lineNo = 0;
 
+    /* FIXME: if jumps are used, use GLSL, else use ARB_fragment_program */
+    shader_addline(&buffer, "!!ARBfp1.0\n");
+
     /* TODO: Think about using a first pass to work out what's required for the second pass. */
     for(i = 0; i < WINED3D_PSHADER_MAX_CONSTANTS; i++)
         This->constants[i] = 0;
@@ -1021,6 +1079,33 @@ #endif
 
     /* TODO: check register usage against GL/Directx limits, and fail if they're exceeded */
 
+    /* Pre-declare registers */
+    for(i = 0; i < This->baseShader.limits.texture; i++) {
+        if (texUsed & (1 << i))
+            shader_addline(&buffer,"TEMP T%lu;\n", i);
+    }
+
+    for(i = 0; i < This->baseShader.limits.temporary; i++) {
+        if (tempsUsed & (1 << i))
+             shader_addline(&buffer, "TEMP R%lu;\n", i);
+    }
+
+    /* Necessary for internal operations */
+    shader_addline(&buffer, "TEMP TMP;\n");
+    shader_addline(&buffer, "TEMP TMP2;\n");
+    shader_addline(&buffer, "TEMP TA;\n");
+    shader_addline(&buffer, "TEMP TB;\n");
+    shader_addline(&buffer, "TEMP TC;\n");
+    shader_addline(&buffer, "PARAM coefdiv = { 0.5, 0.25, 0.125, 0.0625 };\n");
+    shader_addline(&buffer, "PARAM coefmul = { 2, 4, 8, 16 };\n");
+    shader_addline(&buffer, "PARAM one = { 1.0, 1.0, 1.0, 1.0 };\n");
+
+    /* Texture coordinate registers must be pre-loaded */
+    for (i = 0; i < This->baseShader.limits.texture; i++) {
+       if (texUsed & (1 << i))
+          shader_addline(&buffer, "MOV T%lu, fragment.texcoord[%lu];\n", i, i);
+    }
+
     /* Second pass, process opcodes */
     if (NULL != pToken) {
         while (D3DPS_END() != *pToken) {
@@ -1029,79 +1114,15 @@ #if 0 /* For pixel and vertex shader ver
                 instructionSize = pToken & SIZEBITS >> 27;
             }
 #endif
-            if (pshader_is_version_token(*pToken)) { /** version */
-                int numTemps;
-                int numConstants;
-                int numTex;
-
-                /* Extract version *10 into integer value (ie. 1.0 == 10, 1.1==11 etc */
-                version = (((*pToken >> 8) & 0x0F) * 10) + (*pToken & 0x0F);
-
-                TRACE("found version token ps.%lu.%lu;\n", (*pToken >> 8) & 0x0F, (*pToken & 0x0F));
-
-                /* Each release of pixel shaders has had different numbers of temp registers */
-                switch (version) {
-                case 10:
-                case 11:
-                case 12:
-                case 13:numTemps=12;
-                        numConstants=8;
-                        numTex=4;
-                        break;
-                case 14: numTemps=12;
-                        numConstants=8;
-                        numTex=6;
-                        break;
-                case 20: numTemps=12;
-                        numConstants=8;
-                        numTex=8;
-                        FIXME("No work done yet to support ps2.0 in hw\n");
-                        break;
-                case 30: numTemps=32;
-                        numConstants=8;
-                        numTex=0; 
-                        FIXME("No work done yet to support ps3.0 in hw\n");
-                        break;
-                default:
-                        numTemps=12;
-                        numConstants=8;
-                        numTex=8; 
-                        FIXME("Unrecognized pixel shader version!\n");
-                }
-
-                /* FIXME: if jumps are used, use GLSL, else use ARB_fragment_program */
-                shader_addline(&buffer, "!!ARBfp1.0\n");
-
-                for(i = 0; i < numTex; i++) {
-                    if (texUsed & (1 << i)) 
-                        shader_addline(&buffer,"TEMP T%lu;\n", i);
-                }
-
-                for(i = 0; i < numTemps; i++) {
-                    if (tempsUsed & (1 << i)) 
-                        shader_addline(&buffer, "TEMP R%lu;\n", i);
-                }
-
-                shader_addline(&buffer, "TEMP TMP;\n");
-                shader_addline(&buffer, "TEMP TMP2;\n");
-                shader_addline(&buffer, "TEMP TA;\n");
-                shader_addline(&buffer, "TEMP TB;\n");
-                shader_addline(&buffer, "TEMP TC;\n");
-
-                shader_addline(&buffer, "PARAM coefdiv = { 0.5, 0.25, 0.125, 0.0625 };\n");
-                shader_addline(&buffer, "PARAM coefmul = { 2, 4, 8, 16 };\n");
-                shader_addline(&buffer, "PARAM one = { 1.0, 1.0, 1.0, 1.0 };\n");
-
-                for(i = 0; i < numTex; i++) {
-                    if (texUsed & (1 << i)) 
-                        shader_addline(&buffer, "MOV T%lu, fragment.texcoord[%lu];\n", i, i);
-                }
 
+            /* Skip version token */
+            if (pshader_is_version_token(*pToken)) {
                 ++pToken;
                 continue;
             }
 
-            if (pshader_is_comment_token(*pToken)) { /** comment */
+            /* Skip comment tokens */
+            if (pshader_is_comment_token(*pToken)) {
                 DWORD comment_len = (*pToken & D3DSI_COMMENTSIZE_MASK) >> D3DSI_COMMENTSIZE_SHIFT;
                 ++pToken;
                 TRACE("#%s\n", (char*)pToken);
@@ -1750,8 +1771,7 @@ HRESULT WINAPI IWineD3DPixelShaderImpl_S
     if (NULL != pToken) {
         while (D3DPS_END() != *pToken) {
             if (pshader_is_version_token(*pToken)) { /** version */
-                This->baseShader.version = (((*pToken >> 8) & 0x0F) * 10) + (*pToken & 0x0F);
-                TRACE("ps_%lu_%lu\n", (*pToken >> 8) & 0x0F, (*pToken & 0x0F));
+                pshader_set_version(This, *pToken);
                 ++pToken;
                 ++len;
                 continue;
diff --git a/dlls/wined3d/vertexshader.c b/dlls/wined3d/vertexshader.c
index 54fb413..a27336b 100644
--- a/dlls/wined3d/vertexshader.c
+++ b/dlls/wined3d/vertexshader.c
@@ -1112,6 +1112,51 @@ static void parse_decl_usage(IWineD3DVer
     }
 }
 
+void vshader_set_version(
+      IWineD3DVertexShaderImpl *This,
+      DWORD version) {
+
+      DWORD major = (version >> 8) & 0x0F;
+      DWORD minor = version & 0x0F;
+
+      This->baseShader.hex_version = version;
+      This->baseShader.version = major * 10 + minor;
+      TRACE("vs_%lu_%lu\n", major, minor);
+
+      This->baseShader.limits.texture = 0;
+
+      /* Must match D3DCAPS9.MaxVertexShaderConst: at least 256 for vs_2_0 */
+      This->baseShader.limits.constant_float = WINED3D_VSHADER_MAX_CONSTANTS;
+
+      switch (This->baseShader.version) {
+          case 10:
+          case 11: This->baseShader.limits.temporary = 12;
+                   This->baseShader.limits.constant_bool = 0;
+                   This->baseShader.limits.constant_int = 0;
+                   This->baseShader.limits.address = 1;
+                   break;
+      
+          case 20:
+          case 21: This->baseShader.limits.temporary = 12;
+                   This->baseShader.limits.constant_bool = 16;
+                   This->baseShader.limits.constant_int = 16;
+                   This->baseShader.limits.address = 1;
+                   break;
+
+          case 30: This->baseShader.limits.temporary = 32;
+                   This->baseShader.limits.constant_bool = 32;
+                   This->baseShader.limits.constant_int = 32;
+                   This->baseShader.limits.address = 1;
+                   break;
+
+          default: This->baseShader.limits.temporary = 12;
+                   This->baseShader.limits.constant_bool = 0;
+                   This->baseShader.limits.constant_int = 0;
+                   This->baseShader.limits.address = 1;
+                   FIXME("Unrecognized vertex shader version %lu!\n", version);
+      }
+}
+
 /**
  * Function parser ...
  */
@@ -1255,6 +1300,29 @@ #endif
         nUseTempRegister    <=  GL_MAX_PROGRAM_LOCAL_PARAMETERS_ARB
     */
 
+    /* Mesa supports only 95 constants */
+    if (GL_VEND(MESA) || GL_VEND(WINE))
+        This->baseShader.limits.constant_float = 
+           min(95, This->baseShader.limits.constant_float);
+
+    /* FIXME: if jumps are used, use GLSL, else use ARB_vertex_program */
+    shader_addline(&buffer, "!!ARBvp1.0\n");
+
+    /* Declare necessary things.
+     * FIXME: replace with a bitmap
+     * FIXME: loop counts as an address register */
+
+    for (i = 0; i < nUseTempRegister /* we should check numTemps here */ ; i++) {
+        if (tmpsUsed[i])
+            shader_addline(&buffer, "TEMP T%ld;\n", i);
+    }
+    for (i = 0; i < nUseAddressRegister; i++) 
+        shader_addline(&buffer, "ADDRESS A%ld;\n", i);
+
+    shader_addline(&buffer, "PARAM C[%d] = { program.env[0..%d] };\n",
+        This->baseShader.limits.constant_float, 
+        This->baseShader.limits.constant_float - 1);            
+
   /** second pass, now generate */
   pToken = pFunction;
 
@@ -1267,73 +1335,14 @@ #endif
       if (D3DVS_END() == *pToken)
             break;
 
-      if (vshader_is_version_token(*pToken)) { /** version */
-        /* Extract version *10 into integer value (ie. 1.0 == 10, 1.1==11 etc */
-        int version = (((*pToken >> 8) & 0x0F) * 10) + (*pToken & 0x0F);
-        int numTemps;
-        int numConstants;
-
-        TRACE("found version token vs.%lu.%lu;\n", (*pToken >> 8) & 0x0F, (*pToken & 0x0F));
-
-        /* Each release of vertex shaders has had different numbers of temp registers */
-        switch (version) {
-        case 10:
-        case 11: numTemps=12;
-                 numConstants=96;/* min(GL_LIMITS(constants),96) */
-                 break;
-        /* FIXME: if there are no calls or loops then use ARBvp1 otherwise use GLSL instead
-           TODO: see if there are any operations in vs2/3 that aren't supported by ARBvp
-            TODO: only map the maximum possible number of constants supported by openGL and not the maximum required by d3d (even better only map the used constants)*/
-        case 20: numTemps=12; /* min(GL_LIMITS(temps),12) */
-                 numConstants=96; /* min(GL_LIMITS(constants),256) */
-                 FIXME("No work done yet to support vs2.0 in hw\n");
-                 break;
-        case 21: numTemps=12; /* min(GL_LIMITS(temps),12) */
-                 numConstants=96; /* min(GL_LIMITS(constants),256) */
-                 FIXME("No work done yet to support vs2.1 in hw\n");
-                 break;
-        case 30: numTemps=32; /* min(GL_LIMITS(temps),32) */
-                 numConstants=96;/* min(GL_LIMITS(constants),256) */
-                 FIXME("No work done yet to support vs3.0 in hw\n");
-                 break;
-        default:
-                 numTemps=12;/* min(GL_LIMITS(temps),12) */
-                 numConstants=96;/* min(GL_LIMITS(constants),96) */
-                 FIXME("Unrecognized vertex shader version %d!\n", version);
-        }
-
-
-        /* FIXME: if jumps are used, use GLSL, else use ARB_vertex_program */
-        shader_addline(&buffer, "!!ARBvp1.0\n");
-
-        /* This should be a bitmap so that only temp registers that are used are declared. */
-        for (i = 0; i < nUseTempRegister /* we should check numTemps here */ ; i++) {
-            if (tmpsUsed[i])
-                shader_addline(&buffer, "TEMP T%ld;\n", i);
-        }
-        /* TODO: loop register counts as an address register */
-        for (i = 0; i < nUseAddressRegister; i++) {
-            shader_addline(&buffer, "ADDRESS A%ld;\n", i);
-        }
-
-        /* Due to the dynamic constants binding mechanism, we need to declare
-        * all the constants for relative addressing. */
-        /* Mesa supports only 95 constants for VS1.X although we should have at least 96. */
-        if (GL_VEND(MESA) || GL_VEND(WINE)) {
-            numConstants = 95;
-        }
-
-        /* FIXME: We should be counting the number of constants in the first pass 
-         * and then validating that many are supported. Looking at some of the shaders in use 
-         * by applications we'd need to create a list of all used env variables
-         */
-        shader_addline(&buffer, "PARAM C[%d] = { program.env[0..%d] };\n", 
-           numConstants, numConstants - 1);
+      /* Skip version */
+      if (vshader_is_version_token(*pToken)) {
+            ++pToken;
+            continue;
+      }
 
-        ++pToken;
-        continue;
-        }
-        if (vshader_is_comment_token(*pToken)) { /** comment */
+      /* Skip comments */
+      if (vshader_is_comment_token(*pToken)) {
             DWORD comment_len = (*pToken & D3DSI_COMMENTSIZE_MASK) >> D3DSI_COMMENTSIZE_SHIFT;
             ++pToken;
             TRACE("#%s\n", (char*)pToken);
@@ -1961,7 +1970,7 @@ HRESULT WINAPI IWineD3DVertexShaderImpl_
     if (NULL != pToken) {
         while (D3DVS_END() != *pToken) {
             if (vshader_is_version_token(*pToken)) { /** version */
-                TRACE("vs_%lu_%lu\n", (*pToken >> 8) & 0x0F, (*pToken & 0x0F));
+                vshader_set_version(This, *pToken);
                 ++pToken;
                 ++len;
                 continue;
diff --git a/dlls/wined3d/wined3d_private.h b/dlls/wined3d/wined3d_private.h
index b795e2a..03eaa90 100644
--- a/dlls/wined3d/wined3d_private.h
+++ b/dlls/wined3d/wined3d_private.h
@@ -1197,6 +1197,15 @@ typedef struct SHADER_BUFFER {
     unsigned int lineNo;
 } SHADER_BUFFER;
 
+typedef struct SHADER_LIMITS {
+    unsigned int temporary;
+    unsigned int texture;
+    unsigned int constant_int;
+    unsigned int constant_float;
+    unsigned int constant_bool;
+    unsigned int address;
+} SHADER_LIMITS;
+
 /* Base Shader utility functions. 
  * (may move callers into the same file in the future) */
 extern int shader_addline(
@@ -1209,6 +1218,8 @@ extern int shader_addline(
 typedef struct IWineD3DBaseShaderClass
 {
     DWORD                           version;
+    DWORD                           hex_version;
+    SHADER_LIMITS                   limits;
     CONST SHADER_OPCODE             *shader_ins;
     CONST DWORD                     *function;
     UINT                            functionLength;
-- 
1.3.1



More information about the wine-patches mailing list