wined3d: Explicitly pass the shader version to shader_dump_decl_usage().
[wine] / dlls / wined3d / ati_fragment_shader.c
1 /*
2  * Fixed function pipeline replacement using GL_ATI_fragment_shader
3  *
4  * Copyright 2008 Stefan Dösinger(for CodeWeavers)
5  *
6  * This library is free software; you can redistribute it and/or
7  * modify it under the terms of the GNU Lesser General Public
8  * License as published by the Free Software Foundation; either
9  * version 2.1 of the License, or (at your option) any later version.
10  *
11  * This library is distributed in the hope that it will be useful,
12  * but WITHOUT ANY WARRANTY; without even the implied warranty of
13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
14  * Lesser General Public License for more details.
15  *
16  * You should have received a copy of the GNU Lesser General Public
17  * License along with this library; if not, write to the Free Software
18  * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
19  */
20
21 #include "config.h"
22
23 #include <math.h>
24 #include <stdio.h>
25
26 #include "wined3d_private.h"
27
28 WINE_DEFAULT_DEBUG_CHANNEL(d3d_shader);
29 WINE_DECLARE_DEBUG_CHANNEL(d3d);
30
31 /* Some private defines, Constant associations, etc.
32  * Env bump matrix and per stage constant should be independent,
33  * a stage that bump maps can't read the per state constant
34  */
35 #define ATI_FFP_CONST_BUMPMAT(i) (GL_CON_0_ATI + i)
36 #define ATI_FFP_CONST_CONSTANT0 GL_CON_0_ATI
37 #define ATI_FFP_CONST_CONSTANT1 GL_CON_1_ATI
38 #define ATI_FFP_CONST_CONSTANT2 GL_CON_2_ATI
39 #define ATI_FFP_CONST_CONSTANT3 GL_CON_3_ATI
40 #define ATI_FFP_CONST_CONSTANT4 GL_CON_4_ATI
41 #define ATI_FFP_CONST_CONSTANT5 GL_CON_5_ATI
42 #define ATI_FFP_CONST_TFACTOR   GL_CON_6_ATI
43
44 /* GL_ATI_fragment_shader specific fixed function pipeline description. "Inherits" from the common one */
45 struct atifs_ffp_desc
46 {
47     struct ffp_frag_desc parent;
48     GLuint shader;
49     unsigned int num_textures_used;
50 };
51
52 struct atifs_private_data
53 {
54     struct hash_table_t *fragment_shaders; /* A hashtable to track fragment pipeline replacement shaders */
55
56 };
57
58 static const char *debug_dstmod(GLuint mod) {
59     switch(mod) {
60         case GL_NONE:               return "GL_NONE";
61         case GL_2X_BIT_ATI:         return "GL_2X_BIT_ATI";
62         case GL_4X_BIT_ATI:         return "GL_4X_BIT_ATI";
63         case GL_8X_BIT_ATI:         return "GL_8X_BIT_ATI";
64         case GL_HALF_BIT_ATI:       return "GL_HALF_BIT_ATI";
65         case GL_QUARTER_BIT_ATI:    return "GL_QUARTER_BIT_ATI";
66         case GL_EIGHTH_BIT_ATI:     return "GL_EIGHTH_BIT_ATI";
67         case GL_SATURATE_BIT_ATI:   return "GL_SATURATE_BIT_ATI";
68         default:                    return "Unexpected modifier\n";
69     }
70 }
71
72 static const char *debug_argmod(GLuint mod) {
73     switch(mod) {
74         case GL_NONE:
75             return "GL_NONE";
76
77         case GL_2X_BIT_ATI:
78             return "GL_2X_BIT_ATI";
79         case GL_COMP_BIT_ATI:
80             return "GL_COMP_BIT_ATI";
81         case GL_NEGATE_BIT_ATI:
82             return "GL_NEGATE_BIT_ATI";
83         case GL_BIAS_BIT_ATI:
84             return "GL_BIAS_BIT_ATI";
85
86         case GL_2X_BIT_ATI | GL_COMP_BIT_ATI:
87             return "GL_2X_BIT_ATI | GL_COMP_BIT_ATI";
88         case GL_2X_BIT_ATI | GL_NEGATE_BIT_ATI:
89             return "GL_2X_BIT_ATI | GL_NEGATE_BIT_ATI";
90         case GL_2X_BIT_ATI | GL_BIAS_BIT_ATI:
91             return "GL_2X_BIT_ATI | GL_BIAS_BIT_ATI";
92         case GL_COMP_BIT_ATI | GL_NEGATE_BIT_ATI:
93             return "GL_COMP_BIT_ATI | GL_NEGATE_BIT_ATI";
94         case GL_COMP_BIT_ATI | GL_BIAS_BIT_ATI:
95             return "GL_COMP_BIT_ATI | GL_BIAS_BIT_ATI";
96         case GL_NEGATE_BIT_ATI | GL_BIAS_BIT_ATI:
97             return "GL_NEGATE_BIT_ATI | GL_BIAS_BIT_ATI";
98
99         case GL_COMP_BIT_ATI | GL_NEGATE_BIT_ATI | GL_BIAS_BIT_ATI:
100             return "GL_COMP_BIT_ATI | GL_NEGATE_BIT_ATI | GL_BIAS_BIT_ATI";
101         case GL_2X_BIT_ATI | GL_NEGATE_BIT_ATI | GL_BIAS_BIT_ATI:
102             return "GL_2X_BIT_ATI | GL_NEGATE_BIT_ATI | GL_BIAS_BIT_ATI";
103         case GL_2X_BIT_ATI | GL_COMP_BIT_ATI | GL_BIAS_BIT_ATI:
104             return "GL_2X_BIT_ATI | GL_COMP_BIT_ATI | GL_BIAS_BIT_ATI";
105         case GL_2X_BIT_ATI | GL_COMP_BIT_ATI | GL_NEGATE_BIT_ATI:
106             return "GL_2X_BIT_ATI | GL_COMP_BIT_ATI | GL_NEGATE_BIT_ATI";
107
108         case GL_2X_BIT_ATI | GL_COMP_BIT_ATI | GL_NEGATE_BIT_ATI | GL_BIAS_BIT_ATI:
109             return "GL_2X_BIT_ATI | GL_COMP_BIT_ATI | GL_NEGATE_BIT_ATI | GL_BIAS_BIT_ATI";
110
111         default:
112             return "Unexpected argmod combination\n";
113     }
114 }
115 static const char *debug_register(GLuint reg) {
116     switch(reg) {
117         case GL_REG_0_ATI:                  return "GL_REG_0_ATI";
118         case GL_REG_1_ATI:                  return "GL_REG_1_ATI";
119         case GL_REG_2_ATI:                  return "GL_REG_2_ATI";
120         case GL_REG_3_ATI:                  return "GL_REG_3_ATI";
121         case GL_REG_4_ATI:                  return "GL_REG_4_ATI";
122         case GL_REG_5_ATI:                  return "GL_REG_5_ATI";
123
124         case GL_CON_0_ATI:                  return "GL_CON_0_ATI";
125         case GL_CON_1_ATI:                  return "GL_CON_1_ATI";
126         case GL_CON_2_ATI:                  return "GL_CON_2_ATI";
127         case GL_CON_3_ATI:                  return "GL_CON_3_ATI";
128         case GL_CON_4_ATI:                  return "GL_CON_4_ATI";
129         case GL_CON_5_ATI:                  return "GL_CON_5_ATI";
130         case GL_CON_6_ATI:                  return "GL_CON_6_ATI";
131         case GL_CON_7_ATI:                  return "GL_CON_7_ATI";
132
133         case GL_ZERO:                       return "GL_ZERO";
134         case GL_ONE:                        return "GL_ONE";
135         case GL_PRIMARY_COLOR:              return "GL_PRIMARY_COLOR";
136         case GL_SECONDARY_INTERPOLATOR_ATI: return "GL_SECONDARY_INTERPOLATOR_ATI";
137
138         default:                            return "Unknown register\n";
139     }
140 }
141
142 static const char *debug_swizzle(GLuint swizzle) {
143     switch(swizzle) {
144         case GL_SWIZZLE_STR_ATI:        return "GL_SWIZZLE_STR_ATI";
145         case GL_SWIZZLE_STQ_ATI:        return "GL_SWIZZLE_STQ_ATI";
146         case GL_SWIZZLE_STR_DR_ATI:     return "GL_SWIZZLE_STR_DR_ATI";
147         case GL_SWIZZLE_STQ_DQ_ATI:     return "GL_SWIZZLE_STQ_DQ_ATI";
148         default:                        return "unknown swizzle";
149     }
150 }
151
152 static const char *debug_rep(GLuint rep) {
153     switch(rep) {
154         case GL_NONE:                   return "GL_NONE";
155         case GL_RED:                    return "GL_RED";
156         case GL_GREEN:                  return "GL_GREEN";
157         case GL_BLUE:                   return "GL_BLUE";
158         default:                        return "unknown argrep";
159     }
160 }
161
162 #define GLINFO_LOCATION (*gl_info)
163 static GLuint register_for_arg(DWORD arg, const WineD3D_GL_Info *gl_info,
164         unsigned int stage, GLuint *mod, GLuint *rep, GLuint tmparg)
165 {
166     GLenum ret;
167
168     if(mod) *mod = GL_NONE;
169     if(arg == ARG_UNUSED)
170     {
171         if (rep) *rep = GL_NONE;
172         return -1; /* This is the marker for unused registers */
173     }
174
175     switch(arg & WINED3DTA_SELECTMASK) {
176         case WINED3DTA_DIFFUSE:
177             ret = GL_PRIMARY_COLOR;
178             break;
179
180         case WINED3DTA_CURRENT:
181             /* Note that using GL_REG_0_ATI for the passed on register is safe because
182              * texture0 is read at stage0, so in the worst case it is read in the
183              * instruction writing to reg0. Afterwards texture0 is not used any longer.
184              * If we're reading from current
185              */
186             if(stage == 0) {
187                 ret = GL_PRIMARY_COLOR;
188             } else {
189                 ret = GL_REG_0_ATI;
190             }
191             break;
192
193         case WINED3DTA_TEXTURE:
194             ret = GL_REG_0_ATI + stage;
195             break;
196
197         case WINED3DTA_TFACTOR:
198             ret = ATI_FFP_CONST_TFACTOR;
199             break;
200
201         case WINED3DTA_SPECULAR:
202             ret = GL_SECONDARY_INTERPOLATOR_ATI;
203             break;
204
205         case WINED3DTA_TEMP:
206             ret = tmparg;
207             break;
208
209         case WINED3DTA_CONSTANT:
210             FIXME("Unhandled source argument WINED3DTA_TEMP\n");
211             ret = GL_CON_0_ATI;
212             break;
213
214         default:
215             FIXME("Unknown source argument %d\n", arg);
216             ret = GL_ZERO;
217     }
218
219     if(arg & WINED3DTA_COMPLEMENT) {
220         if(mod) *mod |= GL_COMP_BIT_ATI;
221     }
222     if(arg & WINED3DTA_ALPHAREPLICATE) {
223         if(rep) *rep = GL_ALPHA;
224     } else {
225         if(rep) *rep = GL_NONE;
226     }
227     return ret;
228 }
229
230 static GLuint find_tmpreg(const struct texture_stage_op op[MAX_TEXTURES])
231 {
232     int lowest_read = -1;
233     int lowest_write = -1;
234     int i;
235     BOOL tex_used[MAX_TEXTURES];
236
237     memset(tex_used, 0, sizeof(tex_used));
238     for(i = 0; i < MAX_TEXTURES; i++) {
239         if(op[i].cop == WINED3DTOP_DISABLE) {
240             break;
241         }
242
243         if(lowest_read == -1 &&
244           (op[i].carg1 == WINED3DTA_TEMP || op[i].carg2 == WINED3DTA_TEMP || op[i].carg0 == WINED3DTA_TEMP ||
245            op[i].aarg1 == WINED3DTA_TEMP || op[i].aarg2 == WINED3DTA_TEMP || op[i].aarg0 == WINED3DTA_TEMP)) {
246             lowest_read = i;
247         }
248
249         if(lowest_write == -1 && op[i].dst == tempreg) {
250             lowest_write = i;
251         }
252
253         if(op[i].carg1 == WINED3DTA_TEXTURE || op[i].carg2 == WINED3DTA_TEXTURE || op[i].carg0 == WINED3DTA_TEXTURE ||
254            op[i].aarg1 == WINED3DTA_TEXTURE || op[i].aarg2 == WINED3DTA_TEXTURE || op[i].aarg0 == WINED3DTA_TEXTURE) {
255             tex_used[i] = TRUE;
256         }
257     }
258
259     /* Temp reg not read? We don't need it, return GL_NONE */
260     if(lowest_read == -1) return GL_NONE;
261
262     if(lowest_write >= lowest_read) {
263         FIXME("Temp register read before being written\n");
264     }
265
266     if(lowest_write == -1) {
267         /* This needs a test. Maybe we are supposed to return 0.0/0.0/0.0/0.0, or fail drawprim, or whatever */
268         FIXME("Temp register read without being written\n");
269         return GL_REG_1_ATI;
270     } else if(lowest_write >= 1) {
271         /* If we're writing to the temp reg at earliest in stage 1, we can use register 1 for the temp result.
272          * there may be texture data stored in reg 1, but we do not need it any longer since stage 1 already
273          * read it
274          */
275         return GL_REG_1_ATI;
276     } else {
277         /* Search for a free texture register. We have 6 registers available. GL_REG_0_ATI is already used
278          * for the regular result
279          */
280         for(i = 1; i < 6; i++) {
281             if(!tex_used[i]) {
282                 return GL_REG_0_ATI + i;
283             }
284         }
285         /* What to do here? Report it in ValidateDevice? */
286         FIXME("Could not find a register for the temporary register\n");
287         return 0;
288     }
289 }
290
291 static GLuint gen_ati_shader(const struct texture_stage_op op[MAX_TEXTURES], const WineD3D_GL_Info *gl_info)
292 {
293     GLuint ret = GL_EXTCALL(glGenFragmentShadersATI(1));
294     unsigned int stage;
295     GLuint arg0, arg1, arg2, extrarg;
296     GLuint dstmod, argmod0, argmod1, argmod2, argmodextra;
297     GLuint rep0, rep1, rep2;
298     GLuint swizzle;
299     GLuint tmparg = find_tmpreg(op);
300     GLuint dstreg;
301
302     if(!ret) {
303         ERR("Failed to generate a GL_ATI_fragment_shader shader id\n");
304         return 0;
305     }
306     GL_EXTCALL(glBindFragmentShaderATI(ret));
307     checkGLcall("GL_EXTCALL(glBindFragmentShaderATI(ret))");
308
309     TRACE("glBeginFragmentShaderATI()\n");
310     GL_EXTCALL(glBeginFragmentShaderATI());
311     checkGLcall("GL_EXTCALL(glBeginFragmentShaderATI())");
312
313     /* Pass 1: Generate sampling instructions for perturbation maps */
314       for(stage = 0; stage < GL_LIMITS(textures); stage++) {
315         if(op[stage].cop == WINED3DTOP_DISABLE) break;
316         if(op[stage].cop != WINED3DTOP_BUMPENVMAP &&
317            op[stage].cop != WINED3DTOP_BUMPENVMAPLUMINANCE) continue;
318
319         TRACE("glSampleMapATI(GL_REG_%d_ATI, GL_TEXTURE_%d_ARB, GL_SWIZZLE_STR_ATI)\n",
320               stage, stage);
321         GL_EXTCALL(glSampleMapATI(GL_REG_0_ATI + stage,
322                    GL_TEXTURE0_ARB + stage,
323                    GL_SWIZZLE_STR_ATI));
324         if(op[stage + 1].projected == proj_none) {
325             swizzle = GL_SWIZZLE_STR_ATI;
326         } else if(op[stage + 1].projected == proj_count4) {
327             swizzle = GL_SWIZZLE_STQ_DQ_ATI;
328         } else {
329             swizzle = GL_SWIZZLE_STR_DR_ATI;
330         }
331         TRACE("glPassTexCoordATI(GL_REG_%d_ATI, GL_TEXTURE_%d_ARB, %s)\n",
332               stage + 1, stage + 1, debug_swizzle(swizzle));
333         GL_EXTCALL(glPassTexCoordATI(GL_REG_0_ATI + stage + 1,
334                    GL_TEXTURE0_ARB + stage + 1,
335                    swizzle));
336
337         /* We need GL_REG_5_ATI as a temporary register to swizzle the bump matrix. So we run into
338          * issues if we're bump mapping on stage 4 or 5
339          */
340         if(stage >= 4) {
341             FIXME("Bump mapping in stage %d\n", stage);
342         }
343     }
344
345     /* Pass 2: Generate perturbation calculations */
346     for(stage = 0; stage < GL_LIMITS(textures); stage++) {
347         GLuint argmodextra_x, argmodextra_y;
348         struct color_fixup_desc fixup;
349
350         if(op[stage].cop == WINED3DTOP_DISABLE) break;
351         if(op[stage].cop != WINED3DTOP_BUMPENVMAP &&
352            op[stage].cop != WINED3DTOP_BUMPENVMAPLUMINANCE) continue;
353
354         if (fixup.x_source != CHANNEL_SOURCE_X || fixup.y_source != CHANNEL_SOURCE_Y)
355         {
356             FIXME("Swizzles not implemented\n");
357             argmodextra_x = GL_NONE;
358             argmodextra_y = GL_NONE;
359         }
360         else
361         {
362             /* Nice thing, we get the color correction for free :-) */
363             argmodextra_x = fixup.x_sign_fixup ? GL_2X_BIT_ATI | GL_BIAS_BIT_ATI : GL_NONE;
364             argmodextra_y = fixup.y_sign_fixup ? GL_2X_BIT_ATI | GL_BIAS_BIT_ATI : GL_NONE;
365         }
366
367         TRACE("glColorFragmentOp3ATI(GL_DOT2_ADD_ATI, GL_REG_%d_ATI, GL_RED_BIT_ATI, GL_NONE, GL_REG_%d_ATI, GL_NONE, %s, ATI_FFP_CONST_BUMPMAT(%d), GL_NONE, GL_NONE, GL_REG_%d_ATI, GL_RED, GL_NONE)\n",
368               stage + 1, stage, debug_argmod(argmodextra_x), stage, stage + 1);
369         GL_EXTCALL(glColorFragmentOp3ATI(GL_DOT2_ADD_ATI, GL_REG_0_ATI + stage + 1, GL_RED_BIT_ATI, GL_NONE,
370                                          GL_REG_0_ATI + stage, GL_NONE, argmodextra_x,
371                                          ATI_FFP_CONST_BUMPMAT(stage), GL_NONE, GL_2X_BIT_ATI | GL_BIAS_BIT_ATI,
372                                          GL_REG_0_ATI + stage + 1, GL_RED, GL_NONE));
373
374         /* FIXME: How can I make GL_DOT2_ADD_ATI read the factors from blue and alpha? It defaults to red and green,
375          * and it is fairly easy to make it read GL_BLUE or BL_ALPHA, but I can't get an R * B + G * A. So we're wasting
376          * one register and two instructions in this pass for a simple swizzling operation.
377          * For starters it might be good enough to merge the two movs into one, but even that isn't possible :-(
378          *
379          * NOTE: GL_BLUE | GL_ALPHA is not possible. It doesn't throw a compilation error, but an OR operation on the
380          * constants doesn't make sense, considering their values.
381          */
382         TRACE("glColorFragmentOp1ATI(GL_MOV_ATI, GL_REG_5_ATI, GL_RED_BIT_ATI, GL_NONE, ATI_FFP_CONST_BUMPMAT(%d), GL_BLUE, GL_NONE)\n", stage);
383         GL_EXTCALL(glColorFragmentOp1ATI(GL_MOV_ATI, GL_REG_5_ATI, GL_RED_BIT_ATI, GL_NONE,
384                                          ATI_FFP_CONST_BUMPMAT(stage), GL_BLUE, GL_NONE));
385         TRACE("glColorFragmentOp1ATI(GL_MOV_ATI, GL_REG_5_ATI, GL_GREEN_BIT_ATI, GL_NONE, ATI_FFP_CONST_BUMPMAT(%d), GL_ALPHA, GL_NONE)\n", stage);
386         GL_EXTCALL(glColorFragmentOp1ATI(GL_MOV_ATI, GL_REG_5_ATI, GL_GREEN_BIT_ATI, GL_NONE,
387                                         ATI_FFP_CONST_BUMPMAT(stage), GL_ALPHA, GL_NONE));
388         TRACE("glColorFragmentOp3ATI(GL_DOT2_ADD_ATI, GL_REG_%d_ATI, GL_GREEN_BIT_ATI, GL_NONE, GL_REG_%d_ATI, GL_NONE, %s, GL_REG_5_ATI, GL_NONE, GL_NONE, GL_REG_%d_ATI, GL_GREEN, GL_NONE)\n",
389               stage + 1, stage, debug_argmod(argmodextra_y), stage + 1);
390         GL_EXTCALL(glColorFragmentOp3ATI(GL_DOT2_ADD_ATI, GL_REG_0_ATI + stage + 1, GL_GREEN_BIT_ATI, GL_NONE,
391                                          GL_REG_0_ATI + stage, GL_NONE, argmodextra_y,
392                                          GL_REG_5_ATI, GL_NONE, GL_2X_BIT_ATI | GL_BIAS_BIT_ATI,
393                                          GL_REG_0_ATI + stage + 1, GL_GREEN, GL_NONE));
394     }
395
396     /* Pass 3: Generate sampling instructions for regular textures */
397     for(stage = 0; stage < GL_LIMITS(textures); stage++) {
398         if(op[stage].cop == WINED3DTOP_DISABLE) {
399             break;
400         }
401
402         if(op[stage].projected == proj_none) {
403             swizzle = GL_SWIZZLE_STR_ATI;
404         } else if(op[stage].projected == proj_count3) {
405             swizzle = GL_SWIZZLE_STR_DR_ATI;
406         } else {
407             swizzle = GL_SWIZZLE_STQ_DQ_ATI;
408         }
409
410         if((op[stage].carg0 & WINED3DTA_SELECTMASK) == WINED3DTA_TEXTURE ||
411            (op[stage].carg1 & WINED3DTA_SELECTMASK) == WINED3DTA_TEXTURE ||
412            (op[stage].carg2 & WINED3DTA_SELECTMASK) == WINED3DTA_TEXTURE ||
413            (op[stage].aarg0 & WINED3DTA_SELECTMASK) == WINED3DTA_TEXTURE ||
414            (op[stage].aarg1 & WINED3DTA_SELECTMASK) == WINED3DTA_TEXTURE ||
415            (op[stage].aarg2 & WINED3DTA_SELECTMASK) == WINED3DTA_TEXTURE ||
416             op[stage].cop == WINED3DTOP_BLENDTEXTUREALPHA) {
417
418             if(stage > 0 &&
419                (op[stage - 1].cop == WINED3DTOP_BUMPENVMAP ||
420                 op[stage - 1].cop == WINED3DTOP_BUMPENVMAPLUMINANCE)) {
421                 TRACE("glSampleMapATI(GL_REG_%d_ATI, GL_REG_%d_ATI, GL_SWIZZLE_STR_ATI)\n",
422                       stage, stage);
423                 GL_EXTCALL(glSampleMapATI(GL_REG_0_ATI + stage,
424                            GL_REG_0_ATI + stage,
425                            GL_SWIZZLE_STR_ATI));
426             } else {
427                 TRACE("glSampleMapATI(GL_REG_%d_ATI, GL_TEXTURE_%d_ARB, %s)\n",
428                     stage, stage, debug_swizzle(swizzle));
429                 GL_EXTCALL(glSampleMapATI(GL_REG_0_ATI + stage,
430                                         GL_TEXTURE0_ARB + stage,
431                                         swizzle));
432             }
433         }
434     }
435
436     /* Pass 4: Generate the arithmetic instructions */
437     for(stage = 0; stage < MAX_TEXTURES; stage++) {
438         if(op[stage].cop == WINED3DTOP_DISABLE) {
439             if(stage == 0) {
440                 /* Handle complete texture disabling gracefully */
441                 TRACE("glColorFragmentOp1ATI(GL_MOV_ATI, GL_REG_0_ATI, GL_NONE, GL_NONE, GL_PRIMARY_COLOR, GL_NONE, GL_NONE)\n");
442                 GL_EXTCALL(glColorFragmentOp1ATI(GL_MOV_ATI, GL_REG_0_ATI, GL_NONE, GL_NONE,
443                                                  GL_PRIMARY_COLOR, GL_NONE, GL_NONE));
444                 TRACE("glAlphaFragmentOp1ATI(GL_MOV_ATI, GL_REG_0_ATI, GL_NONE, GL_PRIMARY_COLOR, GL_NONE, GL_NONE)\n");
445                 GL_EXTCALL(glAlphaFragmentOp1ATI(GL_MOV_ATI, GL_REG_0_ATI, GL_NONE,
446                                                  GL_PRIMARY_COLOR, GL_NONE, GL_NONE));
447             }
448             break;
449         }
450
451         if(op[stage].dst == tempreg) {
452             /* If we're writing to D3DTA_TEMP, but never reading from it we don't have to write there in the first place.
453              * skip the entire stage, this saves some GPU time
454              */
455             if(tmparg == GL_NONE) continue;
456
457             dstreg = tmparg;
458         } else {
459             dstreg = GL_REG_0_ATI;
460         }
461
462         arg0 = register_for_arg(op[stage].carg0, gl_info, stage, &argmod0, &rep0, tmparg);
463         arg1 = register_for_arg(op[stage].carg1, gl_info, stage, &argmod1, &rep1, tmparg);
464         arg2 = register_for_arg(op[stage].carg2, gl_info, stage, &argmod2, &rep2, tmparg);
465         dstmod = GL_NONE;
466         argmodextra = GL_NONE;
467         extrarg = GL_NONE;
468
469         switch(op[stage].cop) {
470             case WINED3DTOP_SELECTARG2:
471                 arg1 = arg2;
472                 argmod1 = argmod2;
473                 rep1 = rep2;
474             case WINED3DTOP_SELECTARG1:
475                 TRACE("glColorFragmentOp1ATI(GL_MOV_ATI, %s, GL_NONE, GL_NONE, %s, %s, %s)\n",
476                       debug_register(dstreg), debug_register(arg1), debug_rep(rep1), debug_argmod(argmod1));
477                 GL_EXTCALL(glColorFragmentOp1ATI(GL_MOV_ATI, dstreg, GL_NONE, GL_NONE,
478                                                  arg1, rep1, argmod1));
479                 break;
480
481             case WINED3DTOP_MODULATE4X:
482                 if(dstmod == GL_NONE) dstmod = GL_4X_BIT_ATI;
483             case WINED3DTOP_MODULATE2X:
484                 if(dstmod == GL_NONE) dstmod = GL_2X_BIT_ATI;
485                 dstmod |= GL_SATURATE_BIT_ATI;
486             case WINED3DTOP_MODULATE:
487                 TRACE("glColorFragmentOp2ATI(GL_MUL_ATI, %s, GL_NONE, %s, %s, %s, %s, %s, %s, %s)\n",
488                       debug_register(dstreg), debug_dstmod(dstmod),
489                       debug_register(arg1), debug_rep(rep1), debug_argmod(argmod1),
490                       debug_register(arg2), debug_rep(rep2), debug_argmod(argmod2));
491                 GL_EXTCALL(glColorFragmentOp2ATI(GL_MUL_ATI, dstreg, GL_NONE, dstmod,
492                                                  arg1, rep1, argmod1,
493                                                  arg2, rep2, argmod2));
494                 break;
495
496             case WINED3DTOP_ADDSIGNED2X:
497                 dstmod = GL_2X_BIT_ATI;
498             case WINED3DTOP_ADDSIGNED:
499                 argmodextra = GL_BIAS_BIT_ATI;
500             case WINED3DTOP_ADD:
501                 dstmod |= GL_SATURATE_BIT_ATI;
502                 TRACE("glColorFragmentOp2ATI(GL_ADD_ATI, %s, GL_NONE, %s, %s, %s, %s, %s, %s, %s)\n",
503                       debug_register(dstreg), debug_dstmod(dstmod),
504                       debug_register(arg1), debug_rep(rep1), debug_argmod(argmod1),
505                       debug_register(arg2), debug_rep(rep2), debug_argmod(argmodextra | argmod2));
506                 GL_EXTCALL(glColorFragmentOp2ATI(GL_ADD_ATI, GL_REG_0_ATI, GL_NONE, dstmod,
507                                                  arg1, rep1, argmod1,
508                                                  arg2, rep2, argmodextra | argmod2));
509                 break;
510
511             case WINED3DTOP_SUBTRACT:
512                 dstmod |= GL_SATURATE_BIT_ATI;
513                 TRACE("glColorFragmentOp2ATI(GL_SUB_ATI, %s, GL_NONE, %s, %s, %s, %s, %s, %s, %s)\n",
514                       debug_register(dstreg), debug_dstmod(dstmod),
515                       debug_register(arg1), debug_rep(rep1), debug_argmod(argmod1),
516                       debug_register(arg2), debug_rep(rep2), debug_argmod(argmod2));
517                 GL_EXTCALL(glColorFragmentOp2ATI(GL_SUB_ATI, dstreg, GL_NONE, dstmod,
518                                                  arg1, rep1, argmod1,
519                                                  arg2, rep2, argmod2));
520                 break;
521
522             case WINED3DTOP_ADDSMOOTH:
523                 argmodextra = argmod1 & GL_COMP_BIT_ATI ? argmod1 & ~GL_COMP_BIT_ATI : argmod1 | GL_COMP_BIT_ATI;
524                 TRACE("glColorFragmentOp3ATI(GL_MAD_ATI, %s, GL_NONE, GL_SATURATE_BIT_ATI, %s, %s, %s, %s, %s, %s, %s, %s, %s)\n",
525                       debug_register(dstreg),
526                       debug_register(arg2), debug_rep(rep2), debug_argmod(argmod2),
527                       debug_register(arg1), debug_rep(rep1), debug_argmod(argmodextra),
528                       debug_register(arg1), debug_rep(rep1), debug_argmod(argmod1));
529                 /* Dst = arg1 + * arg2(1 -arg 1)
530                  *     = arg2 * (1 - arg1) + arg1
531                  */
532                 GL_EXTCALL(glColorFragmentOp3ATI(GL_MAD_ATI, dstreg, GL_NONE, GL_SATURATE_BIT_ATI,
533                                                  arg2, rep2, argmod2,
534                                                  arg1, rep1, argmodextra,
535                                                  arg1, rep1, argmod1));
536                 break;
537
538             case WINED3DTOP_BLENDCURRENTALPHA:
539                 if(extrarg == GL_NONE) extrarg = register_for_arg(WINED3DTA_CURRENT, gl_info, stage, NULL, NULL, -1);
540             case WINED3DTOP_BLENDFACTORALPHA:
541                 if(extrarg == GL_NONE) extrarg = register_for_arg(WINED3DTA_TFACTOR, gl_info, stage, NULL, NULL, -1);
542             case WINED3DTOP_BLENDTEXTUREALPHA:
543                 if(extrarg == GL_NONE) extrarg = register_for_arg(WINED3DTA_TEXTURE, gl_info, stage, NULL, NULL, -1);
544             case WINED3DTOP_BLENDDIFFUSEALPHA:
545                 if(extrarg == GL_NONE) extrarg = register_for_arg(WINED3DTA_DIFFUSE, gl_info, stage, NULL, NULL, -1);
546                 TRACE("glColorFragmentOp3ATI(GL_LERP_ATI, %s, GL_NONE, GL_NONE, %s, GL_ALPHA, GL_NONE, %s, %s, %s, %s, %s, %s)\n",
547                       debug_register(dstreg),
548                       debug_register(extrarg),
549                       debug_register(arg1), debug_rep(rep1), debug_argmod(argmod1),
550                       debug_register(arg2), debug_rep(rep2), debug_argmod(argmod2));
551                 GL_EXTCALL(glColorFragmentOp3ATI(GL_LERP_ATI, dstreg, GL_NONE, GL_NONE,
552                                                  extrarg, GL_ALPHA, GL_NONE,
553                                                  arg1, rep1, argmod1,
554                                                  arg2, rep2, argmod2));
555                 break;
556
557             case WINED3DTOP_BLENDTEXTUREALPHAPM:
558                 arg0 = register_for_arg(WINED3DTA_TEXTURE, gl_info, stage, NULL, NULL, -1);
559                 TRACE("glColorFragmentOp3ATI(GL_MAD_ATI, %s, GL_NONE, GL_NONE, %s, %s, %s, %s, GL_ALPHA, GL_COMP_BIT_ATI, %s, %s, %s)\n",
560                       debug_register(dstreg),
561                       debug_register(arg2), debug_rep(rep2), debug_argmod(argmod2),
562                       debug_register(arg0),
563                       debug_register(arg1), debug_rep(rep1), debug_argmod(argmod1));
564                 GL_EXTCALL(glColorFragmentOp3ATI(GL_MAD_ATI, dstreg, GL_NONE, GL_NONE,
565                                                  arg2, rep2,  argmod2,
566                                                  arg0, GL_ALPHA, GL_COMP_BIT_ATI,
567                                                  arg1, rep1,  argmod1));
568                 break;
569
570             /* D3DTOP_PREMODULATE ???? */
571
572             case WINED3DTOP_MODULATEINVALPHA_ADDCOLOR:
573                 argmodextra = argmod1 & GL_COMP_BIT_ATI ? argmod1 & ~GL_COMP_BIT_ATI : argmod1 | GL_COMP_BIT_ATI;
574             case WINED3DTOP_MODULATEALPHA_ADDCOLOR:
575                 if(!argmodextra) argmodextra = argmod1;
576                 TRACE("glColorFragmentOp3ATI(GL_MAD_ATI, %s, GL_NONE, GL_SATURATE_BIT_ATI, %s, %s, %s, %s, GL_ALPHA, %s, %s, %s, %s)\n",
577                       debug_register(dstreg),
578                       debug_register(arg2), debug_rep(rep2), debug_argmod(argmod2),
579                       debug_register(arg1), debug_argmod(argmodextra), debug_register(arg1), debug_rep(rep1), debug_argmod(arg1));
580                 GL_EXTCALL(glColorFragmentOp3ATI(GL_MAD_ATI, dstreg, GL_NONE, GL_SATURATE_BIT_ATI,
581                                                  arg2, rep2,  argmod2,
582                                                  arg1, GL_ALPHA, argmodextra,
583                                                  arg1, rep1,  argmod1));
584                 break;
585
586             case WINED3DTOP_MODULATEINVCOLOR_ADDALPHA:
587                 argmodextra = argmod1 & GL_COMP_BIT_ATI ? argmod1 & ~GL_COMP_BIT_ATI : argmod1 | GL_COMP_BIT_ATI;
588             case WINED3DTOP_MODULATECOLOR_ADDALPHA:
589                 if(!argmodextra) argmodextra = argmod1;
590                 TRACE("glColorFragmentOp3ATI(GL_MAD_ATI, %s, GL_NONE, GL_SATURATE_BIT_ATI, %s, %s, %s, %s, %s, %s, %s, GL_ALPHA, %s)\n",
591                       debug_register(dstreg),
592                       debug_register(arg2), debug_rep(rep2), debug_argmod(argmod2),
593                       debug_register(arg1), debug_rep(rep1), debug_argmod(argmodextra),
594                       debug_register(arg1), debug_argmod(argmod1));
595                 GL_EXTCALL(glColorFragmentOp3ATI(GL_MAD_ATI, dstreg, GL_NONE, GL_SATURATE_BIT_ATI,
596                                                  arg2, rep2,  argmod2,
597                                                  arg1, rep1,  argmodextra,
598                                                  arg1, GL_ALPHA, argmod1));
599                 break;
600
601             case WINED3DTOP_DOTPRODUCT3:
602                 TRACE("glColorFragmentOp2ATI(GL_DOT3_ATI, %s, GL_NONE, GL_4X_BIT_ATI | GL_SATURATE_BIT_ATI, %s, %s, %s, %s, %s, %s)\n",
603                       debug_register(dstreg),
604                       debug_register(arg1), debug_rep(rep1), debug_argmod(argmod1 | GL_BIAS_BIT_ATI),
605                       debug_register(arg2), debug_rep(rep2), debug_argmod(argmod2 | GL_BIAS_BIT_ATI));
606                 GL_EXTCALL(glColorFragmentOp2ATI(GL_DOT3_ATI, dstreg, GL_NONE, GL_4X_BIT_ATI | GL_SATURATE_BIT_ATI,
607                                                  arg1, rep1, argmod1 | GL_BIAS_BIT_ATI,
608                                                  arg2, rep2, argmod2 | GL_BIAS_BIT_ATI));
609                 break;
610
611             case WINED3DTOP_MULTIPLYADD:
612                 TRACE("glColorFragmentOp3ATI(GL_MAD_ATI, %s, GL_NONE, GL_SATURATE_BIT_ATI, %s, %s, %s, %s, %s, %s, %s, %s, %s)\n",
613                       debug_register(dstreg),
614                       debug_register(arg1), debug_rep(rep1), debug_argmod(argmod1),
615                       debug_register(arg2), debug_rep(rep2), debug_argmod(argmod2),
616                       debug_register(arg0), debug_rep(rep0), debug_argmod(argmod0));
617                 GL_EXTCALL(glColorFragmentOp3ATI(GL_MAD_ATI, dstreg, GL_NONE, GL_SATURATE_BIT_ATI,
618                                                  arg1, rep1, argmod1,
619                                                  arg2, rep2, argmod2,
620                                                  arg0, rep0, argmod0));
621                 break;
622
623             case WINED3DTOP_LERP:
624                 TRACE("glColorFragmentOp3ATI(GL_LERP_ATI, %s, GL_NONE, GL_NONE, %s, %s, %s, %s, %s, %s, %s, %s, %s)\n",
625                       debug_register(dstreg),
626                       debug_register(arg1), debug_rep(rep1), debug_argmod(argmod1),
627                       debug_register(arg2), debug_rep(rep2), debug_argmod(argmod2),
628                       debug_register(arg0), debug_rep(rep0), debug_argmod(argmod0));
629                 GL_EXTCALL(glColorFragmentOp3ATI(GL_LERP_ATI, dstreg, GL_NONE, GL_NONE,
630                                                  arg0, rep0, argmod0,
631                                                  arg1, rep1, argmod1,
632                                                  arg2, rep2, argmod2));
633                 break;
634
635             case WINED3DTOP_BUMPENVMAP:
636             case WINED3DTOP_BUMPENVMAPLUMINANCE:
637                 /* Those are handled in the first pass of the shader(generation pass 1 and 2) already */
638                 break;
639
640             default: FIXME("Unhandled color operation %d on stage %d\n", op[stage].cop, stage);
641         }
642
643         arg0 = register_for_arg(op[stage].aarg0, gl_info, stage, &argmod0, NULL, tmparg);
644         arg1 = register_for_arg(op[stage].aarg1, gl_info, stage, &argmod1, NULL, tmparg);
645         arg2 = register_for_arg(op[stage].aarg2, gl_info, stage, &argmod2, NULL, tmparg);
646         dstmod = GL_NONE;
647         argmodextra = GL_NONE;
648         extrarg = GL_NONE;
649
650         switch(op[stage].aop) {
651             case WINED3DTOP_DISABLE:
652                 /* Get the primary color to the output if on stage 0, otherwise leave register 0 untouched */
653                 if(stage == 0) {
654                     TRACE("glAlphaFragmentOp1ATI(GL_MOV_ATI, GL_REG_0_ATI, GL_NONE, GL_PRIMARY_COLOR, GL_NONE, GL_NONE)\n");
655                     GL_EXTCALL(glAlphaFragmentOp1ATI(GL_MOV_ATI, GL_REG_0_ATI, GL_NONE,
656                                GL_PRIMARY_COLOR, GL_NONE, GL_NONE));
657                 }
658                 break;
659
660             case WINED3DTOP_SELECTARG2:
661                 arg1 = arg2;
662                 argmod1 = argmod2;
663             case WINED3DTOP_SELECTARG1:
664                 TRACE("glAlphaFragmentOp1ATI(GL_MOV_ATI, %s,          GL_NONE, %s, GL_NONE, %s)\n",
665                       debug_register(dstreg),
666                       debug_register(arg1), debug_argmod(argmod1));
667                 GL_EXTCALL(glAlphaFragmentOp1ATI(GL_MOV_ATI, dstreg, GL_NONE,
668                                                  arg1, GL_NONE, argmod1));
669                 break;
670
671             case WINED3DTOP_MODULATE4X:
672                 if(dstmod == GL_NONE) dstmod = GL_4X_BIT_ATI;
673             case WINED3DTOP_MODULATE2X:
674                 if(dstmod == GL_NONE) dstmod = GL_2X_BIT_ATI;
675                 dstmod |= GL_SATURATE_BIT_ATI;
676             case WINED3DTOP_MODULATE:
677                 TRACE("glAlphaFragmentOp2ATI(GL_MUL_ATI, %s,          %s, %s, GL_NONE, %s, %s, GL_NONE, %s)\n",
678                       debug_register(dstreg), debug_dstmod(dstmod),
679                       debug_register(arg1), debug_argmod(argmod1),
680                       debug_register(arg2), debug_argmod(argmod2));
681                 GL_EXTCALL(glAlphaFragmentOp2ATI(GL_MUL_ATI, dstreg, dstmod,
682                                                  arg1, GL_NONE, argmod1,
683                                                  arg2, GL_NONE, argmod2));
684                 break;
685
686             case WINED3DTOP_ADDSIGNED2X:
687                 dstmod = GL_2X_BIT_ATI;
688             case WINED3DTOP_ADDSIGNED:
689                 argmodextra = GL_BIAS_BIT_ATI;
690             case WINED3DTOP_ADD:
691                 dstmod |= GL_SATURATE_BIT_ATI;
692                 TRACE("glAlphaFragmentOp2ATI(GL_ADD_ATI, %s,          %s, %s, GL_NONE, %s, %s, GL_NONE, %s)\n",
693                       debug_register(dstreg), debug_dstmod(dstmod),
694                       debug_register(arg1), debug_argmod(argmod1),
695                       debug_register(arg2), debug_argmod(argmodextra | argmod2));
696                 GL_EXTCALL(glAlphaFragmentOp2ATI(GL_ADD_ATI, dstreg, dstmod,
697                                                  arg1, GL_NONE, argmod1,
698                                                  arg2, GL_NONE, argmodextra | argmod2));
699                 break;
700
701             case WINED3DTOP_SUBTRACT:
702                 dstmod |= GL_SATURATE_BIT_ATI;
703                 TRACE("glAlphaFragmentOp2ATI(GL_SUB_ATI, %s, GL_NONE, %s, %s, GL_NONE, %s, %s, GL_NONE, %s)\n",
704                       debug_register(dstreg), debug_dstmod(dstmod),
705                       debug_register(arg1), debug_argmod(argmod1),
706                       debug_register(arg2), debug_argmod(argmod2));
707                 GL_EXTCALL(glAlphaFragmentOp2ATI(GL_SUB_ATI, dstreg, dstmod,
708                                                  arg1, GL_NONE, argmod1,
709                                                  arg2, GL_NONE, argmod2));
710                 break;
711
712             case WINED3DTOP_ADDSMOOTH:
713                 argmodextra = argmod1 & GL_COMP_BIT_ATI ? argmod1 & ~GL_COMP_BIT_ATI : argmod1 | GL_COMP_BIT_ATI;
714                 TRACE("glAlphaFragmentOp3ATI(GL_MAD_ATI, %s,          GL_SATURATE_BIT_ATI, %s, GL_NONE, %s, %s, GL_NONE, %s, %s, GL_NONE, %s)\n",
715                       debug_register(dstreg),
716                       debug_register(arg2), debug_argmod(argmod2),
717                       debug_register(arg1), debug_argmod(argmodextra),
718                       debug_register(arg1), debug_argmod(argmod1));
719                 /* Dst = arg1 + * arg2(1 -arg 1)
720                  *     = arg2 * (1 - arg1) + arg1
721                  */
722                 GL_EXTCALL(glAlphaFragmentOp3ATI(GL_MAD_ATI, dstreg, GL_SATURATE_BIT_ATI,
723                                                  arg2, GL_NONE, argmod2,
724                                                  arg1, GL_NONE, argmodextra,
725                                                  arg1, GL_NONE, argmod1));
726                 break;
727
728             case WINED3DTOP_BLENDCURRENTALPHA:
729                 if(extrarg == GL_NONE) extrarg = register_for_arg(WINED3DTA_CURRENT, gl_info, stage, NULL, NULL, -1);
730             case WINED3DTOP_BLENDFACTORALPHA:
731                 if(extrarg == GL_NONE) extrarg = register_for_arg(WINED3DTA_TFACTOR, gl_info, stage, NULL, NULL, -1);
732             case WINED3DTOP_BLENDTEXTUREALPHA:
733                 if(extrarg == GL_NONE) extrarg = register_for_arg(WINED3DTA_TEXTURE, gl_info, stage, NULL, NULL, -1);
734             case WINED3DTOP_BLENDDIFFUSEALPHA:
735                 if(extrarg == GL_NONE) extrarg = register_for_arg(WINED3DTA_DIFFUSE, gl_info, stage, NULL, NULL, -1);
736                 TRACE("glAlphaFragmentOp3ATI(GL_LERP_ATI, %s,          GL_NONE, %s, GL_ALPHA, GL_NONE, %s, GL_NONE, %s, %s, GL_NONE, %s)\n",
737                       debug_register(dstreg),
738                       debug_register(extrarg),
739                       debug_register(arg1), debug_argmod(argmod1),
740                       debug_register(arg2), debug_argmod(argmod2));
741                 GL_EXTCALL(glAlphaFragmentOp3ATI(GL_LERP_ATI, dstreg, GL_NONE,
742                                                  extrarg, GL_ALPHA, GL_NONE,
743                                                  arg1, GL_NONE, argmod1,
744                                                  arg2, GL_NONE, argmod2));
745                 break;
746
747             case WINED3DTOP_BLENDTEXTUREALPHAPM:
748                 arg0 = register_for_arg(WINED3DTA_TEXTURE, gl_info, stage, NULL, NULL, -1);
749                 TRACE("glAlphaFragmentOp3ATI(GL_MAD_ATI, %s,          GL_NONE, %s, GL_NONE, %s, %s, GL_ALPHA, GL_COMP_BIT_ATI, %s, GL_NONE, %s)\n",
750                       debug_register(dstreg),
751                       debug_register(arg2), debug_argmod(argmod2),
752                       debug_register(arg0),
753                       debug_register(arg1), debug_argmod(argmod1));
754                 GL_EXTCALL(glAlphaFragmentOp3ATI(GL_MAD_ATI, dstreg, GL_NONE,
755                                                  arg2, GL_NONE,  argmod2,
756                                                  arg0, GL_ALPHA, GL_COMP_BIT_ATI,
757                                                  arg1, GL_NONE,  argmod1));
758                 break;
759
760             /* D3DTOP_PREMODULATE ???? */
761
762             case WINED3DTOP_DOTPRODUCT3:
763                 TRACE("glAlphaFragmentOp2ATI(GL_DOT3_ATI, %s,          GL_4X_BIT_ATI | GL_SATURATE_BIT_ATI, %s, GL_NONE, %s, %s, GL_NONE, %s)\n",
764                       debug_register(dstreg),
765                       debug_register(arg1), debug_argmod(argmod1 | GL_BIAS_BIT_ATI),
766                       debug_register(arg2), debug_argmod(argmod2 | GL_BIAS_BIT_ATI));
767                 GL_EXTCALL(glAlphaFragmentOp2ATI(GL_DOT3_ATI, dstreg, GL_4X_BIT_ATI | GL_SATURATE_BIT_ATI,
768                                                  arg1, GL_NONE, argmod1 | GL_BIAS_BIT_ATI,
769                                                  arg2, GL_NONE, argmod2 | GL_BIAS_BIT_ATI));
770                 break;
771
772             case WINED3DTOP_MULTIPLYADD:
773                 TRACE("glAlphaFragmentOp3ATI(GL_MAD_ATI, %s,          GL_SATURATE_BIT_ATI, %s, GL_NONE, %s, %s, GL_NONE, %s, %s, GL_NONE, %s)\n",
774                       debug_register(dstreg),
775                       debug_register(arg1), debug_argmod(argmod1),
776                       debug_register(arg2), debug_argmod(argmod2),
777                       debug_register(arg0), debug_argmod(argmod0));
778                 GL_EXTCALL(glAlphaFragmentOp3ATI(GL_MAD_ATI, dstreg,          GL_SATURATE_BIT_ATI,
779                            arg1, GL_NONE, argmod1,
780                            arg2, GL_NONE, argmod2,
781                            arg0, GL_NONE, argmod0));
782                 break;
783
784             case WINED3DTOP_LERP:
785                 TRACE("glAlphaFragmentOp3ATI(GL_LERP_ATI, %s,          GL_SATURATE_BIT_ATI, %s, GL_NONE, %s, %s, GL_NONE, %s, %s, GL_NONE, %s)\n",
786                       debug_register(dstreg),
787                       debug_register(arg1), debug_argmod(argmod1),
788                       debug_register(arg2), debug_argmod(argmod2),
789                       debug_register(arg0), debug_argmod(argmod0));
790                 GL_EXTCALL(glAlphaFragmentOp3ATI(GL_LERP_ATI, dstreg, GL_SATURATE_BIT_ATI,
791                                                  arg1, GL_NONE, argmod1,
792                                                  arg2, GL_NONE, argmod2,
793                                                  arg0, GL_NONE, argmod0));
794                 break;
795
796             case WINED3DTOP_MODULATEINVALPHA_ADDCOLOR:
797             case WINED3DTOP_MODULATEALPHA_ADDCOLOR:
798             case WINED3DTOP_MODULATECOLOR_ADDALPHA:
799             case WINED3DTOP_MODULATEINVCOLOR_ADDALPHA:
800             case WINED3DTOP_BUMPENVMAP:
801             case WINED3DTOP_BUMPENVMAPLUMINANCE:
802                 ERR("Application uses an invalid alpha operation\n");
803                 break;
804
805             default: FIXME("Unhandled alpha operation %d on stage %d\n", op[stage].aop, stage);
806         }
807     }
808
809     TRACE("glEndFragmentShaderATI()\n");
810     GL_EXTCALL(glEndFragmentShaderATI());
811     checkGLcall("GL_EXTCALL(glEndFragmentShaderATI())");
812     return ret;
813 }
814 #undef GLINFO_LOCATION
815
816 #define GLINFO_LOCATION stateblock->wineD3DDevice->adapter->gl_info
817 static void set_tex_op_atifs(DWORD state, IWineD3DStateBlockImpl *stateblock, WineD3DContext *context) {
818     IWineD3DDeviceImpl          *This = stateblock->wineD3DDevice;
819     const struct atifs_ffp_desc *desc;
820     struct ffp_frag_settings     settings;
821     struct atifs_private_data   *priv = (struct atifs_private_data *) This->fragment_priv;
822     DWORD mapped_stage;
823     unsigned int i;
824
825     gen_ffp_frag_op(stateblock, &settings, TRUE);
826     desc = (const struct atifs_ffp_desc *)find_ffp_frag_shader(priv->fragment_shaders, &settings);
827     if(!desc) {
828         struct atifs_ffp_desc *new_desc = HeapAlloc(GetProcessHeap(), 0, sizeof(*new_desc));
829         if (!new_desc)
830         {
831             ERR("Out of memory\n");
832             return;
833         }
834         new_desc->num_textures_used = 0;
835         for(i = 0; i < GL_LIMITS(texture_stages); i++) {
836             if(settings.op[i].cop == WINED3DTOP_DISABLE) break;
837             new_desc->num_textures_used = i;
838         }
839
840         memcpy(&new_desc->parent.settings, &settings, sizeof(settings));
841         new_desc->shader = gen_ati_shader(settings.op, &GLINFO_LOCATION);
842         add_ffp_frag_shader(priv->fragment_shaders, &new_desc->parent);
843         TRACE("Allocated fixed function replacement shader descriptor %p\n", new_desc);
844         desc = new_desc;
845     }
846
847     /* GL_ATI_fragment_shader depends on the GL_TEXTURE_xD enable settings. Update the texture stages
848      * used by this shader
849      */
850     for(i = 0; i < desc->num_textures_used; i++) {
851         mapped_stage = This->texUnitMap[i];
852         if(mapped_stage != -1) {
853             GL_EXTCALL(glActiveTextureARB(GL_TEXTURE0_ARB + mapped_stage));
854             checkGLcall("glActiveTextureARB");
855             texture_activate_dimensions(i, stateblock, context);
856         }
857     }
858
859     GL_EXTCALL(glBindFragmentShaderATI(desc->shader));
860 }
861
862 static void state_texfactor_atifs(DWORD state, IWineD3DStateBlockImpl *stateblock, WineD3DContext *context) {
863     float col[4];
864     D3DCOLORTOGLFLOAT4(stateblock->renderState[WINED3DRS_TEXTUREFACTOR], col);
865
866     GL_EXTCALL(glSetFragmentShaderConstantATI(ATI_FFP_CONST_TFACTOR, col));
867     checkGLcall("glSetFragmentShaderConstantATI(ATI_FFP_CONST_TFACTOR, col)");
868 }
869
870 static void set_bumpmat(DWORD state, IWineD3DStateBlockImpl *stateblock, WineD3DContext *context) {
871     DWORD stage = (state - STATE_TEXTURESTAGE(0, 0)) / WINED3D_HIGHEST_TEXTURE_STATE;
872     float mat[2][2];
873
874     mat[0][0] = *((float *) &stateblock->textureState[stage][WINED3DTSS_BUMPENVMAT00]);
875     mat[1][0] = *((float *) &stateblock->textureState[stage][WINED3DTSS_BUMPENVMAT01]);
876     mat[0][1] = *((float *) &stateblock->textureState[stage][WINED3DTSS_BUMPENVMAT10]);
877     mat[1][1] = *((float *) &stateblock->textureState[stage][WINED3DTSS_BUMPENVMAT11]);
878     /* GL_ATI_fragment_shader allows only constants from 0.0 to 1.0, but the bumpmat
879      * constants can be in any range. While they should stay between [-1.0 and 1.0] because
880      * Shader Model 1.x pixel shaders are clamped to that range negative values are used occasionally,
881      * for example by our d3d9 test. So to get negative values scale -1;1 to 0;1 and undo that in the
882      * shader(it is free). This might potentially reduce precision. However, if the hardware does
883      * support proper floats it shouldn't, and if it doesn't we can't get anything better anyway
884      */
885     mat[0][0] = (mat[0][0] + 1.0) * 0.5;
886     mat[1][0] = (mat[1][0] + 1.0) * 0.5;
887     mat[0][1] = (mat[0][1] + 1.0) * 0.5;
888     mat[1][1] = (mat[1][1] + 1.0) * 0.5;
889     GL_EXTCALL(glSetFragmentShaderConstantATI(ATI_FFP_CONST_BUMPMAT(stage), (float *) mat));
890     checkGLcall("glSetFragmentShaderConstantATI(ATI_FFP_CONST_BUMPMAT(stage), mat)");
891 }
892
893 static void textransform(DWORD state, IWineD3DStateBlockImpl *stateblock, WineD3DContext *context) {
894     if(!isStateDirty(context, STATE_PIXELSHADER)) {
895         set_tex_op_atifs(state, stateblock, context);
896     }
897 }
898
899 #undef GLINFO_LOCATION
900
901 static const struct StateEntryTemplate atifs_fragmentstate_template[] = {
902     {STATE_RENDER(WINED3DRS_TEXTUREFACTOR),               { STATE_RENDER(WINED3DRS_TEXTUREFACTOR),              state_texfactor_atifs   }, 0                               },
903     {STATE_TEXTURESTAGE(0, WINED3DTSS_COLOROP),           { STATE_TEXTURESTAGE(0, WINED3DTSS_COLOROP),          set_tex_op_atifs        }, 0                               },
904     {STATE_TEXTURESTAGE(0, WINED3DTSS_COLORARG1),         { STATE_TEXTURESTAGE(0, WINED3DTSS_COLOROP),          set_tex_op_atifs        }, 0                               },
905     {STATE_TEXTURESTAGE(0, WINED3DTSS_COLORARG2),         { STATE_TEXTURESTAGE(0, WINED3DTSS_COLOROP),          set_tex_op_atifs        }, 0                               },
906     {STATE_TEXTURESTAGE(0, WINED3DTSS_COLORARG0),         { STATE_TEXTURESTAGE(0, WINED3DTSS_COLOROP),          set_tex_op_atifs        }, 0                               },
907     {STATE_TEXTURESTAGE(0, WINED3DTSS_ALPHAOP),           { STATE_TEXTURESTAGE(0, WINED3DTSS_COLOROP),          set_tex_op_atifs        }, 0                               },
908     {STATE_TEXTURESTAGE(0, WINED3DTSS_ALPHAARG1),         { STATE_TEXTURESTAGE(0, WINED3DTSS_COLOROP),          set_tex_op_atifs        }, 0                               },
909     {STATE_TEXTURESTAGE(0, WINED3DTSS_ALPHAARG2),         { STATE_TEXTURESTAGE(0, WINED3DTSS_COLOROP),          set_tex_op_atifs        }, 0                               },
910     {STATE_TEXTURESTAGE(0, WINED3DTSS_ALPHAARG0),         { STATE_TEXTURESTAGE(0, WINED3DTSS_COLOROP),          set_tex_op_atifs        }, 0                               },
911     {STATE_TEXTURESTAGE(0, WINED3DTSS_RESULTARG),         { STATE_TEXTURESTAGE(0, WINED3DTSS_COLOROP),          set_tex_op_atifs        }, 0                               },
912     {STATE_TEXTURESTAGE(0, WINED3DTSS_BUMPENVMAT00),      { STATE_TEXTURESTAGE(0, WINED3DTSS_BUMPENVMAT00),     set_bumpmat             }, 0                               },
913     {STATE_TEXTURESTAGE(0, WINED3DTSS_BUMPENVMAT01),      { STATE_TEXTURESTAGE(0, WINED3DTSS_BUMPENVMAT00),     set_bumpmat             }, 0                               },
914     {STATE_TEXTURESTAGE(0, WINED3DTSS_BUMPENVMAT10),      { STATE_TEXTURESTAGE(0, WINED3DTSS_BUMPENVMAT00),     set_bumpmat             }, 0                               },
915     {STATE_TEXTURESTAGE(0, WINED3DTSS_BUMPENVMAT11),      { STATE_TEXTURESTAGE(0, WINED3DTSS_BUMPENVMAT00),     set_bumpmat             }, 0                               },
916     {STATE_TEXTURESTAGE(1, WINED3DTSS_COLOROP),           { STATE_TEXTURESTAGE(0, WINED3DTSS_COLOROP),          set_tex_op_atifs        }, 0                               },
917     {STATE_TEXTURESTAGE(1, WINED3DTSS_COLORARG1),         { STATE_TEXTURESTAGE(0, WINED3DTSS_COLOROP),          set_tex_op_atifs        }, 0                               },
918     {STATE_TEXTURESTAGE(1, WINED3DTSS_COLORARG2),         { STATE_TEXTURESTAGE(0, WINED3DTSS_COLOROP),          set_tex_op_atifs        }, 0                               },
919     {STATE_TEXTURESTAGE(1, WINED3DTSS_COLORARG0),         { STATE_TEXTURESTAGE(0, WINED3DTSS_COLOROP),          set_tex_op_atifs        }, 0                               },
920     {STATE_TEXTURESTAGE(1, WINED3DTSS_ALPHAOP),           { STATE_TEXTURESTAGE(0, WINED3DTSS_COLOROP),          set_tex_op_atifs        }, 0                               },
921     {STATE_TEXTURESTAGE(1, WINED3DTSS_ALPHAARG1),         { STATE_TEXTURESTAGE(0, WINED3DTSS_COLOROP),          set_tex_op_atifs        }, 0                               },
922     {STATE_TEXTURESTAGE(1, WINED3DTSS_ALPHAARG2),         { STATE_TEXTURESTAGE(0, WINED3DTSS_COLOROP),          set_tex_op_atifs        }, 0                               },
923     {STATE_TEXTURESTAGE(1, WINED3DTSS_ALPHAARG0),         { STATE_TEXTURESTAGE(0, WINED3DTSS_COLOROP),          set_tex_op_atifs        }, 0                               },
924     {STATE_TEXTURESTAGE(1, WINED3DTSS_RESULTARG),         { STATE_TEXTURESTAGE(0, WINED3DTSS_COLOROP),          set_tex_op_atifs        }, 0                               },
925     {STATE_TEXTURESTAGE(1, WINED3DTSS_BUMPENVMAT00),      { STATE_TEXTURESTAGE(1, WINED3DTSS_BUMPENVMAT00),     set_bumpmat             }, 0                               },
926     {STATE_TEXTURESTAGE(1, WINED3DTSS_BUMPENVMAT01),      { STATE_TEXTURESTAGE(1, WINED3DTSS_BUMPENVMAT00),     set_bumpmat             }, 0                               },
927     {STATE_TEXTURESTAGE(1, WINED3DTSS_BUMPENVMAT10),      { STATE_TEXTURESTAGE(1, WINED3DTSS_BUMPENVMAT00),     set_bumpmat             }, 0                               },
928     {STATE_TEXTURESTAGE(1, WINED3DTSS_BUMPENVMAT11),      { STATE_TEXTURESTAGE(1, WINED3DTSS_BUMPENVMAT00),     set_bumpmat             }, 0                               },
929     {STATE_TEXTURESTAGE(2, WINED3DTSS_COLOROP),           { STATE_TEXTURESTAGE(0, WINED3DTSS_COLOROP),          set_tex_op_atifs        }, 0                               },
930     {STATE_TEXTURESTAGE(2, WINED3DTSS_COLORARG1),         { STATE_TEXTURESTAGE(0, WINED3DTSS_COLOROP),          set_tex_op_atifs        }, 0                               },
931     {STATE_TEXTURESTAGE(2, WINED3DTSS_COLORARG2),         { STATE_TEXTURESTAGE(0, WINED3DTSS_COLOROP),          set_tex_op_atifs        }, 0                               },
932     {STATE_TEXTURESTAGE(2, WINED3DTSS_COLORARG0),         { STATE_TEXTURESTAGE(0, WINED3DTSS_COLOROP),          set_tex_op_atifs        }, 0                               },
933     {STATE_TEXTURESTAGE(2, WINED3DTSS_ALPHAOP),           { STATE_TEXTURESTAGE(0, WINED3DTSS_COLOROP),          set_tex_op_atifs        }, 0                               },
934     {STATE_TEXTURESTAGE(2, WINED3DTSS_ALPHAARG1),         { STATE_TEXTURESTAGE(0, WINED3DTSS_COLOROP),          set_tex_op_atifs        }, 0                               },
935     {STATE_TEXTURESTAGE(2, WINED3DTSS_ALPHAARG2),         { STATE_TEXTURESTAGE(0, WINED3DTSS_COLOROP),          set_tex_op_atifs        }, 0                               },
936     {STATE_TEXTURESTAGE(2, WINED3DTSS_ALPHAARG0),         { STATE_TEXTURESTAGE(0, WINED3DTSS_COLOROP),          set_tex_op_atifs        }, 0                               },
937     {STATE_TEXTURESTAGE(2, WINED3DTSS_RESULTARG),         { STATE_TEXTURESTAGE(0, WINED3DTSS_COLOROP),          set_tex_op_atifs        }, 0                               },
938     {STATE_TEXTURESTAGE(2, WINED3DTSS_BUMPENVMAT00),      { STATE_TEXTURESTAGE(2, WINED3DTSS_BUMPENVMAT00),     set_bumpmat             }, 0                               },
939     {STATE_TEXTURESTAGE(2, WINED3DTSS_BUMPENVMAT01),      { STATE_TEXTURESTAGE(2, WINED3DTSS_BUMPENVMAT00),     set_bumpmat             }, 0                               },
940     {STATE_TEXTURESTAGE(2, WINED3DTSS_BUMPENVMAT10),      { STATE_TEXTURESTAGE(2, WINED3DTSS_BUMPENVMAT00),     set_bumpmat             }, 0                               },
941     {STATE_TEXTURESTAGE(2, WINED3DTSS_BUMPENVMAT11),      { STATE_TEXTURESTAGE(2, WINED3DTSS_BUMPENVMAT00),     set_bumpmat             }, 0                               },
942     {STATE_TEXTURESTAGE(3, WINED3DTSS_COLOROP),           { STATE_TEXTURESTAGE(0, WINED3DTSS_COLOROP),          set_tex_op_atifs        }, 0                               },
943     {STATE_TEXTURESTAGE(3, WINED3DTSS_COLORARG1),         { STATE_TEXTURESTAGE(0, WINED3DTSS_COLOROP),          set_tex_op_atifs        }, 0                               },
944     {STATE_TEXTURESTAGE(3, WINED3DTSS_COLORARG2),         { STATE_TEXTURESTAGE(0, WINED3DTSS_COLOROP),          set_tex_op_atifs        }, 0                               },
945     {STATE_TEXTURESTAGE(3, WINED3DTSS_COLORARG0),         { STATE_TEXTURESTAGE(0, WINED3DTSS_COLOROP),          set_tex_op_atifs        }, 0                               },
946     {STATE_TEXTURESTAGE(3, WINED3DTSS_ALPHAOP),           { STATE_TEXTURESTAGE(0, WINED3DTSS_COLOROP),          set_tex_op_atifs        }, 0                               },
947     {STATE_TEXTURESTAGE(3, WINED3DTSS_ALPHAARG1),         { STATE_TEXTURESTAGE(0, WINED3DTSS_COLOROP),          set_tex_op_atifs        }, 0                               },
948     {STATE_TEXTURESTAGE(3, WINED3DTSS_ALPHAARG2),         { STATE_TEXTURESTAGE(0, WINED3DTSS_COLOROP),          set_tex_op_atifs        }, 0                               },
949     {STATE_TEXTURESTAGE(3, WINED3DTSS_ALPHAARG0),         { STATE_TEXTURESTAGE(0, WINED3DTSS_COLOROP),          set_tex_op_atifs        }, 0                               },
950     {STATE_TEXTURESTAGE(3, WINED3DTSS_RESULTARG),         { STATE_TEXTURESTAGE(0, WINED3DTSS_COLOROP),          set_tex_op_atifs        }, 0                               },
951     {STATE_TEXTURESTAGE(3, WINED3DTSS_BUMPENVMAT00),      { STATE_TEXTURESTAGE(3, WINED3DTSS_BUMPENVMAT00),     set_bumpmat             }, 0                               },
952     {STATE_TEXTURESTAGE(3, WINED3DTSS_BUMPENVMAT01),      { STATE_TEXTURESTAGE(3, WINED3DTSS_BUMPENVMAT00),     set_bumpmat             }, 0                               },
953     {STATE_TEXTURESTAGE(3, WINED3DTSS_BUMPENVMAT10),      { STATE_TEXTURESTAGE(3, WINED3DTSS_BUMPENVMAT00),     set_bumpmat             }, 0                               },
954     {STATE_TEXTURESTAGE(3, WINED3DTSS_BUMPENVMAT11),      { STATE_TEXTURESTAGE(3, WINED3DTSS_BUMPENVMAT00),     set_bumpmat             }, 0                               },
955     {STATE_TEXTURESTAGE(4, WINED3DTSS_COLOROP),           { STATE_TEXTURESTAGE(0, WINED3DTSS_COLOROP),          set_tex_op_atifs        }, 0                               },
956     {STATE_TEXTURESTAGE(4, WINED3DTSS_COLORARG1),         { STATE_TEXTURESTAGE(0, WINED3DTSS_COLOROP),          set_tex_op_atifs        }, 0                               },
957     {STATE_TEXTURESTAGE(4, WINED3DTSS_COLORARG2),         { STATE_TEXTURESTAGE(0, WINED3DTSS_COLOROP),          set_tex_op_atifs        }, 0                               },
958     {STATE_TEXTURESTAGE(4, WINED3DTSS_COLORARG0),         { STATE_TEXTURESTAGE(0, WINED3DTSS_COLOROP),          set_tex_op_atifs        }, 0                               },
959     {STATE_TEXTURESTAGE(4, WINED3DTSS_ALPHAOP),           { STATE_TEXTURESTAGE(0, WINED3DTSS_COLOROP),          set_tex_op_atifs        }, 0                               },
960     {STATE_TEXTURESTAGE(4, WINED3DTSS_ALPHAARG1),         { STATE_TEXTURESTAGE(0, WINED3DTSS_COLOROP),          set_tex_op_atifs        }, 0                               },
961     {STATE_TEXTURESTAGE(4, WINED3DTSS_ALPHAARG2),         { STATE_TEXTURESTAGE(0, WINED3DTSS_COLOROP),          set_tex_op_atifs        }, 0                               },
962     {STATE_TEXTURESTAGE(4, WINED3DTSS_ALPHAARG0),         { STATE_TEXTURESTAGE(0, WINED3DTSS_COLOROP),          set_tex_op_atifs        }, 0                               },
963     {STATE_TEXTURESTAGE(4, WINED3DTSS_RESULTARG),         { STATE_TEXTURESTAGE(0, WINED3DTSS_COLOROP),          set_tex_op_atifs        }, 0                               },
964     {STATE_TEXTURESTAGE(4, WINED3DTSS_BUMPENVMAT00),      { STATE_TEXTURESTAGE(4, WINED3DTSS_BUMPENVMAT00),     set_bumpmat             }, 0                               },
965     {STATE_TEXTURESTAGE(4, WINED3DTSS_BUMPENVMAT01),      { STATE_TEXTURESTAGE(4, WINED3DTSS_BUMPENVMAT00),     set_bumpmat             }, 0                               },
966     {STATE_TEXTURESTAGE(4, WINED3DTSS_BUMPENVMAT10),      { STATE_TEXTURESTAGE(4, WINED3DTSS_BUMPENVMAT00),     set_bumpmat             }, 0                               },
967     {STATE_TEXTURESTAGE(4, WINED3DTSS_BUMPENVMAT11),      { STATE_TEXTURESTAGE(4, WINED3DTSS_BUMPENVMAT00),     set_bumpmat             }, 0                               },
968     {STATE_TEXTURESTAGE(5, WINED3DTSS_COLOROP),           { STATE_TEXTURESTAGE(0, WINED3DTSS_COLOROP),          set_tex_op_atifs        }, 0                               },
969     {STATE_TEXTURESTAGE(5, WINED3DTSS_COLORARG1),         { STATE_TEXTURESTAGE(0, WINED3DTSS_COLOROP),          set_tex_op_atifs        }, 0                               },
970     {STATE_TEXTURESTAGE(5, WINED3DTSS_COLORARG2),         { STATE_TEXTURESTAGE(0, WINED3DTSS_COLOROP),          set_tex_op_atifs        }, 0                               },
971     {STATE_TEXTURESTAGE(5, WINED3DTSS_COLORARG0),         { STATE_TEXTURESTAGE(0, WINED3DTSS_COLOROP),          set_tex_op_atifs        }, 0                               },
972     {STATE_TEXTURESTAGE(5, WINED3DTSS_ALPHAOP),           { STATE_TEXTURESTAGE(0, WINED3DTSS_COLOROP),          set_tex_op_atifs        }, 0                               },
973     {STATE_TEXTURESTAGE(5, WINED3DTSS_ALPHAARG1),         { STATE_TEXTURESTAGE(0, WINED3DTSS_COLOROP),          set_tex_op_atifs        }, 0                               },
974     {STATE_TEXTURESTAGE(5, WINED3DTSS_ALPHAARG2),         { STATE_TEXTURESTAGE(0, WINED3DTSS_COLOROP),          set_tex_op_atifs        }, 0                               },
975     {STATE_TEXTURESTAGE(5, WINED3DTSS_ALPHAARG0),         { STATE_TEXTURESTAGE(0, WINED3DTSS_COLOROP),          set_tex_op_atifs        }, 0                               },
976     {STATE_TEXTURESTAGE(5, WINED3DTSS_RESULTARG),         { STATE_TEXTURESTAGE(0, WINED3DTSS_COLOROP),          set_tex_op_atifs        }, 0                               },
977     {STATE_TEXTURESTAGE(5, WINED3DTSS_BUMPENVMAT00),      { STATE_TEXTURESTAGE(5, WINED3DTSS_BUMPENVMAT00),     set_bumpmat             }, 0                               },
978     {STATE_TEXTURESTAGE(5, WINED3DTSS_BUMPENVMAT01),      { STATE_TEXTURESTAGE(5, WINED3DTSS_BUMPENVMAT00),     set_bumpmat             }, 0                               },
979     {STATE_TEXTURESTAGE(5, WINED3DTSS_BUMPENVMAT10),      { STATE_TEXTURESTAGE(5, WINED3DTSS_BUMPENVMAT00),     set_bumpmat             }, 0                               },
980     {STATE_TEXTURESTAGE(5, WINED3DTSS_BUMPENVMAT11),      { STATE_TEXTURESTAGE(5, WINED3DTSS_BUMPENVMAT00),     set_bumpmat             }, 0                               },
981     {STATE_TEXTURESTAGE(6, WINED3DTSS_COLOROP),           { STATE_TEXTURESTAGE(0, WINED3DTSS_COLOROP),          set_tex_op_atifs        }, 0                               },
982     {STATE_TEXTURESTAGE(6, WINED3DTSS_COLORARG1),         { STATE_TEXTURESTAGE(0, WINED3DTSS_COLOROP),          set_tex_op_atifs        }, 0                               },
983     {STATE_TEXTURESTAGE(6, WINED3DTSS_COLORARG2),         { STATE_TEXTURESTAGE(0, WINED3DTSS_COLOROP),          set_tex_op_atifs        }, 0                               },
984     {STATE_TEXTURESTAGE(6, WINED3DTSS_COLORARG0),         { STATE_TEXTURESTAGE(0, WINED3DTSS_COLOROP),          set_tex_op_atifs        }, 0                               },
985     {STATE_TEXTURESTAGE(6, WINED3DTSS_ALPHAOP),           { STATE_TEXTURESTAGE(0, WINED3DTSS_COLOROP),          set_tex_op_atifs        }, 0                               },
986     {STATE_TEXTURESTAGE(6, WINED3DTSS_ALPHAARG1),         { STATE_TEXTURESTAGE(0, WINED3DTSS_COLOROP),          set_tex_op_atifs        }, 0                               },
987     {STATE_TEXTURESTAGE(6, WINED3DTSS_ALPHAARG2),         { STATE_TEXTURESTAGE(0, WINED3DTSS_COLOROP),          set_tex_op_atifs        }, 0                               },
988     {STATE_TEXTURESTAGE(6, WINED3DTSS_ALPHAARG0),         { STATE_TEXTURESTAGE(0, WINED3DTSS_COLOROP),          set_tex_op_atifs        }, 0                               },
989     {STATE_TEXTURESTAGE(6, WINED3DTSS_RESULTARG),         { STATE_TEXTURESTAGE(0, WINED3DTSS_COLOROP),          set_tex_op_atifs        }, 0                               },
990     {STATE_TEXTURESTAGE(6, WINED3DTSS_BUMPENVMAT00),      { STATE_TEXTURESTAGE(6, WINED3DTSS_BUMPENVMAT00),     set_bumpmat             }, 0                               },
991     {STATE_TEXTURESTAGE(6, WINED3DTSS_BUMPENVMAT01),      { STATE_TEXTURESTAGE(6, WINED3DTSS_BUMPENVMAT00),     set_bumpmat             }, 0                               },
992     {STATE_TEXTURESTAGE(6, WINED3DTSS_BUMPENVMAT10),      { STATE_TEXTURESTAGE(6, WINED3DTSS_BUMPENVMAT00),     set_bumpmat             }, 0                               },
993     {STATE_TEXTURESTAGE(6, WINED3DTSS_BUMPENVMAT11),      { STATE_TEXTURESTAGE(6, WINED3DTSS_BUMPENVMAT00),     set_bumpmat             }, 0                               },
994     {STATE_TEXTURESTAGE(7, WINED3DTSS_COLOROP),           { STATE_TEXTURESTAGE(0, WINED3DTSS_COLOROP),          set_tex_op_atifs        }, 0                               },
995     {STATE_TEXTURESTAGE(7, WINED3DTSS_COLORARG1),         { STATE_TEXTURESTAGE(0, WINED3DTSS_COLOROP),          set_tex_op_atifs        }, 0                               },
996     {STATE_TEXTURESTAGE(7, WINED3DTSS_COLORARG2),         { STATE_TEXTURESTAGE(0, WINED3DTSS_COLOROP),          set_tex_op_atifs        }, 0                               },
997     {STATE_TEXTURESTAGE(7, WINED3DTSS_COLORARG0),         { STATE_TEXTURESTAGE(0, WINED3DTSS_COLOROP),          set_tex_op_atifs        }, 0                               },
998     {STATE_TEXTURESTAGE(7, WINED3DTSS_ALPHAOP),           { STATE_TEXTURESTAGE(0, WINED3DTSS_COLOROP),          set_tex_op_atifs        }, 0                               },
999     {STATE_TEXTURESTAGE(7, WINED3DTSS_ALPHAARG1),         { STATE_TEXTURESTAGE(0, WINED3DTSS_COLOROP),          set_tex_op_atifs        }, 0                               },
1000     {STATE_TEXTURESTAGE(7, WINED3DTSS_ALPHAARG2),         { STATE_TEXTURESTAGE(0, WINED3DTSS_COLOROP),          set_tex_op_atifs        }, 0                               },
1001     {STATE_TEXTURESTAGE(7, WINED3DTSS_ALPHAARG0),         { STATE_TEXTURESTAGE(0, WINED3DTSS_COLOROP),          set_tex_op_atifs        }, 0                               },
1002     {STATE_TEXTURESTAGE(7, WINED3DTSS_RESULTARG),         { STATE_TEXTURESTAGE(0, WINED3DTSS_COLOROP),          set_tex_op_atifs        }, 0                               },
1003     {STATE_TEXTURESTAGE(7, WINED3DTSS_BUMPENVMAT00),      { STATE_TEXTURESTAGE(7, WINED3DTSS_BUMPENVMAT00),     set_bumpmat             }, 0                               },
1004     {STATE_TEXTURESTAGE(7, WINED3DTSS_BUMPENVMAT01),      { STATE_TEXTURESTAGE(7, WINED3DTSS_BUMPENVMAT00),     set_bumpmat             }, 0                               },
1005     {STATE_TEXTURESTAGE(7, WINED3DTSS_BUMPENVMAT10),      { STATE_TEXTURESTAGE(7, WINED3DTSS_BUMPENVMAT00),     set_bumpmat             }, 0                               },
1006     {STATE_TEXTURESTAGE(7, WINED3DTSS_BUMPENVMAT11),      { STATE_TEXTURESTAGE(7, WINED3DTSS_BUMPENVMAT00),     set_bumpmat             }, 0                               },
1007     { STATE_SAMPLER(0),                                   { STATE_SAMPLER(0),                                   sampler_texdim          }, 0                               },
1008     { STATE_SAMPLER(1),                                   { STATE_SAMPLER(1),                                   sampler_texdim          }, 0                               },
1009     { STATE_SAMPLER(2),                                   { STATE_SAMPLER(2),                                   sampler_texdim          }, 0                               },
1010     { STATE_SAMPLER(3),                                   { STATE_SAMPLER(3),                                   sampler_texdim          }, 0                               },
1011     { STATE_SAMPLER(4),                                   { STATE_SAMPLER(4),                                   sampler_texdim          }, 0                               },
1012     { STATE_SAMPLER(5),                                   { STATE_SAMPLER(5),                                   sampler_texdim          }, 0                               },
1013     { STATE_SAMPLER(6),                                   { STATE_SAMPLER(6),                                   sampler_texdim          }, 0                               },
1014     { STATE_SAMPLER(7),                                   { STATE_SAMPLER(7),                                   sampler_texdim          }, 0                               },
1015     {STATE_TEXTURESTAGE(0,WINED3DTSS_TEXTURETRANSFORMFLAGS),{STATE_TEXTURESTAGE(0, WINED3DTSS_TEXTURETRANSFORMFLAGS), textransform      }, 0                               },
1016     {STATE_TEXTURESTAGE(1,WINED3DTSS_TEXTURETRANSFORMFLAGS),{STATE_TEXTURESTAGE(1, WINED3DTSS_TEXTURETRANSFORMFLAGS), textransform      }, 0                               },
1017     {STATE_TEXTURESTAGE(2,WINED3DTSS_TEXTURETRANSFORMFLAGS),{STATE_TEXTURESTAGE(2, WINED3DTSS_TEXTURETRANSFORMFLAGS), textransform      }, 0                               },
1018     {STATE_TEXTURESTAGE(3,WINED3DTSS_TEXTURETRANSFORMFLAGS),{STATE_TEXTURESTAGE(3, WINED3DTSS_TEXTURETRANSFORMFLAGS), textransform      }, 0                               },
1019     {STATE_TEXTURESTAGE(4,WINED3DTSS_TEXTURETRANSFORMFLAGS),{STATE_TEXTURESTAGE(4, WINED3DTSS_TEXTURETRANSFORMFLAGS), textransform      }, 0                               },
1020     {STATE_TEXTURESTAGE(5,WINED3DTSS_TEXTURETRANSFORMFLAGS),{STATE_TEXTURESTAGE(5, WINED3DTSS_TEXTURETRANSFORMFLAGS), textransform      }, 0                               },
1021     {STATE_TEXTURESTAGE(6,WINED3DTSS_TEXTURETRANSFORMFLAGS),{STATE_TEXTURESTAGE(6, WINED3DTSS_TEXTURETRANSFORMFLAGS), textransform      }, 0                               },
1022     {STATE_TEXTURESTAGE(7,WINED3DTSS_TEXTURETRANSFORMFLAGS),{STATE_TEXTURESTAGE(7, WINED3DTSS_TEXTURETRANSFORMFLAGS), textransform      }, 0                               },
1023     {0 /* Terminate */,                                   { 0,                                                  0                       }, 0                               },
1024 };
1025
1026 static void atifs_enable(IWineD3DDevice *iface, BOOL enable) {
1027     if(enable) {
1028         glEnable(GL_FRAGMENT_SHADER_ATI);
1029         checkGLcall("glEnable(GL_FRAGMENT_SHADER_ATI)");
1030     } else {
1031         glDisable(GL_FRAGMENT_SHADER_ATI);
1032         checkGLcall("glDisable(GL_FRAGMENT_SHADER_ATI)");
1033     }
1034 }
1035
1036 static void atifs_get_caps(WINED3DDEVTYPE devtype, const WineD3D_GL_Info *gl_info, struct fragment_caps *caps)
1037 {
1038     caps->TextureOpCaps =  WINED3DTEXOPCAPS_DISABLE                     |
1039                            WINED3DTEXOPCAPS_SELECTARG1                  |
1040                            WINED3DTEXOPCAPS_SELECTARG2                  |
1041                            WINED3DTEXOPCAPS_MODULATE4X                  |
1042                            WINED3DTEXOPCAPS_MODULATE2X                  |
1043                            WINED3DTEXOPCAPS_MODULATE                    |
1044                            WINED3DTEXOPCAPS_ADDSIGNED2X                 |
1045                            WINED3DTEXOPCAPS_ADDSIGNED                   |
1046                            WINED3DTEXOPCAPS_ADD                         |
1047                            WINED3DTEXOPCAPS_SUBTRACT                    |
1048                            WINED3DTEXOPCAPS_ADDSMOOTH                   |
1049                            WINED3DTEXOPCAPS_BLENDCURRENTALPHA           |
1050                            WINED3DTEXOPCAPS_BLENDFACTORALPHA            |
1051                            WINED3DTEXOPCAPS_BLENDTEXTUREALPHA           |
1052                            WINED3DTEXOPCAPS_BLENDDIFFUSEALPHA           |
1053                            WINED3DTEXOPCAPS_BLENDTEXTUREALPHAPM         |
1054                            WINED3DTEXOPCAPS_MODULATEALPHA_ADDCOLOR      |
1055                            WINED3DTEXOPCAPS_MODULATECOLOR_ADDALPHA      |
1056                            WINED3DTEXOPCAPS_MODULATEINVCOLOR_ADDALPHA   |
1057                            WINED3DTEXOPCAPS_MODULATEINVALPHA_ADDCOLOR   |
1058                            WINED3DTEXOPCAPS_DOTPRODUCT3                 |
1059                            WINED3DTEXOPCAPS_MULTIPLYADD                 |
1060                            WINED3DTEXOPCAPS_LERP                        |
1061                            WINED3DTEXOPCAPS_BUMPENVMAP;
1062
1063     /* TODO: Implement WINED3DTEXOPCAPS_BUMPENVMAPLUMINANCE
1064     and WINED3DTEXOPCAPS_PREMODULATE */
1065
1066     /* GL_ATI_fragment_shader always supports 6 textures, which was the limit on r200 cards
1067      * which this extension is exclusively focused on(later cards have GL_ARB_fragment_program).
1068      * If the current card has more than 8 fixed function textures in OpenGL's regular fixed
1069      * function pipeline then the ATI_fragment_shader backend imposes a stricter limit. This
1070      * shouldn't be too hard since Nvidia cards have a limit of 4 textures with the default ffp
1071      * pipeline, and almost all games are happy with that. We can however support up to 8
1072      * texture stages because we have a 2nd pass limit of 8 instructions, and per stage we use
1073      * only 1 instruction.
1074      *
1075      * The proper fix for this is not to use GL_ATI_fragment_shader on cards newer than the
1076      * r200 series and use an ARB or GLSL shader instead
1077      */
1078     caps->MaxTextureBlendStages   = 8;
1079     caps->MaxSimultaneousTextures = 6;
1080
1081     caps->PrimitiveMiscCaps |= WINED3DPMISCCAPS_TSSARGTEMP;
1082 }
1083
1084 static HRESULT atifs_alloc(IWineD3DDevice *iface) {
1085     IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
1086     struct atifs_private_data *priv;
1087
1088     This->fragment_priv = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(struct atifs_private_data));
1089     if(!This->fragment_priv) {
1090         ERR("Out of memory\n");
1091         return E_OUTOFMEMORY;
1092     }
1093     priv = (struct atifs_private_data *) This->fragment_priv;
1094     priv->fragment_shaders = hash_table_create(ffp_frag_program_key_hash, ffp_frag_program_key_compare);
1095     return WINED3D_OK;
1096 }
1097
1098 #define GLINFO_LOCATION This->adapter->gl_info
1099 static void atifs_free_ffpshader(void *value, void *device) {
1100     IWineD3DDeviceImpl *This = device;
1101     struct atifs_ffp_desc *entry_ati = value;
1102
1103     ENTER_GL();
1104     GL_EXTCALL(glDeleteFragmentShaderATI(entry_ati->shader));
1105     checkGLcall("glDeleteFragmentShaderATI(entry->shader)");
1106     HeapFree(GetProcessHeap(), 0, entry_ati);
1107     LEAVE_GL();
1108 }
1109
1110 static void atifs_free(IWineD3DDevice *iface) {
1111     IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
1112     struct atifs_private_data *priv = (struct atifs_private_data *) This->fragment_priv;
1113
1114     hash_table_destroy(priv->fragment_shaders, atifs_free_ffpshader, This);
1115
1116     HeapFree(GetProcessHeap(), 0, priv);
1117     This->fragment_priv = NULL;
1118 }
1119 #undef GLINFO_LOCATION
1120
1121 static BOOL atifs_color_fixup_supported(struct color_fixup_desc fixup)
1122 {
1123     if (TRACE_ON(d3d_shader) && TRACE_ON(d3d))
1124     {
1125         TRACE("Checking support for fixup:\n");
1126         dump_color_fixup_desc(fixup);
1127     }
1128
1129     /* We only support sign fixup of the first two channels. */
1130     if (fixup.x_source == CHANNEL_SOURCE_X && fixup.y_source == CHANNEL_SOURCE_Y
1131             && fixup.z_source == CHANNEL_SOURCE_Z && fixup.w_source == CHANNEL_SOURCE_W
1132             && !fixup.z_sign_fixup && !fixup.w_sign_fixup)
1133     {
1134         TRACE("[OK]\n");
1135         return TRUE;
1136     }
1137
1138     TRACE("[FAILED]\n");
1139     return FALSE;
1140 }
1141
1142 const struct fragment_pipeline atifs_fragment_pipeline = {
1143     atifs_enable,
1144     atifs_get_caps,
1145     atifs_alloc,
1146     atifs_free,
1147     atifs_color_fixup_supported,
1148     atifs_fragmentstate_template,
1149     TRUE /* We can disable projected textures */
1150 };