[PATCH] WineD3D: GL_ARB_fragment_program ffp implementation=0A=

Stefan Doesinger stefan at codeweavers.com
Mon Jul 28 11:41:02 CDT 2008


=0A=
---=0A=
 dlls/wined3d/arb_program_shader.c |  983 =
+++++++++++++++++++++++++++++++++----=0A=
 dlls/wined3d/device.c             |    6 +-=0A=
 dlls/wined3d/directx.c            |   19 +-=0A=
 dlls/wined3d/wined3d_private.h    |    3 +=0A=
 4 files changed, 907 insertions(+), 104 deletions(-)=0A=
=0A=
diff --git a/dlls/wined3d/arb_program_shader.c =
b/dlls/wined3d/arb_program_shader.c=0A=
index 2de05bf..4f0e897 100644=0A=
--- a/dlls/wined3d/arb_program_shader.c=0A=
+++ b/dlls/wined3d/arb_program_shader.c=0A=
@@ -637,88 +637,21 @@ static void shader_hw_sample(SHADER_OPCODE_ARG* =
arg, DWORD sampler_idx, const ch=0A=
     }=0A=
 }=0A=
 =0A=
-static void shader_arb_color_correction(SHADER_OPCODE_ARG* arg) {=0A=
-    IWineD3DBaseShaderImpl* shader =3D (IWineD3DBaseShaderImpl*) =
arg->shader;=0A=
-    IWineD3DDeviceImpl* deviceImpl =3D (IWineD3DDeviceImpl*) =
shader->baseShader.device;=0A=
-    WineD3D_GL_Info *gl_info =3D &deviceImpl->adapter->gl_info;=0A=
-    WINED3DFORMAT fmt;=0A=
-    WINED3DFORMAT conversion_group;=0A=
-    IWineD3DBaseTextureImpl *texture;=0A=
-    UINT i;=0A=
-    BOOL recorded =3D FALSE;=0A=
-    DWORD sampler_idx;=0A=
-    DWORD hex_version =3D shader->baseShader.hex_version;=0A=
-    char reg[256];=0A=
-    char writemask[6];=0A=
-=0A=
-    switch(arg->opcode->opcode) {=0A=
-        case WINED3DSIO_TEX:=0A=
-            if (hex_version < WINED3DPS_VERSION(2,0)) {=0A=
-                sampler_idx =3D arg->dst & WINED3DSP_REGNUM_MASK;=0A=
-            } else {=0A=
-                sampler_idx =3D arg->src[1] & WINED3DSP_REGNUM_MASK;=0A=
-            }=0A=
-            break;=0A=
-=0A=
-        case WINED3DSIO_TEXLDL:=0A=
-            FIXME("Add color fixup for vertex texture =
WINED3DSIO_TEXLDL\n");=0A=
-            return;=0A=
-=0A=
-        case WINED3DSIO_TEXDP3TEX:=0A=
-        case WINED3DSIO_TEXM3x3TEX:=0A=
-        case WINED3DSIO_TEXM3x3SPEC:=0A=
-        case WINED3DSIO_TEXM3x3VSPEC:=0A=
-        case WINED3DSIO_TEXBEM:=0A=
-        case WINED3DSIO_TEXREG2AR:=0A=
-        case WINED3DSIO_TEXREG2GB:=0A=
-        case WINED3DSIO_TEXREG2RGB:=0A=
-            sampler_idx =3D arg->dst & WINED3DSP_REGNUM_MASK;=0A=
-            break;=0A=
-=0A=
-        default:=0A=
-            /* Not a texture sampling instruction, nothing to do */=0A=
-            return;=0A=
-    };=0A=
-=0A=
-    texture =3D (IWineD3DBaseTextureImpl *) =
deviceImpl->stateBlock->textures[sampler_idx];=0A=
-    if(texture) {=0A=
-        fmt =3D texture->resource.format;=0A=
-        conversion_group =3D =
texture->baseTexture.shader_conversion_group;=0A=
-    } else {=0A=
-        fmt =3D WINED3DFMT_UNKNOWN;=0A=
-        conversion_group =3D WINED3DFMT_UNKNOWN;=0A=
-    }=0A=
-=0A=
-    /* before doing anything, record the sampler with the format in the =
format conversion list,=0A=
-     * but check if it's not there already=0A=
-     */=0A=
-    for(i =3D 0; i < shader->baseShader.num_sampled_samplers; i++) {=0A=
-        if(shader->baseShader.sampled_samplers[i] =3D=3D sampler_idx) {=0A=
-            recorded =3D TRUE;=0A=
-        }=0A=
-    }=0A=
-    if(!recorded) {=0A=
-        =
shader->baseShader.sampled_samplers[shader->baseShader.num_sampled_sample=
rs] =3D sampler_idx;=0A=
-        shader->baseShader.num_sampled_samplers++;=0A=
-        shader->baseShader.sampled_format[sampler_idx] =3D =
conversion_group;=0A=
-    }=0A=
-=0A=
-    pshader_get_register_name(arg->shader, arg->dst, reg);=0A=
-    shader_arb_get_write_mask(arg, arg->dst, writemask);=0A=
-    if(strlen(writemask) =3D=3D 0) strcpy(writemask, ".xyzw");=0A=
-=0A=
+static void gen_color_correction(SHADER_BUFFER *buffer, const char =
*reg, const char *writemask,=0A=
+                                 const char *one, const char *two, =
WINED3DFORMAT fmt,=0A=
+                                 WineD3D_GL_Info *gl_info) {=0A=
     switch(fmt) {=0A=
         case WINED3DFMT_V8U8:=0A=
         case WINED3DFMT_V16U16:=0A=
             if(GL_SUPPORT(NV_TEXTURE_SHADER) ||=0A=
-               (GL_SUPPORT(ATI_ENVMAP_BUMPMAP) && fmt =3D=3D =
WINED3DFMT_V8U8)) {=0A=
+              (GL_SUPPORT(ATI_ENVMAP_BUMPMAP) && fmt =3D=3D =
WINED3DFMT_V8U8)) {=0A=
 #if 0=0A=
                 /* The 3rd channel returns 1.0 in d3d, but 0.0 in gl. =
Fix this while we're at it :-)=0A=
                  * disabled until an application that needs it is found =
because it causes unneeded=0A=
                  * shader recompilation in some game=0A=
                  */=0A=
                 if(strlen(writemask) >=3D 4) {=0A=
-                    shader_addline(arg->buffer, "MOV %s.%c, one.z;\n", =
reg, writemask[3]);=0A=
+                    shader_addline(buffer, "MOV %s.%c, %s;\n", reg, =
one);=0A=
                 }=0A=
 #endif=0A=
             } else {=0A=
@@ -727,17 +660,19 @@ static void =
shader_arb_color_correction(SHADER_OPCODE_ARG* arg) {=0A=
                  * all registers, do so, this saves an instruction.=0A=
                  */=0A=
                 if(strlen(writemask) >=3D 5) {=0A=
-                    shader_addline(arg->buffer, "MAD %s, %s, coefmul.x, =
-one;\n", reg, reg);=0A=
+                    shader_addline(buffer, "MAD %s, %s, %s, -%s;\n", =
reg, reg, two, one);=0A=
                 } else if(strlen(writemask) >=3D 3) {=0A=
-                    shader_addline(arg->buffer, "MAD %s.%c, %s.%c, =
coefmul.x, -one;\n",=0A=
+                    shader_addline(buffer, "MAD %s.%c, %s.%c, %s, =
-%s;\n",=0A=
+                                   reg, writemask[1],=0A=
                                    reg, writemask[1],=0A=
-                                   reg, writemask[1]);=0A=
-                    shader_addline(arg->buffer, "MAD %s.%c, %s.%c, =
coefmul.x, -one;\n",=0A=
+                                   two, one);=0A=
+                    shader_addline(buffer, "MAD %s.%c, %s.%c, %s, =
-%s;\n",=0A=
                                    reg, writemask[2],=0A=
-                                   reg, writemask[2]);=0A=
+                                   reg, writemask[2],=0A=
+                                   two, one);=0A=
                 } else if(strlen(writemask) =3D=3D 2) {=0A=
-                    shader_addline(arg->buffer, "MAD %s.%c, %s.%c, =
coefmul.x, -one;\n", reg, writemask[1],=0A=
-                                   reg, writemask[1]);=0A=
+                    shader_addline(buffer, "MAD %s.%c, %s.%c, %s, =
-%s;\n", reg, writemask[1],=0A=
+                                   reg, writemask[1], two, one);=0A=
                 }=0A=
             }=0A=
             break;=0A=
@@ -748,16 +683,19 @@ static void =
shader_arb_color_correction(SHADER_OPCODE_ARG* arg) {=0A=
                  * and a(X) is always 1.0. Cannot do a full conversion =
due to L(blue)=0A=
                  */=0A=
                 if(strlen(writemask) >=3D 3) {=0A=
-                    shader_addline(arg->buffer, "MAD %s.%c, %s.%c, =
coefmul.x, -one;\n",=0A=
+                    shader_addline(buffer, "MAD %s.%c, %s.%c, %s, =
-%s;\n",=0A=
+                                   reg, writemask[1],=0A=
                                    reg, writemask[1],=0A=
-                                   reg, writemask[1]);=0A=
-                    shader_addline(arg->buffer, "MAD %s.%c, %s.%c, =
coefmul.x, -one;\n",=0A=
+                                   two, one);=0A=
+                    shader_addline(buffer, "MAD %s.%c, %s.%c, %s, =
-%s;\n",=0A=
                                    reg, writemask[2],=0A=
-                                   reg, writemask[2]);=0A=
+                                   reg, writemask[2],=0A=
+                                   two, one);=0A=
                 } else if(strlen(writemask) =3D=3D 2) {=0A=
-                    shader_addline(arg->buffer, "MAD %s.%c, %s.%c, =
coefmul.x, -one;\n",=0A=
+                    shader_addline(buffer, "MAD %s.%c, %s.%c, %s, =
-%s;\n",=0A=
                                    reg, writemask[1],=0A=
-                                   reg, writemask[1]);=0A=
+                                   reg, writemask[1],=0A=
+                                   two, one);=0A=
                 }=0A=
             }=0A=
             break;=0A=
@@ -766,20 +704,22 @@ static void =
shader_arb_color_correction(SHADER_OPCODE_ARG* arg) {=0A=
             if(!GL_SUPPORT(NV_TEXTURE_SHADER)) {=0A=
                 if(strlen(writemask) >=3D 4) {=0A=
                     /* Swap y and z (U and L), and do a sign conversion =
on x and the new y(V and U) */=0A=
-                    shader_addline(arg->buffer, "MOV TMP.g, %s.%c;\n",=0A=
+                    shader_addline(buffer, "MOV TMP.g, %s.%c;\n",=0A=
                                    reg, writemask[2]);=0A=
-                    shader_addline(arg->buffer, "MAD %s.%c%c, %s.%c%c, =
coefmul.x, -one;\n",=0A=
+                    shader_addline(buffer, "MAD %s.%c%c, %s.%c%c, %s, =
-%s;\n",=0A=
                                    reg, writemask[1], writemask[1],=0A=
-                                   reg, writemask[1], writemask[3]);=0A=
-                    shader_addline(arg->buffer, "MOV %s.%c, TMP.g;\n", =
reg,=0A=
+                                   reg, writemask[1], writemask[3],=0A=
+                                   two, one);=0A=
+                    shader_addline(buffer, "MOV %s.%c, TMP.g;\n", reg,=0A=
                                    writemask[3]);=0A=
                 } else if(strlen(writemask) =3D=3D 3) {=0A=
                     /* This is bad: We have VL, but we need VU */=0A=
                     FIXME("2 components sampled from a converted L6V5U5 =
texture\n");=0A=
                 } else {=0A=
-                    shader_addline(arg->buffer, "MAD %s.%c, %s.%c, =
coefmul.x, -one;\n",=0A=
+                    shader_addline(buffer, "MAD %s.%c, %s.%c, %s, =
-%s;\n",=0A=
+                                   reg, writemask[1],=0A=
                                    reg, writemask[1],=0A=
-                                   reg, writemask[1]);=0A=
+                                   two, one);=0A=
                 }=0A=
             }=0A=
             break;=0A=
@@ -789,17 +729,17 @@ static void =
shader_arb_color_correction(SHADER_OPCODE_ARG* arg) {=0A=
                 /* Correct the sign in all channels */=0A=
                 switch(strlen(writemask)) {=0A=
                     case 4:=0A=
-                        shader_addline(arg->buffer, "MAD %s.%c, %s.%c, =
coefmul.x, -one;\n",=0A=
+                        shader_addline(buffer, "MAD %s.%c, %s.%c, =
coefmul.x, -one;\n",=0A=
                                        reg, writemask[3],=0A=
                                        reg, writemask[3]);=0A=
                         /* drop through */=0A=
                     case 3:=0A=
-                        shader_addline(arg->buffer, "MAD %s.%c, %s.%c, =
coefmul.x, -one;\n",=0A=
+                        shader_addline(buffer, "MAD %s.%c, %s.%c, =
coefmul.x, -one;\n",=0A=
                                        reg, writemask[2],=0A=
                                        reg, writemask[2]);=0A=
                         /* drop through */=0A=
                     case 2:=0A=
-                        shader_addline(arg->buffer, "MAD %s.%c, %s.%c, =
coefmul.x, -one;\n",=0A=
+                        shader_addline(buffer, "MAD %s.%c, %s.%c, =
coefmul.x, -one;\n",=0A=
                                        reg, writemask[1],=0A=
                                        reg, writemask[1]);=0A=
                         break;=0A=
@@ -811,7 +751,7 @@ static void =
shader_arb_color_correction(SHADER_OPCODE_ARG* arg) {=0A=
 =0A=
                     case 5:=0A=
                     default:=0A=
-                        shader_addline(arg->buffer, "MAD %s, %s, =
coefmul.x, -one;\n", reg, reg);=0A=
+                        shader_addline(buffer, "MAD %s, %s, coefmul.x, =
-one;\n", reg, reg);=0A=
                 }=0A=
             }=0A=
             break;=0A=
@@ -825,11 +765,11 @@ static void =
shader_arb_color_correction(SHADER_OPCODE_ARG* arg) {=0A=
              * are swapped compared to d3d. So swap red and green.=0A=
              */=0A=
             if(GL_SUPPORT(EXT_TEXTURE_COMPRESSION_RGTC)) {=0A=
-                shader_addline(arg->buffer, "SWZ %s, %s, %c, %c, 1, =
0;\n",=0A=
+                shader_addline(buffer, "SWZ %s, %s, %c, %c, 1, 0;\n",=0A=
                                reg, reg, writemask[2], writemask[1]);=0A=
             } else {=0A=
                 if(strlen(writemask) =3D=3D 5) {=0A=
-                    shader_addline(arg->buffer, "MOV %s.%c, %s.%c;\n",=0A=
+                    shader_addline(buffer, "MOV %s.%c, %s.%c;\n",=0A=
                                 reg, writemask[2], reg, writemask[4]);=0A=
                 } else if(strlen(writemask) =3D=3D 2) {=0A=
                     /* Nothing to do */=0A=
@@ -846,6 +786,80 @@ static void =
shader_arb_color_correction(SHADER_OPCODE_ARG* arg) {=0A=
     }=0A=
 }=0A=
 =0A=
+static void shader_arb_color_correction(SHADER_OPCODE_ARG* arg) {=0A=
+    IWineD3DBaseShaderImpl* shader =3D (IWineD3DBaseShaderImpl*) =
arg->shader;=0A=
+    IWineD3DDeviceImpl* deviceImpl =3D (IWineD3DDeviceImpl*) =
shader->baseShader.device;=0A=
+    WineD3D_GL_Info *gl_info =3D &deviceImpl->adapter->gl_info;=0A=
+    WINED3DFORMAT fmt;=0A=
+    WINED3DFORMAT conversion_group;=0A=
+    IWineD3DBaseTextureImpl *texture;=0A=
+    UINT i;=0A=
+    BOOL recorded =3D FALSE;=0A=
+    DWORD sampler_idx;=0A=
+    DWORD hex_version =3D shader->baseShader.hex_version;=0A=
+    char reg[256];=0A=
+    char writemask[6];=0A=
+=0A=
+    switch(arg->opcode->opcode) {=0A=
+        case WINED3DSIO_TEX:=0A=
+            if (hex_version < WINED3DPS_VERSION(2,0)) {=0A=
+                sampler_idx =3D arg->dst & WINED3DSP_REGNUM_MASK;=0A=
+            } else {=0A=
+                sampler_idx =3D arg->src[1] & WINED3DSP_REGNUM_MASK;=0A=
+            }=0A=
+            break;=0A=
+=0A=
+        case WINED3DSIO_TEXLDL:=0A=
+            FIXME("Add color fixup for vertex texture =
WINED3DSIO_TEXLDL\n");=0A=
+            return;=0A=
+=0A=
+        case WINED3DSIO_TEXDP3TEX:=0A=
+        case WINED3DSIO_TEXM3x3TEX:=0A=
+        case WINED3DSIO_TEXM3x3SPEC:=0A=
+        case WINED3DSIO_TEXM3x3VSPEC:=0A=
+        case WINED3DSIO_TEXBEM:=0A=
+        case WINED3DSIO_TEXREG2AR:=0A=
+        case WINED3DSIO_TEXREG2GB:=0A=
+        case WINED3DSIO_TEXREG2RGB:=0A=
+            sampler_idx =3D arg->dst & WINED3DSP_REGNUM_MASK;=0A=
+            break;=0A=
+=0A=
+        default:=0A=
+            /* Not a texture sampling instruction, nothing to do */=0A=
+            return;=0A=
+    };=0A=
+=0A=
+    texture =3D (IWineD3DBaseTextureImpl *) =
deviceImpl->stateBlock->textures[sampler_idx];=0A=
+    if(texture) {=0A=
+        fmt =3D texture->resource.format;=0A=
+        conversion_group =3D =
texture->baseTexture.shader_conversion_group;=0A=
+    } else {=0A=
+        fmt =3D WINED3DFMT_UNKNOWN;=0A=
+        conversion_group =3D WINED3DFMT_UNKNOWN;=0A=
+    }=0A=
+=0A=
+    /* before doing anything, record the sampler with the format in the =
format conversion list,=0A=
+     * but check if it's not there already=0A=
+     */=0A=
+    for(i =3D 0; i < shader->baseShader.num_sampled_samplers; i++) {=0A=
+        if(shader->baseShader.sampled_samplers[i] =3D=3D sampler_idx) {=0A=
+            recorded =3D TRUE;=0A=
+        }=0A=
+    }=0A=
+    if(!recorded) {=0A=
+        =
shader->baseShader.sampled_samplers[shader->baseShader.num_sampled_sample=
rs] =3D sampler_idx;=0A=
+        shader->baseShader.num_sampled_samplers++;=0A=
+        shader->baseShader.sampled_format[sampler_idx] =3D =
conversion_group;=0A=
+    }=0A=
+=0A=
+    pshader_get_register_name(arg->shader, arg->dst, reg);=0A=
+    shader_arb_get_write_mask(arg, arg->dst, writemask);=0A=
+    if(strlen(writemask) =3D=3D 0) strcpy(writemask, ".xyzw");=0A=
+=0A=
+    gen_color_correction(arg->buffer, reg, writemask, "one", =
"coefmul.x", fmt, gl_info);=0A=
+=0A=
+}=0A=
+=0A=
 =0A=
 static void pshader_gen_input_modifier_line (=0A=
     IWineD3DBaseShader *iface,=0A=
@@ -1840,10 +1854,17 @@ static void shader_arb_select(IWineD3DDevice =
*iface, BOOL usePS, BOOL useVS) {=0A=
         glEnable(GL_FRAGMENT_PROGRAM_ARB);=0A=
         checkGLcall("glEnable(GL_FRAGMENT_PROGRAM_ARB);");=0A=
         TRACE("(%p) : Bound fragment program %u and enabled =
GL_FRAGMENT_PROGRAM_ARB\n", This, priv->current_fprogram_id);=0A=
-    } else if(GL_SUPPORT(ARB_FRAGMENT_PROGRAM)) {=0A=
+    } else {=0A=
         priv->current_fprogram_id =3D 0;=0A=
-        glDisable(GL_FRAGMENT_PROGRAM_ARB);=0A=
-        checkGLcall("glDisable(GL_FRAGMENT_PROGRAM_ARB)");=0A=
+=0A=
+        if(GL_SUPPORT(ARB_FRAGMENT_PROGRAM) && =
!priv->use_arbfp_fixed_func) {=0A=
+            /* Disable only if we're not using arbfp fixed function =
fragment processing. If this is used,=0A=
+             * keep GL_FRAGMENT_PROGRAM_ARB enabled, and the fixed =
function pipeline will bind the fixed function=0A=
+             * replacement shader=0A=
+             */=0A=
+            glDisable(GL_FRAGMENT_PROGRAM_ARB);=0A=
+            checkGLcall("glDisable(GL_FRAGMENT_PROGRAM_ARB)");=0A=
+        }=0A=
     }=0A=
 }=0A=
 =0A=
@@ -2174,3 +2195,765 @@ const shader_backend_t =
arb_program_shader_backend =3D {=0A=
     shader_arb_generate_vshader,=0A=
     shader_arb_get_caps,=0A=
 };=0A=
+=0A=
+/* ARB_fragment_program fixed function pipeline replacement definitions =
*/=0A=
+#define ARB_FFP_CONST_TFACTOR     0=0A=
+#define ARB_FFP_CONST_CONSTANT(i) ((ARB_FFP_CONST_TFACTOR) + 1 + i)=0A=
+#define ARB_FFP_CONST_BUMPMAT(i)  ((ARB_FFP_CONST_CONSTANT(7)) + 1 + i)=0A=
+=0A=
+struct arbfp_ffp_desc=0A=
+{=0A=
+    struct ffp_desc parent;=0A=
+    GLuint shader;=0A=
+    unsigned int num_textures_used;=0A=
+};=0A=
+=0A=
+static void arbfp_enable(IWineD3DDevice *iface, BOOL enable) {=0A=
+    if(enable) {=0A=
+        glEnable(GL_FRAGMENT_PROGRAM_ARB);=0A=
+        checkGLcall("glEnable(GL_FRAGMENT_PROGRAM_ARB)");=0A=
+    } else {=0A=
+        glDisable(GL_FRAGMENT_PROGRAM_ARB);=0A=
+        checkGLcall("glDisable(GL_FRAGMENT_PROGRAM_ARB)");=0A=
+    }=0A=
+}=0A=
+=0A=
+static HRESULT arbfp_alloc(IWineD3DDevice *iface) {=0A=
+    IWineD3DDeviceImpl *This =3D (IWineD3DDeviceImpl *) iface;=0A=
+    struct shader_arb_priv *priv;=0A=
+    /* Share private data between the shader backend and the pipeline =
replacement, if both=0A=
+     * are the arb implementation. This is needed to figure out wether =
ARBfp should be disabled=0A=
+     * if no pixel shader is bound or not=0A=
+     */=0A=
+    if(This->shader_backend =3D=3D &arb_program_shader_backend) {=0A=
+        This->fragment_priv =3D This->shader_priv;=0A=
+    } else {=0A=
+        This->fragment_priv =3D HeapAlloc(GetProcessHeap(), =
HEAP_ZERO_MEMORY, sizeof(struct shader_arb_priv));=0A=
+        if(!This->fragment_priv) return E_OUTOFMEMORY;=0A=
+    }=0A=
+    priv =3D (struct shader_arb_priv *) This->fragment_priv;=0A=
+    priv->fragment_shaders =3D hash_table_create(ffp_program_key_hash, =
ffp_program_key_compare);=0A=
+    priv->use_arbfp_fixed_func =3D TRUE;=0A=
+    return WINED3D_OK;=0A=
+}=0A=
+=0A=
+static void arbfp_free_ffpshader(void *value, void *gli) {=0A=
+    WineD3D_GL_Info *gl_info =3D gli;=0A=
+    struct arbfp_ffp_desc *entry_arb =3D value;=0A=
+=0A=
+    ENTER_GL();=0A=
+    GL_EXTCALL(glDeleteProgramsARB(1, &entry_arb->shader));=0A=
+    checkGLcall("glDeleteProgramsARB(1, &entry_arb->shader)");=0A=
+    HeapFree(GetProcessHeap(), 0, entry_arb);=0A=
+    LEAVE_GL();=0A=
+}=0A=
+=0A=
+static void arbfp_free(IWineD3DDevice *iface) {=0A=
+    IWineD3DDeviceImpl *This =3D (IWineD3DDeviceImpl *) iface;=0A=
+    struct shader_arb_priv *priv =3D (struct shader_arb_priv *) =
This->fragment_priv;=0A=
+=0A=
+    hash_table_destroy(priv->fragment_shaders, arbfp_free_ffpshader, =
&This->adapter->gl_info);=0A=
+    priv->use_arbfp_fixed_func =3D FALSE;=0A=
+=0A=
+    if(This->shader_backend !=3D &arb_program_shader_backend) {=0A=
+        HeapFree(GetProcessHeap(), 0, This->fragment_priv);=0A=
+    }=0A=
+}=0A=
+=0A=
+static void arbfp_get_caps(WINED3DDEVTYPE devtype, WineD3D_GL_Info =
*gl_info, struct fragment_caps *caps) {=0A=
+    caps->TextureOpCaps =3D  WINED3DTEXOPCAPS_DISABLE                   =
  |=0A=
+                           WINED3DTEXOPCAPS_SELECTARG1                  =
|=0A=
+                           WINED3DTEXOPCAPS_SELECTARG2                  =
|=0A=
+                           WINED3DTEXOPCAPS_MODULATE4X                  =
|=0A=
+                           WINED3DTEXOPCAPS_MODULATE2X                  =
|=0A=
+                           WINED3DTEXOPCAPS_MODULATE                    =
|=0A=
+                           WINED3DTEXOPCAPS_ADDSIGNED2X                 =
|=0A=
+                           WINED3DTEXOPCAPS_ADDSIGNED                   =
|=0A=
+                           WINED3DTEXOPCAPS_ADD                         =
|=0A=
+                           WINED3DTEXOPCAPS_SUBTRACT                    =
|=0A=
+                           WINED3DTEXOPCAPS_ADDSMOOTH                   =
|=0A=
+                           WINED3DTEXOPCAPS_BLENDCURRENTALPHA           =
|=0A=
+                           WINED3DTEXOPCAPS_BLENDFACTORALPHA            =
|=0A=
+                           WINED3DTEXOPCAPS_BLENDTEXTUREALPHA           =
|=0A=
+                           WINED3DTEXOPCAPS_BLENDDIFFUSEALPHA           =
|=0A=
+                           WINED3DTEXOPCAPS_BLENDTEXTUREALPHAPM         =
|=0A=
+                           WINED3DTEXOPCAPS_MODULATEALPHA_ADDCOLOR      =
|=0A=
+                           WINED3DTEXOPCAPS_MODULATECOLOR_ADDALPHA      =
|=0A=
+                           WINED3DTEXOPCAPS_MODULATEINVCOLOR_ADDALPHA   =
|=0A=
+                           WINED3DTEXOPCAPS_MODULATEINVALPHA_ADDCOLOR   =
|=0A=
+                           WINED3DTEXOPCAPS_DOTPRODUCT3                 =
|=0A=
+                           WINED3DTEXOPCAPS_MULTIPLYADD                 =
|=0A=
+                           WINED3DTEXOPCAPS_LERP                        =
|=0A=
+                           WINED3DTEXOPCAPS_BUMPENVMAP;=0A=
+=0A=
+    /* TODO: Implement WINED3DTEXOPCAPS_BUMPENVMAPLUMINANCE=0A=
+    and WINED3DTEXOPCAPS_PREMODULATE */=0A=
+=0A=
+    caps->MaxTextureBlendStages   =3D 8;=0A=
+    caps->MaxSimultaneousTextures =3D min(GL_LIMITS(fragment_samplers), =
8);=0A=
+=0A=
+    caps->PrimitiveMiscCaps |=3D WINED3DPMISCCAPS_TSSARGTEMP;=0A=
+}=0A=
+#undef GLINFO_LOCATION=0A=
+=0A=
+#define GLINFO_LOCATION stateblock->wineD3DDevice->adapter->gl_info=0A=
+static void state_texfactor_arbfp(DWORD state, IWineD3DStateBlockImpl =
*stateblock, WineD3DContext *context) {=0A=
+    float col[4];=0A=
+    IWineD3DDeviceImpl *device =3D stateblock->wineD3DDevice;=0A=
+=0A=
+    /* Do not overwrite pixel shader constants if a pshader is in use */=0A=
+    if(use_ps(device)) return;=0A=
+=0A=
+    =
D3DCOLORTOGLFLOAT4(stateblock->renderState[WINED3DRS_TEXTUREFACTOR], =
col);=0A=
+    GL_EXTCALL(glProgramEnvParameter4fvARB(GL_FRAGMENT_PROGRAM_ARB, =
ARB_FFP_CONST_TFACTOR, col));=0A=
+    checkGLcall("glProgramEnvParameter4fvARB(GL_FRAGMENT_PROGRAM_ARB, =
ARB_FFP_CONST_TFACTOR, col)");=0A=
+=0A=
+    if(device->shader_backend =3D=3D &arb_program_shader_backend) {=0A=
+        device =3D stateblock->wineD3DDevice;=0A=
+        =
device->activeContext->pshader_const_dirty[ARB_FFP_CONST_TFACTOR] =3D 1;=0A=
+        device->highest_dirty_ps_const =3D =
max(device->highest_dirty_ps_const, ARB_FFP_CONST_TFACTOR + 1);=0A=
+    }=0A=
+}=0A=
+=0A=
+static void set_bumpmat_arbfp(DWORD state, IWineD3DStateBlockImpl =
*stateblock, WineD3DContext *context) {=0A=
+    DWORD stage =3D (state - STATE_TEXTURESTAGE(0, 0)) / =
WINED3D_HIGHEST_TEXTURE_STATE;=0A=
+    IWineD3DDeviceImpl *device =3D stateblock->wineD3DDevice;=0A=
+    float mat[2][2];=0A=
+=0A=
+    if(use_ps(device)) {=0A=
+        if(stage !=3D 0 &&=0A=
+           ((IWineD3DPixelShaderImpl *) =
stateblock->pixelShader)->baseShader.reg_maps.bumpmat[stage]) {=0A=
+            /* The pixel shader has to know the bump env matrix. Do a =
constants update if it isn't scheduled=0A=
+             * anyway=0A=
+             */=0A=
+            if(!isStateDirty(context, STATE_PIXELSHADERCONSTANT)) {=0A=
+                =
device->StateTable[STATE_PIXELSHADERCONSTANT].apply(STATE_PIXELSHADERCONS=
TANT, stateblock, context);=0A=
+            }=0A=
+        }=0A=
+        /* Exit now, don't set the bumpmat below, otherwise we may =
overwrite pixel shader constants */=0A=
+        return;=0A=
+    }=0A=
+=0A=
+    mat[0][0] =3D *((float *) =
&stateblock->textureState[stage][WINED3DTSS_BUMPENVMAT00]);=0A=
+    mat[0][1] =3D *((float *) =
&stateblock->textureState[stage][WINED3DTSS_BUMPENVMAT01]);=0A=
+    mat[1][0] =3D *((float *) =
&stateblock->textureState[stage][WINED3DTSS_BUMPENVMAT10]);=0A=
+    mat[1][1] =3D *((float *) =
&stateblock->textureState[stage][WINED3DTSS_BUMPENVMAT11]);=0A=
+=0A=
+    GL_EXTCALL(glProgramEnvParameter4fvARB(GL_FRAGMENT_PROGRAM_ARB, =
ARB_FFP_CONST_BUMPMAT(stage), &mat[0][0]));=0A=
+    checkGLcall("glProgramEnvParameter4fvARB(GL_FRAGMENT_PROGRAM_ARB, =
ARB_FFP_CONST_BUMPMAT(stage), &mat[0][0])");=0A=
+=0A=
+    if(device->shader_backend =3D=3D &arb_program_shader_backend) {=0A=
+        =
device->activeContext->pshader_const_dirty[ARB_FFP_CONST_BUMPMAT(stage)] =
=3D 1;=0A=
+        device->highest_dirty_ps_const =3D =
max(device->highest_dirty_ps_const, ARB_FFP_CONST_BUMPMAT(stage) + 1);=0A=
+    }=0A=
+}=0A=
+=0A=
+static const char *get_argreg(SHADER_BUFFER *buffer, DWORD argnum, =
unsigned int stage, DWORD arg) {=0A=
+    const char *ret;=0A=
+=0A=
+    if(arg > WINED3DTOP_LERP) return "unused"; /* This is the marker =
for unused registers */=0A=
+=0A=
+    switch(arg & WINED3DTA_SELECTMASK) {=0A=
+        case WINED3DTA_DIFFUSE:=0A=
+            ret =3D "fragment.color.primary"; break;=0A=
+=0A=
+        case WINED3DTA_CURRENT:=0A=
+            if(stage =3D=3D 0) ret =3D "fragment.color.primary";=0A=
+            else ret =3D "ret";=0A=
+            break;=0A=
+=0A=
+        case WINED3DTA_TEXTURE:=0A=
+            switch(stage) {=0A=
+                case 0: ret =3D "tex0"; break;=0A=
+                case 1: ret =3D "tex1"; break;=0A=
+                case 2: ret =3D "tex2"; break;=0A=
+                case 3: ret =3D "tex3"; break;=0A=
+                case 4: ret =3D "tex4"; break;=0A=
+                case 5: ret =3D "tex5"; break;=0A=
+                case 6: ret =3D "tex6"; break;=0A=
+                case 7: ret =3D "tex7"; break;=0A=
+                default: ret =3D "unknown texture";=0A=
+            }=0A=
+            break;=0A=
+=0A=
+        case WINED3DTA_TFACTOR:=0A=
+            ret =3D "tfactor"; break;=0A=
+=0A=
+        case WINED3DTA_SPECULAR:=0A=
+            ret =3D "fragment.color.secondary"; break;=0A=
+=0A=
+        case WINED3DTA_TEMP:=0A=
+            ret =3D "tempreg"; break;=0A=
+=0A=
+        case WINED3DTA_CONSTANT:=0A=
+            FIXME("Implement perstage constants\n");=0A=
+            switch(stage) {=0A=
+                case 0: ret =3D "const0"; break;=0A=
+                case 1: ret =3D "const1"; break;=0A=
+                case 2: ret =3D "const2"; break;=0A=
+                case 3: ret =3D "const3"; break;=0A=
+                case 4: ret =3D "const4"; break;=0A=
+                case 5: ret =3D "const5"; break;=0A=
+                case 6: ret =3D "const6"; break;=0A=
+                case 7: ret =3D "const7"; break;=0A=
+            }=0A=
+        default:=0A=
+            return "unknown";=0A=
+    }=0A=
+=0A=
+    if(arg & WINED3DTA_COMPLEMENT) {=0A=
+        shader_addline(buffer, "SUB arg%u, const.x, %s;\n", argnum, =
ret);=0A=
+        if(argnum =3D=3D 0) ret =3D "arg0";=0A=
+        if(argnum =3D=3D 1) ret =3D "arg1";=0A=
+        if(argnum =3D=3D 2) ret =3D "arg2";=0A=
+    }=0A=
+    return ret;=0A=
+}=0A=
+=0A=
+static void gen_ffp_instr(SHADER_BUFFER *buffer, unsigned int stage, =
BOOL color, BOOL alpha, BOOL last,=0A=
+                          DWORD dst, DWORD op, DWORD dw_arg0, DWORD =
dw_arg1, DWORD dw_arg2) {=0A=
+    const char *dstmask, *dstreg, *arg0, *arg1, *arg2;=0A=
+    unsigned int mul =3D 1;=0A=
+    BOOL mul_final_dest =3D FALSE;=0A=
+=0A=
+    if(color && alpha) dstmask =3D "";=0A=
+    else if(color) dstmask =3D ".rgb";=0A=
+    else dstmask =3D ".a";=0A=
+=0A=
+    if(dst =3D=3D tempreg && last) FIXME("Last texture stage writes to =
D3DTA_TEMP\n");=0A=
+    if(dst =3D=3D tempreg) dstreg =3D "tempreg";=0A=
+    else if(last) dstreg =3D "result.color";=0A=
+    else dstreg =3D "ret";=0A=
+=0A=
+    arg0 =3D get_argreg(buffer, 0, stage, dw_arg0);=0A=
+    arg1 =3D get_argreg(buffer, 1, stage, dw_arg1);=0A=
+    arg2 =3D get_argreg(buffer, 2, stage, dw_arg2);=0A=
+=0A=
+    switch(op) {=0A=
+        case WINED3DTOP_DISABLE:=0A=
+            if(stage =3D=3D 1) shader_addline(buffer, "MOV %s%s, =
fragment.color.primary;\n", dstreg, dstmask);=0A=
+            break;=0A=
+=0A=
+        case WINED3DTOP_SELECTARG2:=0A=
+            arg1 =3D arg2;=0A=
+        case WINED3DTOP_SELECTARG1:=0A=
+            shader_addline(buffer, "MOV %s%s, %s;\n", dstreg, dstmask, =
arg1);=0A=
+            break;=0A=
+=0A=
+        case WINED3DTOP_MODULATE4X:=0A=
+            mul =3D 2;=0A=
+        case WINED3DTOP_MODULATE2X:=0A=
+            mul *=3D 2;=0A=
+            if(strcmp(dstreg, "result.color") =3D=3D 0) {=0A=
+                dstreg =3D "ret";=0A=
+                mul_final_dest =3D TRUE;=0A=
+            }=0A=
+        case WINED3DTOP_MODULATE:=0A=
+            shader_addline(buffer, "MUL %s%s, %s, %s;\n", dstreg, =
dstmask, arg1, arg2);=0A=
+            break;=0A=
+=0A=
+        case WINED3DTOP_ADDSIGNED2X:=0A=
+            mul =3D 2;=0A=
+            if(strcmp(dstreg, "result.color") =3D=3D 0) {=0A=
+                dstreg =3D "ret";=0A=
+                mul_final_dest =3D TRUE;=0A=
+            }=0A=
+        case WINED3DTOP_ADDSIGNED:=0A=
+            shader_addline(buffer, "SUB arg2, %s, const.w;\n", arg2);=0A=
+            arg2 =3D "arg2";=0A=
+        case WINED3DTOP_ADD:=0A=
+            shader_addline(buffer, "ADD %s%s, %s, %s;\n", dstreg, =
dstmask, arg1, arg2);=0A=
+            break;=0A=
+=0A=
+        case WINED3DTOP_SUBTRACT:=0A=
+            shader_addline(buffer, "SUB %s%s, %s, %s;\n", dstreg, =
dstmask, arg1, arg2);=0A=
+            break;=0A=
+=0A=
+        case WINED3DTOP_ADDSMOOTH:=0A=
+            shader_addline(buffer, "SUB arg1, const.x, %s;\n", arg1);=0A=
+            shader_addline(buffer, "MAD %s%s, arg1, %s, %s;\n", dstreg, =
dstmask, arg2, arg1);=0A=
+            break;=0A=
+=0A=
+        case WINED3DTOP_BLENDCURRENTALPHA:=0A=
+            arg0 =3D get_argreg(buffer, 0, stage, WINED3DTA_CURRENT);=0A=
+            shader_addline(buffer, "LRP %s%s, %s.a, %s, %s;\n", dstreg, =
dstmask, arg0, arg1, arg2);=0A=
+            break;=0A=
+        case WINED3DTOP_BLENDFACTORALPHA:=0A=
+            arg0 =3D get_argreg(buffer, 0, stage, WINED3DTA_TFACTOR);=0A=
+            shader_addline(buffer, "LRP %s%s, %s.a, %s, %s;\n", dstreg, =
dstmask, arg0, arg1, arg2);=0A=
+            break;=0A=
+        case WINED3DTOP_BLENDTEXTUREALPHA:=0A=
+            arg0 =3D get_argreg(buffer, 0, stage, WINED3DTA_TEXTURE);=0A=
+            shader_addline(buffer, "LRP %s%s, %s.a, %s, %s;\n", dstreg, =
dstmask, arg0, arg1, arg2);=0A=
+            break;=0A=
+        case WINED3DTOP_BLENDDIFFUSEALPHA:=0A=
+            arg0 =3D get_argreg(buffer, 0, stage, WINED3DTA_DIFFUSE);=0A=
+            shader_addline(buffer, "LRP %s%s, %s.a, %s, %s;\n", dstreg, =
dstmask, arg0, arg1, arg2);=0A=
+            break;=0A=
+=0A=
+        case WINED3DTOP_BLENDTEXTUREALPHAPM:=0A=
+            shader_addline(buffer, "SUB arg0.a, const.x, %s;\n", arg1);=0A=
+            shader_addline(buffer, "MAD %s%s, %s, arg0.a, %s;\n", =
dstreg, dstmask, arg2, arg1);=0A=
+            break;=0A=
+=0A=
+        /* D3DTOP_PREMODULATE ???? */=0A=
+=0A=
+        case WINED3DTOP_MODULATEINVALPHA_ADDCOLOR:=0A=
+            shader_addline(buffer, "SUB arg0.a, const.x, %s;\n", arg1);=0A=
+            shader_addline(buffer, "MAD %s%s, arg0.a, %s, %s;\n", =
dstreg, dstmask, arg2, arg1);=0A=
+            break;=0A=
+        case WINED3DTOP_MODULATEALPHA_ADDCOLOR:=0A=
+            shader_addline(buffer, "MAD %s%s, %s.a, %s, %s;\n", dstreg, =
dstmask, arg1, arg2, arg1);=0A=
+            break;=0A=
+        case WINED3DTOP_MODULATEINVCOLOR_ADDALPHA:=0A=
+            shader_addline(buffer, "SUB arg0, const.x, %s;\n", arg1);=0A=
+            shader_addline(buffer, "MAD %s%s, arg0, %s, %s.a;\n", =
dstreg, dstmask, arg2, arg1);=0A=
+            break;=0A=
+        case WINED3DTOP_MODULATECOLOR_ADDALPHA:=0A=
+            shader_addline(buffer, "MAD %s%s, %s, %s, %s.a;\n", dstreg, =
dstmask, arg1, arg2, arg1);=0A=
+            break;=0A=
+=0A=
+        case WINED3DTOP_DOTPRODUCT3:=0A=
+            mul =3D 4;=0A=
+            if(strcmp(dstreg, "result.color") =3D=3D 0) {=0A=
+                dstreg =3D "ret";=0A=
+                mul_final_dest =3D TRUE;=0A=
+            }=0A=
+            shader_addline(buffer, "SUB arg1, %s, const.w;\n", arg1);=0A=
+            shader_addline(buffer, "SUB arg2, %s, const.w;\n", arg2);=0A=
+            shader_addline(buffer, "DP3 %s%s, arg1, arg2;\n", dstreg, =
dstmask);=0A=
+            break;=0A=
+=0A=
+        case WINED3DTOP_MULTIPLYADD:=0A=
+            shader_addline(buffer, "MAD %s%s, %s, %s, %s;\n", dstreg, =
dstmask, arg1, arg2, arg0);=0A=
+            break;=0A=
+=0A=
+        case WINED3DTOP_LERP:=0A=
+            /* The msdn is not quite right here */=0A=
+            shader_addline(buffer, "LRP %s%s, %s, %s, %s;\n", dstreg, =
dstmask, arg0, arg1, arg2);=0A=
+            break;=0A=
+=0A=
+        case WINED3DTOP_BUMPENVMAP:=0A=
+        case WINED3DTOP_BUMPENVMAPLUMINANCE:=0A=
+            /* Those are handled in the first pass of the =
shader(generation pass 1 and 2) already */=0A=
+            break;=0A=
+=0A=
+        default:=0A=
+            FIXME("Unhandled texture op %08x\n", op);=0A=
+    }=0A=
+=0A=
+    if(mul =3D=3D 2) {=0A=
+        shader_addline(buffer, "MUL %s%s, %s, const.y;\n", =
mul_final_dest ? "result.color" : dstreg, dstmask, dstreg);=0A=
+    } else if(mul =3D=3D 4) {=0A=
+        shader_addline(buffer, "MUL %s%s, %s, const.z;\n", =
mul_final_dest ? "result.color" : dstreg, dstmask, dstreg);=0A=
+    }=0A=
+}=0A=
+=0A=
+/* The stateblock is passed for GLINFO_LOCATION */=0A=
+static GLuint gen_arbfp_ffp_shader(struct ffp_settings *settings, =
IWineD3DStateBlockImpl *stateblock) {=0A=
+    unsigned int stage;=0A=
+    SHADER_BUFFER buffer;=0A=
+    BOOL tex_read[MAX_TEXTURES] =3D {FALSE, FALSE, FALSE, FALSE, FALSE, =
FALSE, FALSE, FALSE};=0A=
+    BOOL bump_used[MAX_TEXTURES] =3D {FALSE, FALSE, FALSE, FALSE, =
FALSE, FALSE, FALSE, FALSE};=0A=
+    const char *textype;=0A=
+    const char *instr;=0A=
+    char colorcor_dst[8];=0A=
+    GLuint ret;=0A=
+    DWORD arg0, arg1, arg2;=0A=
+    BOOL tempreg_used =3D FALSE, tfactor_used =3D FALSE;=0A=
+    BOOL last =3D FALSE;=0A=
+=0A=
+    /* Find out which textures are read */=0A=
+    for(stage =3D 0; stage < MAX_TEXTURES; stage++) {=0A=
+        if(settings->op[stage].cop =3D=3D WINED3DTOP_DISABLE) break;=0A=
+        arg0 =3D settings->op[stage].carg0 & WINED3DTA_SELECTMASK;=0A=
+        arg1 =3D settings->op[stage].carg1 & WINED3DTA_SELECTMASK;=0A=
+        arg2 =3D settings->op[stage].carg2 & WINED3DTA_SELECTMASK;=0A=
+        if(arg0 =3D=3D WINED3DTA_TEXTURE) tex_read[stage] =3D TRUE;=0A=
+        if(arg1 =3D=3D WINED3DTA_TEXTURE) tex_read[stage] =3D TRUE;=0A=
+        if(arg2 =3D=3D WINED3DTA_TEXTURE) tex_read[stage] =3D TRUE;=0A=
+=0A=
+        if(settings->op[stage].cop =3D=3D WINED3DTOP_BLENDTEXTUREALPHA) =
tex_read[stage] =3D TRUE;=0A=
+        if(settings->op[stage].cop =3D=3D WINED3DTOP_BUMPENVMAP) {=0A=
+            bump_used[stage] =3D TRUE;=0A=
+            tex_read[stage] =3D TRUE;=0A=
+        }=0A=
+        if(settings->op[stage].cop =3D=3D =
WINED3DTOP_BUMPENVMAPLUMINANCE) {=0A=
+            bump_used[stage] =3D TRUE;=0A=
+            tex_read[stage] =3D TRUE;=0A=
+        }=0A=
+=0A=
+        if(arg0 =3D=3D WINED3DTA_TFACTOR || arg1 =3D=3D =
WINED3DTA_TFACTOR || arg2 =3D=3D WINED3DTA_TFACTOR) {=0A=
+            tfactor_used =3D TRUE;=0A=
+        }=0A=
+=0A=
+        if(settings->op[stage].dst =3D=3D tempreg) tempreg_used =3D =
TRUE;=0A=
+        if(arg0 =3D=3D WINED3DTA_TEMP || arg1 =3D=3D WINED3DTA_TEMP || =
arg2 =3D=3D WINED3DTA_TEMP) {=0A=
+            tempreg_used =3D TRUE;=0A=
+        }=0A=
+=0A=
+        if(settings->op[stage].aop =3D=3D WINED3DTOP_DISABLE) continue;=0A=
+        arg0 =3D settings->op[stage].aarg0 & WINED3DTA_SELECTMASK;=0A=
+        arg1 =3D settings->op[stage].aarg1 & WINED3DTA_SELECTMASK;=0A=
+        arg2 =3D settings->op[stage].aarg2 & WINED3DTA_SELECTMASK;=0A=
+        if(arg0 =3D=3D WINED3DTA_TEXTURE) tex_read[stage] =3D TRUE;=0A=
+        if(arg1 =3D=3D WINED3DTA_TEXTURE) tex_read[stage] =3D TRUE;=0A=
+        if(arg2 =3D=3D WINED3DTA_TEXTURE) tex_read[stage] =3D TRUE;=0A=
+=0A=
+        if(arg0 =3D=3D WINED3DTA_TEMP || arg1 =3D=3D WINED3DTA_TEMP || =
arg2 =3D=3D WINED3DTA_TEMP) {=0A=
+            tempreg_used =3D TRUE;=0A=
+        }=0A=
+        if(arg0 =3D=3D WINED3DTA_TFACTOR || arg1 =3D=3D =
WINED3DTA_TFACTOR || arg2 =3D=3D WINED3DTA_TFACTOR) {=0A=
+            tfactor_used =3D TRUE;=0A=
+        }=0A=
+    }=0A=
+=0A=
+    /* Shader header */=0A=
+    buffer.bsize =3D 0;=0A=
+    buffer.lineNo =3D 0;=0A=
+    buffer.newline =3D TRUE;=0A=
+    buffer.buffer =3D HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, =
SHADER_PGMSIZE);=0A=
+=0A=
+    shader_addline(&buffer, "!!ARBfp1.0\n");=0A=
+=0A=
+    switch(settings->fog) {=0A=
+        case FOG_OFF:                                                   =
      break;=0A=
+        case FOG_LINEAR: shader_addline(&buffer, "OPTION =
ARB_fog_linear;\n"); break;=0A=
+        case FOG_EXP:    shader_addline(&buffer, "OPTION =
ARB_fog_exp;\n");    break;=0A=
+        case FOG_EXP2:   shader_addline(&buffer, "OPTION =
ARB_fog_exp2;\n");   break;=0A=
+        default: FIXME("Unexpected fog setting %d\n", settings->fog);=0A=
+    }=0A=
+=0A=
+    shader_addline(&buffer, "PARAM const =3D {1, 2, 4, 0.5};\n");=0A=
+    shader_addline(&buffer, "TEMP ret;\n");=0A=
+    if(tempreg_used) shader_addline(&buffer, "TEMP tempreg;\n");=0A=
+    shader_addline(&buffer, "TEMP arg0;\n");=0A=
+    shader_addline(&buffer, "TEMP arg1;\n");=0A=
+    shader_addline(&buffer, "TEMP arg2;\n");=0A=
+    for(stage =3D 0; stage < MAX_TEXTURES; stage++) {=0A=
+        if(!tex_read[stage]) continue;=0A=
+        shader_addline(&buffer, "TEMP tex%u;\n", stage);=0A=
+        if(!bump_used[stage]) continue;=0A=
+        shader_addline(&buffer, "PARAM bumpmat%u =3D =
program.env[%u];\n", stage, ARB_FFP_CONST_BUMPMAT(stage));=0A=
+    }=0A=
+    if(tfactor_used) {=0A=
+        shader_addline(&buffer, "PARAM tfactor =3D program.env[%u];\n", =
ARB_FFP_CONST_TFACTOR);=0A=
+    }=0A=
+=0A=
+    /* Generate texture sampling instructions) */=0A=
+    for(stage =3D 0; stage < MAX_TEXTURES && settings->op[stage].cop =
!=3D WINED3DTOP_DISABLE; stage++) {=0A=
+        if(!tex_read[stage]) continue;=0A=
+=0A=
+        switch(settings->op[stage].tex_type) {=0A=
+            case tex_1d:                    textype =3D "1D";     break;=0A=
+            case tex_2d:                    textype =3D "2D";     break;=0A=
+            case tex_3d:                    textype =3D "3D";     break;=0A=
+            case tex_cube:                  textype =3D "CUBE";   break;=0A=
+            case tex_rect:                  textype =3D "RECT";   break;=0A=
+            default: textype =3D "unexpected_textype";   break;=0A=
+        }=0A=
+=0A=
+        if(settings->op[stage].projected =3D=3D proj_none) {=0A=
+            instr =3D "TEX";=0A=
+        } else if(settings->op[stage].projected =3D=3D proj_count4) {=0A=
+            instr =3D "TXP";=0A=
+        } else {=0A=
+            instr =3D "TXP";=0A=
+            ERR("Implement proj_count3\n");=0A=
+        }=0A=
+=0A=
+        if(stage > 0 &&=0A=
+           (settings->op[stage - 1].cop =3D=3D WINED3DTOP_BUMPENVMAP ||=0A=
+            settings->op[stage - 1].cop =3D=3D =
WINED3DTOP_BUMPENVMAPLUMINANCE)) {=0A=
+            shader_addline(&buffer, "SWZ arg1, bumpmat%u, x, z, 0, =
0;\n", stage - 1);=0A=
+            shader_addline(&buffer, "DP3 ret.r, arg1, tex%u;\n", stage =
- 1);=0A=
+            shader_addline(&buffer, "SWZ arg1, bumpmat%u, y, w, 0, =
0;\n", stage - 1);=0A=
+            shader_addline(&buffer, "DP3 ret.g, arg1, tex%u;\n", stage =
- 1);=0A=
+            shader_addline(&buffer, "ADD ret, ret, =
fragment.texcoord[%u];\n", stage);=0A=
+            shader_addline(&buffer, "%s tex%u, ret, texture[%u], %s;\n",=0A=
+                            instr, stage, stage, textype);=0A=
+        } else {=0A=
+            shader_addline(&buffer, "%s tex%u, fragment.texcoord[%u], =
texture[%u], %s;\n",=0A=
+                            instr, stage, stage, stage, textype);=0A=
+        }=0A=
+=0A=
+        sprintf(colorcor_dst, "tex%u", stage);=0A=
+        gen_color_correction(&buffer, colorcor_dst, ".rgba", "const.x", =
"const.y",=0A=
+                                settings->op[stage].color_correction, =
&GLINFO_LOCATION);=0A=
+    }=0A=
+=0A=
+    /* Generate the main shader */=0A=
+    for(stage =3D 0; stage < MAX_TEXTURES; stage++) {=0A=
+        if(settings->op[stage].cop =3D=3D WINED3DTOP_DISABLE) {=0A=
+            if(stage =3D=3D 0) {=0A=
+                shader_addline(&buffer, "MOV result.color, =
fragment.color.primary;\n");=0A=
+            }=0A=
+            break;=0A=
+        } else if(stage =3D=3D (MAX_TEXTURES - 1)) {=0A=
+            last =3D TRUE;=0A=
+        } else if(settings->op[stage + 1].cop =3D=3D =
WINED3DTOP_DISABLE) {=0A=
+            last =3D TRUE;=0A=
+        }=0A=
+=0A=
+        if(settings->op[stage].aop =3D=3D WINED3DTOP_DISABLE) {=0A=
+            gen_ffp_instr(&buffer, stage, TRUE, FALSE, last, =
settings->op[stage].dst,=0A=
+                          settings->op[stage].cop, =
settings->op[stage].carg0,=0A=
+                          settings->op[stage].carg1, =
settings->op[stage].carg2);=0A=
+            if(last && stage =3D=3D 0) {=0A=
+                shader_addline(&buffer, "MOV result.color.a, =
fragment.color.primary.a;\n");=0A=
+            } else if(last) {=0A=
+                shader_addline(&buffer, "MOV result.color.a, ret.a;\n");=0A=
+            } else if(stage =3D=3D 0) {=0A=
+                shader_addline(&buffer, "MOV ret.a, =
fragment.color.primary.a;\n");=0A=
+            }=0A=
+        } else if(settings->op[stage].aop   =3D=3D =
settings->op[stage].cop &&=0A=
+                  settings->op[stage].carg0 =3D=3D =
settings->op[stage].aarg0 &&=0A=
+                  settings->op[stage].carg1 =3D=3D =
settings->op[stage].aarg1 &&=0A=
+                  settings->op[stage].carg2 =3D=3D =
settings->op[stage].aarg2) {=0A=
+            gen_ffp_instr(&buffer, stage, TRUE, TRUE, last, =
settings->op[stage].dst,=0A=
+                          settings->op[stage].cop, =
settings->op[stage].carg0,=0A=
+                          settings->op[stage].carg1, =
settings->op[stage].carg2);=0A=
+        } else {=0A=
+            gen_ffp_instr(&buffer, stage, TRUE, FALSE, last, =
settings->op[stage].dst,=0A=
+                          settings->op[stage].cop, =
settings->op[stage].carg0,=0A=
+                          settings->op[stage].carg1, =
settings->op[stage].carg2);=0A=
+            gen_ffp_instr(&buffer, stage, FALSE, TRUE, last, =
settings->op[stage].dst,=0A=
+                          settings->op[stage].aop, =
settings->op[stage].aarg0,=0A=
+                          settings->op[stage].aarg1, =
settings->op[stage].aarg2);=0A=
+        }=0A=
+    }=0A=
+=0A=
+    /* TODO: Generate sRGB write color correction */=0A=
+=0A=
+    /* Footer */=0A=
+    shader_addline(&buffer, "END\n");=0A=
+=0A=
+    /* Generate the shader */=0A=
+    GL_EXTCALL(glGenProgramsARB(1, &ret));=0A=
+    GL_EXTCALL(glBindProgramARB(GL_FRAGMENT_PROGRAM_ARB, ret));=0A=
+    GL_EXTCALL(glProgramStringARB(GL_FRAGMENT_PROGRAM_ARB, =
GL_PROGRAM_FORMAT_ASCII_ARB, strlen(buffer.buffer), buffer.buffer));=0A=
+=0A=
+    if (glGetError() =3D=3D GL_INVALID_OPERATION) {=0A=
+        GLint pos;=0A=
+        glGetIntegerv(GL_PROGRAM_ERROR_POSITION_ARB, &pos);=0A=
+        FIXME("Vertex program error at position %d: %s\n", pos,=0A=
+              debugstr_a((const char =
*)glGetString(GL_PROGRAM_ERROR_STRING_ARB)));=0A=
+    }=0A=
+    return ret;=0A=
+}=0A=
+=0A=
+static void fragment_prog_arbfp(DWORD state, IWineD3DStateBlockImpl =
*stateblock, WineD3DContext *context) {=0A=
+    IWineD3DDeviceImpl *device =3D stateblock->wineD3DDevice;=0A=
+    struct shader_arb_priv *priv =3D (struct shader_arb_priv *) =
device->fragment_priv;=0A=
+    BOOL use_pshader =3D use_ps(device);=0A=
+    BOOL use_vshader =3D use_vs(device);=0A=
+    struct ffp_settings settings;=0A=
+    struct arbfp_ffp_desc *desc;=0A=
+    unsigned int i;=0A=
+=0A=
+    if(isStateDirty(context, STATE_RENDER(WINED3DRS_FOGENABLE))) return;=0A=
+=0A=
+    if(use_pshader) {=0A=
+        IWineD3DPixelShader_CompileShader(stateblock->pixelShader);=0A=
+    } else {=0A=
+        /* Find or create a shader implementing the fixed function =
pipeline settings, then activate it */=0A=
+        gen_ffp_op(stateblock, &settings, FALSE);=0A=
+        desc =3D (struct arbfp_ffp_desc *) =
find_ffp_shader(priv->fragment_shaders, &settings);=0A=
+        if(!desc) {=0A=
+            desc =3D HeapAlloc(GetProcessHeap(), 0, sizeof(*desc));=0A=
+            if(!desc) {=0A=
+                ERR("Out of memory\n");=0A=
+                return;=0A=
+            }=0A=
+            desc->num_textures_used =3D 0;=0A=
+            for(i =3D 0; i < GL_LIMITS(texture_stages); i++) {=0A=
+                if(settings.op[i].cop =3D=3D WINED3DTOP_DISABLE) break;=0A=
+                desc->num_textures_used =3D i;=0A=
+            }=0A=
+=0A=
+            memcpy(&desc->parent.settings, &settings, sizeof(settings));=0A=
+            desc->shader =3D gen_arbfp_ffp_shader(&settings, =
stateblock);=0A=
+            add_ffp_shader(priv->fragment_shaders, &desc->parent);=0A=
+            TRACE("Allocated fixed function replacement shader =
descriptor %p\n", desc);=0A=
+        }=0A=
+=0A=
+        /* Now activate the replacement program. =
GL_FRAGMENT_PROGRAM_ARB is already active(however, note the=0A=
+         * comment above the shader_select call below). If e.g. GLSL is =
active, the shader_select call will=0A=
+         * deactivate it.=0A=
+         */=0A=
+        GL_EXTCALL(glBindProgramARB(GL_FRAGMENT_PROGRAM_ARB, =
desc->shader));=0A=
+        checkGLcall("glBindProgramARB(GL_FRAGMENT_PROGRAM_ARB, =
desc->shader)");=0A=
+=0A=
+        if(device->shader_backend =3D=3D &arb_program_shader_backend && =
context->last_was_pshader) {=0A=
+            /* Reload fixed function constants since they collide with =
the pixel shader constants */=0A=
+            for(i =3D 0; i < MAX_TEXTURES; i++) {=0A=
+                set_bumpmat_arbfp(STATE_TEXTURESTAGE(i, =
WINED3DTSS_BUMPENVMAT00), stateblock, context);=0A=
+            }=0A=
+            =
state_texfactor_arbfp(STATE_RENDER(WINED3DRS_TEXTUREFACTOR), stateblock, =
context);=0A=
+        }=0A=
+    }=0A=
+=0A=
+    /* Finally, select the shader. If a pixel shader is used, it will =
be set and enabled by the shader backend.=0A=
+     * If this shader backend is arbfp(most likely), then it will =
simply overwrite the last fixed function replace-=0A=
+     * ment shader. If the shader backend is not ARB, it currently is =
important that the opengl implementation=0A=
+     * type overwrites GL_ARB_fragment_program. This is currently the =
case with GLSL. If we really want to use=0A=
+     * atifs or nvrc pixel shaders with arb fragment programs we'd have =
to disable GL_FRAGMENT_PROGRAM_ARB here=0A=
+     *=0A=
+     * Don't call shader_select if the vertex shader is dirty, because =
some shader backends(GLSL) need both shaders=0A=
+     * to be compiled before activating them(needs some cleanups in the =
shader backend interface)=0A=
+     */=0A=
+    if(!isStateDirty(context, =
device->StateTable[STATE_VSHADER].representative)) {=0A=
+        device->shader_backend->shader_select((IWineD3DDevice =
*)stateblock->wineD3DDevice, use_pshader, use_vshader);=0A=
+=0A=
+        if (!isStateDirty(context, STATE_VERTEXSHADERCONSTANT) && =
(use_vshader || use_pshader)) {=0A=
+            =
device->StateTable[STATE_VERTEXSHADERCONSTANT].apply(STATE_VERTEXSHADERCO=
NSTANT, stateblock, context);=0A=
+        }=0A=
+    }=0A=
+    context->last_was_pshader =3D use_pshader;=0A=
+    if(use_pshader) {=0A=
+        =
device->StateTable[STATE_PIXELSHADERCONSTANT].apply(STATE_PIXELSHADERCONS=
TANT, stateblock, context);=0A=
+    }=0A=
+}=0A=
+=0A=
+/* We can't link the fog states to the fragment state directly since =
the vertex pipeline links them=0A=
+ * to FOGENABLE. A different linking in different pipeline parts can't =
be expressed in the combined=0A=
+ * state table, so we need to handle that with a forwarding function. =
The other invisible side effect=0A=
+ * is that changing the fog start and fog end(which links to FOGENABLE =
in vertex) results in the=0A=
+ * fragment_prog_arbfp function being called because FOGENABLE is =
dirty, which calls this function here=0A=
+ */=0A=
+static void state_arbfp_fog(DWORD state, IWineD3DStateBlockImpl =
*stateblock, WineD3DContext *context) {=0A=
+    if(!isStateDirty(context, STATE_PIXELSHADER)) {=0A=
+        fragment_prog_arbfp(state, stateblock, context);=0A=
+    }=0A=
+}=0A=
+=0A=
+#undef GLINFO_LOCATION=0A=
+=0A=
+static const struct StateEntryTemplate arbfp_fragmentstate_template[] =
=3D {=0A=
+    {STATE_RENDER(WINED3DRS_TEXTUREFACTOR),               { =
STATE_RENDER(WINED3DRS_TEXTUREFACTOR),              =
state_texfactor_arbfp   }, 0                               },=0A=
+    {STATE_TEXTURESTAGE(0, WINED3DTSS_COLOROP),           { =
STATE_PIXELSHADER,                                  fragment_prog_arbfp  =
   }, 0                               },=0A=
+    {STATE_TEXTURESTAGE(0, WINED3DTSS_COLORARG1),         { =
STATE_PIXELSHADER,                                  fragment_prog_arbfp  =
   }, 0                               },=0A=
+    {STATE_TEXTURESTAGE(0, WINED3DTSS_COLORARG2),         { =
STATE_PIXELSHADER,                                  fragment_prog_arbfp  =
   }, 0                               },=0A=
+    {STATE_TEXTURESTAGE(0, WINED3DTSS_COLORARG0),         { =
STATE_PIXELSHADER,                                  fragment_prog_arbfp  =
   }, 0                               },=0A=
+    {STATE_TEXTURESTAGE(0, WINED3DTSS_ALPHAOP),           { =
STATE_PIXELSHADER,                                  fragment_prog_arbfp  =
   }, 0                               },=0A=
+    {STATE_TEXTURESTAGE(0, WINED3DTSS_ALPHAARG1),         { =
STATE_PIXELSHADER,                                  fragment_prog_arbfp  =
   }, 0                               },=0A=
+    {STATE_TEXTURESTAGE(0, WINED3DTSS_ALPHAARG2),         { =
STATE_PIXELSHADER,                                  fragment_prog_arbfp  =
   }, 0                               },=0A=
+    {STATE_TEXTURESTAGE(0, WINED3DTSS_ALPHAARG0),         { =
STATE_PIXELSHADER,                                  fragment_prog_arbfp  =
   }, 0                               },=0A=
+    {STATE_TEXTURESTAGE(0, WINED3DTSS_RESULTARG),         { =
STATE_PIXELSHADER,                                  fragment_prog_arbfp  =
   }, 0                               },=0A=
+    {STATE_TEXTURESTAGE(0, WINED3DTSS_BUMPENVMAT00),      { =
STATE_TEXTURESTAGE(0, WINED3DTSS_BUMPENVMAT00),     set_bumpmat_arbfp    =
   }, 0                               },=0A=
+    {STATE_TEXTURESTAGE(0, WINED3DTSS_BUMPENVMAT01),      { =
STATE_TEXTURESTAGE(0, WINED3DTSS_BUMPENVMAT00),     set_bumpmat_arbfp    =
   }, 0                               },=0A=
+    {STATE_TEXTURESTAGE(0, WINED3DTSS_BUMPENVMAT10),      { =
STATE_TEXTURESTAGE(0, WINED3DTSS_BUMPENVMAT00),     set_bumpmat_arbfp    =
   }, 0                               },=0A=
+    {STATE_TEXTURESTAGE(0, WINED3DTSS_BUMPENVMAT11),      { =
STATE_TEXTURESTAGE(0, WINED3DTSS_BUMPENVMAT00),     set_bumpmat_arbfp    =
   }, 0                               },=0A=
+    {STATE_TEXTURESTAGE(1, WINED3DTSS_COLOROP),           { =
STATE_PIXELSHADER,                                  fragment_prog_arbfp  =
   }, 0                               },=0A=
+    {STATE_TEXTURESTAGE(1, WINED3DTSS_COLORARG1),         { =
STATE_PIXELSHADER,                                  fragment_prog_arbfp  =
   }, 0                               },=0A=
+    {STATE_TEXTURESTAGE(1, WINED3DTSS_COLORARG2),         { =
STATE_PIXELSHADER,                                  fragment_prog_arbfp  =
   }, 0                               },=0A=
+    {STATE_TEXTURESTAGE(1, WINED3DTSS_COLORARG0),         { =
STATE_PIXELSHADER,                                  fragment_prog_arbfp  =
   }, 0                               },=0A=
+    {STATE_TEXTURESTAGE(1, WINED3DTSS_ALPHAOP),           { =
STATE_PIXELSHADER,                                  fragment_prog_arbfp  =
   }, 0                               },=0A=
+    {STATE_TEXTURESTAGE(1, WINED3DTSS_ALPHAARG1),         { =
STATE_PIXELSHADER,                                  fragment_prog_arbfp  =
   }, 0                               },=0A=
+    {STATE_TEXTURESTAGE(1, WINED3DTSS_ALPHAARG2),         { =
STATE_PIXELSHADER,                                  fragment_prog_arbfp  =
   }, 0                               },=0A=
+    {STATE_TEXTURESTAGE(1, WINED3DTSS_ALPHAARG0),         { =
STATE_PIXELSHADER,                                  fragment_prog_arbfp  =
   }, 0                               },=0A=
+    {STATE_TEXTURESTAGE(1, WINED3DTSS_RESULTARG),         { =
STATE_PIXELSHADER,                                  fragment_prog_arbfp  =
   }, 0                               },=0A=
+    {STATE_TEXTURESTAGE(1, WINED3DTSS_BUMPENVMAT00),      { =
STATE_TEXTURESTAGE(1, WINED3DTSS_BUMPENVMAT00),     set_bumpmat_arbfp    =
   }, 0                               },=0A=
+    {STATE_TEXTURESTAGE(1, WINED3DTSS_BUMPENVMAT01),      { =
STATE_TEXTURESTAGE(1, WINED3DTSS_BUMPENVMAT00),     set_bumpmat_arbfp    =
   }, 0                               },=0A=
+    {STATE_TEXTURESTAGE(1, WINED3DTSS_BUMPENVMAT10),      { =
STATE_TEXTURESTAGE(1, WINED3DTSS_BUMPENVMAT00),     set_bumpmat_arbfp    =
   }, 0                               },=0A=
+    {STATE_TEXTURESTAGE(1, WINED3DTSS_BUMPENVMAT11),      { =
STATE_TEXTURESTAGE(1, WINED3DTSS_BUMPENVMAT00),     set_bumpmat_arbfp    =
   }, 0                               },=0A=
+    {STATE_TEXTURESTAGE(2, WINED3DTSS_COLOROP),           { =
STATE_PIXELSHADER,                                  fragment_prog_arbfp  =
   }, 0                               },=0A=
+    {STATE_TEXTURESTAGE(2, WINED3DTSS_COLORARG1),         { =
STATE_PIXELSHADER,                                  fragment_prog_arbfp  =
   }, 0                               },=0A=
+    {STATE_TEXTURESTAGE(2, WINED3DTSS_COLORARG2),         { =
STATE_PIXELSHADER,                                  fragment_prog_arbfp  =
   }, 0                               },=0A=
+    {STATE_TEXTURESTAGE(2, WINED3DTSS_COLORARG0),         { =
STATE_PIXELSHADER,                                  fragment_prog_arbfp  =
   }, 0                               },=0A=
+    {STATE_TEXTURESTAGE(2, WINED3DTSS_ALPHAOP),           { =
STATE_PIXELSHADER,                                  fragment_prog_arbfp  =
   }, 0                               },=0A=
+    {STATE_TEXTURESTAGE(2, WINED3DTSS_ALPHAARG1),         { =
STATE_PIXELSHADER,                                  fragment_prog_arbfp  =
   }, 0                               },=0A=
+    {STATE_TEXTURESTAGE(2, WINED3DTSS_ALPHAARG2),         { =
STATE_PIXELSHADER,                                  fragment_prog_arbfp  =
   }, 0                               },=0A=
+    {STATE_TEXTURESTAGE(2, WINED3DTSS_ALPHAARG0),         { =
STATE_PIXELSHADER,                                  fragment_prog_arbfp  =
   }, 0                               },=0A=
+    {STATE_TEXTURESTAGE(2, WINED3DTSS_RESULTARG),         { =
STATE_PIXELSHADER,                                  fragment_prog_arbfp  =
   }, 0                               },=0A=
+    {STATE_TEXTURESTAGE(2, WINED3DTSS_BUMPENVMAT00),      { =
STATE_TEXTURESTAGE(2, WINED3DTSS_BUMPENVMAT00),     set_bumpmat_arbfp    =
   }, 0                               },=0A=
+    {STATE_TEXTURESTAGE(2, WINED3DTSS_BUMPENVMAT01),      { =
STATE_TEXTURESTAGE(2, WINED3DTSS_BUMPENVMAT00),     set_bumpmat_arbfp    =
   }, 0                               },=0A=
+    {STATE_TEXTURESTAGE(2, WINED3DTSS_BUMPENVMAT10),      { =
STATE_TEXTURESTAGE(2, WINED3DTSS_BUMPENVMAT00),     set_bumpmat_arbfp    =
   }, 0                               },=0A=
+    {STATE_TEXTURESTAGE(2, WINED3DTSS_BUMPENVMAT11),      { =
STATE_TEXTURESTAGE(2, WINED3DTSS_BUMPENVMAT00),     set_bumpmat_arbfp    =
   }, 0                               },=0A=
+    {STATE_TEXTURESTAGE(3, WINED3DTSS_COLOROP),           { =
STATE_PIXELSHADER,                                  fragment_prog_arbfp  =
   }, 0                               },=0A=
+    {STATE_TEXTURESTAGE(3, WINED3DTSS_COLORARG1),         { =
STATE_PIXELSHADER,                                  fragment_prog_arbfp  =
   }, 0                               },=0A=
+    {STATE_TEXTURESTAGE(3, WINED3DTSS_COLORARG2),         { =
STATE_PIXELSHADER,                                  fragment_prog_arbfp  =
   }, 0                               },=0A=
+    {STATE_TEXTURESTAGE(3, WINED3DTSS_COLORARG0),         { =
STATE_PIXELSHADER,                                  fragment_prog_arbfp  =
   }, 0                               },=0A=
+    {STATE_TEXTURESTAGE(3, WINED3DTSS_ALPHAOP),           { =
STATE_PIXELSHADER,                                  fragment_prog_arbfp  =
   }, 0                               },=0A=
+    {STATE_TEXTURESTAGE(3, WINED3DTSS_ALPHAARG1),         { =
STATE_PIXELSHADER,                                  fragment_prog_arbfp  =
   }, 0                               },=0A=
+    {STATE_TEXTURESTAGE(3, WINED3DTSS_ALPHAARG2),         { =
STATE_PIXELSHADER,                                  fragment_prog_arbfp  =
   }, 0                               },=0A=
+    {STATE_TEXTURESTAGE(3, WINED3DTSS_ALPHAARG0),         { =
STATE_PIXELSHADER,                                  fragment_prog_arbfp  =
   }, 0                               },=0A=
+    {STATE_TEXTURESTAGE(3, WINED3DTSS_RESULTARG),         { =
STATE_PIXELSHADER,                                  fragment_prog_arbfp  =
   }, 0                               },=0A=
+    {STATE_TEXTURESTAGE(3, WINED3DTSS_BUMPENVMAT00),      { =
STATE_TEXTURESTAGE(3, WINED3DTSS_BUMPENVMAT00),     set_bumpmat_arbfp    =
   }, 0                               },=0A=
+    {STATE_TEXTURESTAGE(3, WINED3DTSS_BUMPENVMAT01),      { =
STATE_TEXTURESTAGE(3, WINED3DTSS_BUMPENVMAT00),     set_bumpmat_arbfp    =
   }, 0                               },=0A=
+    {STATE_TEXTURESTAGE(3, WINED3DTSS_BUMPENVMAT10),      { =
STATE_TEXTURESTAGE(3, WINED3DTSS_BUMPENVMAT00),     set_bumpmat_arbfp    =
   }, 0                               },=0A=
+    {STATE_TEXTURESTAGE(3, WINED3DTSS_BUMPENVMAT11),      { =
STATE_TEXTURESTAGE(3, WINED3DTSS_BUMPENVMAT00),     set_bumpmat_arbfp    =
   }, 0                               },=0A=
+    {STATE_TEXTURESTAGE(4, WINED3DTSS_COLOROP),           { =
STATE_PIXELSHADER,                                  fragment_prog_arbfp  =
   }, 0                               },=0A=
+    {STATE_TEXTURESTAGE(4, WINED3DTSS_COLORARG1),         { =
STATE_PIXELSHADER,                                  fragment_prog_arbfp  =
   }, 0                               },=0A=
+    {STATE_TEXTURESTAGE(4, WINED3DTSS_COLORARG2),         { =
STATE_PIXELSHADER,                                  fragment_prog_arbfp  =
   }, 0                               },=0A=
+    {STATE_TEXTURESTAGE(4, WINED3DTSS_COLORARG0),         { =
STATE_PIXELSHADER,                                  fragment_prog_arbfp  =
   }, 0                               },=0A=
+    {STATE_TEXTURESTAGE(4, WINED3DTSS_ALPHAOP),           { =
STATE_PIXELSHADER,                                  fragment_prog_arbfp  =
   }, 0                               },=0A=
+    {STATE_TEXTURESTAGE(4, WINED3DTSS_ALPHAARG1),         { =
STATE_PIXELSHADER,                                  fragment_prog_arbfp  =
   }, 0                               },=0A=
+    {STATE_TEXTURESTAGE(4, WINED3DTSS_ALPHAARG2),         { =
STATE_PIXELSHADER,                                  fragment_prog_arbfp  =
   }, 0                               },=0A=
+    {STATE_TEXTURESTAGE(4, WINED3DTSS_ALPHAARG0),         { =
STATE_PIXELSHADER,                                  fragment_prog_arbfp  =
   }, 0                               },=0A=
+    {STATE_TEXTURESTAGE(4, WINED3DTSS_RESULTARG),         { =
STATE_PIXELSHADER,                                  fragment_prog_arbfp  =
   }, 0                               },=0A=
+    {STATE_TEXTURESTAGE(4, WINED3DTSS_BUMPENVMAT00),      { =
STATE_TEXTURESTAGE(4, WINED3DTSS_BUMPENVMAT00),     set_bumpmat_arbfp    =
   }, 0                               },=0A=
+    {STATE_TEXTURESTAGE(4, WINED3DTSS_BUMPENVMAT01),      { =
STATE_TEXTURESTAGE(4, WINED3DTSS_BUMPENVMAT00),     set_bumpmat_arbfp    =
   }, 0                               },=0A=
+    {STATE_TEXTURESTAGE(4, WINED3DTSS_BUMPENVMAT10),      { =
STATE_TEXTURESTAGE(4, WINED3DTSS_BUMPENVMAT00),     set_bumpmat_arbfp    =
   }, 0                               },=0A=
+    {STATE_TEXTURESTAGE(4, WINED3DTSS_BUMPENVMAT11),      { =
STATE_TEXTURESTAGE(4, WINED3DTSS_BUMPENVMAT00),     set_bumpmat_arbfp    =
   }, 0                               },=0A=
+    {STATE_TEXTURESTAGE(5, WINED3DTSS_COLOROP),           { =
STATE_PIXELSHADER,                                  fragment_prog_arbfp  =
   }, 0                               },=0A=
+    {STATE_TEXTURESTAGE(5, WINED3DTSS_COLORARG1),         { =
STATE_PIXELSHADER,                                  fragment_prog_arbfp  =
   }, 0                               },=0A=
+    {STATE_TEXTURESTAGE(5, WINED3DTSS_COLORARG2),         { =
STATE_PIXELSHADER,                                  fragment_prog_arbfp  =
   }, 0                               },=0A=
+    {STATE_TEXTURESTAGE(5, WINED3DTSS_COLORARG0),         { =
STATE_PIXELSHADER,                                  fragment_prog_arbfp  =
   }, 0                               },=0A=
+    {STATE_TEXTURESTAGE(5, WINED3DTSS_ALPHAOP),           { =
STATE_PIXELSHADER,                                  fragment_prog_arbfp  =
   }, 0                               },=0A=
+    {STATE_TEXTURESTAGE(5, WINED3DTSS_ALPHAARG1),         { =
STATE_PIXELSHADER,                                  fragment_prog_arbfp  =
   }, 0                               },=0A=
+    {STATE_TEXTURESTAGE(5, WINED3DTSS_ALPHAARG2),         { =
STATE_PIXELSHADER,                                  fragment_prog_arbfp  =
   }, 0                               },=0A=
+    {STATE_TEXTURESTAGE(5, WINED3DTSS_ALPHAARG0),         { =
STATE_PIXELSHADER,                                  fragment_prog_arbfp  =
   }, 0                               },=0A=
+    {STATE_TEXTURESTAGE(5, WINED3DTSS_RESULTARG),         { =
STATE_PIXELSHADER,                                  fragment_prog_arbfp  =
   }, 0                               },=0A=
+    {STATE_TEXTURESTAGE(5, WINED3DTSS_BUMPENVMAT00),      { =
STATE_TEXTURESTAGE(5, WINED3DTSS_BUMPENVMAT00),     set_bumpmat_arbfp    =
   }, 0                               },=0A=
+    {STATE_TEXTURESTAGE(5, WINED3DTSS_BUMPENVMAT01),      { =
STATE_TEXTURESTAGE(5, WINED3DTSS_BUMPENVMAT00),     set_bumpmat_arbfp    =
   }, 0                               },=0A=
+    {STATE_TEXTURESTAGE(5, WINED3DTSS_BUMPENVMAT10),      { =
STATE_TEXTURESTAGE(5, WINED3DTSS_BUMPENVMAT00),     set_bumpmat_arbfp    =
   }, 0                               },=0A=
+    {STATE_TEXTURESTAGE(5, WINED3DTSS_BUMPENVMAT11),      { =
STATE_TEXTURESTAGE(5, WINED3DTSS_BUMPENVMAT00),     set_bumpmat_arbfp    =
   }, 0                               },=0A=
+    {STATE_TEXTURESTAGE(6, WINED3DTSS_COLOROP),           { =
STATE_PIXELSHADER,                                  fragment_prog_arbfp  =
   }, 0                               },=0A=
+    {STATE_TEXTURESTAGE(6, WINED3DTSS_COLORARG1),         { =
STATE_PIXELSHADER,                                  fragment_prog_arbfp  =
   }, 0                               },=0A=
+    {STATE_TEXTURESTAGE(6, WINED3DTSS_COLORARG2),         { =
STATE_PIXELSHADER,                                  fragment_prog_arbfp  =
   }, 0                               },=0A=
+    {STATE_TEXTURESTAGE(6, WINED3DTSS_COLORARG0),         { =
STATE_PIXELSHADER,                                  fragment_prog_arbfp  =
   }, 0                               },=0A=
+    {STATE_TEXTURESTAGE(6, WINED3DTSS_ALPHAOP),           { =
STATE_PIXELSHADER,                                  fragment_prog_arbfp  =
   }, 0                               },=0A=
+    {STATE_TEXTURESTAGE(6, WINED3DTSS_ALPHAARG1),         { =
STATE_PIXELSHADER,                                  fragment_prog_arbfp  =
   }, 0                               },=0A=
+    {STATE_TEXTURESTAGE(6, WINED3DTSS_ALPHAARG2),         { =
STATE_PIXELSHADER,                                  fragment_prog_arbfp  =
   }, 0                               },=0A=
+    {STATE_TEXTURESTAGE(6, WINED3DTSS_ALPHAARG0),         { =
STATE_PIXELSHADER,                                  fragment_prog_arbfp  =
   }, 0                               },=0A=
+    {STATE_TEXTURESTAGE(6, WINED3DTSS_RESULTARG),         { =
STATE_PIXELSHADER,                                  fragment_prog_arbfp  =
   }, 0                               },=0A=
+    {STATE_TEXTURESTAGE(6, WINED3DTSS_BUMPENVMAT00),      { =
STATE_TEXTURESTAGE(6, WINED3DTSS_BUMPENVMAT00),     set_bumpmat_arbfp    =
   }, 0                               },=0A=
+    {STATE_TEXTURESTAGE(6, WINED3DTSS_BUMPENVMAT01),      { =
STATE_TEXTURESTAGE(6, WINED3DTSS_BUMPENVMAT00),     set_bumpmat_arbfp    =
   }, 0                               },=0A=
+    {STATE_TEXTURESTAGE(6, WINED3DTSS_BUMPENVMAT10),      { =
STATE_TEXTURESTAGE(6, WINED3DTSS_BUMPENVMAT00),     set_bumpmat_arbfp    =
   }, 0                               },=0A=
+    {STATE_TEXTURESTAGE(6, WINED3DTSS_BUMPENVMAT11),      { =
STATE_TEXTURESTAGE(6, WINED3DTSS_BUMPENVMAT00),     set_bumpmat_arbfp    =
   }, 0                               },=0A=
+    {STATE_TEXTURESTAGE(7, WINED3DTSS_COLOROP),           { =
STATE_PIXELSHADER,                                  fragment_prog_arbfp  =
   }, 0                               },=0A=
+    {STATE_TEXTURESTAGE(7, WINED3DTSS_COLORARG1),         { =
STATE_PIXELSHADER,                                  fragment_prog_arbfp  =
   }, 0                               },=0A=
+    {STATE_TEXTURESTAGE(7, WINED3DTSS_COLORARG2),         { =
STATE_PIXELSHADER,                                  fragment_prog_arbfp  =
   }, 0                               },=0A=
+    {STATE_TEXTURESTAGE(7, WINED3DTSS_COLORARG0),         { =
STATE_PIXELSHADER,                                  fragment_prog_arbfp  =
   }, 0                               },=0A=
+    {STATE_TEXTURESTAGE(7, WINED3DTSS_ALPHAOP),           { =
STATE_PIXELSHADER,                                  fragment_prog_arbfp  =
   }, 0                               },=0A=
+    {STATE_TEXTURESTAGE(7, WINED3DTSS_ALPHAARG1),         { =
STATE_PIXELSHADER,                                  fragment_prog_arbfp  =
   }, 0                               },=0A=
+    {STATE_TEXTURESTAGE(7, WINED3DTSS_ALPHAARG2),         { =
STATE_PIXELSHADER,                                  fragment_prog_arbfp  =
   }, 0                               },=0A=
+    {STATE_TEXTURESTAGE(7, WINED3DTSS_ALPHAARG0),         { =
STATE_PIXELSHADER,                                  fragment_prog_arbfp  =
   }, 0                               },=0A=
+    {STATE_TEXTURESTAGE(7, WINED3DTSS_RESULTARG),         { =
STATE_PIXELSHADER,                                  fragment_prog_arbfp  =
   }, 0                               },=0A=
+    {STATE_TEXTURESTAGE(7, WINED3DTSS_BUMPENVMAT00),      { =
STATE_TEXTURESTAGE(7, WINED3DTSS_BUMPENVMAT00),     set_bumpmat_arbfp    =
   }, 0                               },=0A=
+    {STATE_TEXTURESTAGE(7, WINED3DTSS_BUMPENVMAT01),      { =
STATE_TEXTURESTAGE(7, WINED3DTSS_BUMPENVMAT00),     set_bumpmat_arbfp    =
   }, 0                               },=0A=
+    {STATE_TEXTURESTAGE(7, WINED3DTSS_BUMPENVMAT10),      { =
STATE_TEXTURESTAGE(7, WINED3DTSS_BUMPENVMAT00),     set_bumpmat_arbfp    =
   }, 0                               },=0A=
+    {STATE_TEXTURESTAGE(7, WINED3DTSS_BUMPENVMAT11),      { =
STATE_TEXTURESTAGE(7, WINED3DTSS_BUMPENVMAT00),     set_bumpmat_arbfp    =
   }, 0                               },=0A=
+    { STATE_SAMPLER(0),                                   { =
STATE_SAMPLER(0),                                   sampler_texdim       =
   }, 0                               },=0A=
+    { STATE_SAMPLER(1),                                   { =
STATE_SAMPLER(1),                                   sampler_texdim       =
   }, 0                               },=0A=
+    { STATE_SAMPLER(2),                                   { =
STATE_SAMPLER(2),                                   sampler_texdim       =
   }, 0                               },=0A=
+    { STATE_SAMPLER(3),                                   { =
STATE_SAMPLER(3),                                   sampler_texdim       =
   }, 0                               },=0A=
+    { STATE_SAMPLER(4),                                   { =
STATE_SAMPLER(4),                                   sampler_texdim       =
   }, 0                               },=0A=
+    { STATE_SAMPLER(5),                                   { =
STATE_SAMPLER(5),                                   sampler_texdim       =
   }, 0                               },=0A=
+    { STATE_SAMPLER(6),                                   { =
STATE_SAMPLER(6),                                   sampler_texdim       =
   }, 0                               },=0A=
+    { STATE_SAMPLER(7),                                   { =
STATE_SAMPLER(7),                                   sampler_texdim       =
   }, 0                               },=0A=
+    { STATE_PIXELSHADER,                                  { =
STATE_PIXELSHADER,                                  fragment_prog_arbfp  =
   }, 0                               },=0A=
+    { STATE_RENDER(WINED3DRS_FOGENABLE),                  { =
STATE_RENDER(WINED3DRS_FOGENABLE),                  state_arbfp_fog      =
   }, 0                               },=0A=
+    { STATE_RENDER(WINED3DRS_FOGTABLEMODE),               { =
STATE_RENDER(WINED3DRS_FOGENABLE),                  state_arbfp_fog      =
   }, 0                               },=0A=
+    { STATE_RENDER(WINED3DRS_FOGVERTEXMODE),              { =
STATE_RENDER(WINED3DRS_FOGENABLE),                  state_arbfp_fog      =
   }, 0                               },=0A=
+    {0 /* Terminate */,                                   { 0,          =
                                        0                       }, 0     =
                          },=0A=
+};=0A=
+=0A=
+const struct fragment_pipeline arbfp_fragment_pipeline =3D {=0A=
+    arbfp_enable,=0A=
+    arbfp_get_caps,=0A=
+    arbfp_alloc,=0A=
+    arbfp_free,=0A=
+    arbfp_fragmentstate_template=0A=
+};=0A=
diff --git a/dlls/wined3d/device.c b/dlls/wined3d/device.c=0A=
index 0a6bd2b..1531379 100644=0A=
--- a/dlls/wined3d/device.c=0A=
+++ b/dlls/wined3d/device.c=0A=
@@ -2234,8 +2234,8 @@ err_out:=0A=
         IWineD3DStateBlock_Release((IWineD3DStateBlock *) =
This->stateBlock);=0A=
         This->stateBlock =3D NULL;=0A=
     }=0A=
-    This->shader_backend->shader_free_private(iface);=0A=
     This->frag_pipe->free_private(iface);=0A=
+    This->shader_backend->shader_free_private(iface);=0A=
     return hr;=0A=
 }=0A=
 =0A=
@@ -2324,8 +2324,8 @@ static HRESULT WINAPI =
IWineD3DDeviceImpl_Uninit3D(IWineD3DDevice *iface, D3DCB_D=0A=
     }=0A=
 =0A=
     /* Destroy the shader backend. Note that this has to happen after =
all shaders are destroyed. */=0A=
-    This->shader_backend->shader_free_private(iface);=0A=
     This->frag_pipe->free_private(iface);=0A=
+    This->shader_backend->shader_free_private(iface);=0A=
 =0A=
     /* Release the buffers (with sanity checks)*/=0A=
     TRACE("Releasing the depth stencil buffer at %p\n", =
This->stencilBufferTarget);=0A=
@@ -7248,8 +7248,8 @@ static HRESULT WINAPI =
IWineD3DDeviceImpl_Reset(IWineD3DDevice* iface, WINED3DPRE=0A=
         This->depth_blt_rb_w =3D 0;=0A=
         This->depth_blt_rb_h =3D 0;=0A=
     }=0A=
-    This->shader_backend->shader_free_private(iface);=0A=
     This->frag_pipe->free_private(iface);=0A=
+    This->shader_backend->shader_free_private(iface);=0A=
 =0A=
     for (i =3D 0; i < GL_LIMITS(textures); i++) {=0A=
         /* Textures are recreated below */=0A=
diff --git a/dlls/wined3d/directx.c b/dlls/wined3d/directx.c=0A=
index a95c778..9cbb406 100644=0A=
--- a/dlls/wined3d/directx.c=0A=
+++ b/dlls/wined3d/directx.c=0A=
@@ -1963,6 +1963,7 @@ static HRESULT WINAPI =
IWineD3DImpl_CheckDeviceType(IWineD3D *iface, UINT Adapter=0A=
 /* Check if we support bumpmapping for a format */=0A=
 static BOOL CheckBumpMapCapability(UINT Adapter, WINED3DFORMAT =
CheckFormat)=0A=
 {=0A=
+    /* TODO: Check this in the fixed function pipeline backend */=0A=
     if(GL_SUPPORT(NV_REGISTER_COMBINERS) && =
GL_SUPPORT(NV_TEXTURE_SHADER2)) {=0A=
         switch (CheckFormat) {=0A=
             case WINED3DFMT_V8U8:=0A=
@@ -1984,6 +1985,20 @@ static BOOL CheckBumpMapCapability(UINT Adapter, =
WINED3DFORMAT CheckFormat)=0A=
                 return FALSE;=0A=
         }=0A=
     }=0A=
+    if(GL_SUPPORT(ARB_FRAGMENT_PROGRAM)) {=0A=
+        switch (CheckFormat) {=0A=
+            case WINED3DFMT_V8U8:=0A=
+            case WINED3DFMT_V16U16:=0A=
+            case WINED3DFMT_L6V5U5:=0A=
+            case WINED3DFMT_X8L8V8U8:=0A=
+            case WINED3DFMT_Q8W8V8U8:=0A=
+                TRACE_(d3d_caps)("[OK]\n");=0A=
+                return TRUE;=0A=
+            default:=0A=
+                TRACE_(d3d_caps)("[FAILED]\n");=0A=
+                return FALSE;=0A=
+        }=0A=
+    }=0A=
     TRACE_(d3d_caps)("[FAILED]\n");=0A=
     return FALSE;=0A=
 }=0A=
@@ -2902,7 +2917,9 @@ static const struct fragment_pipeline =
*select_fragment_implementation(UINT Adapt=0A=
     int ps_selected_mode;=0A=
 =0A=
     select_shader_mode(&GLINFO_LOCATION, DeviceType, &ps_selected_mode, =
&vs_selected_mode);=0A=
-    if(ps_selected_mode =3D=3D SHADER_ATI) {=0A=
+    if((ps_selected_mode =3D=3D SHADER_ARB || ps_selected_mode =3D=3D =
SHADER_GLSL) && GL_SUPPORT(ARB_FRAGMENT_PROGRAM)) {=0A=
+        return &arbfp_fragment_pipeline;=0A=
+    } else if(ps_selected_mode =3D=3D SHADER_ATI) {=0A=
         return &atifs_fragment_pipeline;=0A=
     } else if(GL_SUPPORT(NV_REGISTER_COMBINERS) && =
GL_SUPPORT(NV_TEXTURE_SHADER2)) {=0A=
         return &nvts_fragment_pipeline;=0A=
diff --git a/dlls/wined3d/wined3d_private.h =
b/dlls/wined3d/wined3d_private.h=0A=
index 5b19acc..7ba6617 100644=0A=
--- a/dlls/wined3d/wined3d_private.h=0A=
+++ b/dlls/wined3d/wined3d_private.h=0A=
@@ -267,6 +267,8 @@ struct shader_arb_priv {=0A=
     GLuint                  current_fprogram_id;=0A=
     GLuint                  depth_blt_vprogram_id;=0A=
     GLuint                  depth_blt_fprogram_id;=0A=
+    BOOL                    use_arbfp_fixed_func;=0A=
+    hash_table_t            *fragment_shaders;=0A=
 };=0A=
 =0A=
 /* X11 locking */=0A=
@@ -561,6 +563,7 @@ extern const struct StateEntryTemplate =
misc_state_template[];=0A=
 extern const struct StateEntryTemplate ffp_vertexstate_template[];=0A=
 extern const struct fragment_pipeline ffp_fragment_pipeline;=0A=
 extern const struct fragment_pipeline atifs_fragment_pipeline;=0A=
+extern const struct fragment_pipeline arbfp_fragment_pipeline;=0A=
 extern const struct fragment_pipeline nvts_fragment_pipeline;=0A=
 extern const struct fragment_pipeline nvrc_fragment_pipeline;=0A=
 =0A=
-- =0A=
1.5.4.5=0A=
=0A=

------=_NextPart_000_0001_01C8F16E.29347760--




More information about the wine-patches mailing list