[WINED3D 8/9] Improve Sampler support on 2.0 and 3.0 shaders

Ivan Gyurdiev ivg231 at gmail.com
Mon Jun 12 01:59:16 CDT 2006


- track sampler declarations and store the sampler usage in reg_maps 
structure
- store a fake sampler usage for 1.X shaders (defined as 2D sampler)
- re-sync glsl TEX implementation with the ARB one (no idea why they 
diverged..)
- use sampler type in new TEX implementation to support 2D, 3D, and Cube 
sampling
- change drawprim to bind pixel shader samplers

Additional improvements:
- rename texture limit to texcoord to prevent confusion
- add sampler limit, and use that for samplers - *not* the same as 
texcoord above

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

 dlls/wined3d/baseshader.c      |   65 ++++++++++++++++++++++++++++++++--------
 dlls/wined3d/drawprim.c        |   33 ++++++++++++++++++++
 dlls/wined3d/glsl_shader.c     |   61 +++++++++++++++++++++++++-------------
 dlls/wined3d/pixelshader.c     |   23 +++++++++-----
 dlls/wined3d/vertexshader.c    |   10 ++++--
 dlls/wined3d/wined3d_private.h |    9 +++++-
 6 files changed, 155 insertions(+), 46 deletions(-)

cc3544cee1d98042ae6d6c0b85db85f94a23f7ab
diff --git a/dlls/wined3d/baseshader.c b/dlls/wined3d/baseshader.c
index 7877bcd..7771b79 100644
--- a/dlls/wined3d/baseshader.c
+++ b/dlls/wined3d/baseshader.c
@@ -339,6 +339,8 @@ void shader_get_registers_used(
             DWORD regtype = shader_get_regtype(param);
             unsigned int regnum = param & D3DSP_REGNUM_MASK;
 
+            /* Vshader: mark attributes used
+               Pshader: mark 3.0 input registers used, save token */
             if (D3DSPR_INPUT == regtype) {
 
                 if (!pshader)
@@ -348,21 +350,36 @@ void shader_get_registers_used(
 
                 shader_parse_decl_usage(reg_maps->semantics_in, usage, param);
 
+            /* Vshader: mark 3.0 output registers used, save token */
             } else if (D3DSPR_OUTPUT == regtype) {
                 reg_maps->packed_output[regnum] = 1;
                 shader_parse_decl_usage(reg_maps->semantics_out, usage, param);
-            }
 
-            /* Handle samplers here */
+            /* Save sampler usage token */
+            } else if (D3DSPR_SAMPLER == regtype)
+                reg_maps->samplers[regnum] = usage;
 
         /* Skip definitions (for now) */
         } else if (D3DSIO_DEF == curOpcode->opcode) {
             pToken += curOpcode->num_params;
 
-        /* Set texture registers, and temporary registers */
+        /* Set texture, address, temporary registers */
         } else {
             int i, limit;
 
+            /* Declare 1.X samplers implicitly, based on the destination reg. number */
+            if (D3DSHADER_VERSION_MAJOR(This->baseShader.hex_version) == 1 && 
+                (D3DSIO_TEX == curOpcode->opcode ||
+                 D3DSIO_TEXM3x2TEX == curOpcode->opcode ||
+                 D3DSIO_TEXM3x3TEX == curOpcode->opcode ||
+                 D3DSIO_TEXM3x3SPEC == curOpcode->opcode ||
+                 D3DSIO_TEXM3x3VSPEC == curOpcode->opcode)) {
+
+                /* Fake sampler usage, only set reserved bit and ttype */
+                DWORD sampler_code = *pToken & D3DSP_REGNUM_MASK;
+                reg_maps->samplers[sampler_code] = (0x1 << 31) | D3DSTT_2D;
+            }
+
             /* This will loop over all the registers and try to
              * make a bitmask of the ones we're interested in. 
              *
@@ -511,7 +528,7 @@ void shader_dump_param(
     DWORD regtype = shader_get_regtype(param);
 
     /* There are some minor differences between pixel and vertex shaders */
-    BOOL pshader = shader_is_pshader_version(This->baseShader.hex_version);
+    char pshader = shader_is_pshader_version(This->baseShader.hex_version);
 
     /* For one, we'd prefer color components to be shown for pshaders.
      * FIXME: use the swizzle function for this */
@@ -678,13 +695,13 @@ void shader_generate_arb_declarations(
             shader_addline(buffer, "ADDRESS A%ld;\n", i);
     }
 
-    for(i = 0; i < This->baseShader.limits.texture; i++) {
+    for(i = 0; i < This->baseShader.limits.texcoord; i++) {
         if (reg_maps->texcoord[i])
             shader_addline(buffer,"TEMP T%lu;\n", i);
     }
 
     /* Texture coordinate registers must be pre-loaded */
-    for (i = 0; i < This->baseShader.limits.texture; i++) {
+    for (i = 0; i < This->baseShader.limits.texcoord; i++) {
         if (reg_maps->texcoord[i])
             shader_addline(buffer, "MOV T%lu, fragment.texcoord[%lu];\n", i, i);
     }
@@ -704,15 +721,36 @@ void shader_generate_glsl_declarations(
     IWineD3DBaseShaderImpl* This = (IWineD3DBaseShaderImpl*) iface;
     int i;
 
-    FIXME("GLSL not fully implemented yet.\n");
+    /* There are some minor differences between pixel and vertex shaders */
+    char pshader = shader_is_pshader_version(This->baseShader.hex_version);
 
     /* Declare the constants (aka uniforms) */
     shader_addline(buffer, "uniform vec4 C[%u];\n", This->baseShader.limits.constant_float);
 
-    /* Declare texture samplers 
-     * TODO: Make this work for textures other than 2D */
-    for (i = 0; i < This->baseShader.limits.texture; i++) {
-        shader_addline(buffer, "uniform sampler2D mytex%lu;\n", i);
+    /* Declare texture samplers */ 
+    for (i = 0; i < This->baseShader.limits.sampler; i++) {
+        if (reg_maps->samplers[i]) {
+
+            const char* prefix = pshader? "psampler": "vsampler";
+
+            DWORD stype = reg_maps->samplers[i] & D3DSP_TEXTURETYPE_MASK;
+            switch (stype) {
+
+                case D3DSTT_2D:
+                    shader_addline(buffer, "uniform sampler2D %s%lu;\n", prefix, i);
+                    break;
+                case D3DSTT_CUBE:
+                    shader_addline(buffer, "uniform samplerCube %s%lu;\n", prefix, i);
+                    break;
+                case D3DSTT_VOLUME:
+                    shader_addline(buffer, "uniform sampler3D %s%lu;\n", prefix, i);
+                    break;
+                default:
+                    shader_addline(buffer, "uniform unsupported_sampler %s%lu;\n", prefix, i);
+                    FIXME("Unrecognized sampler type: %#lx\n", stype);
+                    break;
+            }
+        }
     }
     
     /* Declare address variables */
@@ -722,8 +760,9 @@ void shader_generate_glsl_declarations(
     }
 
     /* Declare texture coordinate temporaries and initialize them */
-    for (i = 0; i < This->baseShader.limits.texture; i++) {
-        shader_addline(buffer, "vec4 T%lu = gl_TexCoord[%lu];\n", i, i);
+    for (i = 0; i < This->baseShader.limits.texcoord; i++) {
+        if (reg_maps->texcoord[i]) 
+            shader_addline(buffer, "vec4 T%lu = gl_TexCoord[%lu];\n", i, i);
     }
 
     /* Declare input register temporaries */
diff --git a/dlls/wined3d/drawprim.c b/dlls/wined3d/drawprim.c
index acd708c..a4715e7 100644
--- a/dlls/wined3d/drawprim.c
+++ b/dlls/wined3d/drawprim.c
@@ -1686,6 +1686,36 @@ void drawStridedSoftwareVS(IWineD3DDevic
 
 #endif
 
+/**
+ * Loads (pixel shader) samplers
+ */
+void drawPrimLoadPSamplersGLSL(
+    IWineD3DDevice* iface) {
+
+    IWineD3DDeviceImpl* This = (IWineD3DDeviceImpl *)iface;
+    GLhandleARB programId = This->stateBlock->shaderPrgId;
+    GLhandleARB name_loc;
+    int i;
+    char sampler_name[20];
+
+    if (programId == 0) {
+        /* No GLSL program set - nothing to do. */
+        return;
+    }
+
+    for (i=0; i< GL_LIMITS(textures); ++i) {
+        if (This->stateBlock->textures[i] != NULL) {
+           snprintf(sampler_name, sizeof(sampler_name), "psampler%d", i);
+           name_loc = GL_EXTCALL(glGetUniformLocationARB(programId, sampler_name));
+           if (name_loc != -1) {
+               TRACE_(d3d_shader)("Loading %s for texture %d\n", sampler_name, i);
+               GL_EXTCALL(glUniform1iARB(name_loc, i));
+               checkGLcall("glUniform1iARB");
+           }
+        }
+    }
+}
+
 /** 
  * Loads floating point constants (aka uniforms) into the currently set GLSL program.
  * When @constants_set == NULL, it will load all the constants.
@@ -1780,6 +1810,9 @@ void drawPrimLoadConstants(IWineD3DDevic
         }
         if (usePixelShader) {
 
+            /* Load pixel shader samplers */
+            drawPrimLoadPSamplersGLSL(iface);
+
             /* Load DirectX 9 float constants/uniforms for pixel shader */
             drawPrimLoadConstantsGLSL_F(iface, WINED3D_PSHADER_MAX_CONSTANTS,
                                         This->stateBlock->pixelShaderConstantF,
diff --git a/dlls/wined3d/glsl_shader.c b/dlls/wined3d/glsl_shader.c
index bed5b98..32b7f9c 100644
--- a/dlls/wined3d/glsl_shader.c
+++ b/dlls/wined3d/glsl_shader.c
@@ -242,7 +242,10 @@ static void shader_glsl_get_register_nam
         }
     break;
     case D3DSPR_SAMPLER:
-        sprintf(tmpStr, "mytex%lu", reg);
+        if (pshader)
+            sprintf(tmpStr, "psampler%lu", reg);
+        else
+            sprintf(tmpStr, "vsampler%lu", reg);
     break;
     case D3DSPR_COLOROUT:
         if (reg == 0)
@@ -729,30 +732,48 @@ void pshader_glsl_tex(SHADER_OPCODE_ARG*
     DWORD hex_version = This->baseShader.hex_version;
 
     char dst_str[100],   dst_reg[50],  dst_mask[6];
-    char src0_str[100], src0_reg[50], src0_mask[6];
-    char src1_str[100], src1_reg[50], src1_mask[6];
+    char coord_str[100], coord_reg[50], coord_mask[6];
+    char sampler_str[100], sampler_reg[50], sampler_mask[6];
     DWORD reg_dest_code = arg->dst & D3DSP_REGNUM_MASK;
+    DWORD sampler_code, sampler_type;
 
     /* All versions have a destination register */
     shader_glsl_add_param(arg, arg->dst, 0, FALSE, dst_reg, dst_mask, dst_str);
-    
+
     /* 1.0-1.3: Use destination register as coordinate source.
+       1.4+: Use provided coordinate source register. */
+    if (hex_version < D3DPS_VERSION(1,4))
+       strcpy(coord_reg, dst_reg);
+    else
+       shader_glsl_add_param(arg, arg->src[0], arg->src_addr[0], TRUE, coord_reg, coord_mask, coord_str);
+
+    /* 1.0-1.4: Use destination register as coordinate source.
      * 2.0+: Use provided coordinate source register. */
-    if (hex_version == D3DPS_VERSION(1,4)) {
-        shader_glsl_add_param(arg, arg->src[0], arg->src_addr[0], TRUE, src0_reg, src0_mask, src0_str);
-        sprintf(src1_str, "mytex%lu", reg_dest_code); 
-    } else if (hex_version > D3DPS_VERSION(1,4)) {
-        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);
-    }
-       
-    /* 1.0-1.4: Use destination register number as texture code.
-     * 2.0+: Use provided sampler number as texure code. */
-    if (hex_version < D3DPS_VERSION(1,4)) {
-        shader_addline(buffer, "%s = texture2D(mytex%lu, gl_TexCoord[%lu].st);\n",
-                       dst_str, reg_dest_code, reg_dest_code);
-    } else {
-        shader_addline(buffer, "%s = texture2D(%s, %s.st);\n", dst_str, src1_str, src0_reg);
+    if (hex_version < D3DPS_VERSION(2,0)) {
+        sprintf(sampler_str, "psampler%lu", reg_dest_code); 
+        sampler_code = reg_dest_code;
+    }       
+    else {
+        shader_glsl_add_param(arg, arg->src[1], arg->src_addr[1], TRUE, sampler_reg, sampler_mask, sampler_str);
+        sampler_code = arg->src[1] & D3DSP_REGNUM_MASK;
+    }         
+
+    sampler_type = arg->reg_maps->samplers[sampler_code] & D3DSP_TEXTURETYPE_MASK;
+    switch(sampler_type) {
+
+        case D3DSTT_2D:
+            shader_addline(buffer, "%s = texture2D(%s, %s.st);\n", dst_str, sampler_str, coord_reg);
+            break;
+        case D3DSTT_CUBE:
+            shader_addline(buffer, "%s = textureCube(%s, %s.stp);\n", dst_str, sampler_str, coord_reg);
+            break;
+        case D3DSTT_VOLUME:
+            shader_addline(buffer, "%s = texture3D(%s, %s.stp);\n", dst_str, sampler_str, coord_reg);
+            break;
+        default:
+            shader_addline(buffer, "%s = unrecognized_stype(%s, %s.stp);\n", dst_str, sampler_str, coord_reg);
+            FIXME("Unrecognized sampler type: %#lx;\n", sampler_type);
+            break;
     }
 }
 
@@ -806,7 +827,7 @@ void pshader_glsl_texm3x2tex(SHADER_OPCO
 
     shader_glsl_add_param(arg, arg->src[0], arg->src_addr[0], TRUE, src0_name, src0_mask, src0_str);
     shader_addline(buffer, "tmp0.y = dot(vec3(T%lu), vec3(%s));\n", reg, src0_str);
-    shader_addline(buffer, "T%lu = texture2D(mytex%lu, tmp0.st);\n", reg, reg);
+    shader_addline(buffer, "T%lu = texture2D(psampler%lu, tmp0.st);\n", reg, reg);
 }
 
 void pshader_glsl_input_pack(
diff --git a/dlls/wined3d/pixelshader.c b/dlls/wined3d/pixelshader.c
index 9b83e62..f4fe007 100644
--- a/dlls/wined3d/pixelshader.c
+++ b/dlls/wined3d/pixelshader.c
@@ -947,7 +947,8 @@ static void pshader_set_limits(
                    This->baseShader.limits.constant_float = 8;
                    This->baseShader.limits.constant_int = 0;
                    This->baseShader.limits.constant_bool = 0;
-                   This->baseShader.limits.texture = 4;
+                   This->baseShader.limits.texcoord = 4;
+                   This->baseShader.limits.sampler = 4;
                    This->baseShader.limits.packed_input = 0;
                    break;
 
@@ -956,7 +957,8 @@ static void pshader_set_limits(
                    This->baseShader.limits.constant_float = 8;
                    This->baseShader.limits.constant_int = 0;
                    This->baseShader.limits.constant_bool = 0;
-                   This->baseShader.limits.texture = 6;
+                   This->baseShader.limits.texcoord = 6;
+                   This->baseShader.limits.sampler = 6;
                    This->baseShader.limits.packed_input = 0;
                    break;
                
@@ -967,7 +969,8 @@ static void pshader_set_limits(
                    This->baseShader.limits.constant_float = 32;
                    This->baseShader.limits.constant_int = 16;
                    This->baseShader.limits.constant_bool = 16;
-                   This->baseShader.limits.texture = 8;
+                   This->baseShader.limits.texcoord = 8;
+                   This->baseShader.limits.sampler = 16;
                    This->baseShader.limits.packed_input = 0;
                    break;
 
@@ -976,15 +979,17 @@ static void pshader_set_limits(
                    This->baseShader.limits.constant_float = 224;
                    This->baseShader.limits.constant_int = 16;
                    This->baseShader.limits.constant_bool = 16;
-                   This->baseShader.limits.texture = 0;
+                   This->baseShader.limits.texcoord = 0;
+                   This->baseShader.limits.sampler = 16;
                    This->baseShader.limits.packed_input = 12;
                    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;
+                   This->baseShader.limits.constant_float = 32;
+                   This->baseShader.limits.constant_int = 16;
+                   This->baseShader.limits.constant_bool = 16;
+                   This->baseShader.limits.texcoord = 8;
+                   This->baseShader.limits.sampler = 16;
                    This->baseShader.limits.packed_input = 0;
                    FIXME("Unrecognized pixel shader version %#lx\n", 
                        This->baseShader.hex_version);
@@ -1124,7 +1129,7 @@ static void pshader_hw_tex(SHADER_OPCODE
     get_register_name(dst, reg_dest, arg->reg_maps->constantsF);
 
     /* 1.0-1.3: Use destination register as coordinate source.
-       2.0+: Use provided coordinate source register. */
+       1.4+: Use provided coordinate source register. */
    if (hex_version < D3DPS_VERSION(1,4))
       strcpy(reg_coord, reg_dest);
    else
diff --git a/dlls/wined3d/vertexshader.c b/dlls/wined3d/vertexshader.c
index 04a8337..ec04d54 100644
--- a/dlls/wined3d/vertexshader.c
+++ b/dlls/wined3d/vertexshader.c
@@ -712,7 +712,7 @@ inline static void vshader_program_add_p
 static void vshader_set_limits(
       IWineD3DVertexShaderImpl *This) {
 
-      This->baseShader.limits.texture = 0;
+      This->baseShader.limits.texcoord = 0;
       This->baseShader.limits.attributes = 16;
       This->baseShader.limits.packed_input = 0;
 
@@ -727,6 +727,7 @@ static void vshader_set_limits(
                    This->baseShader.limits.constant_int = 0;
                    This->baseShader.limits.address = 1;
                    This->baseShader.limits.packed_output = 0;
+                   This->baseShader.limits.sampler = 0;
                    break;
       
           case D3DVS_VERSION(2,0):
@@ -736,6 +737,7 @@ static void vshader_set_limits(
                    This->baseShader.limits.constant_int = 16;
                    This->baseShader.limits.address = 1;
                    This->baseShader.limits.packed_output = 0;
+                   This->baseShader.limits.sampler = 0;
                    break;
 
           case D3DVS_VERSION(3,0):
@@ -744,13 +746,15 @@ static void vshader_set_limits(
                    This->baseShader.limits.constant_int = 32;
                    This->baseShader.limits.address = 1;
                    This->baseShader.limits.packed_output = 12;
+                   This->baseShader.limits.sampler = 4;
                    break;
 
           default: This->baseShader.limits.temporary = 12;
-                   This->baseShader.limits.constant_bool = 0;
-                   This->baseShader.limits.constant_int = 0;
+                   This->baseShader.limits.constant_bool = 16;
+                   This->baseShader.limits.constant_int = 16;
                    This->baseShader.limits.address = 1;
                    This->baseShader.limits.packed_output = 0;
+                   This->baseShader.limits.sampler = 0;
                    FIXME("Unrecognized vertex shader version %#lx\n",
                        This->baseShader.hex_version);
       }
diff --git a/dlls/wined3d/wined3d_private.h b/dlls/wined3d/wined3d_private.h
index a53bc1c..5f97fb3 100644
--- a/dlls/wined3d/wined3d_private.h
+++ b/dlls/wined3d/wined3d_private.h
@@ -1269,9 +1269,15 @@ typedef struct shader_reg_maps {
     char constantsF[MAX_CONST_F];           /* pixel, vertex */
     /* TODO: Integer and bool constants */
 
+    /* Semantics maps (semantic -> reg_token)
+     * Use 0 as default (bit 31 is always 1 on a valid token) */
     DWORD* semantics_in;                    /* vertex, pixel */
     DWORD* semantics_out;                   /* vertex */
 
+    /* Sampler usage tokens 
+     * Use 0 as default (bit 31 is always 1 on a valid token) */
+    DWORD samplers[MAX_SAMPLERS];
+
 } shader_reg_maps;
 
 #define SHADER_PGMSIZE 65535
@@ -1307,7 +1313,8 @@ typedef struct SHADER_OPCODE_ARG {
 
 typedef struct SHADER_LIMITS {
     unsigned int temporary;
-    unsigned int texture;
+    unsigned int texcoord;
+    unsigned int sampler;
     unsigned int constant_int;
     unsigned int constant_float;
     unsigned int constant_bool;
-- 
1.3.3



More information about the wine-patches mailing list