[WINED3D]
[reactos.git] / reactos / dll / directx / wine / 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 "wined3d_private.h"
22
23 WINE_DEFAULT_DEBUG_CHANNEL(d3d_shader);
24 WINE_DECLARE_DEBUG_CHANNEL(d3d);
25
26 /* Context activation for state handlers is done by the caller. */
27
28 /* Some private defines, Constant associations, etc.
29 * Env bump matrix and per stage constant should be independent,
30 * a stage that bump maps can't read the per state constant
31 */
32 #define ATI_FFP_CONST_BUMPMAT(i) (GL_CON_0_ATI + i)
33 #define ATI_FFP_CONST_CONSTANT0 GL_CON_0_ATI
34 #define ATI_FFP_CONST_CONSTANT1 GL_CON_1_ATI
35 #define ATI_FFP_CONST_CONSTANT2 GL_CON_2_ATI
36 #define ATI_FFP_CONST_CONSTANT3 GL_CON_3_ATI
37 #define ATI_FFP_CONST_CONSTANT4 GL_CON_4_ATI
38 #define ATI_FFP_CONST_CONSTANT5 GL_CON_5_ATI
39 #define ATI_FFP_CONST_TFACTOR GL_CON_6_ATI
40
41 /* GL_ATI_fragment_shader specific fixed function pipeline description. "Inherits" from the common one */
42 struct atifs_ffp_desc
43 {
44 struct ffp_frag_desc parent;
45 GLuint shader;
46 unsigned int num_textures_used;
47 };
48
49 struct atifs_private_data
50 {
51 struct wine_rb_tree fragment_shaders; /* A rb-tree to track fragment pipeline replacement shaders */
52 };
53
54 static const char *debug_dstmod(GLuint mod) {
55 switch(mod) {
56 case GL_NONE: return "GL_NONE";
57 case GL_2X_BIT_ATI: return "GL_2X_BIT_ATI";
58 case GL_4X_BIT_ATI: return "GL_4X_BIT_ATI";
59 case GL_8X_BIT_ATI: return "GL_8X_BIT_ATI";
60 case GL_HALF_BIT_ATI: return "GL_HALF_BIT_ATI";
61 case GL_QUARTER_BIT_ATI: return "GL_QUARTER_BIT_ATI";
62 case GL_EIGHTH_BIT_ATI: return "GL_EIGHTH_BIT_ATI";
63 case GL_SATURATE_BIT_ATI: return "GL_SATURATE_BIT_ATI";
64 default: return "Unexpected modifier\n";
65 }
66 }
67
68 static const char *debug_argmod(GLuint mod) {
69 switch(mod) {
70 case GL_NONE:
71 return "GL_NONE";
72
73 case GL_2X_BIT_ATI:
74 return "GL_2X_BIT_ATI";
75 case GL_COMP_BIT_ATI:
76 return "GL_COMP_BIT_ATI";
77 case GL_NEGATE_BIT_ATI:
78 return "GL_NEGATE_BIT_ATI";
79 case GL_BIAS_BIT_ATI:
80 return "GL_BIAS_BIT_ATI";
81
82 case GL_2X_BIT_ATI | GL_COMP_BIT_ATI:
83 return "GL_2X_BIT_ATI | GL_COMP_BIT_ATI";
84 case GL_2X_BIT_ATI | GL_NEGATE_BIT_ATI:
85 return "GL_2X_BIT_ATI | GL_NEGATE_BIT_ATI";
86 case GL_2X_BIT_ATI | GL_BIAS_BIT_ATI:
87 return "GL_2X_BIT_ATI | GL_BIAS_BIT_ATI";
88 case GL_COMP_BIT_ATI | GL_NEGATE_BIT_ATI:
89 return "GL_COMP_BIT_ATI | GL_NEGATE_BIT_ATI";
90 case GL_COMP_BIT_ATI | GL_BIAS_BIT_ATI:
91 return "GL_COMP_BIT_ATI | GL_BIAS_BIT_ATI";
92 case GL_NEGATE_BIT_ATI | GL_BIAS_BIT_ATI:
93 return "GL_NEGATE_BIT_ATI | GL_BIAS_BIT_ATI";
94
95 case GL_COMP_BIT_ATI | GL_NEGATE_BIT_ATI | GL_BIAS_BIT_ATI:
96 return "GL_COMP_BIT_ATI | GL_NEGATE_BIT_ATI | GL_BIAS_BIT_ATI";
97 case GL_2X_BIT_ATI | GL_NEGATE_BIT_ATI | GL_BIAS_BIT_ATI:
98 return "GL_2X_BIT_ATI | GL_NEGATE_BIT_ATI | GL_BIAS_BIT_ATI";
99 case GL_2X_BIT_ATI | GL_COMP_BIT_ATI | GL_BIAS_BIT_ATI:
100 return "GL_2X_BIT_ATI | GL_COMP_BIT_ATI | GL_BIAS_BIT_ATI";
101 case GL_2X_BIT_ATI | GL_COMP_BIT_ATI | GL_NEGATE_BIT_ATI:
102 return "GL_2X_BIT_ATI | GL_COMP_BIT_ATI | GL_NEGATE_BIT_ATI";
103
104 case GL_2X_BIT_ATI | GL_COMP_BIT_ATI | GL_NEGATE_BIT_ATI | GL_BIAS_BIT_ATI:
105 return "GL_2X_BIT_ATI | GL_COMP_BIT_ATI | GL_NEGATE_BIT_ATI | GL_BIAS_BIT_ATI";
106
107 default:
108 return "Unexpected argmod combination\n";
109 }
110 }
111 static const char *debug_register(GLuint reg) {
112 switch(reg) {
113 case GL_REG_0_ATI: return "GL_REG_0_ATI";
114 case GL_REG_1_ATI: return "GL_REG_1_ATI";
115 case GL_REG_2_ATI: return "GL_REG_2_ATI";
116 case GL_REG_3_ATI: return "GL_REG_3_ATI";
117 case GL_REG_4_ATI: return "GL_REG_4_ATI";
118 case GL_REG_5_ATI: return "GL_REG_5_ATI";
119
120 case GL_CON_0_ATI: return "GL_CON_0_ATI";
121 case GL_CON_1_ATI: return "GL_CON_1_ATI";
122 case GL_CON_2_ATI: return "GL_CON_2_ATI";
123 case GL_CON_3_ATI: return "GL_CON_3_ATI";
124 case GL_CON_4_ATI: return "GL_CON_4_ATI";
125 case GL_CON_5_ATI: return "GL_CON_5_ATI";
126 case GL_CON_6_ATI: return "GL_CON_6_ATI";
127 case GL_CON_7_ATI: return "GL_CON_7_ATI";
128
129 case GL_ZERO: return "GL_ZERO";
130 case GL_ONE: return "GL_ONE";
131 case GL_PRIMARY_COLOR: return "GL_PRIMARY_COLOR";
132 case GL_SECONDARY_INTERPOLATOR_ATI: return "GL_SECONDARY_INTERPOLATOR_ATI";
133
134 default: return "Unknown register\n";
135 }
136 }
137
138 static const char *debug_swizzle(GLuint swizzle) {
139 switch(swizzle) {
140 case GL_SWIZZLE_STR_ATI: return "GL_SWIZZLE_STR_ATI";
141 case GL_SWIZZLE_STQ_ATI: return "GL_SWIZZLE_STQ_ATI";
142 case GL_SWIZZLE_STR_DR_ATI: return "GL_SWIZZLE_STR_DR_ATI";
143 case GL_SWIZZLE_STQ_DQ_ATI: return "GL_SWIZZLE_STQ_DQ_ATI";
144 default: return "unknown swizzle";
145 }
146 }
147
148 static const char *debug_rep(GLuint rep) {
149 switch(rep) {
150 case GL_NONE: return "GL_NONE";
151 case GL_RED: return "GL_RED";
152 case GL_GREEN: return "GL_GREEN";
153 case GL_BLUE: return "GL_BLUE";
154 case GL_ALPHA: return "GL_ALPHA";
155 default: return "unknown argrep";
156 }
157 }
158
159 static const char *debug_op(GLuint op) {
160 switch(op) {
161 case GL_MOV_ATI: return "GL_MOV_ATI";
162 case GL_ADD_ATI: return "GL_ADD_ATI";
163 case GL_MUL_ATI: return "GL_MUL_ATI";
164 case GL_SUB_ATI: return "GL_SUB_ATI";
165 case GL_DOT3_ATI: return "GL_DOT3_ATI";
166 case GL_DOT4_ATI: return "GL_DOT4_ATI";
167 case GL_MAD_ATI: return "GL_MAD_ATI";
168 case GL_LERP_ATI: return "GL_LERP_ATI";
169 case GL_CND_ATI: return "GL_CND_ATI";
170 case GL_CND0_ATI: return "GL_CND0_ATI";
171 case GL_DOT2_ADD_ATI: return "GL_DOT2_ADD_ATI";
172 default: return "unexpected op";
173 }
174 }
175
176 static const char *debug_mask(GLuint mask) {
177 switch(mask) {
178 case GL_NONE: return "GL_NONE";
179 case GL_RED_BIT_ATI: return "GL_RED_BIT_ATI";
180 case GL_GREEN_BIT_ATI: return "GL_GREEN_BIT_ATI";
181 case GL_BLUE_BIT_ATI: return "GL_BLUE_BIT_ATI";
182 case GL_RED_BIT_ATI | GL_GREEN_BIT_ATI: return "GL_RED_BIT_ATI | GL_GREEN_BIT_ATI";
183 case GL_RED_BIT_ATI | GL_BLUE_BIT_ATI: return "GL_RED_BIT_ATI | GL_BLUE_BIT_ATI";
184 case GL_GREEN_BIT_ATI | GL_BLUE_BIT_ATI:return "GL_GREEN_BIT_ATI | GL_BLUE_BIT_ATI";
185 case GL_RED_BIT_ATI | GL_GREEN_BIT_ATI | GL_BLUE_BIT_ATI:return "GL_RED_BIT_ATI | GL_GREEN_BIT_ATI | GL_BLUE_BIT_ATI";
186 default: return "Unexpected writemask";
187 }
188 }
189
190 static void wrap_op1(const struct wined3d_gl_info *gl_info, GLuint op, GLuint dst, GLuint dstMask, GLuint dstMod,
191 GLuint arg1, GLuint arg1Rep, GLuint arg1Mod)
192 {
193 if(dstMask == GL_ALPHA) {
194 TRACE("glAlphaFragmentOp1ATI(%s, %s, %s, %s, %s, %s)\n", debug_op(op), debug_register(dst), debug_dstmod(dstMod),
195 debug_register(arg1), debug_rep(arg1Rep), debug_argmod(arg1Mod));
196 GL_EXTCALL(glAlphaFragmentOp1ATI(op, dst, dstMod, arg1, arg1Rep, arg1Mod));
197 } else {
198 TRACE("glColorFragmentOp1ATI(%s, %s, %s, %s, %s, %s, %s)\n", debug_op(op), debug_register(dst),
199 debug_mask(dstMask), debug_dstmod(dstMod),
200 debug_register(arg1), debug_rep(arg1Rep), debug_argmod(arg1Mod));
201 GL_EXTCALL(glColorFragmentOp1ATI(op, dst, dstMask, dstMod, arg1, arg1Rep, arg1Mod));
202 }
203 }
204
205 static void wrap_op2(const struct wined3d_gl_info *gl_info, GLuint op, GLuint dst, GLuint dstMask, GLuint dstMod,
206 GLuint arg1, GLuint arg1Rep, GLuint arg1Mod, GLuint arg2, GLuint arg2Rep, GLuint arg2Mod)
207 {
208 if(dstMask == GL_ALPHA) {
209 TRACE("glAlphaFragmentOp2ATI(%s, %s, %s, %s, %s, %s, %s, %s, %s)\n", debug_op(op), debug_register(dst), debug_dstmod(dstMod),
210 debug_register(arg1), debug_rep(arg1Rep), debug_argmod(arg1Mod),
211 debug_register(arg2), debug_rep(arg2Rep), debug_argmod(arg2Mod));
212 GL_EXTCALL(glAlphaFragmentOp2ATI(op, dst, dstMod, arg1, arg1Rep, arg1Mod, arg2, arg2Rep, arg2Mod));
213 } else {
214 TRACE("glColorFragmentOp2ATI(%s, %s, %s, %s, %s, %s, %s, %s, %s, %s)\n", debug_op(op), debug_register(dst),
215 debug_mask(dstMask), debug_dstmod(dstMod),
216 debug_register(arg1), debug_rep(arg1Rep), debug_argmod(arg1Mod),
217 debug_register(arg2), debug_rep(arg2Rep), debug_argmod(arg2Mod));
218 GL_EXTCALL(glColorFragmentOp2ATI(op, dst, dstMask, dstMod, arg1, arg1Rep, arg1Mod, arg2, arg2Rep, arg2Mod));
219 }
220 }
221
222 static void wrap_op3(const struct wined3d_gl_info *gl_info, GLuint op, GLuint dst, GLuint dstMask, GLuint dstMod,
223 GLuint arg1, GLuint arg1Rep, GLuint arg1Mod, GLuint arg2, GLuint arg2Rep, GLuint arg2Mod,
224 GLuint arg3, GLuint arg3Rep, GLuint arg3Mod)
225 {
226 if(dstMask == GL_ALPHA) {
227 /* Leave some free space to fit "GL_NONE, " in to align most alpha and color op lines */
228 TRACE("glAlphaFragmentOp3ATI(%s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s)\n", debug_op(op), debug_register(dst), debug_dstmod(dstMod),
229 debug_register(arg1), debug_rep(arg1Rep), debug_argmod(arg1Mod),
230 debug_register(arg2), debug_rep(arg2Rep), debug_argmod(arg2Mod),
231 debug_register(arg3), debug_rep(arg3Rep), debug_argmod(arg3Mod));
232 GL_EXTCALL(glAlphaFragmentOp3ATI(op, dst, dstMod,
233 arg1, arg1Rep, arg1Mod,
234 arg2, arg2Rep, arg2Mod,
235 arg3, arg3Rep, arg3Mod));
236 } else {
237 TRACE("glColorFragmentOp3ATI(%s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s)\n", debug_op(op), debug_register(dst),
238 debug_mask(dstMask), debug_dstmod(dstMod),
239 debug_register(arg1), debug_rep(arg1Rep), debug_argmod(arg1Mod),
240 debug_register(arg2), debug_rep(arg2Rep), debug_argmod(arg2Mod),
241 debug_register(arg3), debug_rep(arg3Rep), debug_argmod(arg3Mod));
242 GL_EXTCALL(glColorFragmentOp3ATI(op, dst, dstMask, dstMod,
243 arg1, arg1Rep, arg1Mod,
244 arg2, arg2Rep, arg2Mod,
245 arg3, arg3Rep, arg3Mod));
246 }
247 }
248
249 static GLuint register_for_arg(DWORD arg, const struct wined3d_gl_info *gl_info,
250 unsigned int stage, GLuint *mod, GLuint *rep, GLuint tmparg)
251 {
252 GLenum ret;
253
254 if(mod) *mod = GL_NONE;
255 if(arg == ARG_UNUSED)
256 {
257 if (rep) *rep = GL_NONE;
258 return -1; /* This is the marker for unused registers */
259 }
260
261 switch(arg & WINED3DTA_SELECTMASK) {
262 case WINED3DTA_DIFFUSE:
263 ret = GL_PRIMARY_COLOR;
264 break;
265
266 case WINED3DTA_CURRENT:
267 /* Note that using GL_REG_0_ATI for the passed on register is safe because
268 * texture0 is read at stage0, so in the worst case it is read in the
269 * instruction writing to reg0. Afterwards texture0 is not used any longer.
270 * If we're reading from current
271 */
272 ret = stage ? GL_REG_0_ATI : GL_PRIMARY_COLOR;
273 break;
274
275 case WINED3DTA_TEXTURE:
276 ret = GL_REG_0_ATI + stage;
277 break;
278
279 case WINED3DTA_TFACTOR:
280 ret = ATI_FFP_CONST_TFACTOR;
281 break;
282
283 case WINED3DTA_SPECULAR:
284 ret = GL_SECONDARY_INTERPOLATOR_ATI;
285 break;
286
287 case WINED3DTA_TEMP:
288 ret = tmparg;
289 break;
290
291 case WINED3DTA_CONSTANT:
292 FIXME("Unhandled source argument WINED3DTA_TEMP\n");
293 ret = GL_CON_0_ATI;
294 break;
295
296 default:
297 FIXME("Unknown source argument %d\n", arg);
298 ret = GL_ZERO;
299 }
300
301 if(arg & WINED3DTA_COMPLEMENT) {
302 if(mod) *mod |= GL_COMP_BIT_ATI;
303 }
304 if(arg & WINED3DTA_ALPHAREPLICATE) {
305 if(rep) *rep = GL_ALPHA;
306 } else {
307 if(rep) *rep = GL_NONE;
308 }
309 return ret;
310 }
311
312 static GLuint find_tmpreg(const struct texture_stage_op op[MAX_TEXTURES])
313 {
314 int lowest_read = -1;
315 int lowest_write = -1;
316 int i;
317 BOOL tex_used[MAX_TEXTURES];
318
319 memset(tex_used, 0, sizeof(tex_used));
320 for (i = 0; i < MAX_TEXTURES; ++i)
321 {
322 if (op[i].cop == WINED3D_TOP_DISABLE)
323 break;
324
325 if(lowest_read == -1 &&
326 (op[i].carg1 == WINED3DTA_TEMP || op[i].carg2 == WINED3DTA_TEMP || op[i].carg0 == WINED3DTA_TEMP ||
327 op[i].aarg1 == WINED3DTA_TEMP || op[i].aarg2 == WINED3DTA_TEMP || op[i].aarg0 == WINED3DTA_TEMP)) {
328 lowest_read = i;
329 }
330
331 if(lowest_write == -1 && op[i].dst == tempreg) {
332 lowest_write = i;
333 }
334
335 if(op[i].carg1 == WINED3DTA_TEXTURE || op[i].carg2 == WINED3DTA_TEXTURE || op[i].carg0 == WINED3DTA_TEXTURE ||
336 op[i].aarg1 == WINED3DTA_TEXTURE || op[i].aarg2 == WINED3DTA_TEXTURE || op[i].aarg0 == WINED3DTA_TEXTURE) {
337 tex_used[i] = TRUE;
338 }
339 }
340
341 /* Temp reg not read? We don't need it, return GL_NONE */
342 if(lowest_read == -1) return GL_NONE;
343
344 if(lowest_write >= lowest_read) {
345 FIXME("Temp register read before being written\n");
346 }
347
348 if(lowest_write == -1) {
349 /* This needs a test. Maybe we are supposed to return 0.0/0.0/0.0/0.0, or fail drawprim, or whatever */
350 FIXME("Temp register read without being written\n");
351 return GL_REG_1_ATI;
352 } else if(lowest_write >= 1) {
353 /* If we're writing to the temp reg at earliest in stage 1, we can use register 1 for the temp result.
354 * there may be texture data stored in reg 1, but we do not need it any longer since stage 1 already
355 * read it
356 */
357 return GL_REG_1_ATI;
358 } else {
359 /* Search for a free texture register. We have 6 registers available. GL_REG_0_ATI is already used
360 * for the regular result
361 */
362 for(i = 1; i < 6; i++) {
363 if(!tex_used[i]) {
364 return GL_REG_0_ATI + i;
365 }
366 }
367 /* What to do here? Report it in ValidateDevice? */
368 FIXME("Could not find a register for the temporary register\n");
369 return 0;
370 }
371 }
372
373 static GLuint gen_ati_shader(const struct texture_stage_op op[MAX_TEXTURES], const struct wined3d_gl_info *gl_info)
374 {
375 GLuint ret = GL_EXTCALL(glGenFragmentShadersATI(1));
376 unsigned int stage;
377 GLuint arg0, arg1, arg2, extrarg;
378 GLuint dstmod, argmod0, argmod1, argmod2, argmodextra;
379 GLuint rep0, rep1, rep2;
380 GLuint swizzle;
381 GLuint tmparg = find_tmpreg(op);
382 GLuint dstreg;
383
384 if(!ret) {
385 ERR("Failed to generate a GL_ATI_fragment_shader shader id\n");
386 return 0;
387 }
388 GL_EXTCALL(glBindFragmentShaderATI(ret));
389 checkGLcall("GL_EXTCALL(glBindFragmentShaderATI(ret))");
390
391 TRACE("glBeginFragmentShaderATI()\n");
392 GL_EXTCALL(glBeginFragmentShaderATI());
393 checkGLcall("GL_EXTCALL(glBeginFragmentShaderATI())");
394
395 /* Pass 1: Generate sampling instructions for perturbation maps */
396 for (stage = 0; stage < gl_info->limits.textures; ++stage)
397 {
398 if (op[stage].cop == WINED3D_TOP_DISABLE)
399 break;
400 if (op[stage].cop != WINED3D_TOP_BUMPENVMAP
401 && op[stage].cop != WINED3D_TOP_BUMPENVMAP_LUMINANCE)
402 continue;
403
404 TRACE("glSampleMapATI(GL_REG_%d_ATI, GL_TEXTURE_%d_ARB, GL_SWIZZLE_STR_ATI)\n",
405 stage, stage);
406 GL_EXTCALL(glSampleMapATI(GL_REG_0_ATI + stage,
407 GL_TEXTURE0_ARB + stage,
408 GL_SWIZZLE_STR_ATI));
409 if(op[stage + 1].projected == proj_none) {
410 swizzle = GL_SWIZZLE_STR_ATI;
411 } else if(op[stage + 1].projected == proj_count4) {
412 swizzle = GL_SWIZZLE_STQ_DQ_ATI;
413 } else {
414 swizzle = GL_SWIZZLE_STR_DR_ATI;
415 }
416 TRACE("glPassTexCoordATI(GL_REG_%d_ATI, GL_TEXTURE_%d_ARB, %s)\n",
417 stage + 1, stage + 1, debug_swizzle(swizzle));
418 GL_EXTCALL(glPassTexCoordATI(GL_REG_0_ATI + stage + 1,
419 GL_TEXTURE0_ARB + stage + 1,
420 swizzle));
421 }
422
423 /* Pass 2: Generate perturbation calculations */
424 for (stage = 0; stage < gl_info->limits.textures; ++stage)
425 {
426 GLuint argmodextra_x, argmodextra_y;
427 struct color_fixup_desc fixup;
428
429 if (op[stage].cop == WINED3D_TOP_DISABLE)
430 break;
431 if (op[stage].cop != WINED3D_TOP_BUMPENVMAP
432 && op[stage].cop != WINED3D_TOP_BUMPENVMAP_LUMINANCE)
433 continue;
434
435 fixup = op[stage].color_fixup;
436 if (fixup.x_source != CHANNEL_SOURCE_X || fixup.y_source != CHANNEL_SOURCE_Y)
437 {
438 FIXME("Swizzles not implemented\n");
439 argmodextra_x = GL_NONE;
440 argmodextra_y = GL_NONE;
441 }
442 else
443 {
444 /* Nice thing, we get the color correction for free :-) */
445 argmodextra_x = fixup.x_sign_fixup ? GL_2X_BIT_ATI | GL_BIAS_BIT_ATI : GL_NONE;
446 argmodextra_y = fixup.y_sign_fixup ? GL_2X_BIT_ATI | GL_BIAS_BIT_ATI : GL_NONE;
447 }
448
449 wrap_op3(gl_info, GL_DOT2_ADD_ATI, GL_REG_0_ATI + stage + 1, GL_RED_BIT_ATI, GL_NONE,
450 GL_REG_0_ATI + stage, GL_NONE, argmodextra_x,
451 ATI_FFP_CONST_BUMPMAT(stage), GL_NONE, GL_2X_BIT_ATI | GL_BIAS_BIT_ATI,
452 GL_REG_0_ATI + stage + 1, GL_RED, GL_NONE);
453
454 /* Don't use GL_DOT2_ADD_ATI here because we cannot configure it to read the blue and alpha
455 * component of the bump matrix. Instead do this with two MADs:
456 *
457 * coord.a = tex.r * bump.b + coord.g
458 * coord.g = tex.g * bump.a + coord.a
459 *
460 * The first instruction writes to alpha so it can be coissued with the above DOT2_ADD.
461 * coord.a is unused. If the perturbed texture is projected, this was already handled
462 * in the glPassTexCoordATI above.
463 */
464 wrap_op3(gl_info, GL_MAD_ATI, GL_REG_0_ATI + stage + 1, GL_ALPHA, GL_NONE,
465 GL_REG_0_ATI + stage, GL_RED, argmodextra_y,
466 ATI_FFP_CONST_BUMPMAT(stage), GL_BLUE, GL_2X_BIT_ATI | GL_BIAS_BIT_ATI,
467 GL_REG_0_ATI + stage + 1, GL_GREEN, GL_NONE);
468 wrap_op3(gl_info, GL_MAD_ATI, GL_REG_0_ATI + stage + 1, GL_GREEN_BIT_ATI, GL_NONE,
469 GL_REG_0_ATI + stage, GL_GREEN, argmodextra_y,
470 ATI_FFP_CONST_BUMPMAT(stage), GL_ALPHA, GL_2X_BIT_ATI | GL_BIAS_BIT_ATI,
471 GL_REG_0_ATI + stage + 1, GL_ALPHA, GL_NONE);
472 }
473
474 /* Pass 3: Generate sampling instructions for regular textures */
475 for (stage = 0; stage < gl_info->limits.textures; ++stage)
476 {
477 if (op[stage].cop == WINED3D_TOP_DISABLE)
478 break;
479
480 if(op[stage].projected == proj_none) {
481 swizzle = GL_SWIZZLE_STR_ATI;
482 } else if(op[stage].projected == proj_count3) {
483 swizzle = GL_SWIZZLE_STR_DR_ATI;
484 } else {
485 swizzle = GL_SWIZZLE_STQ_DQ_ATI;
486 }
487
488 if ((op[stage].carg0 & WINED3DTA_SELECTMASK) == WINED3DTA_TEXTURE
489 || (op[stage].carg1 & WINED3DTA_SELECTMASK) == WINED3DTA_TEXTURE
490 || (op[stage].carg2 & WINED3DTA_SELECTMASK) == WINED3DTA_TEXTURE
491 || (op[stage].aarg0 & WINED3DTA_SELECTMASK) == WINED3DTA_TEXTURE
492 || (op[stage].aarg1 & WINED3DTA_SELECTMASK) == WINED3DTA_TEXTURE
493 || (op[stage].aarg2 & WINED3DTA_SELECTMASK) == WINED3DTA_TEXTURE
494 || op[stage].cop == WINED3D_TOP_BLEND_TEXTURE_ALPHA)
495 {
496 if (stage > 0
497 && (op[stage - 1].cop == WINED3D_TOP_BUMPENVMAP
498 || op[stage - 1].cop == WINED3D_TOP_BUMPENVMAP_LUMINANCE))
499 {
500 TRACE("glSampleMapATI(GL_REG_%d_ATI, GL_REG_%d_ATI, GL_SWIZZLE_STR_ATI)\n",
501 stage, stage);
502 GL_EXTCALL(glSampleMapATI(GL_REG_0_ATI + stage,
503 GL_REG_0_ATI + stage,
504 GL_SWIZZLE_STR_ATI));
505 } else {
506 TRACE("glSampleMapATI(GL_REG_%d_ATI, GL_TEXTURE_%d_ARB, %s)\n",
507 stage, stage, debug_swizzle(swizzle));
508 GL_EXTCALL(glSampleMapATI(GL_REG_0_ATI + stage,
509 GL_TEXTURE0_ARB + stage,
510 swizzle));
511 }
512 }
513 }
514
515 /* Pass 4: Generate the arithmetic instructions */
516 for (stage = 0; stage < MAX_TEXTURES; ++stage)
517 {
518 if (op[stage].cop == WINED3D_TOP_DISABLE)
519 {
520 if (!stage)
521 {
522 /* Handle complete texture disabling gracefully */
523 wrap_op1(gl_info, GL_MOV_ATI, GL_REG_0_ATI, GL_NONE, GL_NONE,
524 GL_PRIMARY_COLOR, GL_NONE, GL_NONE);
525 wrap_op1(gl_info, GL_MOV_ATI, GL_REG_0_ATI, GL_ALPHA, GL_NONE,
526 GL_PRIMARY_COLOR, GL_NONE, GL_NONE);
527 }
528 break;
529 }
530
531 if(op[stage].dst == tempreg) {
532 /* If we're writing to D3DTA_TEMP, but never reading from it we don't have to write there in the first place.
533 * skip the entire stage, this saves some GPU time
534 */
535 if(tmparg == GL_NONE) continue;
536
537 dstreg = tmparg;
538 } else {
539 dstreg = GL_REG_0_ATI;
540 }
541
542 arg0 = register_for_arg(op[stage].carg0, gl_info, stage, &argmod0, &rep0, tmparg);
543 arg1 = register_for_arg(op[stage].carg1, gl_info, stage, &argmod1, &rep1, tmparg);
544 arg2 = register_for_arg(op[stage].carg2, gl_info, stage, &argmod2, &rep2, tmparg);
545 dstmod = GL_NONE;
546 argmodextra = GL_NONE;
547 extrarg = GL_NONE;
548
549 switch (op[stage].cop)
550 {
551 case WINED3D_TOP_SELECT_ARG2:
552 arg1 = arg2;
553 argmod1 = argmod2;
554 rep1 = rep2;
555 /* fall through */
556 case WINED3D_TOP_SELECT_ARG1:
557 wrap_op1(gl_info, GL_MOV_ATI, dstreg, GL_NONE, GL_NONE,
558 arg1, rep1, argmod1);
559 break;
560
561 case WINED3D_TOP_MODULATE_4X:
562 if(dstmod == GL_NONE) dstmod = GL_4X_BIT_ATI;
563 /* fall through */
564 case WINED3D_TOP_MODULATE_2X:
565 if(dstmod == GL_NONE) dstmod = GL_2X_BIT_ATI;
566 dstmod |= GL_SATURATE_BIT_ATI;
567 /* fall through */
568 case WINED3D_TOP_MODULATE:
569 wrap_op2(gl_info, GL_MUL_ATI, dstreg, GL_NONE, dstmod,
570 arg1, rep1, argmod1,
571 arg2, rep2, argmod2);
572 break;
573
574 case WINED3D_TOP_ADD_SIGNED_2X:
575 dstmod = GL_2X_BIT_ATI;
576 /* fall through */
577 case WINED3D_TOP_ADD_SIGNED:
578 argmodextra = GL_BIAS_BIT_ATI;
579 /* fall through */
580 case WINED3D_TOP_ADD:
581 dstmod |= GL_SATURATE_BIT_ATI;
582 wrap_op2(gl_info, GL_ADD_ATI, GL_REG_0_ATI, GL_NONE, dstmod,
583 arg1, rep1, argmod1,
584 arg2, rep2, argmodextra | argmod2);
585 break;
586
587 case WINED3D_TOP_SUBTRACT:
588 dstmod |= GL_SATURATE_BIT_ATI;
589 wrap_op2(gl_info, GL_SUB_ATI, dstreg, GL_NONE, dstmod,
590 arg1, rep1, argmod1,
591 arg2, rep2, argmod2);
592 break;
593
594 case WINED3D_TOP_ADD_SMOOTH:
595 argmodextra = argmod1 & GL_COMP_BIT_ATI ? argmod1 & ~GL_COMP_BIT_ATI : argmod1 | GL_COMP_BIT_ATI;
596 /* Dst = arg1 + * arg2(1 -arg 1)
597 * = arg2 * (1 - arg1) + arg1
598 */
599 wrap_op3(gl_info, GL_MAD_ATI, dstreg, GL_NONE, GL_SATURATE_BIT_ATI,
600 arg2, rep2, argmod2,
601 arg1, rep1, argmodextra,
602 arg1, rep1, argmod1);
603 break;
604
605 case WINED3D_TOP_BLEND_CURRENT_ALPHA:
606 if (extrarg == GL_NONE)
607 extrarg = register_for_arg(WINED3DTA_CURRENT, gl_info, stage, NULL, NULL, -1);
608 /* fall through */
609 case WINED3D_TOP_BLEND_FACTOR_ALPHA:
610 if (extrarg == GL_NONE)
611 extrarg = register_for_arg(WINED3DTA_TFACTOR, gl_info, stage, NULL, NULL, -1);
612 /* fall through */
613 case WINED3D_TOP_BLEND_TEXTURE_ALPHA:
614 if (extrarg == GL_NONE)
615 extrarg = register_for_arg(WINED3DTA_TEXTURE, gl_info, stage, NULL, NULL, -1);
616 /* fall through */
617 case WINED3D_TOP_BLEND_DIFFUSE_ALPHA:
618 if (extrarg == GL_NONE)
619 extrarg = register_for_arg(WINED3DTA_DIFFUSE, gl_info, stage, NULL, NULL, -1);
620 wrap_op3(gl_info, GL_LERP_ATI, dstreg, GL_NONE, GL_NONE,
621 extrarg, GL_ALPHA, GL_NONE,
622 arg1, rep1, argmod1,
623 arg2, rep2, argmod2);
624 break;
625
626 case WINED3D_TOP_BLEND_TEXTURE_ALPHA_PM:
627 arg0 = register_for_arg(WINED3DTA_TEXTURE, gl_info, stage, NULL, NULL, -1);
628 wrap_op3(gl_info, GL_MAD_ATI, dstreg, GL_NONE, GL_NONE,
629 arg2, rep2, argmod2,
630 arg0, GL_ALPHA, GL_COMP_BIT_ATI,
631 arg1, rep1, argmod1);
632 break;
633
634 /* D3DTOP_PREMODULATE ???? */
635
636 case WINED3D_TOP_MODULATE_INVALPHA_ADD_COLOR:
637 argmodextra = argmod1 & GL_COMP_BIT_ATI ? argmod1 & ~GL_COMP_BIT_ATI : argmod1 | GL_COMP_BIT_ATI;
638 /* fall through */
639 case WINED3D_TOP_MODULATE_ALPHA_ADD_COLOR:
640 if (!argmodextra)
641 argmodextra = argmod1;
642 wrap_op3(gl_info, GL_MAD_ATI, dstreg, GL_NONE, GL_SATURATE_BIT_ATI,
643 arg2, rep2, argmod2,
644 arg1, GL_ALPHA, argmodextra,
645 arg1, rep1, argmod1);
646 break;
647
648 case WINED3D_TOP_MODULATE_INVCOLOR_ADD_ALPHA:
649 argmodextra = argmod1 & GL_COMP_BIT_ATI ? argmod1 & ~GL_COMP_BIT_ATI : argmod1 | GL_COMP_BIT_ATI;
650 /* fall through */
651 case WINED3D_TOP_MODULATE_COLOR_ADD_ALPHA:
652 if (!argmodextra)
653 argmodextra = argmod1;
654 wrap_op3(gl_info, GL_MAD_ATI, dstreg, GL_NONE, GL_SATURATE_BIT_ATI,
655 arg2, rep2, argmod2,
656 arg1, rep1, argmodextra,
657 arg1, GL_ALPHA, argmod1);
658 break;
659
660 case WINED3D_TOP_DOTPRODUCT3:
661 wrap_op2(gl_info, GL_DOT3_ATI, dstreg, GL_NONE, GL_4X_BIT_ATI | GL_SATURATE_BIT_ATI,
662 arg1, rep1, argmod1 | GL_BIAS_BIT_ATI,
663 arg2, rep2, argmod2 | GL_BIAS_BIT_ATI);
664 break;
665
666 case WINED3D_TOP_MULTIPLY_ADD:
667 wrap_op3(gl_info, GL_MAD_ATI, dstreg, GL_NONE, GL_SATURATE_BIT_ATI,
668 arg1, rep1, argmod1,
669 arg2, rep2, argmod2,
670 arg0, rep0, argmod0);
671 break;
672
673 case WINED3D_TOP_LERP:
674 wrap_op3(gl_info, GL_LERP_ATI, dstreg, GL_NONE, GL_NONE,
675 arg0, rep0, argmod0,
676 arg1, rep1, argmod1,
677 arg2, rep2, argmod2);
678 break;
679
680 case WINED3D_TOP_BUMPENVMAP:
681 case WINED3D_TOP_BUMPENVMAP_LUMINANCE:
682 /* Those are handled in the first pass of the shader(generation pass 1 and 2) already */
683 break;
684
685 default: FIXME("Unhandled color operation %d on stage %d\n", op[stage].cop, stage);
686 }
687
688 arg0 = register_for_arg(op[stage].aarg0, gl_info, stage, &argmod0, NULL, tmparg);
689 arg1 = register_for_arg(op[stage].aarg1, gl_info, stage, &argmod1, NULL, tmparg);
690 arg2 = register_for_arg(op[stage].aarg2, gl_info, stage, &argmod2, NULL, tmparg);
691 dstmod = GL_NONE;
692 argmodextra = GL_NONE;
693 extrarg = GL_NONE;
694
695 switch (op[stage].aop)
696 {
697 case WINED3D_TOP_DISABLE:
698 /* Get the primary color to the output if on stage 0, otherwise leave register 0 untouched */
699 if (!stage)
700 {
701 wrap_op1(gl_info, GL_MOV_ATI, GL_REG_0_ATI, GL_ALPHA, GL_NONE,
702 GL_PRIMARY_COLOR, GL_NONE, GL_NONE);
703 }
704 break;
705
706 case WINED3D_TOP_SELECT_ARG2:
707 arg1 = arg2;
708 argmod1 = argmod2;
709 /* fall through */
710 case WINED3D_TOP_SELECT_ARG1:
711 wrap_op1(gl_info, GL_MOV_ATI, dstreg, GL_ALPHA, GL_NONE,
712 arg1, GL_NONE, argmod1);
713 break;
714
715 case WINED3D_TOP_MODULATE_4X:
716 if (dstmod == GL_NONE)
717 dstmod = GL_4X_BIT_ATI;
718 /* fall through */
719 case WINED3D_TOP_MODULATE_2X:
720 if (dstmod == GL_NONE)
721 dstmod = GL_2X_BIT_ATI;
722 dstmod |= GL_SATURATE_BIT_ATI;
723 /* fall through */
724 case WINED3D_TOP_MODULATE:
725 wrap_op2(gl_info, GL_MUL_ATI, dstreg, GL_ALPHA, dstmod,
726 arg1, GL_NONE, argmod1,
727 arg2, GL_NONE, argmod2);
728 break;
729
730 case WINED3D_TOP_ADD_SIGNED_2X:
731 dstmod = GL_2X_BIT_ATI;
732 /* fall through */
733 case WINED3D_TOP_ADD_SIGNED:
734 argmodextra = GL_BIAS_BIT_ATI;
735 /* fall through */
736 case WINED3D_TOP_ADD:
737 dstmod |= GL_SATURATE_BIT_ATI;
738 wrap_op2(gl_info, GL_ADD_ATI, dstreg, GL_ALPHA, dstmod,
739 arg1, GL_NONE, argmod1,
740 arg2, GL_NONE, argmodextra | argmod2);
741 break;
742
743 case WINED3D_TOP_SUBTRACT:
744 dstmod |= GL_SATURATE_BIT_ATI;
745 wrap_op2(gl_info, GL_SUB_ATI, dstreg, GL_ALPHA, dstmod,
746 arg1, GL_NONE, argmod1,
747 arg2, GL_NONE, argmod2);
748 break;
749
750 case WINED3D_TOP_ADD_SMOOTH:
751 argmodextra = argmod1 & GL_COMP_BIT_ATI ? argmod1 & ~GL_COMP_BIT_ATI : argmod1 | GL_COMP_BIT_ATI;
752 /* Dst = arg1 + * arg2(1 -arg 1)
753 * = arg2 * (1 - arg1) + arg1
754 */
755 wrap_op3(gl_info, GL_MAD_ATI, dstreg, GL_ALPHA, GL_SATURATE_BIT_ATI,
756 arg2, GL_NONE, argmod2,
757 arg1, GL_NONE, argmodextra,
758 arg1, GL_NONE, argmod1);
759 break;
760
761 case WINED3D_TOP_BLEND_CURRENT_ALPHA:
762 if (extrarg == GL_NONE)
763 extrarg = register_for_arg(WINED3DTA_CURRENT, gl_info, stage, NULL, NULL, -1);
764 /* fall through */
765 case WINED3D_TOP_BLEND_FACTOR_ALPHA:
766 if (extrarg == GL_NONE)
767 extrarg = register_for_arg(WINED3DTA_TFACTOR, gl_info, stage, NULL, NULL, -1);
768 /* fall through */
769 case WINED3D_TOP_BLEND_TEXTURE_ALPHA:
770 if (extrarg == GL_NONE)
771 extrarg = register_for_arg(WINED3DTA_TEXTURE, gl_info, stage, NULL, NULL, -1);
772 /* fall through */
773 case WINED3D_TOP_BLEND_DIFFUSE_ALPHA:
774 if (extrarg == GL_NONE)
775 extrarg = register_for_arg(WINED3DTA_DIFFUSE, gl_info, stage, NULL, NULL, -1);
776 wrap_op3(gl_info, GL_LERP_ATI, dstreg, GL_ALPHA, GL_NONE,
777 extrarg, GL_ALPHA, GL_NONE,
778 arg1, GL_NONE, argmod1,
779 arg2, GL_NONE, argmod2);
780 break;
781
782 case WINED3D_TOP_BLEND_TEXTURE_ALPHA_PM:
783 arg0 = register_for_arg(WINED3DTA_TEXTURE, gl_info, stage, NULL, NULL, -1);
784 wrap_op3(gl_info, GL_MAD_ATI, dstreg, GL_ALPHA, GL_NONE,
785 arg2, GL_NONE, argmod2,
786 arg0, GL_ALPHA, GL_COMP_BIT_ATI,
787 arg1, GL_NONE, argmod1);
788 break;
789
790 /* D3DTOP_PREMODULATE ???? */
791
792 case WINED3D_TOP_DOTPRODUCT3:
793 wrap_op2(gl_info, GL_DOT3_ATI, dstreg, GL_ALPHA, GL_4X_BIT_ATI | GL_SATURATE_BIT_ATI,
794 arg1, GL_NONE, argmod1 | GL_BIAS_BIT_ATI,
795 arg2, GL_NONE, argmod2 | GL_BIAS_BIT_ATI);
796 break;
797
798 case WINED3D_TOP_MULTIPLY_ADD:
799 wrap_op3(gl_info, GL_MAD_ATI, dstreg, GL_ALPHA, GL_SATURATE_BIT_ATI,
800 arg1, GL_NONE, argmod1,
801 arg2, GL_NONE, argmod2,
802 arg0, GL_NONE, argmod0);
803 break;
804
805 case WINED3D_TOP_LERP:
806 wrap_op3(gl_info, GL_LERP_ATI, dstreg, GL_ALPHA, GL_SATURATE_BIT_ATI,
807 arg1, GL_NONE, argmod1,
808 arg2, GL_NONE, argmod2,
809 arg0, GL_NONE, argmod0);
810 break;
811
812 case WINED3D_TOP_MODULATE_INVALPHA_ADD_COLOR:
813 case WINED3D_TOP_MODULATE_ALPHA_ADD_COLOR:
814 case WINED3D_TOP_MODULATE_COLOR_ADD_ALPHA:
815 case WINED3D_TOP_MODULATE_INVCOLOR_ADD_ALPHA:
816 case WINED3D_TOP_BUMPENVMAP:
817 case WINED3D_TOP_BUMPENVMAP_LUMINANCE:
818 ERR("Application uses an invalid alpha operation\n");
819 break;
820
821 default: FIXME("Unhandled alpha operation %d on stage %d\n", op[stage].aop, stage);
822 }
823 }
824
825 TRACE("glEndFragmentShaderATI()\n");
826 GL_EXTCALL(glEndFragmentShaderATI());
827 checkGLcall("GL_EXTCALL(glEndFragmentShaderATI())");
828 return ret;
829 }
830
831 static void set_tex_op_atifs(struct wined3d_context *context, const struct wined3d_state *state, DWORD state_id)
832 {
833 const struct wined3d_device *device = context->swapchain->device;
834 const struct wined3d_gl_info *gl_info = context->gl_info;
835 const struct wined3d_d3d_info *d3d_info = context->d3d_info;
836 const struct atifs_ffp_desc *desc;
837 struct ffp_frag_settings settings;
838 struct atifs_private_data *priv = device->fragment_priv;
839 DWORD mapped_stage;
840 unsigned int i;
841
842 gen_ffp_frag_op(context, state, &settings, TRUE);
843 desc = (const struct atifs_ffp_desc *)find_ffp_frag_shader(&priv->fragment_shaders, &settings);
844 if(!desc) {
845 struct atifs_ffp_desc *new_desc = HeapAlloc(GetProcessHeap(), 0, sizeof(*new_desc));
846 if (!new_desc)
847 {
848 ERR("Out of memory\n");
849 return;
850 }
851 new_desc->num_textures_used = 0;
852 for (i = 0; i < d3d_info->limits.ffp_blend_stages; ++i)
853 {
854 if (settings.op[i].cop == WINED3D_TOP_DISABLE)
855 break;
856 new_desc->num_textures_used = i + 1;
857 }
858
859 new_desc->parent.settings = settings;
860 new_desc->shader = gen_ati_shader(settings.op, gl_info);
861 add_ffp_frag_shader(&priv->fragment_shaders, &new_desc->parent);
862 TRACE("Allocated fixed function replacement shader descriptor %p\n", new_desc);
863 desc = new_desc;
864 }
865
866 /* GL_ATI_fragment_shader depends on the GL_TEXTURE_xD enable settings. Update the texture stages
867 * used by this shader
868 */
869 for (i = 0; i < desc->num_textures_used; ++i)
870 {
871 mapped_stage = device->texUnitMap[i];
872 if (mapped_stage != WINED3D_UNMAPPED_STAGE)
873 {
874 context_active_texture(context, gl_info, mapped_stage);
875 texture_activate_dimensions(state->textures[i], gl_info);
876 }
877 }
878
879 GL_EXTCALL(glBindFragmentShaderATI(desc->shader));
880 }
881
882 static void state_texfactor_atifs(struct wined3d_context *context, const struct wined3d_state *state, DWORD state_id)
883 {
884 const struct wined3d_gl_info *gl_info = context->gl_info;
885 float col[4];
886
887 D3DCOLORTOGLFLOAT4(state->render_states[WINED3D_RS_TEXTUREFACTOR], col);
888 GL_EXTCALL(glSetFragmentShaderConstantATI(ATI_FFP_CONST_TFACTOR, col));
889 checkGLcall("glSetFragmentShaderConstantATI(ATI_FFP_CONST_TFACTOR, col)");
890 }
891
892 static void set_bumpmat(struct wined3d_context *context, const struct wined3d_state *state, DWORD state_id)
893 {
894 DWORD stage = (state_id - STATE_TEXTURESTAGE(0, 0)) / (WINED3D_HIGHEST_TEXTURE_STATE + 1);
895 const struct wined3d_gl_info *gl_info = context->gl_info;
896 float mat[2][2];
897
898 mat[0][0] = *((float *)&state->texture_states[stage][WINED3D_TSS_BUMPENV_MAT00]);
899 mat[1][0] = *((float *)&state->texture_states[stage][WINED3D_TSS_BUMPENV_MAT01]);
900 mat[0][1] = *((float *)&state->texture_states[stage][WINED3D_TSS_BUMPENV_MAT10]);
901 mat[1][1] = *((float *)&state->texture_states[stage][WINED3D_TSS_BUMPENV_MAT11]);
902 /* GL_ATI_fragment_shader allows only constants from 0.0 to 1.0, but the bumpmat
903 * constants can be in any range. While they should stay between [-1.0 and 1.0] because
904 * Shader Model 1.x pixel shaders are clamped to that range negative values are used occasionally,
905 * for example by our d3d9 test. So to get negative values scale -1;1 to 0;1 and undo that in the
906 * shader(it is free). This might potentially reduce precision. However, if the hardware does
907 * support proper floats it shouldn't, and if it doesn't we can't get anything better anyway
908 */
909 mat[0][0] = (mat[0][0] + 1.0f) * 0.5f;
910 mat[1][0] = (mat[1][0] + 1.0f) * 0.5f;
911 mat[0][1] = (mat[0][1] + 1.0f) * 0.5f;
912 mat[1][1] = (mat[1][1] + 1.0f) * 0.5f;
913 GL_EXTCALL(glSetFragmentShaderConstantATI(ATI_FFP_CONST_BUMPMAT(stage), (float *) mat));
914 checkGLcall("glSetFragmentShaderConstantATI(ATI_FFP_CONST_BUMPMAT(stage), mat)");
915 }
916
917 static void textransform(struct wined3d_context *context, const struct wined3d_state *state, DWORD state_id)
918 {
919 if (!isStateDirty(context, STATE_PIXELSHADER))
920 set_tex_op_atifs(context, state, state_id);
921 }
922
923 static void atifs_apply_pixelshader(struct wined3d_context *context, const struct wined3d_state *state, DWORD state_id)
924 {
925 context->last_was_pshader = use_ps(state);
926 /* The ATIFS code does not support pixel shaders currently, but we have to
927 * provide a state handler to call shader_select to select a vertex shader
928 * if one is applied because the vertex shader state may defer calling the
929 * shader backend if the pshader state is dirty.
930 *
931 * In theory the application should not be able to mark the pixel shader
932 * dirty because it cannot create a shader, and thus has no way to set the
933 * state to something != NULL. However, a different pipeline part may link
934 * a different state to its pixelshader handler, thus a pshader state
935 * exists and can be dirtified. Also the pshader is always dirtified at
936 * startup, and blitting disables all shaders and dirtifies all shader
937 * states. If atifs can deal with this it keeps the rest of the code
938 * simpler. */
939 context->shader_update_mask |= 1 << WINED3D_SHADER_TYPE_PIXEL;
940 }
941
942 static void atifs_srgbwriteenable(struct wined3d_context *context, const struct wined3d_state *state, DWORD state_id)
943 {
944 if (state->render_states[WINED3D_RS_SRGBWRITEENABLE])
945 WARN("sRGB writes are not supported by this fragment pipe.\n");
946 }
947
948 static const struct StateEntryTemplate atifs_fragmentstate_template[] = {
949 {STATE_RENDER(WINED3D_RS_TEXTUREFACTOR), { STATE_RENDER(WINED3D_RS_TEXTUREFACTOR), state_texfactor_atifs }, WINED3D_GL_EXT_NONE },
950 {STATE_RENDER(WINED3D_RS_FOGCOLOR), { STATE_RENDER(WINED3D_RS_FOGCOLOR), state_fogcolor }, WINED3D_GL_EXT_NONE },
951 {STATE_RENDER(WINED3D_RS_FOGDENSITY), { STATE_RENDER(WINED3D_RS_FOGDENSITY), state_fogdensity }, WINED3D_GL_EXT_NONE },
952 {STATE_RENDER(WINED3D_RS_FOGENABLE), { STATE_RENDER(WINED3D_RS_FOGENABLE), state_fog_fragpart }, WINED3D_GL_EXT_NONE },
953 {STATE_RENDER(WINED3D_RS_FOGTABLEMODE), { STATE_RENDER(WINED3D_RS_FOGENABLE), NULL }, WINED3D_GL_EXT_NONE },
954 {STATE_RENDER(WINED3D_RS_FOGVERTEXMODE), { STATE_RENDER(WINED3D_RS_FOGENABLE), NULL }, WINED3D_GL_EXT_NONE },
955 {STATE_RENDER(WINED3D_RS_FOGSTART), { STATE_RENDER(WINED3D_RS_FOGSTART), state_fogstartend }, WINED3D_GL_EXT_NONE },
956 {STATE_RENDER(WINED3D_RS_FOGEND), { STATE_RENDER(WINED3D_RS_FOGSTART), NULL }, WINED3D_GL_EXT_NONE },
957 {STATE_RENDER(WINED3D_RS_SRGBWRITEENABLE), { STATE_RENDER(WINED3D_RS_SRGBWRITEENABLE), atifs_srgbwriteenable }, WINED3D_GL_EXT_NONE },
958 {STATE_TEXTURESTAGE(0, WINED3D_TSS_COLOR_OP), { STATE_TEXTURESTAGE(0, WINED3D_TSS_COLOR_OP), set_tex_op_atifs }, WINED3D_GL_EXT_NONE },
959 {STATE_TEXTURESTAGE(0, WINED3D_TSS_COLOR_ARG1), { STATE_TEXTURESTAGE(0, WINED3D_TSS_COLOR_OP), NULL }, WINED3D_GL_EXT_NONE },
960 {STATE_TEXTURESTAGE(0, WINED3D_TSS_COLOR_ARG2), { STATE_TEXTURESTAGE(0, WINED3D_TSS_COLOR_OP), NULL }, WINED3D_GL_EXT_NONE },
961 {STATE_TEXTURESTAGE(0, WINED3D_TSS_COLOR_ARG0), { STATE_TEXTURESTAGE(0, WINED3D_TSS_COLOR_OP), NULL }, WINED3D_GL_EXT_NONE },
962 {STATE_TEXTURESTAGE(0, WINED3D_TSS_ALPHA_OP), { STATE_TEXTURESTAGE(0, WINED3D_TSS_COLOR_OP), NULL }, WINED3D_GL_EXT_NONE },
963 {STATE_TEXTURESTAGE(0, WINED3D_TSS_ALPHA_ARG1), { STATE_TEXTURESTAGE(0, WINED3D_TSS_COLOR_OP), NULL }, WINED3D_GL_EXT_NONE },
964 {STATE_TEXTURESTAGE(0, WINED3D_TSS_ALPHA_ARG2), { STATE_TEXTURESTAGE(0, WINED3D_TSS_COLOR_OP), NULL }, WINED3D_GL_EXT_NONE },
965 {STATE_TEXTURESTAGE(0, WINED3D_TSS_ALPHA_ARG0), { STATE_TEXTURESTAGE(0, WINED3D_TSS_COLOR_OP), NULL }, WINED3D_GL_EXT_NONE },
966 {STATE_TEXTURESTAGE(0, WINED3D_TSS_RESULT_ARG), { STATE_TEXTURESTAGE(0, WINED3D_TSS_COLOR_OP), NULL }, WINED3D_GL_EXT_NONE },
967 {STATE_TEXTURESTAGE(0, WINED3D_TSS_BUMPENV_MAT00), { STATE_TEXTURESTAGE(0, WINED3D_TSS_BUMPENV_MAT00), set_bumpmat }, WINED3D_GL_EXT_NONE },
968 {STATE_TEXTURESTAGE(0, WINED3D_TSS_BUMPENV_MAT01), { STATE_TEXTURESTAGE(0, WINED3D_TSS_BUMPENV_MAT00), NULL }, WINED3D_GL_EXT_NONE },
969 {STATE_TEXTURESTAGE(0, WINED3D_TSS_BUMPENV_MAT10), { STATE_TEXTURESTAGE(0, WINED3D_TSS_BUMPENV_MAT00), NULL }, WINED3D_GL_EXT_NONE },
970 {STATE_TEXTURESTAGE(0, WINED3D_TSS_BUMPENV_MAT11), { STATE_TEXTURESTAGE(0, WINED3D_TSS_BUMPENV_MAT00), NULL }, WINED3D_GL_EXT_NONE },
971 {STATE_TEXTURESTAGE(1, WINED3D_TSS_COLOR_OP), { STATE_TEXTURESTAGE(0, WINED3D_TSS_COLOR_OP), NULL }, WINED3D_GL_EXT_NONE },
972 {STATE_TEXTURESTAGE(1, WINED3D_TSS_COLOR_ARG1), { STATE_TEXTURESTAGE(0, WINED3D_TSS_COLOR_OP), NULL }, WINED3D_GL_EXT_NONE },
973 {STATE_TEXTURESTAGE(1, WINED3D_TSS_COLOR_ARG2), { STATE_TEXTURESTAGE(0, WINED3D_TSS_COLOR_OP), NULL }, WINED3D_GL_EXT_NONE },
974 {STATE_TEXTURESTAGE(1, WINED3D_TSS_COLOR_ARG0), { STATE_TEXTURESTAGE(0, WINED3D_TSS_COLOR_OP), NULL }, WINED3D_GL_EXT_NONE },
975 {STATE_TEXTURESTAGE(1, WINED3D_TSS_ALPHA_OP), { STATE_TEXTURESTAGE(0, WINED3D_TSS_COLOR_OP), NULL }, WINED3D_GL_EXT_NONE },
976 {STATE_TEXTURESTAGE(1, WINED3D_TSS_ALPHA_ARG1), { STATE_TEXTURESTAGE(0, WINED3D_TSS_COLOR_OP), NULL }, WINED3D_GL_EXT_NONE },
977 {STATE_TEXTURESTAGE(1, WINED3D_TSS_ALPHA_ARG2), { STATE_TEXTURESTAGE(0, WINED3D_TSS_COLOR_OP), NULL }, WINED3D_GL_EXT_NONE },
978 {STATE_TEXTURESTAGE(1, WINED3D_TSS_ALPHA_ARG0), { STATE_TEXTURESTAGE(0, WINED3D_TSS_COLOR_OP), NULL }, WINED3D_GL_EXT_NONE },
979 {STATE_TEXTURESTAGE(1, WINED3D_TSS_RESULT_ARG), { STATE_TEXTURESTAGE(0, WINED3D_TSS_COLOR_OP), NULL }, WINED3D_GL_EXT_NONE },
980 {STATE_TEXTURESTAGE(1, WINED3D_TSS_BUMPENV_MAT00), { STATE_TEXTURESTAGE(1, WINED3D_TSS_BUMPENV_MAT00), set_bumpmat }, WINED3D_GL_EXT_NONE },
981 {STATE_TEXTURESTAGE(1, WINED3D_TSS_BUMPENV_MAT01), { STATE_TEXTURESTAGE(1, WINED3D_TSS_BUMPENV_MAT00), NULL }, WINED3D_GL_EXT_NONE },
982 {STATE_TEXTURESTAGE(1, WINED3D_TSS_BUMPENV_MAT10), { STATE_TEXTURESTAGE(1, WINED3D_TSS_BUMPENV_MAT00), NULL }, WINED3D_GL_EXT_NONE },
983 {STATE_TEXTURESTAGE(1, WINED3D_TSS_BUMPENV_MAT11), { STATE_TEXTURESTAGE(1, WINED3D_TSS_BUMPENV_MAT00), NULL }, WINED3D_GL_EXT_NONE },
984 {STATE_TEXTURESTAGE(2, WINED3D_TSS_COLOR_OP), { STATE_TEXTURESTAGE(0, WINED3D_TSS_COLOR_OP), NULL }, WINED3D_GL_EXT_NONE },
985 {STATE_TEXTURESTAGE(2, WINED3D_TSS_COLOR_ARG1), { STATE_TEXTURESTAGE(0, WINED3D_TSS_COLOR_OP), NULL }, WINED3D_GL_EXT_NONE },
986 {STATE_TEXTURESTAGE(2, WINED3D_TSS_COLOR_ARG2), { STATE_TEXTURESTAGE(0, WINED3D_TSS_COLOR_OP), NULL }, WINED3D_GL_EXT_NONE },
987 {STATE_TEXTURESTAGE(2, WINED3D_TSS_COLOR_ARG0), { STATE_TEXTURESTAGE(0, WINED3D_TSS_COLOR_OP), NULL }, WINED3D_GL_EXT_NONE },
988 {STATE_TEXTURESTAGE(2, WINED3D_TSS_ALPHA_OP), { STATE_TEXTURESTAGE(0, WINED3D_TSS_COLOR_OP), NULL }, WINED3D_GL_EXT_NONE },
989 {STATE_TEXTURESTAGE(2, WINED3D_TSS_ALPHA_ARG1), { STATE_TEXTURESTAGE(0, WINED3D_TSS_COLOR_OP), NULL }, WINED3D_GL_EXT_NONE },
990 {STATE_TEXTURESTAGE(2, WINED3D_TSS_ALPHA_ARG2), { STATE_TEXTURESTAGE(0, WINED3D_TSS_COLOR_OP), NULL }, WINED3D_GL_EXT_NONE },
991 {STATE_TEXTURESTAGE(2, WINED3D_TSS_ALPHA_ARG0), { STATE_TEXTURESTAGE(0, WINED3D_TSS_COLOR_OP), NULL }, WINED3D_GL_EXT_NONE },
992 {STATE_TEXTURESTAGE(2, WINED3D_TSS_RESULT_ARG), { STATE_TEXTURESTAGE(0, WINED3D_TSS_COLOR_OP), NULL }, WINED3D_GL_EXT_NONE },
993 {STATE_TEXTURESTAGE(2, WINED3D_TSS_BUMPENV_MAT00), { STATE_TEXTURESTAGE(2, WINED3D_TSS_BUMPENV_MAT00), set_bumpmat }, WINED3D_GL_EXT_NONE },
994 {STATE_TEXTURESTAGE(2, WINED3D_TSS_BUMPENV_MAT01), { STATE_TEXTURESTAGE(2, WINED3D_TSS_BUMPENV_MAT00), NULL }, WINED3D_GL_EXT_NONE },
995 {STATE_TEXTURESTAGE(2, WINED3D_TSS_BUMPENV_MAT10), { STATE_TEXTURESTAGE(2, WINED3D_TSS_BUMPENV_MAT00), NULL }, WINED3D_GL_EXT_NONE },
996 {STATE_TEXTURESTAGE(2, WINED3D_TSS_BUMPENV_MAT11), { STATE_TEXTURESTAGE(2, WINED3D_TSS_BUMPENV_MAT00), NULL }, WINED3D_GL_EXT_NONE },
997 {STATE_TEXTURESTAGE(3, WINED3D_TSS_COLOR_OP), { STATE_TEXTURESTAGE(0, WINED3D_TSS_COLOR_OP), NULL }, WINED3D_GL_EXT_NONE },
998 {STATE_TEXTURESTAGE(3, WINED3D_TSS_COLOR_ARG1), { STATE_TEXTURESTAGE(0, WINED3D_TSS_COLOR_OP), NULL }, WINED3D_GL_EXT_NONE },
999 {STATE_TEXTURESTAGE(3, WINED3D_TSS_COLOR_ARG2), { STATE_TEXTURESTAGE(0, WINED3D_TSS_COLOR_OP), NULL }, WINED3D_GL_EXT_NONE },
1000 {STATE_TEXTURESTAGE(3, WINED3D_TSS_COLOR_ARG0), { STATE_TEXTURESTAGE(0, WINED3D_TSS_COLOR_OP), NULL }, WINED3D_GL_EXT_NONE },
1001 {STATE_TEXTURESTAGE(3, WINED3D_TSS_ALPHA_OP), { STATE_TEXTURESTAGE(0, WINED3D_TSS_COLOR_OP), NULL }, WINED3D_GL_EXT_NONE },
1002 {STATE_TEXTURESTAGE(3, WINED3D_TSS_ALPHA_ARG1), { STATE_TEXTURESTAGE(0, WINED3D_TSS_COLOR_OP), NULL }, WINED3D_GL_EXT_NONE },
1003 {STATE_TEXTURESTAGE(3, WINED3D_TSS_ALPHA_ARG2), { STATE_TEXTURESTAGE(0, WINED3D_TSS_COLOR_OP), NULL }, WINED3D_GL_EXT_NONE },
1004 {STATE_TEXTURESTAGE(3, WINED3D_TSS_ALPHA_ARG0), { STATE_TEXTURESTAGE(0, WINED3D_TSS_COLOR_OP), NULL }, WINED3D_GL_EXT_NONE },
1005 {STATE_TEXTURESTAGE(3, WINED3D_TSS_RESULT_ARG), { STATE_TEXTURESTAGE(0, WINED3D_TSS_COLOR_OP), NULL }, WINED3D_GL_EXT_NONE },
1006 {STATE_TEXTURESTAGE(3, WINED3D_TSS_BUMPENV_MAT00), { STATE_TEXTURESTAGE(3, WINED3D_TSS_BUMPENV_MAT00), set_bumpmat }, WINED3D_GL_EXT_NONE },
1007 {STATE_TEXTURESTAGE(3, WINED3D_TSS_BUMPENV_MAT01), { STATE_TEXTURESTAGE(3, WINED3D_TSS_BUMPENV_MAT00), NULL }, WINED3D_GL_EXT_NONE },
1008 {STATE_TEXTURESTAGE(3, WINED3D_TSS_BUMPENV_MAT10), { STATE_TEXTURESTAGE(3, WINED3D_TSS_BUMPENV_MAT00), NULL }, WINED3D_GL_EXT_NONE },
1009 {STATE_TEXTURESTAGE(3, WINED3D_TSS_BUMPENV_MAT11), { STATE_TEXTURESTAGE(3, WINED3D_TSS_BUMPENV_MAT00), NULL }, WINED3D_GL_EXT_NONE },
1010 {STATE_TEXTURESTAGE(4, WINED3D_TSS_COLOR_OP), { STATE_TEXTURESTAGE(0, WINED3D_TSS_COLOR_OP), NULL }, WINED3D_GL_EXT_NONE },
1011 {STATE_TEXTURESTAGE(4, WINED3D_TSS_COLOR_ARG1), { STATE_TEXTURESTAGE(0, WINED3D_TSS_COLOR_OP), NULL }, WINED3D_GL_EXT_NONE },
1012 {STATE_TEXTURESTAGE(4, WINED3D_TSS_COLOR_ARG2), { STATE_TEXTURESTAGE(0, WINED3D_TSS_COLOR_OP), NULL }, WINED3D_GL_EXT_NONE },
1013 {STATE_TEXTURESTAGE(4, WINED3D_TSS_COLOR_ARG0), { STATE_TEXTURESTAGE(0, WINED3D_TSS_COLOR_OP), NULL }, WINED3D_GL_EXT_NONE },
1014 {STATE_TEXTURESTAGE(4, WINED3D_TSS_ALPHA_OP), { STATE_TEXTURESTAGE(0, WINED3D_TSS_COLOR_OP), NULL }, WINED3D_GL_EXT_NONE },
1015 {STATE_TEXTURESTAGE(4, WINED3D_TSS_ALPHA_ARG1), { STATE_TEXTURESTAGE(0, WINED3D_TSS_COLOR_OP), NULL }, WINED3D_GL_EXT_NONE },
1016 {STATE_TEXTURESTAGE(4, WINED3D_TSS_ALPHA_ARG2), { STATE_TEXTURESTAGE(0, WINED3D_TSS_COLOR_OP), NULL }, WINED3D_GL_EXT_NONE },
1017 {STATE_TEXTURESTAGE(4, WINED3D_TSS_ALPHA_ARG0), { STATE_TEXTURESTAGE(0, WINED3D_TSS_COLOR_OP), NULL }, WINED3D_GL_EXT_NONE },
1018 {STATE_TEXTURESTAGE(4, WINED3D_TSS_RESULT_ARG), { STATE_TEXTURESTAGE(0, WINED3D_TSS_COLOR_OP), NULL }, WINED3D_GL_EXT_NONE },
1019 {STATE_TEXTURESTAGE(4, WINED3D_TSS_BUMPENV_MAT00), { STATE_TEXTURESTAGE(4, WINED3D_TSS_BUMPENV_MAT00), set_bumpmat }, WINED3D_GL_EXT_NONE },
1020 {STATE_TEXTURESTAGE(4, WINED3D_TSS_BUMPENV_MAT01), { STATE_TEXTURESTAGE(4, WINED3D_TSS_BUMPENV_MAT00), NULL }, WINED3D_GL_EXT_NONE },
1021 {STATE_TEXTURESTAGE(4, WINED3D_TSS_BUMPENV_MAT10), { STATE_TEXTURESTAGE(4, WINED3D_TSS_BUMPENV_MAT00), NULL }, WINED3D_GL_EXT_NONE },
1022 {STATE_TEXTURESTAGE(4, WINED3D_TSS_BUMPENV_MAT11), { STATE_TEXTURESTAGE(4, WINED3D_TSS_BUMPENV_MAT00), NULL }, WINED3D_GL_EXT_NONE },
1023 {STATE_TEXTURESTAGE(5, WINED3D_TSS_COLOR_OP), { STATE_TEXTURESTAGE(0, WINED3D_TSS_COLOR_OP), NULL }, WINED3D_GL_EXT_NONE },
1024 {STATE_TEXTURESTAGE(5, WINED3D_TSS_COLOR_ARG1), { STATE_TEXTURESTAGE(0, WINED3D_TSS_COLOR_OP), NULL }, WINED3D_GL_EXT_NONE },
1025 {STATE_TEXTURESTAGE(5, WINED3D_TSS_COLOR_ARG2), { STATE_TEXTURESTAGE(0, WINED3D_TSS_COLOR_OP), NULL }, WINED3D_GL_EXT_NONE },
1026 {STATE_TEXTURESTAGE(5, WINED3D_TSS_COLOR_ARG0), { STATE_TEXTURESTAGE(0, WINED3D_TSS_COLOR_OP), NULL }, WINED3D_GL_EXT_NONE },
1027 {STATE_TEXTURESTAGE(5, WINED3D_TSS_ALPHA_OP), { STATE_TEXTURESTAGE(0, WINED3D_TSS_COLOR_OP), NULL }, WINED3D_GL_EXT_NONE },
1028 {STATE_TEXTURESTAGE(5, WINED3D_TSS_ALPHA_ARG1), { STATE_TEXTURESTAGE(0, WINED3D_TSS_COLOR_OP), NULL }, WINED3D_GL_EXT_NONE },
1029 {STATE_TEXTURESTAGE(5, WINED3D_TSS_ALPHA_ARG2), { STATE_TEXTURESTAGE(0, WINED3D_TSS_COLOR_OP), NULL }, WINED3D_GL_EXT_NONE },
1030 {STATE_TEXTURESTAGE(5, WINED3D_TSS_ALPHA_ARG0), { STATE_TEXTURESTAGE(0, WINED3D_TSS_COLOR_OP), NULL }, WINED3D_GL_EXT_NONE },
1031 {STATE_TEXTURESTAGE(5, WINED3D_TSS_RESULT_ARG), { STATE_TEXTURESTAGE(0, WINED3D_TSS_COLOR_OP), NULL }, WINED3D_GL_EXT_NONE },
1032 {STATE_TEXTURESTAGE(5, WINED3D_TSS_BUMPENV_MAT00), { STATE_TEXTURESTAGE(5, WINED3D_TSS_BUMPENV_MAT00), set_bumpmat }, WINED3D_GL_EXT_NONE },
1033 {STATE_TEXTURESTAGE(5, WINED3D_TSS_BUMPENV_MAT01), { STATE_TEXTURESTAGE(5, WINED3D_TSS_BUMPENV_MAT00), NULL }, WINED3D_GL_EXT_NONE },
1034 {STATE_TEXTURESTAGE(5, WINED3D_TSS_BUMPENV_MAT10), { STATE_TEXTURESTAGE(5, WINED3D_TSS_BUMPENV_MAT00), NULL }, WINED3D_GL_EXT_NONE },
1035 {STATE_TEXTURESTAGE(5, WINED3D_TSS_BUMPENV_MAT11), { STATE_TEXTURESTAGE(5, WINED3D_TSS_BUMPENV_MAT00), NULL }, WINED3D_GL_EXT_NONE },
1036 {STATE_TEXTURESTAGE(6, WINED3D_TSS_COLOR_OP), { STATE_TEXTURESTAGE(0, WINED3D_TSS_COLOR_OP), NULL }, WINED3D_GL_EXT_NONE },
1037 {STATE_TEXTURESTAGE(6, WINED3D_TSS_COLOR_ARG1), { STATE_TEXTURESTAGE(0, WINED3D_TSS_COLOR_OP), NULL }, WINED3D_GL_EXT_NONE },
1038 {STATE_TEXTURESTAGE(6, WINED3D_TSS_COLOR_ARG2), { STATE_TEXTURESTAGE(0, WINED3D_TSS_COLOR_OP), NULL }, WINED3D_GL_EXT_NONE },
1039 {STATE_TEXTURESTAGE(6, WINED3D_TSS_COLOR_ARG0), { STATE_TEXTURESTAGE(0, WINED3D_TSS_COLOR_OP), NULL }, WINED3D_GL_EXT_NONE },
1040 {STATE_TEXTURESTAGE(6, WINED3D_TSS_ALPHA_OP), { STATE_TEXTURESTAGE(0, WINED3D_TSS_COLOR_OP), NULL }, WINED3D_GL_EXT_NONE },
1041 {STATE_TEXTURESTAGE(6, WINED3D_TSS_ALPHA_ARG1), { STATE_TEXTURESTAGE(0, WINED3D_TSS_COLOR_OP), NULL }, WINED3D_GL_EXT_NONE },
1042 {STATE_TEXTURESTAGE(6, WINED3D_TSS_ALPHA_ARG2), { STATE_TEXTURESTAGE(0, WINED3D_TSS_COLOR_OP), NULL }, WINED3D_GL_EXT_NONE },
1043 {STATE_TEXTURESTAGE(6, WINED3D_TSS_ALPHA_ARG0), { STATE_TEXTURESTAGE(0, WINED3D_TSS_COLOR_OP), NULL }, WINED3D_GL_EXT_NONE },
1044 {STATE_TEXTURESTAGE(6, WINED3D_TSS_RESULT_ARG), { STATE_TEXTURESTAGE(0, WINED3D_TSS_COLOR_OP), NULL }, WINED3D_GL_EXT_NONE },
1045 {STATE_TEXTURESTAGE(6, WINED3D_TSS_BUMPENV_MAT00), { STATE_TEXTURESTAGE(6, WINED3D_TSS_BUMPENV_MAT00), set_bumpmat }, WINED3D_GL_EXT_NONE },
1046 {STATE_TEXTURESTAGE(6, WINED3D_TSS_BUMPENV_MAT01), { STATE_TEXTURESTAGE(6, WINED3D_TSS_BUMPENV_MAT00), NULL }, WINED3D_GL_EXT_NONE },
1047 {STATE_TEXTURESTAGE(6, WINED3D_TSS_BUMPENV_MAT10), { STATE_TEXTURESTAGE(6, WINED3D_TSS_BUMPENV_MAT00), NULL }, WINED3D_GL_EXT_NONE },
1048 {STATE_TEXTURESTAGE(6, WINED3D_TSS_BUMPENV_MAT11), { STATE_TEXTURESTAGE(6, WINED3D_TSS_BUMPENV_MAT00), NULL }, WINED3D_GL_EXT_NONE },
1049 {STATE_TEXTURESTAGE(7, WINED3D_TSS_COLOR_OP), { STATE_TEXTURESTAGE(0, WINED3D_TSS_COLOR_OP), NULL }, WINED3D_GL_EXT_NONE },
1050 {STATE_TEXTURESTAGE(7, WINED3D_TSS_COLOR_ARG1), { STATE_TEXTURESTAGE(0, WINED3D_TSS_COLOR_OP), NULL }, WINED3D_GL_EXT_NONE },
1051 {STATE_TEXTURESTAGE(7, WINED3D_TSS_COLOR_ARG2), { STATE_TEXTURESTAGE(0, WINED3D_TSS_COLOR_OP), NULL }, WINED3D_GL_EXT_NONE },
1052 {STATE_TEXTURESTAGE(7, WINED3D_TSS_COLOR_ARG0), { STATE_TEXTURESTAGE(0, WINED3D_TSS_COLOR_OP), NULL }, WINED3D_GL_EXT_NONE },
1053 {STATE_TEXTURESTAGE(7, WINED3D_TSS_ALPHA_OP), { STATE_TEXTURESTAGE(0, WINED3D_TSS_COLOR_OP), NULL }, WINED3D_GL_EXT_NONE },
1054 {STATE_TEXTURESTAGE(7, WINED3D_TSS_ALPHA_ARG1), { STATE_TEXTURESTAGE(0, WINED3D_TSS_COLOR_OP), NULL }, WINED3D_GL_EXT_NONE },
1055 {STATE_TEXTURESTAGE(7, WINED3D_TSS_ALPHA_ARG2), { STATE_TEXTURESTAGE(0, WINED3D_TSS_COLOR_OP), NULL }, WINED3D_GL_EXT_NONE },
1056 {STATE_TEXTURESTAGE(7, WINED3D_TSS_ALPHA_ARG0), { STATE_TEXTURESTAGE(0, WINED3D_TSS_COLOR_OP), NULL }, WINED3D_GL_EXT_NONE },
1057 {STATE_TEXTURESTAGE(7, WINED3D_TSS_RESULT_ARG), { STATE_TEXTURESTAGE(0, WINED3D_TSS_COLOR_OP), NULL }, WINED3D_GL_EXT_NONE },
1058 {STATE_TEXTURESTAGE(7, WINED3D_TSS_BUMPENV_MAT00), { STATE_TEXTURESTAGE(7, WINED3D_TSS_BUMPENV_MAT00), set_bumpmat }, WINED3D_GL_EXT_NONE },
1059 {STATE_TEXTURESTAGE(7, WINED3D_TSS_BUMPENV_MAT01), { STATE_TEXTURESTAGE(7, WINED3D_TSS_BUMPENV_MAT00), NULL }, WINED3D_GL_EXT_NONE },
1060 {STATE_TEXTURESTAGE(7, WINED3D_TSS_BUMPENV_MAT10), { STATE_TEXTURESTAGE(7, WINED3D_TSS_BUMPENV_MAT00), NULL }, WINED3D_GL_EXT_NONE },
1061 {STATE_TEXTURESTAGE(7, WINED3D_TSS_BUMPENV_MAT11), { STATE_TEXTURESTAGE(7, WINED3D_TSS_BUMPENV_MAT00), NULL }, WINED3D_GL_EXT_NONE },
1062 { STATE_SAMPLER(0), { STATE_SAMPLER(0), sampler_texdim }, WINED3D_GL_EXT_NONE },
1063 { STATE_SAMPLER(1), { STATE_SAMPLER(1), sampler_texdim }, WINED3D_GL_EXT_NONE },
1064 { STATE_SAMPLER(2), { STATE_SAMPLER(2), sampler_texdim }, WINED3D_GL_EXT_NONE },
1065 { STATE_SAMPLER(3), { STATE_SAMPLER(3), sampler_texdim }, WINED3D_GL_EXT_NONE },
1066 { STATE_SAMPLER(4), { STATE_SAMPLER(4), sampler_texdim }, WINED3D_GL_EXT_NONE },
1067 { STATE_SAMPLER(5), { STATE_SAMPLER(5), sampler_texdim }, WINED3D_GL_EXT_NONE },
1068 { STATE_SAMPLER(6), { STATE_SAMPLER(6), sampler_texdim }, WINED3D_GL_EXT_NONE },
1069 { STATE_SAMPLER(7), { STATE_SAMPLER(7), sampler_texdim }, WINED3D_GL_EXT_NONE },
1070 {STATE_TEXTURESTAGE(0,WINED3D_TSS_TEXTURE_TRANSFORM_FLAGS), {STATE_TEXTURESTAGE(0, WINED3D_TSS_TEXTURE_TRANSFORM_FLAGS), textransform }, WINED3D_GL_EXT_NONE },
1071 {STATE_TEXTURESTAGE(1,WINED3D_TSS_TEXTURE_TRANSFORM_FLAGS), {STATE_TEXTURESTAGE(1, WINED3D_TSS_TEXTURE_TRANSFORM_FLAGS), textransform }, WINED3D_GL_EXT_NONE },
1072 {STATE_TEXTURESTAGE(2,WINED3D_TSS_TEXTURE_TRANSFORM_FLAGS), {STATE_TEXTURESTAGE(2, WINED3D_TSS_TEXTURE_TRANSFORM_FLAGS), textransform }, WINED3D_GL_EXT_NONE },
1073 {STATE_TEXTURESTAGE(3,WINED3D_TSS_TEXTURE_TRANSFORM_FLAGS), {STATE_TEXTURESTAGE(3, WINED3D_TSS_TEXTURE_TRANSFORM_FLAGS), textransform }, WINED3D_GL_EXT_NONE },
1074 {STATE_TEXTURESTAGE(4,WINED3D_TSS_TEXTURE_TRANSFORM_FLAGS), {STATE_TEXTURESTAGE(4, WINED3D_TSS_TEXTURE_TRANSFORM_FLAGS), textransform }, WINED3D_GL_EXT_NONE },
1075 {STATE_TEXTURESTAGE(5,WINED3D_TSS_TEXTURE_TRANSFORM_FLAGS), {STATE_TEXTURESTAGE(5, WINED3D_TSS_TEXTURE_TRANSFORM_FLAGS), textransform }, WINED3D_GL_EXT_NONE },
1076 {STATE_TEXTURESTAGE(6,WINED3D_TSS_TEXTURE_TRANSFORM_FLAGS), {STATE_TEXTURESTAGE(6, WINED3D_TSS_TEXTURE_TRANSFORM_FLAGS), textransform }, WINED3D_GL_EXT_NONE },
1077 {STATE_TEXTURESTAGE(7,WINED3D_TSS_TEXTURE_TRANSFORM_FLAGS), {STATE_TEXTURESTAGE(7, WINED3D_TSS_TEXTURE_TRANSFORM_FLAGS), textransform }, WINED3D_GL_EXT_NONE },
1078 {STATE_PIXELSHADER, { STATE_PIXELSHADER, atifs_apply_pixelshader }, WINED3D_GL_EXT_NONE },
1079 {0 /* Terminate */, { 0, 0 }, WINED3D_GL_EXT_NONE },
1080 };
1081
1082 /* Context activation is done by the caller. */
1083 static void atifs_enable(const struct wined3d_gl_info *gl_info, BOOL enable)
1084 {
1085 if (enable)
1086 {
1087 gl_info->gl_ops.gl.p_glEnable(GL_FRAGMENT_SHADER_ATI);
1088 checkGLcall("glEnable(GL_FRAGMENT_SHADER_ATI)");
1089 }
1090 else
1091 {
1092 gl_info->gl_ops.gl.p_glDisable(GL_FRAGMENT_SHADER_ATI);
1093 checkGLcall("glDisable(GL_FRAGMENT_SHADER_ATI)");
1094 }
1095 }
1096
1097 static void atifs_get_caps(const struct wined3d_gl_info *gl_info, struct fragment_caps *caps)
1098 {
1099 caps->wined3d_caps = WINED3D_FRAGMENT_CAP_PROJ_CONTROL;
1100 caps->PrimitiveMiscCaps = WINED3DPMISCCAPS_TSSARGTEMP;
1101 caps->TextureOpCaps = WINED3DTEXOPCAPS_DISABLE |
1102 WINED3DTEXOPCAPS_SELECTARG1 |
1103 WINED3DTEXOPCAPS_SELECTARG2 |
1104 WINED3DTEXOPCAPS_MODULATE4X |
1105 WINED3DTEXOPCAPS_MODULATE2X |
1106 WINED3DTEXOPCAPS_MODULATE |
1107 WINED3DTEXOPCAPS_ADDSIGNED2X |
1108 WINED3DTEXOPCAPS_ADDSIGNED |
1109 WINED3DTEXOPCAPS_ADD |
1110 WINED3DTEXOPCAPS_SUBTRACT |
1111 WINED3DTEXOPCAPS_ADDSMOOTH |
1112 WINED3DTEXOPCAPS_BLENDCURRENTALPHA |
1113 WINED3DTEXOPCAPS_BLENDFACTORALPHA |
1114 WINED3DTEXOPCAPS_BLENDTEXTUREALPHA |
1115 WINED3DTEXOPCAPS_BLENDDIFFUSEALPHA |
1116 WINED3DTEXOPCAPS_BLENDTEXTUREALPHAPM |
1117 WINED3DTEXOPCAPS_MODULATEALPHA_ADDCOLOR |
1118 WINED3DTEXOPCAPS_MODULATECOLOR_ADDALPHA |
1119 WINED3DTEXOPCAPS_MODULATEINVCOLOR_ADDALPHA |
1120 WINED3DTEXOPCAPS_MODULATEINVALPHA_ADDCOLOR |
1121 WINED3DTEXOPCAPS_DOTPRODUCT3 |
1122 WINED3DTEXOPCAPS_MULTIPLYADD |
1123 WINED3DTEXOPCAPS_LERP |
1124 WINED3DTEXOPCAPS_BUMPENVMAP;
1125
1126 /* TODO: Implement WINED3DTEXOPCAPS_BUMPENVMAPLUMINANCE
1127 and WINED3DTEXOPCAPS_PREMODULATE */
1128
1129 /* GL_ATI_fragment_shader always supports 6 textures, which was the limit on r200 cards
1130 * which this extension is exclusively focused on(later cards have GL_ARB_fragment_program).
1131 * If the current card has more than 8 fixed function textures in OpenGL's regular fixed
1132 * function pipeline then the ATI_fragment_shader backend imposes a stricter limit. This
1133 * shouldn't be too hard since Nvidia cards have a limit of 4 textures with the default ffp
1134 * pipeline, and almost all games are happy with that. We can however support up to 8
1135 * texture stages because we have a 2nd pass limit of 8 instructions, and per stage we use
1136 * only 1 instruction.
1137 *
1138 * The proper fix for this is not to use GL_ATI_fragment_shader on cards newer than the
1139 * r200 series and use an ARB or GLSL shader instead
1140 */
1141 caps->MaxTextureBlendStages = 8;
1142 caps->MaxSimultaneousTextures = 6;
1143 }
1144
1145 static void *atifs_alloc(const struct wined3d_shader_backend_ops *shader_backend, void *shader_priv)
1146 {
1147 struct atifs_private_data *priv;
1148
1149 if (!(priv = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*priv))))
1150 return NULL;
1151
1152 if (wine_rb_init(&priv->fragment_shaders, &wined3d_ffp_frag_program_rb_functions) == -1)
1153 {
1154 ERR("Failed to initialize rbtree.\n");
1155 HeapFree(GetProcessHeap(), 0, priv);
1156 return NULL;
1157 }
1158
1159 return priv;
1160 }
1161
1162 /* Context activation is done by the caller. */
1163 static void atifs_free_ffpshader(struct wine_rb_entry *entry, void *cb_ctx)
1164 {
1165 const struct wined3d_gl_info *gl_info = cb_ctx;
1166 struct atifs_ffp_desc *entry_ati = WINE_RB_ENTRY_VALUE(entry, struct atifs_ffp_desc, parent.entry);
1167
1168 GL_EXTCALL(glDeleteFragmentShaderATI(entry_ati->shader));
1169 checkGLcall("glDeleteFragmentShaderATI(entry->shader)");
1170 HeapFree(GetProcessHeap(), 0, entry_ati);
1171 }
1172
1173 /* Context activation is done by the caller. */
1174 static void atifs_free(struct wined3d_device *device)
1175 {
1176 struct atifs_private_data *priv = device->fragment_priv;
1177
1178 wine_rb_destroy(&priv->fragment_shaders, atifs_free_ffpshader, &device->adapter->gl_info);
1179
1180 HeapFree(GetProcessHeap(), 0, priv);
1181 device->fragment_priv = NULL;
1182 }
1183
1184 static BOOL atifs_color_fixup_supported(struct color_fixup_desc fixup)
1185 {
1186 if (TRACE_ON(d3d_shader) && TRACE_ON(d3d))
1187 {
1188 TRACE("Checking support for fixup:\n");
1189 dump_color_fixup_desc(fixup);
1190 }
1191
1192 /* We only support sign fixup of the first two channels. */
1193 if (fixup.x_source == CHANNEL_SOURCE_X && fixup.y_source == CHANNEL_SOURCE_Y
1194 && fixup.z_source == CHANNEL_SOURCE_Z && fixup.w_source == CHANNEL_SOURCE_W
1195 && !fixup.z_sign_fixup && !fixup.w_sign_fixup)
1196 {
1197 TRACE("[OK]\n");
1198 return TRUE;
1199 }
1200
1201 TRACE("[FAILED]\n");
1202 return FALSE;
1203 }
1204
1205 const struct fragment_pipeline atifs_fragment_pipeline = {
1206 atifs_enable,
1207 atifs_get_caps,
1208 atifs_alloc,
1209 atifs_free,
1210 atifs_color_fixup_supported,
1211 atifs_fragmentstate_template,
1212 };