[WINED3D 4] More flow control instructions

Ivan Gyurdiev ivg231 at gmail.com
Mon Jul 10 04:11:35 CDT 2006


- Implement if, else, endif, rep, endrep, break
- Implement ifc, breakc, using undocumented comparison bits in the 
instruction token
- Fix bug in main loop processing of codes with no dst token
- Fix bug in GLSL output modifier processing of codes with no dst token
- Fix bug in loop implementation (src1 contains the integer data, src0 
is aL)
- Add versioning for all the instructions above, and remove 
GLSL_REQUIRED thing, which is useless and should be removed from all 
opcodes in general.

Note that loops will not work on pixel shaders at the moment - will 
return a GLSL error.
That's either a hardware or a GLSL limitation. Loops seem to work 
properly on vertex shaders.

-------------- next part --------------
---
 dlls/wined3d/baseshader.c      |   39 ++++++++++++-----
 dlls/wined3d/glsl_shader.c     |   91 +++++++++++++++++++++++++++++++++++-----
 dlls/wined3d/pixelshader.c     |   20 ++++-----
 dlls/wined3d/vertexshader.c    |   20 ++++-----
 dlls/wined3d/wined3d_private.h |   22 +++++++++-
 5 files changed, 147 insertions(+), 45 deletions(-)

diff --git a/dlls/wined3d/baseshader.c b/dlls/wined3d/baseshader.c
index 5baca25..1275dd5 100644
--- a/dlls/wined3d/baseshader.c
+++ b/dlls/wined3d/baseshader.c
@@ -273,7 +273,8 @@ HRESULT shader_get_registers_used(
             pToken += curOpcode->num_params;
 
         /* If there's a loop in the shader */
-        } else if (D3DSIO_LOOP == curOpcode->opcode) {
+        } else if (D3DSIO_LOOP == curOpcode->opcode ||
+                   D3DSIO_REP == curOpcode->opcode) {
             reg_maps->loop = 1;
             pToken += curOpcode->num_params;
         
@@ -632,7 +633,6 @@ void shader_generate_main(
     const DWORD *pToken = pFunction;
     const SHADER_OPCODE *curOpcode = NULL;
     SHADER_HANDLER hw_fct = NULL;
-    DWORD opcode_token;
     DWORD i;
     SHADER_OPCODE_ARG hw_arg;
 
@@ -662,8 +662,8 @@ void shader_generate_main(
             }
 
             /* Read opcode */
-            opcode_token = *pToken++;
-            curOpcode = shader_get_opcode(iface, opcode_token);
+            hw_arg.opcode_token = *pToken++;
+            curOpcode = shader_get_opcode(iface, hw_arg.opcode_token);
 
             /* Select handler */
             if (curOpcode == NULL)
@@ -675,7 +675,7 @@ void shader_generate_main(
 
             /* Unknown opcode and its parameters */
             if (NULL == curOpcode) {
-                FIXME("Unrecognized opcode: token=%08lX\n", opcode_token);
+                FIXME("Unrecognized opcode: token=%08lX\n", hw_arg.opcode_token);
                 pToken += shader_skip_unrecognized(iface, pToken); 
 
             /* Nothing to do */
@@ -685,7 +685,7 @@ void shader_generate_main(
                        D3DSIO_DEFI == curOpcode->opcode ||
                        D3DSIO_DEFB == curOpcode->opcode) {
 
-                pToken += shader_skip_opcode(This, curOpcode, opcode_token);
+                pToken += shader_skip_opcode(This, curOpcode, hw_arg.opcode_token);
 
             /* If a generator function is set for current shader target, use it */
             } else if (hw_fct != NULL) {
@@ -702,17 +702,16 @@ void shader_generate_main(
                 }
 
                 /* Predication token */
-                if (opcode_token & D3DSHADER_INSTRUCTION_PREDICATED) 
+                if (hw_arg.opcode_token & D3DSHADER_INSTRUCTION_PREDICATED) 
                     hw_arg.predicate = *pToken++;
 
                 /* Other source tokens */
-                for (i = curOpcode->dst_token; i < curOpcode->num_params; i++) {
+                for (i = 0; i < (curOpcode->num_params - curOpcode->dst_token); i++) {
 
                     DWORD param, addr_token = 0; 
-
                     pToken += shader_get_param(iface, pToken, &param, &addr_token);
-                    hw_arg.src[i-1] = param;
-                    hw_arg.src_addr[i-1] = addr_token;
+                    hw_arg.src[i] = param;
+                    hw_arg.src_addr[i] = addr_token;
                 }
 
                 /* Call appropriate function for output target */
@@ -726,7 +725,7 @@ void shader_generate_main(
             } else {
 
                 FIXME("Can't handle opcode %s in hwShader\n", curOpcode->name);
-                pToken += shader_skip_opcode(This, curOpcode, opcode_token);
+                pToken += shader_skip_opcode(This, curOpcode, hw_arg.opcode_token);
             }
         }
         /* TODO: What about result.depth? */
@@ -863,6 +862,22 @@ void shader_trace_init(
 
                     TRACE("%s", curOpcode->name);
 
+                    if (curOpcode->opcode == D3DSIO_IFC ||
+                        curOpcode->opcode == D3DSIO_BREAKC) {
+
+                        DWORD op = (opcode_token & INST_CONTROLS_MASK) >> INST_CONTROLS_SHIFT;
+                        switch (op) {
+                            case COMPARISON_GT: TRACE("_gt"); break;
+                            case COMPARISON_EQ: TRACE("_eq"); break;
+                            case COMPARISON_GE: TRACE("_ge"); break;
+                            case COMPARISON_LT: TRACE("_lt"); break;
+                            case COMPARISON_NE: TRACE("_ne"); break;
+                            case COMPARISON_LE: TRACE("_le"); break;
+                            default:
+                                TRACE("_(%lu)", op);
+                        }
+                    }
+
                     /* Destination token */
                     if (curOpcode->dst_token) {
 
diff --git a/dlls/wined3d/glsl_shader.c b/dlls/wined3d/glsl_shader.c
index 0d0ed3a..bd91f10 100644
--- a/dlls/wined3d/glsl_shader.c
+++ b/dlls/wined3d/glsl_shader.c
@@ -755,9 +755,10 @@ static void shader_glsl_add_param(
 
 /** Process GLSL instruction modifiers */
 void shader_glsl_add_instruction_modifiers(SHADER_OPCODE_ARG* arg) {
-        
-    if (0 != (arg->dst & D3DSP_DSTMOD_MASK)) {
-        DWORD mask = arg->dst & D3DSP_DSTMOD_MASK;
+    
+    DWORD mask = arg->dst & D3DSP_DSTMOD_MASK;
+ 
+    if (arg->opcode->dst_token && mask != 0) {
         char dst_reg[50];
         char dst_mask[6];
         char dst_str[100];
@@ -777,6 +778,23 @@ void shader_glsl_add_instruction_modifie
     }
 }
 
+static inline const char* shader_get_comp_op(
+    const DWORD opcode) {
+
+    DWORD op = (opcode & INST_CONTROLS_MASK) >> INST_CONTROLS_SHIFT;
+    switch (op) {
+        case COMPARISON_GT: return ">";
+        case COMPARISON_EQ: return "==";
+        case COMPARISON_GE: return ">=";
+        case COMPARISON_LT: return "<";
+        case COMPARISON_NE: return "!=";
+        case COMPARISON_LE: return "<=";
+        default:
+            FIXME("Unrecognized comparison value: %lu\n", op);
+            return "(\?\?)";
+    }
+}
+
 /*****************************************************************************
  * 
  * Begin processing individual instruction opcodes
@@ -1152,24 +1170,73 @@ void shader_glsl_sincos(SHADER_OPCODE_AR
  */
 void shader_glsl_loop(SHADER_OPCODE_ARG* arg) {
     
+    char src1_str[100];
+    char src1_reg[50];
+    char src1_mask[6];
+    
+    shader_glsl_add_param(arg, arg->src[1], arg->src_addr[1], TRUE, src1_reg, src1_mask, src1_str);
+  
+    shader_addline(arg->buffer, "for (tmpInt = 0, aL = %s.y; tmpInt < %s.x; tmpInt++, aL += %s.z) {\n",
+                   src1_reg, src1_reg, src1_reg);
+}
+
+void shader_glsl_end(SHADER_OPCODE_ARG* arg) {
+    shader_addline(arg->buffer, "}\n");
+}
+
+void shader_glsl_rep(SHADER_OPCODE_ARG* arg) {
+
     char src0_str[100];
     char src0_reg[50];
     char src0_mask[6];
-    
+
     shader_glsl_add_param(arg, arg->src[0], arg->src_addr[0], TRUE, src0_reg, src0_mask, src0_str);
-  
-    shader_addline(arg->buffer, "for (tmpInt = 0, aL = %s.y; tmpInt < %s.x; tmpInt++, aL += %s.z) {\n",
-                   src0_reg, src0_reg, src0_reg);
+    shader_addline(arg->buffer, "for (tmpInt = 0; tmpInt < %s.x; tmpInt++) {\n", src0_reg);
 }
 
-/** Process the D3DSIO_ENDLOOP instruction in GLSL:
- * End the for() loop
- */
-void shader_glsl_endloop(SHADER_OPCODE_ARG* arg) {
+void shader_glsl_if(SHADER_OPCODE_ARG* arg) {
 
-    shader_addline(arg->buffer, "}\n");
+    char src0_str[100];
+    char src0_reg[50];
+    char src0_mask[6];
+
+    shader_glsl_add_param(arg, arg->src[0], arg->src_addr[0], TRUE, src0_reg, src0_mask, src0_str);
+    shader_addline(arg->buffer, "if (%s) {\n", src0_str); 
+}
+
+void shader_glsl_ifc(SHADER_OPCODE_ARG* arg) {
+
+    char src0_str[100], src1_str[100];
+    char src0_reg[50], src1_reg[50];
+    char src0_mask[6], src1_mask[6];
+
+    shader_glsl_add_param(arg, arg->src[0], arg->src_addr[0], TRUE, src0_reg, src0_mask, src0_str);
+    shader_glsl_add_param(arg, arg->src[1], arg->src_addr[1], TRUE, src1_reg, src1_mask, src1_str);
+
+    shader_addline(arg->buffer, "if (%s %s %s) {\n",
+        src0_str, shader_get_comp_op(arg->opcode_token), src1_str);
+}
+
+void shader_glsl_else(SHADER_OPCODE_ARG* arg) {
+    shader_addline(arg->buffer, "} else {\n");
 }
 
+void shader_glsl_break(SHADER_OPCODE_ARG* arg) {
+    shader_addline(arg->buffer, "break;\n");
+}
+
+void shader_glsl_breakc(SHADER_OPCODE_ARG* arg) {
+
+    char src0_str[100], src1_str[100];
+    char src0_reg[50], src1_reg[50];
+    char src0_mask[6], src1_mask[6];
+
+    shader_glsl_add_param(arg, arg->src[0], arg->src_addr[0], TRUE, src0_reg, src0_mask, src0_str);
+    shader_glsl_add_param(arg, arg->src[1], arg->src_addr[1], TRUE, src1_reg, src1_mask, src1_str);
+
+    shader_addline(arg->buffer, "if (%s %s %s) break;\n",
+        src0_str, shader_get_comp_op(arg->opcode_token), src1_str);
+}
 
 /*********************************************
  * Pixel Shader Specific Code begins here
diff --git a/dlls/wined3d/pixelshader.c b/dlls/wined3d/pixelshader.c
index 40d7a40..977cb4e 100644
--- a/dlls/wined3d/pixelshader.c
+++ b/dlls/wined3d/pixelshader.c
@@ -676,20 +676,20 @@ CONST SHADER_OPCODE IWineD3DPixelShaderI
     {D3DSIO_DCL,      "dcl",      NULL, 0, 2, pshader_dcl,     NULL, NULL, 0, 0},
 
     /* Flow control - requires GLSL or software shaders */
-    {D3DSIO_REP ,     "rep",      GLNAME_REQUIRE_GLSL, 0, 1, pshader_rep,     NULL, NULL, 0, 0},
-    {D3DSIO_ENDREP,   "endrep",   GLNAME_REQUIRE_GLSL, 0, 0, pshader_endrep,  NULL, NULL, 0, 0},
-    {D3DSIO_IF,       "if",       GLNAME_REQUIRE_GLSL, 0, 1, pshader_if,      NULL, NULL, 0, 0},
-    {D3DSIO_IFC,      "ifc",      GLNAME_REQUIRE_GLSL, 0, 2, pshader_ifc,     NULL, NULL, 0, 0},
-    {D3DSIO_ELSE,     "else",     GLNAME_REQUIRE_GLSL, 0, 0, pshader_else,    NULL, NULL, 0, 0},
-    {D3DSIO_ENDIF,    "endif",    GLNAME_REQUIRE_GLSL, 0, 0, pshader_endif,   NULL, NULL, 0, 0},
-    {D3DSIO_BREAK,    "break",    GLNAME_REQUIRE_GLSL, 0, 0, pshader_break,   NULL, NULL, 0, 0},
-    {D3DSIO_BREAKC,   "breakc",   GLNAME_REQUIRE_GLSL, 0, 2, pshader_breakc,  NULL, NULL, 0, 0},
+    {D3DSIO_REP ,     "rep",      NULL, 0, 1, pshader_rep,     NULL, shader_glsl_rep,    D3DPS_VERSION(2,1), -1},
+    {D3DSIO_ENDREP,   "endrep",   NULL, 0, 0, pshader_endrep,  NULL, shader_glsl_end,    D3DPS_VERSION(2,1), -1},
+    {D3DSIO_IF,       "if",       NULL, 0, 1, pshader_if,      NULL, shader_glsl_if,     D3DPS_VERSION(2,1), -1},
+    {D3DSIO_IFC,      "ifc",      NULL, 0, 2, pshader_ifc,     NULL, shader_glsl_ifc,    D3DPS_VERSION(2,1), -1},
+    {D3DSIO_ELSE,     "else",     NULL, 0, 0, pshader_else,    NULL, shader_glsl_else,   D3DPS_VERSION(2,1), -1},
+    {D3DSIO_ENDIF,    "endif",    NULL, 0, 0, pshader_endif,   NULL, shader_glsl_end,    D3DPS_VERSION(2,1), -1},
+    {D3DSIO_BREAK,    "break",    NULL, 0, 0, pshader_break,   NULL, shader_glsl_break,  D3DPS_VERSION(2,1), -1},
+    {D3DSIO_BREAKC,   "breakc",   NULL, 0, 2, pshader_breakc,  NULL, shader_glsl_breakc, D3DPS_VERSION(2,1), -1},
     {D3DSIO_BREAKP,   "breakp",   GLNAME_REQUIRE_GLSL, 0, 1, pshader_breakp,  NULL, NULL, 0, 0},
     {D3DSIO_CALL,     "call",     GLNAME_REQUIRE_GLSL, 0, 1, pshader_call,    NULL, NULL, 0, 0},
     {D3DSIO_CALLNZ,   "callnz",   GLNAME_REQUIRE_GLSL, 0, 2, pshader_callnz,  NULL, NULL, 0, 0},
-    {D3DSIO_LOOP,     "loop",     GLNAME_REQUIRE_GLSL, 0, 2, pshader_loop,    NULL, shader_glsl_loop, 0, 0},
+    {D3DSIO_LOOP,     "loop",     NULL, 0, 2, pshader_loop,    NULL, shader_glsl_loop,   D3DPS_VERSION(3,0), -1},
     {D3DSIO_RET,      "ret",      GLNAME_REQUIRE_GLSL, 0, 0, pshader_ret,     NULL, NULL, 0, 0},
-    {D3DSIO_ENDLOOP,  "endloop",  GLNAME_REQUIRE_GLSL, 0, 0, pshader_endloop, NULL, shader_glsl_endloop, 0, 0},
+    {D3DSIO_ENDLOOP,  "endloop",  NULL, 0, 0, pshader_endloop, NULL, shader_glsl_end,    D3DPS_VERSION(3,0), -1},
     {D3DSIO_LABEL,    "label",    GLNAME_REQUIRE_GLSL, 0, 1, pshader_label,   NULL, NULL, 0, 0},
 
     /* Constant definitions */
diff --git a/dlls/wined3d/vertexshader.c b/dlls/wined3d/vertexshader.c
index d71b5c5..20d1d40 100644
--- a/dlls/wined3d/vertexshader.c
+++ b/dlls/wined3d/vertexshader.c
@@ -536,20 +536,20 @@ CONST SHADER_OPCODE IWineD3DVertexShader
     {D3DSIO_DEFI,     "defi",     GLNAME_REQUIRE_GLSL, 1, 5, vshader_defi,    NULL, NULL, 0, 0},
 
     /* Flow control - requires GLSL or software shaders */
-    {D3DSIO_REP ,     "rep",      GLNAME_REQUIRE_GLSL, 0, 1, vshader_rep,     NULL, NULL, 0, 0},
-    {D3DSIO_ENDREP,   "endrep",   GLNAME_REQUIRE_GLSL, 0, 0, vshader_endrep,  NULL, NULL, 0, 0},
-    {D3DSIO_IF,       "if",       GLNAME_REQUIRE_GLSL, 0, 1, vshader_if,      NULL, NULL, 0, 0},
-    {D3DSIO_IFC,      "ifc",      GLNAME_REQUIRE_GLSL, 0, 2, vshader_ifc,     NULL, NULL, 0, 0},
-    {D3DSIO_ELSE,     "else",     GLNAME_REQUIRE_GLSL, 0, 0, vshader_else,    NULL, NULL, 0, 0},
-    {D3DSIO_ENDIF,    "endif",    GLNAME_REQUIRE_GLSL, 0, 0, vshader_endif,   NULL, NULL, 0, 0},
-    {D3DSIO_BREAK,    "break",    GLNAME_REQUIRE_GLSL, 0, 0, vshader_break,   NULL, NULL, 0, 0},
-    {D3DSIO_BREAKC,   "breakc",   GLNAME_REQUIRE_GLSL, 0, 2, vshader_breakc,  NULL, NULL, 0, 0},
+    {D3DSIO_REP ,     "rep",      NULL, 0, 1, vshader_rep,     NULL, shader_glsl_rep,    D3DVS_VERSION(2,0), -1},
+    {D3DSIO_ENDREP,   "endrep",   NULL, 0, 0, vshader_endrep,  NULL, shader_glsl_end,    D3DVS_VERSION(2,0), -1},
+    {D3DSIO_IF,       "if",       NULL, 0, 1, vshader_if,      NULL, shader_glsl_if,     D3DVS_VERSION(2,0), -1},
+    {D3DSIO_IFC,      "ifc",      NULL, 0, 2, vshader_ifc,     NULL, shader_glsl_ifc,    D3DVS_VERSION(2,1), -1},
+    {D3DSIO_ELSE,     "else",     NULL, 0, 0, vshader_else,    NULL, shader_glsl_else,   D3DVS_VERSION(2,0), -1},
+    {D3DSIO_ENDIF,    "endif",    NULL, 0, 0, vshader_endif,   NULL, shader_glsl_end,    D3DVS_VERSION(2,0), -1},
+    {D3DSIO_BREAK,    "break",    NULL, 0, 0, vshader_break,   NULL, shader_glsl_break,  D3DVS_VERSION(2,1), -1},
+    {D3DSIO_BREAKC,   "breakc",   NULL, 0, 2, vshader_breakc,  NULL, shader_glsl_breakc, D3DVS_VERSION(2,1), -1},
     {D3DSIO_BREAKP,   "breakp",   GLNAME_REQUIRE_GLSL, 0, 1, vshader_breakp,  NULL, NULL, 0, 0},
     {D3DSIO_CALL,     "call",     GLNAME_REQUIRE_GLSL, 0, 1, vshader_call,    NULL, NULL, 0, 0},
     {D3DSIO_CALLNZ,   "callnz",   GLNAME_REQUIRE_GLSL, 0, 2, vshader_callnz,  NULL, NULL, 0, 0},
-    {D3DSIO_LOOP,     "loop",     GLNAME_REQUIRE_GLSL, 0, 2, vshader_loop,    NULL, shader_glsl_loop, 0, 0},
+    {D3DSIO_LOOP,     "loop",     NULL, 0, 2, vshader_loop,    NULL, shader_glsl_loop,   D3DVS_VERSION(2,0), -1},
     {D3DSIO_RET,      "ret",      GLNAME_REQUIRE_GLSL, 0, 0, vshader_ret,     NULL, NULL, 0, 0},
-    {D3DSIO_ENDLOOP,  "endloop",  GLNAME_REQUIRE_GLSL, 0, 0, vshader_endloop, NULL, shader_glsl_endloop, 0, 0},
+    {D3DSIO_ENDLOOP,  "endloop",  NULL, 0, 0, vshader_endloop, NULL, shader_glsl_end,    D3DVS_VERSION(2,0), -1},
     {D3DSIO_LABEL,    "label",    GLNAME_REQUIRE_GLSL, 0, 1, vshader_label,   NULL, NULL, 0, 0},
 
     {D3DSIO_MOVA,     "mova",     GLNAME_REQUIRE_GLSL, 1, 2, vshader_mova,    NULL, shader_glsl_mov, 0, 0},
diff --git a/dlls/wined3d/wined3d_private.h b/dlls/wined3d/wined3d_private.h
index 0fc8b3f..5102e7c 100644
--- a/dlls/wined3d/wined3d_private.h
+++ b/dlls/wined3d/wined3d_private.h
@@ -1318,6 +1318,19 @@ typedef struct SHADER_BUFFER {
     unsigned int lineNo;
 } SHADER_BUFFER;
 
+/* Undocumented opcode controls */
+#define INST_CONTROLS_SHIFT 16
+#define INST_CONTROLS_MASK 0x00ff0000
+
+typedef enum COMPARISON_TYPE {
+    COMPARISON_GT = 1,
+    COMPARISON_EQ = 2,
+    COMPARISON_GE = 3,
+    COMPARISON_LT = 4,
+    COMPARISON_NE = 5,
+    COMPARISON_LE = 6
+} COMPARISON_TYPE;
+
 typedef struct SHADER_OPCODE {
     unsigned int  opcode;
     const char*   name;
@@ -1335,6 +1348,7 @@ typedef struct SHADER_OPCODE_ARG {
     IWineD3DBaseShader* shader;
     shader_reg_maps* reg_maps;
     CONST SHADER_OPCODE* opcode;
+    DWORD opcode_token;
     DWORD dst;
     DWORD dst_addr;
     DWORD predicate;
@@ -1442,7 +1456,13 @@ extern void shader_glsl_lit(SHADER_OPCOD
 extern void shader_glsl_dst(SHADER_OPCODE_ARG* arg);
 extern void shader_glsl_sincos(SHADER_OPCODE_ARG* arg);
 extern void shader_glsl_loop(SHADER_OPCODE_ARG* arg);
-extern void shader_glsl_endloop(SHADER_OPCODE_ARG* arg);
+extern void shader_glsl_end(SHADER_OPCODE_ARG* arg);
+extern void shader_glsl_if(SHADER_OPCODE_ARG* arg);
+extern void shader_glsl_ifc(SHADER_OPCODE_ARG* arg);
+extern void shader_glsl_else(SHADER_OPCODE_ARG* arg);
+extern void shader_glsl_break(SHADER_OPCODE_ARG* arg);
+extern void shader_glsl_breakc(SHADER_OPCODE_ARG* arg);
+extern void shader_glsl_rep(SHADER_OPCODE_ARG* arg);
 
 /** GLSL Pixel Shader Prototypes */
 extern void pshader_glsl_tex(SHADER_OPCODE_ARG* arg);
-- 
1.4.0



More information about the wine-patches mailing list