[3/10] WineD3D: Implement texbem in arb, improve it in glsl

Stefan Dösinger stefan at codeweavers.com
Wed Feb 14 20:00:57 CST 2007


Thanks to res2k from irc for his help on writing the arb shader code. I have 
to read up some glsl docs to implement the same for glsl shaders. the shader 
now just samples without bump mapping(but obeying the projection flag)

This fixes the water in dxlevel 80 in hl2

Note that you won't see any bump mapping with this patch because bump mapping 
pixel formats are broken
-------------- next part --------------
From fdff2633987a52598f6127df4a7bd4e869d78a93 Mon Sep 17 00:00:00 2001
From: Stefan Doesinger <stefan at codeweavers.com>
Date: Sun, 4 Feb 2007 12:42:52 +0100
Subject: [PATCH] WineD3D: Implement texbem in arb, improve it in glsl

---
 dlls/wined3d/arb_program_shader.c |   53 ++++++++++++++++++++++++++++++++++++-
 dlls/wined3d/glsl_shader.c        |   47 ++++++++++++++++++++++++++++----
 2 files changed, 93 insertions(+), 7 deletions(-)

diff --git a/dlls/wined3d/arb_program_shader.c b/dlls/wined3d/arb_program_shader.c
index 86e8430..4742447 100644
--- a/dlls/wined3d/arb_program_shader.c
+++ b/dlls/wined3d/arb_program_shader.c
@@ -119,6 +119,15 @@ void shader_arb_load_constants(
                                    GL_LIMITS(pshader_constantsF),
                                    stateBlock->pixelShaderConstantF,
                                    &stateBlock->set_pconstantsF);
+        if(((IWineD3DPixelShaderImpl *) pshader)->bumpenvmatconst) {
+            /* needsbumpmat stores the stage number from where to load the matrix. bumpenvmatconst stores the
+             * number of the constant to load the matrix into.
+             * The state manager takes care that this function is always called if the bump env matrix changes
+             */
+            IWineD3DPixelShaderImpl *psi = (IWineD3DPixelShaderImpl *) pshader;
+            float *data = (float *) &stateBlock->textureState[(int) psi->needsbumpmat][WINED3DTSS_BUMPENVMAT00];
+            GL_EXTCALL(glProgramEnvParameter4fvARB(GL_FRAGMENT_PROGRAM_ARB, psi->bumpenvmatconst, data));
+        }
     }
 }
 
@@ -159,6 +168,19 @@ void shader_generate_arb_declarations(
             shader_addline(buffer, "MOV T%u, fragment.texcoord[%u];\n", i, i);
     }
 
+    if(reg_maps->bumpmat /* Only  a pshader can use texbem */) {
+        /* If the shader does not use all available constants, use the next free constant to load the bump mapping environment matrix from
+         * the stateblock into the shader. If no constant is available don't load, texbem will then just sample the texture without applying
+         * bump mapping.
+         */
+        if(max_constantsF < GL_LIMITS(pshader_constantsF)) {
+            ((IWineD3DPixelShaderImpl *)This)->bumpenvmatconst = max_constantsF;
+            shader_addline(buffer, "PARAM bumpenvmat = program.env[%d];\n", ((IWineD3DPixelShaderImpl *)This)->bumpenvmatconst);
+        } else {
+            FIXME("No free constant found to load environemnt bump mapping matrix into the shader. texbem instruction will not apply bump mapping\n");
+        }
+    }
+
     /* Need to PARAM the environment parameters (constants) so we can use relative addressing */
     shader_addline(buffer, "PARAM C[%d] = { program.env[0..%d] };\n",
                    max_constantsF, max_constantsF - 1);
@@ -662,7 +684,7 @@ void pshader_hw_texreg2gb(SHADER_OPCODE_ARG* arg) {
 }
 
 void pshader_hw_texbem(SHADER_OPCODE_ARG* arg) {
-
+#if 0
      SHADER_BUFFER* buffer = arg->buffer;
      DWORD reg1 = arg->dst  & WINED3DSP_REGNUM_MASK;
      DWORD reg2 = arg->src[0] & WINED3DSP_REGNUM_MASK;
@@ -672,6 +694,35 @@ void pshader_hw_texbem(SHADER_OPCODE_ARG* arg) {
      sprintf(dst_str, "T%u", reg1);
      shader_addline(buffer, "ADD TMP.rg, fragment.texcoord[%u], T%u;\n", reg1, reg2);
      shader_hw_sample(arg, reg1, dst_str, "TMP");
+#endif
+    IWineD3DPixelShaderImpl* This = (IWineD3DPixelShaderImpl*) arg->shader;
+
+    DWORD dst = arg->dst;
+    DWORD src = arg->src[0] & WINED3DSP_REGNUM_MASK;
+    SHADER_BUFFER* buffer = arg->buffer;
+
+    char reg_coord[40];
+    DWORD reg_dest_code;
+
+    /* All versions have a destination register */
+    reg_dest_code = dst & WINED3DSP_REGNUM_MASK;
+    /* Can directly use the name because texbem is only valid for <= 1.3 shaders */
+    pshader_get_register_name(dst, reg_coord);
+
+    if(This->bumpenvmatconst) {
+        /*shader_addline(buffer, "MOV T%u, fragment.texcoord[%u];\n", 1, 1); Not needed - done already */
+        shader_addline(buffer, "SWZ TMP2, bumpenvmat, x, z, 0, 0;\n");
+        shader_addline(buffer, "DP3 TMP.r, TMP2, T%u;\n", src);
+        shader_addline(buffer, "SWZ TMP2, bumpenvmat, y, w, 0, 0;\n");
+        shader_addline(buffer, "DP3 TMP.g, TMP2, T%u;\n", src);
+        shader_addline(buffer, "ADD TMP.rg, TMP, %s;\n", reg_coord);
+        /* Not sure about this, but hl2 needs it. It uses a projected texture with texbem and depends on the 4th coordinate */
+        shader_addline(buffer, "MOV TMP.a, %s;\n", reg_coord);
+        shader_hw_sample(arg, reg_dest_code, reg_coord, "TMP");
+    } else {
+        /* Without a bump matrix loaded, just sample with the unmodified coordinates */
+        shader_hw_sample(arg, reg_dest_code, reg_coord, reg_coord);
+    }
 }
 
 void pshader_hw_texm3x2pad(SHADER_OPCODE_ARG* arg) {
diff --git a/dlls/wined3d/glsl_shader.c b/dlls/wined3d/glsl_shader.c
index 566442b..f270af7 100644
--- a/dlls/wined3d/glsl_shader.c
+++ b/dlls/wined3d/glsl_shader.c
@@ -1767,15 +1767,50 @@ void pshader_glsl_texm3x3vspec(SHADER_OPCODE_ARG* arg) {
 
 /** Process the WINED3DSIO_TEXBEM instruction in GLSL.
  * Apply a fake bump map transform.
- * FIXME: Should apply the BUMPMAPENV matrix.  For now, just sample the texture */
+ * texbem is pshader <= 1.3 only, this saves a few version checks
+ */
 void pshader_glsl_texbem(SHADER_OPCODE_ARG* arg) {
+    IWineD3DPixelShaderImpl* This = (IWineD3DPixelShaderImpl*) arg->shader;
+    IWineD3DDeviceImpl* deviceImpl = (IWineD3DDeviceImpl*) This->baseShader.device;
+    char dst_swizzle[6];
+    glsl_sample_function_t sample_function;
+    DWORD sampler_type;
+    DWORD sampler_idx;
+    BOOL projected;
+    DWORD mask = 0;
+    DWORD flags;
+    char coord_mask[6];
+
+    /* All versions have a destination register */
+    shader_glsl_append_dst(arg->buffer, arg);
+
+    sampler_idx = arg->dst & WINED3DSP_REGNUM_MASK;
+    flags = deviceImpl->stateBlock->textureState[sampler_idx][WINED3DTSS_TEXTURETRANSFORMFLAGS];
+
+    /* TODO: Does texbem even support projected textures? half-life 2 uses it */
+    if (flags & WINED3DTTFF_PROJECTED) {
+        projected = TRUE;
+        switch (flags & ~WINED3DTTFF_PROJECTED) {
+            case WINED3DTTFF_COUNT1: FIXME("WINED3DTTFF_PROJECTED with WINED3DTTFF_COUNT1?\n"); break;
+            case WINED3DTTFF_COUNT2: mask = WINED3DSP_WRITEMASK_1; break;
+            case WINED3DTTFF_COUNT3: mask = WINED3DSP_WRITEMASK_2; break;
+            case WINED3DTTFF_COUNT4:
+            case WINED3DTTFF_DISABLE: mask = WINED3DSP_WRITEMASK_3; break;
+        }
+    } else {
+        projected = FALSE;
+    }
+
+    sampler_type = arg->reg_maps->samplers[sampler_idx] & WINED3DSP_TEXTURETYPE_MASK;
+    shader_glsl_get_sample_function(sampler_type, projected, &sample_function);
+    mask |= sample_function.coord_mask;
 
-    DWORD reg1 = arg->dst & WINED3DSP_REGNUM_MASK;
-    DWORD reg2 = arg->src[0] & WINED3DSP_REGNUM_MASK;
+    shader_glsl_get_write_mask(arg->dst, dst_swizzle);
 
-    FIXME("Not applying the BUMPMAPENV matrix for pixel shader instruction texbem.\n");
-    shader_addline(arg->buffer, "T%u = texture2D(Psampler%u, gl_TexCoord[%u].xy + T%u.xy);\n",
-            reg1, reg1, reg1, reg2);
+    shader_glsl_get_write_mask(mask, coord_mask);
+    FIXME("Bump map transform not handled yet\n");
+    shader_addline(arg->buffer, "%s(Psampler%u, T%u%s)%s);\n",
+                   sample_function.name, sampler_idx, sampler_idx, coord_mask, dst_swizzle);
 }
 
 /** Process the WINED3DSIO_TEXREG2AR instruction in GLSL
-- 
1.4.4.3



More information about the wine-patches mailing list