Implement more GLSL instructions

Jason Green jave27 at gmail.com
Tue Jun 13 21:32:14 CDT 2006


- Implemented: D3DSIO_SGN, LOOP, ENDLOOP, LOGP, LIT, DST, SINCOS
- Process instruction-based modifiers (function existed, it just
wasn't being called)
- Add loop checking to register maps.
- Renamed "sng" to "sgn" for D3DSIO_SGN - it's not handled anywhere
except for GLSL, so won't matter.
- Note: The LOOP opcodes won't actually work until we handle integer
constants (will submit a patch after i get all the kinks worked out)

As of this patch, Wine now supports more opcodes in GLSL than
ARB_vp/fp and we can handle many of the shader 2.0+ instructions not
available before.  There are a few missing texture operations compared
to ARB still, and we're not properly handling textures for any shaders
<2.0, but that's true in ARB as well.
-------------- next part --------------
diff --git a/dlls/wined3d/baseshader.c b/dlls/wined3d/baseshader.c
index b148bb3..f19a03b 100644
--- a/dlls/wined3d/baseshader.c
+++ b/dlls/wined3d/baseshader.c
@@ -411,6 +411,9 @@ void shader_get_registers_used(
 
                 else if (D3DSPR_INPUT == regtype && !pshader)
                     reg_maps->attributes[reg] = 1;
+
+                else if (D3DSPR_LOOP == regtype)
+                    reg_maps->loop = 1;
              }
         }
     }
@@ -792,6 +795,10 @@ void shader_generate_glsl_declarations(
             shader_addline(buffer, "attribute vec4 attrib%i;\n", i);
     }
 
+    /* Declare loop register aL */
+    if (reg_maps->loop)
+        shader_addline(buffer, "int aL;\n");
+    
     /* Temporary variables for matrix operations */
     shader_addline(buffer, "vec4 tmp0;\n");
     shader_addline(buffer, "vec4 tmp1;\n");
@@ -901,6 +908,10 @@ void shader_generate_main(
                 /* Call appropriate function for output target */
                 hw_fct(&hw_arg);
 
+                /* Process instruction modifiers for GLSL apps ( _sat, etc. ) */
+                if (wined3d_settings.shader_mode == SHADER_GLSL)
+                    shader_glsl_add_instruction_modifiers(&hw_arg);
+
             /* Unhandled opcode */
             } else {
 
diff --git a/dlls/wined3d/glsl_shader.c b/dlls/wined3d/glsl_shader.c
index 3661d06..e99a2a2 100644
--- a/dlls/wined3d/glsl_shader.c
+++ b/dlls/wined3d/glsl_shader.c
@@ -245,6 +245,9 @@ static void shader_glsl_get_register_nam
             sprintf(tmpStr, "A%lu", reg);
         }
     break;
+    case D3DSPR_LOOP:
+        sprintf(tmpStr, "aL");
+    break;
     case D3DSPR_SAMPLER:
         if (pshader)
             sprintf(tmpStr, "psampler%lu", reg);
@@ -508,11 +511,13 @@ void shader_glsl_map2gl(SHADER_OPCODE_AR
             case D3DSIO_POW:    strcat(tmpLine, "pow"); break;
             case D3DSIO_CRS:    strcat(tmpLine, "cross"); break;
             case D3DSIO_NRM:    strcat(tmpLine, "normalize"); break;
+            case D3DSIO_LOGP:
             case D3DSIO_LOG:    strcat(tmpLine, "log2"); break;
             case D3DSIO_EXPP:
             case D3DSIO_EXP:    strcat(tmpLine, "exp2"); break;
             case D3DSIO_SGE:    strcat(tmpLine, "greaterThanEqual"); break;
             case D3DSIO_SLT:    strcat(tmpLine, "lessThan"); break;
+            case D3DSIO_SGN:    strcat(tmpLine, "sign"); break;
         default:
             FIXME("Opcode %s not yet handled in GLSL\n", curOpcode->name);
             break;
@@ -728,6 +733,93 @@ void shader_glsl_def(SHADER_OPCODE_ARG* 
     arg->reg_maps->constantsF[reg] = 1;
 }
 
+/** Process the D3DSIO_LIT instruction in GLSL:
+ * dst.x = dst.w = 1.0
+ * dst.y = (src0.x > 0) ? src0.x
+ * dst.z = (src0.x > 0) ? ((src0.y > 0) ? pow(src0.y, src.w) : 0) : 0
+ *                                        where src.w is clamped at +- 128
+ */
+void shader_glsl_lit(SHADER_OPCODE_ARG* arg) {
+
+    char dst_str[100], src0_str[100];
+    char dst_reg[50], src0_reg[50];
+    char dst_mask[6], src0_mask[6];
+   
+    shader_glsl_add_param(arg, arg->dst, 0, FALSE, dst_reg, dst_mask, dst_str);
+    shader_glsl_add_param(arg, arg->src[0], arg->src_addr[0], TRUE, src0_reg, src0_mask, src0_str);
+
+    shader_addline(arg->buffer,
+        "%s = vec4(1.0, (%s.x > 0.0 ? %s.x : 0.0), (%s.x > 0.0 ? ((%s.y > 0.0) ? pow(%s.y, clamp(%s.w, -128.0, 128.0)) : 0.0) : 0.0), 1.0)%s;\n",
+        dst_str, src0_reg, src0_reg, src0_reg, src0_reg, src0_reg, src0_reg, dst_mask);
+}
+
+/** Process the D3DSIO_DST instruction in GLSL:
+ * dst.x = 1.0
+ * dst.y = src0.x * src0.y
+ * dst.z = src0.z
+ * dst.w = src1.w
+ */
+void shader_glsl_dst(SHADER_OPCODE_ARG* arg) {
+
+    char dst_str[100], src0_str[100], src1_str[100];
+    char dst_reg[50], src0_reg[50], src1_reg[50];
+    char dst_mask[6], src0_mask[6], src1_mask[6];
+   
+    shader_glsl_add_param(arg, arg->dst, 0, FALSE, dst_reg, dst_mask, dst_str);
+    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, "%s = vec4(1.0, %s.x * %s.y, %s.z, %s.w)%s;\n",
+                   dst_str, src0_reg, src1_reg, src0_reg, src1_reg, dst_mask);
+}
+
+/** Process the D3DSIO_SINCOS instruction in GLSL:
+ * VS 2.0 requires that specific cosine and sine constants be passed to this instruction so the hardware
+ * can handle it.  But, these functions are built-in for GLSL, so we can just ignore the last 2 params.
+ * 
+ * dst.x = cos(src0.?)
+ * dst.y = sin(src0.?)
+ * dst.z = dst.z
+ * dst.w = dst.w
+ */
+void shader_glsl_sincos(SHADER_OPCODE_ARG* arg) {
+    
+    char dst_str[100], src0_str[100];
+    char dst_reg[50], src0_reg[50];
+    char dst_mask[6], src0_mask[6];
+   
+    shader_glsl_add_param(arg, arg->dst, 0, FALSE, dst_reg, dst_mask, dst_str);
+    shader_glsl_add_param(arg, arg->src[0], arg->src_addr[0], TRUE, src0_reg, src0_mask, src0_str);
+
+    shader_addline(arg->buffer, "%s = vec4(cos(%s), sin(%s), %s.z, %s.w)%s;\n",
+                   dst_str, src0_str, src0_str, dst_reg, dst_reg, dst_mask);
+}
+
+/** Process the D3DSIO_LOOP instruction in GLSL:
+ * Start a for() loop where src0.y is the initial value of aL,
+ *  increment aL by src0.z while (aL < src0.x).
+ */
+void shader_glsl_loop(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 (aL = %s.y; aL < %s.x; aL += %s.z) {\n",
+            src0_reg, src0_reg, src0_reg);
+}
+
+/** Process the D3DSIO_ENDLOOP instruction in GLSL:
+ * End the for() loop
+ */
+void shader_glsl_endloop(SHADER_OPCODE_ARG* arg) {
+
+    shader_addline(arg->buffer, "}\n");
+}
+
+
 /*********************************************
  * Pixel Shader Specific Code begins here
  ********************************************/
diff --git a/dlls/wined3d/pixelshader.c b/dlls/wined3d/pixelshader.c
index 60bbfaf..4c72390 100644
--- a/dlls/wined3d/pixelshader.c
+++ b/dlls/wined3d/pixelshader.c
@@ -654,8 +654,8 @@ CONST SHADER_OPCODE IWineD3DPixelShaderI
     {D3DSIO_EXP,  "exp",  "EX2", 1, 2, pshader_exp, pshader_hw_map2gl, shader_glsl_map2gl, 0, 0},
     {D3DSIO_LOG,  "log",  "LG2", 1, 2, pshader_log, pshader_hw_map2gl, shader_glsl_map2gl, 0, 0},
     {D3DSIO_EXPP, "expp", "EXP", 1, 2, pshader_expp, pshader_hw_map2gl, shader_glsl_map2gl, 0, 0},
-    {D3DSIO_LOGP, "logp", "LOG", 1, 2, pshader_logp, pshader_hw_map2gl, NULL, 0, 0},
-    {D3DSIO_DST,  "dst",  "DST", 1, 3, pshader_dst, pshader_hw_map2gl, NULL, 0, 0},
+    {D3DSIO_LOGP, "logp", "LOG", 1, 2, pshader_logp, pshader_hw_map2gl, shader_glsl_map2gl, 0, 0},
+    {D3DSIO_DST,  "dst",  "DST", 1, 3, pshader_dst, pshader_hw_map2gl, shader_glsl_dst, 0, 0},
     {D3DSIO_LRP,  "lrp",  "LRP", 1, 4, pshader_lrp, pshader_hw_map2gl, shader_glsl_lrp, 0, 0},
     {D3DSIO_FRC,  "frc",  "FRC", 1, 2, pshader_frc, pshader_hw_map2gl, shader_glsl_map2gl, 0, 0},
     {D3DSIO_CND,  "cnd",  NULL, 1, 4, pshader_cnd, pshader_hw_cnd, shader_glsl_cnd, D3DPS_VERSION(1,1), D3DPS_VERSION(1,4)},
@@ -673,8 +673,8 @@ CONST SHADER_OPCODE IWineD3DPixelShaderI
 
     */
     {D3DSIO_NRM,      "nrm",      NULL, 1, 2, pshader_nrm,     NULL, shader_glsl_map2gl, 0, 0},
-    {D3DSIO_SINCOS,   "sincos",   NULL, 1, 4, pshader_sincos2, NULL, NULL, D3DPS_VERSION(2,0), D3DPS_VERSION(2,0)},
-    {D3DSIO_SINCOS,   "sincos",   NULL, 1, 2, pshader_sincos3, NULL, NULL, D3DPS_VERSION(3,0), -1},
+    {D3DSIO_SINCOS,   "sincos",   NULL, 1, 4, pshader_sincos2, NULL, shader_glsl_sincos, D3DPS_VERSION(2,0), D3DPS_VERSION(2,0)},
+    {D3DSIO_SINCOS,   "sincos",   NULL, 1, 2, pshader_sincos3, NULL, shader_glsl_sincos, D3DPS_VERSION(3,0), -1},
     /* TODO: dp2add can be made out of multiple instuctions */
     {D3DSIO_DP2ADD,   "dp2add",   GLNAME_REQUIRE_GLSL,  1, 4, pshader_dp2add,  NULL, NULL, D3DPS_VERSION(2,0), -1},
 
@@ -700,9 +700,9 @@ CONST SHADER_OPCODE IWineD3DPixelShaderI
     {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, NULL, 0, 0},
+    {D3DSIO_LOOP,     "loop",     GLNAME_REQUIRE_GLSL, 0, 2, pshader_loop,    NULL, shader_glsl_loop, 0, 0},
     {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, NULL, 0, 0},
+    {D3DSIO_ENDLOOP,  "endloop",  GLNAME_REQUIRE_GLSL, 0, 0, pshader_endloop, NULL, shader_glsl_endloop, 0, 0},
     {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 56648b9..d2028f2 100644
--- a/dlls/wined3d/vertexshader.c
+++ b/dlls/wined3d/vertexshader.c
@@ -397,7 +397,7 @@ static void vshader_pow(WINED3DSHADERVEC
     FIXME(" : Stub\n");
 }
 
-static void vshader_sng(WINED3DSHADERVECTOR* d, WINED3DSHADERVECTOR* s0) {
+static void vshader_sgn(WINED3DSHADERVECTOR* d, WINED3DSHADERVECTOR* s0) {
     FIXME(" : Stub\n");
 }
 
@@ -501,9 +501,9 @@ CONST SHADER_OPCODE IWineD3DVertexShader
     {D3DSIO_EXP,  "exp",  "EX2", 1, 2, vshader_exp,  vshader_hw_map2gl, shader_glsl_map2gl, 0, 0},
     {D3DSIO_LOG,  "log",  "LG2", 1, 2, vshader_log,  vshader_hw_map2gl, shader_glsl_map2gl, 0, 0},
     {D3DSIO_EXPP, "expp", "EXP", 1, 2, vshader_expp, vshader_hw_map2gl, shader_glsl_map2gl, 0, 0},
-    {D3DSIO_LOGP, "logp", "LOG", 1, 2, vshader_logp, vshader_hw_map2gl, NULL, 0, 0},
-    {D3DSIO_LIT,  "lit",  "LIT", 1, 2, vshader_lit,  vshader_hw_map2gl, NULL, 0, 0},
-    {D3DSIO_DST,  "dst",  "DST", 1, 3, vshader_dst,  vshader_hw_map2gl, NULL, 0, 0},
+    {D3DSIO_LOGP, "logp", "LOG", 1, 2, vshader_logp, vshader_hw_map2gl, shader_glsl_map2gl, 0, 0},
+    {D3DSIO_LIT,  "lit",  "LIT", 1, 2, vshader_lit,  vshader_hw_map2gl, shader_glsl_lit, 0, 0},
+    {D3DSIO_DST,  "dst",  "DST", 1, 3, vshader_dst,  vshader_hw_map2gl, shader_glsl_dst, 0, 0},
     {D3DSIO_LRP,  "lrp",  "LRP", 1, 4, vshader_lrp,  NULL,              shader_glsl_lrp, 0, 0},
     {D3DSIO_FRC,  "frc",  "FRC", 1, 2, vshader_frc,  vshader_hw_map2gl, shader_glsl_map2gl, 0, 0},
     {D3DSIO_POW,  "pow",  "POW", 1, 3, vshader_pow,  NULL, shader_glsl_map2gl, 0, 0},
@@ -511,7 +511,7 @@ CONST SHADER_OPCODE IWineD3DVertexShader
     /* TODO: sng can possibly be performed a  s
         RCP tmp, vec
         MUL out, tmp, vec*/
-    {D3DSIO_SGN,  "sng",  NULL, 1, 2, vshader_sng,  NULL,   NULL, 0, 0},
+    {D3DSIO_SGN,  "sgn",  NULL, 1, 2, vshader_sgn,  NULL,   shader_glsl_map2gl, 0, 0},
     /* TODO: xyz normalise can be performed as VS_ARB using one temporary register,
         DP3 tmp , vec, vec;
         RSQ tmp, tmp.x;
@@ -523,8 +523,8 @@ CONST SHADER_OPCODE IWineD3DVertexShader
 
     */
     {D3DSIO_NRM,      "nrm",      NULL, 1, 2, vshader_nrm,    NULL, shader_glsl_map2gl, 0, 0},
-    {D3DSIO_SINCOS,   "sincos",   NULL, 1, 4, vshader_sincos2, NULL, NULL, D3DVS_VERSION(2,0), D3DVS_VERSION(2,0)},
-    {D3DSIO_SINCOS,   "sincos",   NULL, 1, 2, vshader_sincos3, NULL, NULL, D3DVS_VERSION(3,0), -1},
+    {D3DSIO_SINCOS,   "sincos",   NULL, 1, 4, vshader_sincos2, NULL, shader_glsl_sincos, D3DVS_VERSION(2,0), D3DVS_VERSION(2,0)},
+    {D3DSIO_SINCOS,   "sincos",   NULL, 1, 2, vshader_sincos3, NULL, shader_glsl_sincos, D3DVS_VERSION(3,0), -1},
 
     /* Matrix */
     {D3DSIO_M4x4, "m4x4", "undefined", 1, 3, vshader_m4x4, vshader_hw_mnxn, shader_glsl_mnxn, 0, 0},
@@ -553,9 +553,9 @@ CONST SHADER_OPCODE IWineD3DVertexShader
     {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, NULL, 0, 0},
+    {D3DSIO_LOOP,     "loop",     GLNAME_REQUIRE_GLSL, 0, 2, vshader_loop,    NULL, shader_glsl_loop, 0, 0},
     {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, NULL, 0, 0},
+    {D3DSIO_ENDLOOP,  "endloop",  GLNAME_REQUIRE_GLSL, 0, 0, vshader_endloop, NULL, shader_glsl_endloop, 0, 0},
     {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 cb9abc6..22f194c 100644
--- a/dlls/wined3d/wined3d_private.h
+++ b/dlls/wined3d/wined3d_private.h
@@ -1277,6 +1277,9 @@ typedef struct shader_reg_maps {
      * Use 0 as default (bit 31 is always 1 on a valid token) */
     DWORD samplers[MAX_SAMPLERS];
 
+    /* Whether or not a loop is used in this shader */
+    char loop;
+
 } shader_reg_maps;
 
 #define SHADER_PGMSIZE 65535
@@ -1344,8 +1347,9 @@ extern const SHADER_OPCODE* shader_get_o
 /* ARB shader program Prototypes */
 extern void shader_hw_def(SHADER_OPCODE_ARG *arg);
 
-/* GLSL helper programs */
+/* GLSL helper functions */
 extern void set_glsl_shader_program(IWineD3DDevice *iface);
+extern void shader_glsl_add_instruction_modifiers(SHADER_OPCODE_ARG *arg);
 
 /** The following translate DirectX pixel/vertex shader opcodes to GLSL lines */
 extern void shader_glsl_map2gl(SHADER_OPCODE_ARG* arg);
@@ -1360,6 +1364,11 @@ extern void shader_glsl_cnd(SHADER_OPCOD
 extern void shader_glsl_compare(SHADER_OPCODE_ARG* arg);
 extern void shader_glsl_def(SHADER_OPCODE_ARG* arg);
 extern void shader_glsl_cmp(SHADER_OPCODE_ARG* arg);
+extern void shader_glsl_lit(SHADER_OPCODE_ARG* arg);
+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);
 
 /** GLSL Pixel Shader Prototypes */
 extern void pshader_glsl_tex(SHADER_OPCODE_ARG* arg);


More information about the wine-patches mailing list