comctl32/tests: Destroy the window after the tests.
[wine] / dlls / wined3d / baseshader.c
1 /*
2  * shaders implementation
3  *
4  * Copyright 2002-2003 Jason Edmeades
5  * Copyright 2002-2003 Raphael Junqueira
6  * Copyright 2004 Christian Costa
7  * Copyright 2005 Oliver Stieber
8  * Copyright 2006 Ivan Gyurdiev
9  * Copyright 2007-2008 Stefan Dösinger for CodeWeavers
10  *
11  * This library is free software; you can redistribute it and/or
12  * modify it under the terms of the GNU Lesser General Public
13  * License as published by the Free Software Foundation; either
14  * version 2.1 of the License, or (at your option) any later version.
15  *
16  * This library is distributed in the hope that it will be useful,
17  * but WITHOUT ANY WARRANTY; without even the implied warranty of
18  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
19  * Lesser General Public License for more details.
20  *
21  * You should have received a copy of the GNU Lesser General Public
22  * License along with this library; if not, write to the Free Software
23  * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
24  */
25
26 #include "config.h"
27 #include <string.h>
28 #include <stdio.h>
29 #include "wined3d_private.h"
30
31 WINE_DEFAULT_DEBUG_CHANNEL(d3d_shader);
32 WINE_DECLARE_DEBUG_CHANNEL(d3d);
33
34 #define GLNAME_REQUIRE_GLSL  ((const char *)1)
35
36 static void shader_dump_param(const DWORD param, const DWORD addr_token, int input, DWORD shader_version);
37
38 static inline BOOL shader_is_version_token(DWORD token) {
39     return shader_is_pshader_version(token) ||
40            shader_is_vshader_version(token);
41 }
42
43 void shader_buffer_init(struct SHADER_BUFFER *buffer)
44 {
45     buffer->buffer = HeapAlloc(GetProcessHeap(), 0, SHADER_PGMSIZE);
46     buffer->buffer[0] = '\0';
47     buffer->bsize = 0;
48     buffer->lineNo = 0;
49     buffer->newline = TRUE;
50 }
51
52 void shader_buffer_free(struct SHADER_BUFFER *buffer)
53 {
54     HeapFree(GetProcessHeap(), 0, buffer->buffer);
55 }
56
57 int shader_addline(
58     SHADER_BUFFER* buffer,  
59     const char *format, ...) {
60
61     char* base = buffer->buffer + buffer->bsize;
62     int rc;
63
64     va_list args;
65     va_start(args, format);
66     rc = vsnprintf(base, SHADER_PGMSIZE - 1 - buffer->bsize, format, args);
67     va_end(args);
68
69     if (rc < 0 ||                                   /* C89 */ 
70         rc > SHADER_PGMSIZE - 1 - buffer->bsize) {  /* C99 */
71
72         ERR("The buffer allocated for the shader program string "
73             "is too small at %d bytes.\n", SHADER_PGMSIZE);
74         buffer->bsize = SHADER_PGMSIZE - 1;
75         return -1;
76     }
77
78     if (buffer->newline) {
79         TRACE("GL HW (%u, %u) : %s", buffer->lineNo + 1, buffer->bsize, base);
80         buffer->newline = FALSE;
81     } else {
82         TRACE("%s", base);
83     }
84
85     buffer->bsize += rc;
86     if (buffer->buffer[buffer->bsize-1] == '\n') {
87         buffer->lineNo++;
88         buffer->newline = TRUE;
89     }
90     return 0;
91 }
92
93 const SHADER_OPCODE *shader_get_opcode(const SHADER_OPCODE *opcode_table, DWORD shader_version, DWORD code)
94 {
95     DWORD i = 0;
96
97     /** TODO: use dichotomic search */
98     while (opcode_table[i].name)
99     {
100         if ((code & WINED3DSI_OPCODE_MASK) == opcode_table[i].opcode
101                 && shader_version >= opcode_table[i].min_version
102                 && (!opcode_table[i].max_version || shader_version <= opcode_table[i].max_version))
103         {
104             return &opcode_table[i];
105         }
106         ++i;
107     }
108
109     FIXME("Unsupported opcode %#x(%d) masked %#x, shader version %#x\n",
110             code, code, code & WINED3DSI_OPCODE_MASK, shader_version);
111
112     return NULL;
113 }
114
115 /* Read a parameter opcode from the input stream,
116  * and possibly a relative addressing token.
117  * Return the number of tokens read */
118 static int shader_get_param(const DWORD *pToken, DWORD shader_version, DWORD *param, DWORD *addr_token)
119 {
120     /* PS >= 3.0 have relative addressing (with token)
121      * VS >= 2.0 have relative addressing (with token)
122      * VS >= 1.0 < 2.0 have relative addressing (without token)
123      * The version check below should work in general */
124
125     char rel_token = WINED3DSHADER_VERSION_MAJOR(shader_version) >= 2 &&
126         ((*pToken & WINED3DSHADER_ADDRESSMODE_MASK) == WINED3DSHADER_ADDRMODE_RELATIVE);
127
128     *param = *pToken;
129     *addr_token = rel_token? *(pToken + 1): 0;
130     return rel_token? 2:1;
131 }
132
133 /* Return the number of parameters to skip for an opcode */
134 static inline int shader_skip_opcode(const SHADER_OPCODE *curOpcode, DWORD opcode_token, DWORD shader_version)
135 {
136    /* Shaders >= 2.0 may contain address tokens, but fortunately they
137     * have a useful length mask - use it here. Shaders 1.0 contain no such tokens */
138     return (WINED3DSHADER_VERSION_MAJOR(shader_version) >= 2)
139             ? ((opcode_token & WINED3DSI_INSTLENGTH_MASK) >> WINED3DSI_INSTLENGTH_SHIFT) : curOpcode->num_params;
140 }
141
142 /* Read the parameters of an unrecognized opcode from the input stream
143  * Return the number of tokens read. 
144  * 
145  * Note: This function assumes source or destination token format.
146  * It will not work with specially-formatted tokens like DEF or DCL, 
147  * but hopefully those would be recognized */
148 static int shader_skip_unrecognized(const DWORD *pToken, DWORD shader_version)
149 {
150     int tokens_read = 0;
151     int i = 0;
152
153     /* TODO: Think of a good name for 0x80000000 and replace it with a constant */
154     while (*pToken & 0x80000000) {
155
156         DWORD param, addr_token;
157         tokens_read += shader_get_param(pToken, shader_version, &param, &addr_token);
158         pToken += tokens_read;
159
160         FIXME("Unrecognized opcode param: token=0x%08x "
161             "addr_token=0x%08x name=", param, addr_token);
162         shader_dump_param(param, addr_token, i, shader_version);
163         FIXME("\n");
164         ++i;
165     }
166     return tokens_read;
167 }
168
169 /* Convert floating point offset relative
170  * to a register file to an absolute offset for float constants */
171 static unsigned int shader_get_float_offset(const DWORD reg)
172 {
173      unsigned int regnum = reg & WINED3DSP_REGNUM_MASK;
174      int regtype = shader_get_regtype(reg);
175
176      switch (regtype) {
177         case WINED3DSPR_CONST: return regnum;
178         case WINED3DSPR_CONST2: return 2048 + regnum;
179         case WINED3DSPR_CONST3: return 4096 + regnum;
180         case WINED3DSPR_CONST4: return 6144 + regnum;
181         default:
182             FIXME("Unsupported register type: %d\n", regtype);
183             return regnum;
184      }
185 }
186
187 static void shader_delete_constant_list(struct list* clist) {
188
189     struct list *ptr;
190     struct local_constant* constant;
191
192     ptr = list_head(clist);
193     while (ptr) {
194         constant = LIST_ENTRY(ptr, struct local_constant, entry);
195         ptr = list_next(clist, ptr);
196         HeapFree(GetProcessHeap(), 0, constant);
197     }
198     list_init(clist);
199 }
200
201 /* Note that this does not count the loop register
202  * as an address register. */
203
204 HRESULT shader_get_registers_used(IWineD3DBaseShader *iface, struct shader_reg_maps *reg_maps,
205         struct semantic *semantics_in, struct semantic *semantics_out, const DWORD *byte_code)
206 {
207     IWineD3DBaseShaderImpl* This = (IWineD3DBaseShaderImpl*) iface;
208     const SHADER_OPCODE *shader_ins = This->baseShader.shader_ins;
209     DWORD shader_version;
210     unsigned int cur_loop_depth = 0, max_loop_depth = 0;
211     const DWORD* pToken = byte_code;
212     char pshader;
213
214     /* There are some minor differences between pixel and vertex shaders */
215
216     memset(reg_maps->bumpmat, 0, sizeof(reg_maps->bumpmat));
217     memset(reg_maps->luminanceparams, 0, sizeof(reg_maps->luminanceparams));
218
219     if (!pToken)
220     {
221         WARN("Got a NULL pFunction, returning.\n");
222         This->baseShader.functionLength = 0;
223         return WINED3D_OK;
224     }
225
226     /* get_registers_used is called on every compile on some 1.x shaders, which can result
227      * in stacking up a collection of local constants. Delete the old constants if existing
228      */
229     shader_delete_constant_list(&This->baseShader.constantsF);
230     shader_delete_constant_list(&This->baseShader.constantsB);
231     shader_delete_constant_list(&This->baseShader.constantsI);
232
233     /* The version token is supposed to be the first token */
234     if (!shader_is_version_token(*pToken))
235     {
236         FIXME("First token is not a version token, invalid shader.\n");
237         return WINED3DERR_INVALIDCALL;
238     }
239     reg_maps->shader_version = shader_version = *pToken++;
240     pshader = shader_is_pshader_version(shader_version);
241
242     while (WINED3DVS_END() != *pToken) {
243         CONST SHADER_OPCODE* curOpcode;
244         DWORD opcode_token;
245
246         /* Skip comments */
247         if (shader_is_comment(*pToken))
248         {
249              DWORD comment_len = (*pToken & WINED3DSI_COMMENTSIZE_MASK) >> WINED3DSI_COMMENTSIZE_SHIFT;
250              ++pToken;
251              pToken += comment_len;
252              continue;
253         }
254
255         /* Fetch opcode */
256         opcode_token = *pToken++;
257         curOpcode = shader_get_opcode(shader_ins, shader_version, opcode_token);
258
259         /* Unhandled opcode, and its parameters */
260         if (NULL == curOpcode) {
261            while (*pToken & 0x80000000)
262                ++pToken;
263
264         /* Handle declarations */
265         } else if (WINED3DSIO_DCL == curOpcode->opcode) {
266
267             DWORD usage = *pToken++;
268             DWORD param = *pToken++;
269             DWORD regtype = shader_get_regtype(param);
270             unsigned int regnum = param & WINED3DSP_REGNUM_MASK;
271
272             /* Vshader: mark attributes used
273                Pshader: mark 3.0 input registers used, save token */
274             if (WINED3DSPR_INPUT == regtype) {
275
276                 if (!pshader)
277                     reg_maps->attributes[regnum] = 1;
278                 else
279                     reg_maps->packed_input[regnum] = 1;
280
281                 semantics_in[regnum].usage = usage;
282                 semantics_in[regnum].reg = param;
283
284             /* Vshader: mark 3.0 output registers used, save token */
285             } else if (WINED3DSPR_OUTPUT == regtype) {
286                 reg_maps->packed_output[regnum] = 1;
287                 semantics_out[regnum].usage = usage;
288                 semantics_out[regnum].reg = param;
289                 if (usage & (WINED3DDECLUSAGE_FOG << WINED3DSP_DCL_USAGE_SHIFT))
290                     reg_maps->fog = 1;
291
292             /* Save sampler usage token */
293             } else if (WINED3DSPR_SAMPLER == regtype)
294                 reg_maps->samplers[regnum] = usage;
295
296         } else if (WINED3DSIO_DEF == curOpcode->opcode) {
297
298             local_constant* lconst = HeapAlloc(GetProcessHeap(), 0, sizeof(local_constant));
299             if (!lconst) return E_OUTOFMEMORY;
300             lconst->idx = *pToken & WINED3DSP_REGNUM_MASK;
301             memcpy(lconst->value, pToken + 1, 4 * sizeof(DWORD));
302
303             /* In pixel shader 1.X shaders, the constants are clamped between [-1;1] */
304             if (WINED3DSHADER_VERSION_MAJOR(shader_version) == 1 && pshader)
305             {
306                 float *value = (float *) lconst->value;
307                 if(value[0] < -1.0) value[0] = -1.0;
308                 else if(value[0] >  1.0) value[0] =  1.0;
309                 if(value[1] < -1.0) value[1] = -1.0;
310                 else if(value[1] >  1.0) value[1] =  1.0;
311                 if(value[2] < -1.0) value[2] = -1.0;
312                 else if(value[2] >  1.0) value[2] =  1.0;
313                 if(value[3] < -1.0) value[3] = -1.0;
314                 else if(value[3] >  1.0) value[3] =  1.0;
315             }
316
317             list_add_head(&This->baseShader.constantsF, &lconst->entry);
318             pToken += curOpcode->num_params;
319
320         } else if (WINED3DSIO_DEFI == curOpcode->opcode) {
321
322             local_constant* lconst = HeapAlloc(GetProcessHeap(), 0, sizeof(local_constant));
323             if (!lconst) return E_OUTOFMEMORY;
324             lconst->idx = *pToken & WINED3DSP_REGNUM_MASK;
325             memcpy(lconst->value, pToken + 1, 4 * sizeof(DWORD));
326             list_add_head(&This->baseShader.constantsI, &lconst->entry);
327             pToken += curOpcode->num_params;
328
329         } else if (WINED3DSIO_DEFB == curOpcode->opcode) {
330
331             local_constant* lconst = HeapAlloc(GetProcessHeap(), 0, sizeof(local_constant));
332             if (!lconst) return E_OUTOFMEMORY;
333             lconst->idx = *pToken & WINED3DSP_REGNUM_MASK;
334             memcpy(lconst->value, pToken + 1, 1 * sizeof(DWORD));
335             list_add_head(&This->baseShader.constantsB, &lconst->entry);
336             pToken += curOpcode->num_params;
337
338         /* If there's a loop in the shader */
339         } else if (WINED3DSIO_LOOP == curOpcode->opcode ||
340                    WINED3DSIO_REP == curOpcode->opcode) {
341             cur_loop_depth++;
342             if(cur_loop_depth > max_loop_depth)
343                 max_loop_depth = cur_loop_depth;
344             pToken += curOpcode->num_params;
345
346             /* Rep and Loop always use an integer constant for the control parameters */
347             This->baseShader.uses_int_consts = TRUE;
348         } else if (WINED3DSIO_ENDLOOP == curOpcode->opcode ||
349                    WINED3DSIO_ENDREP == curOpcode->opcode) {
350             cur_loop_depth--;
351
352         /* For subroutine prototypes */
353         } else if (WINED3DSIO_LABEL == curOpcode->opcode) {
354
355             DWORD snum = *pToken & WINED3DSP_REGNUM_MASK; 
356             reg_maps->labels[snum] = 1;
357             pToken += curOpcode->num_params;
358
359         /* Set texture, address, temporary registers */
360         } else {
361             int i, limit;
362
363             /* Declare 1.X samplers implicitly, based on the destination reg. number */
364             if (WINED3DSHADER_VERSION_MAJOR(shader_version) == 1
365                     && pshader /* Filter different instructions with the same enum values in VS */
366                     && (WINED3DSIO_TEX == curOpcode->opcode
367                         || WINED3DSIO_TEXBEM == curOpcode->opcode
368                         || WINED3DSIO_TEXBEML == curOpcode->opcode
369                         || WINED3DSIO_TEXDP3TEX == curOpcode->opcode
370                         || WINED3DSIO_TEXM3x2TEX == curOpcode->opcode
371                         || WINED3DSIO_TEXM3x3SPEC == curOpcode->opcode
372                         || WINED3DSIO_TEXM3x3TEX == curOpcode->opcode
373                         || WINED3DSIO_TEXM3x3VSPEC == curOpcode->opcode
374                         || WINED3DSIO_TEXREG2AR == curOpcode->opcode
375                         || WINED3DSIO_TEXREG2GB == curOpcode->opcode
376                         || WINED3DSIO_TEXREG2RGB == curOpcode->opcode))
377             {
378                 /* Fake sampler usage, only set reserved bit and ttype */
379                 DWORD sampler_code = *pToken & WINED3DSP_REGNUM_MASK;
380
381                 TRACE("Setting fake 2D sampler for 1.x pixelshader\n");
382                 reg_maps->samplers[sampler_code] = (0x1 << 31) | WINED3DSTT_2D;
383
384                 /* texbem is only valid with < 1.4 pixel shaders */
385                 if(WINED3DSIO_TEXBEM  == curOpcode->opcode ||
386                     WINED3DSIO_TEXBEML == curOpcode->opcode) {
387                     reg_maps->bumpmat[sampler_code] = TRUE;
388                     if(WINED3DSIO_TEXBEML == curOpcode->opcode) {
389                         reg_maps->luminanceparams[sampler_code] = TRUE;
390                     }
391                 }
392             }
393             if(WINED3DSIO_NRM  == curOpcode->opcode) {
394                 reg_maps->usesnrm = 1;
395             } else if(WINED3DSIO_BEM == curOpcode->opcode && pshader) {
396                 DWORD regnum = *pToken & WINED3DSP_REGNUM_MASK;
397                 reg_maps->bumpmat[regnum] = TRUE;
398             } else if(WINED3DSIO_DSY  == curOpcode->opcode) {
399                 reg_maps->usesdsy = 1;
400             }
401
402             /* This will loop over all the registers and try to
403              * make a bitmask of the ones we're interested in. 
404              *
405              * Relative addressing tokens are ignored, but that's 
406              * okay, since we'll catch any address registers when 
407              * they are initialized (required by spec) */
408
409             limit = (opcode_token & WINED3DSHADER_INSTRUCTION_PREDICATED)?
410                 curOpcode->num_params + 1: curOpcode->num_params;
411
412             for (i = 0; i < limit; ++i) {
413
414                 DWORD param, addr_token, reg, regtype;
415                 pToken += shader_get_param(pToken, shader_version, &param, &addr_token);
416
417                 regtype = shader_get_regtype(param);
418                 reg = param & WINED3DSP_REGNUM_MASK;
419
420                 if (WINED3DSPR_TEXTURE == regtype) { /* vs: WINED3DSPR_ADDR */
421
422                     if (pshader)
423                         reg_maps->texcoord[reg] = 1;
424                     else
425                         reg_maps->address[reg] = 1;
426                 }
427
428                 else if (WINED3DSPR_TEMP == regtype)
429                     reg_maps->temporary[reg] = 1;
430
431                 else if (WINED3DSPR_INPUT == regtype) {
432                     if( !pshader)
433                         reg_maps->attributes[reg] = 1;
434                     else {
435                         if(param & WINED3DSHADER_ADDRMODE_RELATIVE) {
436                             /* If relative addressing is used, we must assume that all registers
437                              * are used. Even if it is a construct like v3[aL], we can't assume
438                              * that v0, v1 and v2 aren't read because aL can be negative
439                              */
440                             unsigned int i;
441                             for(i = 0; i < MAX_REG_INPUT; i++) {
442                                 ((IWineD3DPixelShaderImpl *) This)->input_reg_used[i] = TRUE;
443                             }
444                         } else {
445                             ((IWineD3DPixelShaderImpl *) This)->input_reg_used[reg] = TRUE;
446                         }
447                     }
448                 }
449
450                 else if (WINED3DSPR_RASTOUT == regtype && reg == 1)
451                     reg_maps->fog = 1;
452
453                 else if (WINED3DSPR_MISCTYPE == regtype && reg == 0 && pshader)
454                     reg_maps->vpos = 1;
455
456                 else if(WINED3DSPR_CONST == regtype) {
457                     if(param & WINED3DSHADER_ADDRMODE_RELATIVE) {
458                         if(!pshader) {
459                             if(reg <= ((IWineD3DVertexShaderImpl *) This)->min_rel_offset) {
460                                 ((IWineD3DVertexShaderImpl *) This)->min_rel_offset = reg;
461                             } else if(reg >= ((IWineD3DVertexShaderImpl *) This)->max_rel_offset) {
462                                 ((IWineD3DVertexShaderImpl *) This)->max_rel_offset = reg;
463                             }
464                         }
465                         reg_maps->usesrelconstF = TRUE;
466                     }
467                 }
468                 else if(WINED3DSPR_CONSTINT == regtype) {
469                     This->baseShader.uses_int_consts = TRUE;
470                 }
471                 else if(WINED3DSPR_CONSTBOOL == regtype) {
472                     This->baseShader.uses_bool_consts = TRUE;
473                 }
474
475                 /* WINED3DSPR_TEXCRDOUT is the same as WINED3DSPR_OUTPUT. _OUTPUT can be > MAX_REG_TEXCRD and is used
476                  * in >= 3.0 shaders. Filter 3.0 shaders to prevent overflows, and also filter pixel shaders because TECRDOUT
477                  * isn't used in them, but future register types might cause issues
478                  */
479                 else if (WINED3DSPR_TEXCRDOUT == regtype && i == 0 /* Only look at writes */
480                         && !pshader && WINED3DSHADER_VERSION_MAJOR(shader_version) < 3)
481                 {
482                     reg_maps->texcoord_mask[reg] |= shader_get_writemask(param);
483                 }
484             }
485         }
486     }
487     ++pToken;
488     reg_maps->loop_depth = max_loop_depth;
489
490     This->baseShader.functionLength = ((char *)pToken - (char *)byte_code);
491
492     return WINED3D_OK;
493 }
494
495 static void shader_dump_decl_usage(DWORD decl, DWORD param, DWORD shader_version)
496 {
497     DWORD regtype = shader_get_regtype(param);
498
499     TRACE("dcl");
500
501     if (regtype == WINED3DSPR_SAMPLER) {
502         DWORD ttype = decl & WINED3DSP_TEXTURETYPE_MASK;
503
504         switch (ttype) {
505             case WINED3DSTT_2D: TRACE("_2d"); break;
506             case WINED3DSTT_CUBE: TRACE("_cube"); break;
507             case WINED3DSTT_VOLUME: TRACE("_volume"); break;
508             default: TRACE("_unknown_ttype(0x%08x)", ttype);
509        }
510
511     } else { 
512
513         DWORD usage = decl & WINED3DSP_DCL_USAGE_MASK;
514         DWORD idx = (decl & WINED3DSP_DCL_USAGEINDEX_MASK) >> WINED3DSP_DCL_USAGEINDEX_SHIFT;
515
516         /* Pixel shaders 3.0 don't have usage semantics */
517         if (shader_is_pshader_version(shader_version) && shader_version < WINED3DPS_VERSION(3,0))
518             return;
519         else
520             TRACE("_");
521
522         switch(usage) {
523         case WINED3DDECLUSAGE_POSITION:
524             TRACE("position%d", idx);
525             break;
526         case WINED3DDECLUSAGE_BLENDINDICES:
527             TRACE("blend");
528             break;
529         case WINED3DDECLUSAGE_BLENDWEIGHT:
530             TRACE("weight");
531             break;
532         case WINED3DDECLUSAGE_NORMAL:
533             TRACE("normal%d", idx);
534             break;
535         case WINED3DDECLUSAGE_PSIZE:
536             TRACE("psize");
537             break;
538         case WINED3DDECLUSAGE_COLOR:
539             if(idx == 0)  {
540                 TRACE("color");
541             } else {
542                 TRACE("specular%d", (idx - 1));
543             }
544             break;
545         case WINED3DDECLUSAGE_TEXCOORD:
546             TRACE("texture%d", idx);
547             break;
548         case WINED3DDECLUSAGE_TANGENT:
549             TRACE("tangent");
550             break;
551         case WINED3DDECLUSAGE_BINORMAL:
552             TRACE("binormal");
553             break;
554         case WINED3DDECLUSAGE_TESSFACTOR:
555             TRACE("tessfactor");
556             break;
557         case WINED3DDECLUSAGE_POSITIONT:
558             TRACE("positionT%d", idx);
559             break;
560         case WINED3DDECLUSAGE_FOG:
561             TRACE("fog");
562             break;
563         case WINED3DDECLUSAGE_DEPTH:
564             TRACE("depth");
565             break;
566         case WINED3DDECLUSAGE_SAMPLE:
567             TRACE("sample");
568             break;
569         default:
570             FIXME("unknown_semantics(0x%08x)", usage);
571         }
572     }
573 }
574
575 static void shader_dump_arr_entry(const DWORD param, const DWORD addr_token,
576         unsigned int reg, int input, DWORD shader_version)
577 {
578     char relative =
579         ((param & WINED3DSHADER_ADDRESSMODE_MASK) == WINED3DSHADER_ADDRMODE_RELATIVE);
580
581     if (relative) {
582         TRACE("[");
583         if (addr_token)
584             shader_dump_param(addr_token, 0, input, shader_version);
585         else
586             TRACE("a0.x");
587         TRACE(" + ");
588      }
589      TRACE("%u", reg);
590      if (relative)
591          TRACE("]");
592 }
593
594 static void shader_dump_param(const DWORD param, const DWORD addr_token, int input, DWORD shader_version)
595 {
596     static const char * const rastout_reg_names[] = { "oPos", "oFog", "oPts" };
597     static const char * const misctype_reg_names[] = { "vPos", "vFace"};
598     char swizzle_reg_chars[4];
599
600     DWORD reg = param & WINED3DSP_REGNUM_MASK;
601     DWORD regtype = shader_get_regtype(param);
602     DWORD modifier = param & WINED3DSP_SRCMOD_MASK;
603
604     /* There are some minor differences between pixel and vertex shaders */
605     char pshader = shader_is_pshader_version(shader_version);
606
607     /* For one, we'd prefer color components to be shown for pshaders.
608      * FIXME: use the swizzle function for this */
609
610     swizzle_reg_chars[0] = pshader? 'r': 'x';
611     swizzle_reg_chars[1] = pshader? 'g': 'y';
612     swizzle_reg_chars[2] = pshader? 'b': 'z';
613     swizzle_reg_chars[3] = pshader? 'a': 'w';
614
615     if (input) {
616         if ( (modifier == WINED3DSPSM_NEG) ||
617              (modifier == WINED3DSPSM_BIASNEG) ||
618              (modifier == WINED3DSPSM_SIGNNEG) ||
619              (modifier == WINED3DSPSM_X2NEG) ||
620              (modifier == WINED3DSPSM_ABSNEG) )
621             TRACE("-");
622         else if (modifier == WINED3DSPSM_COMP)
623             TRACE("1-");
624         else if (modifier == WINED3DSPSM_NOT)
625             TRACE("!");
626
627         if (modifier == WINED3DSPSM_ABS || modifier == WINED3DSPSM_ABSNEG) 
628             TRACE("abs(");
629     }
630
631     switch (regtype) {
632         case WINED3DSPR_TEMP:
633             TRACE("r%u", reg);
634             break;
635         case WINED3DSPR_INPUT:
636             TRACE("v");
637             shader_dump_arr_entry(param, addr_token, reg, input, shader_version);
638             break;
639         case WINED3DSPR_CONST:
640         case WINED3DSPR_CONST2:
641         case WINED3DSPR_CONST3:
642         case WINED3DSPR_CONST4:
643             TRACE("c");
644             shader_dump_arr_entry(param, addr_token, shader_get_float_offset(param), input, shader_version);
645             break;
646         case WINED3DSPR_TEXTURE: /* vs: case D3DSPR_ADDR */
647             TRACE("%c%u", (pshader? 't':'a'), reg);
648             break;        
649         case WINED3DSPR_RASTOUT:
650             TRACE("%s", rastout_reg_names[reg]);
651             break;
652         case WINED3DSPR_COLOROUT:
653             TRACE("oC%u", reg);
654             break;
655         case WINED3DSPR_DEPTHOUT:
656             TRACE("oDepth");
657             break;
658         case WINED3DSPR_ATTROUT:
659             TRACE("oD%u", reg);
660             break;
661         case WINED3DSPR_TEXCRDOUT: 
662
663             /* Vertex shaders >= 3.0 use general purpose output registers
664              * (WINED3DSPR_OUTPUT), which can include an address token */
665
666             if (WINED3DSHADER_VERSION_MAJOR(shader_version) >= 3) {
667                 TRACE("o");
668                 shader_dump_arr_entry(param, addr_token, reg, input, shader_version);
669             }
670             else 
671                TRACE("oT%u", reg);
672             break;
673         case WINED3DSPR_CONSTINT:
674             TRACE("i");
675             shader_dump_arr_entry(param, addr_token, reg, input, shader_version);
676             break;
677         case WINED3DSPR_CONSTBOOL:
678             TRACE("b");
679             shader_dump_arr_entry(param, addr_token, reg, input, shader_version);
680             break;
681         case WINED3DSPR_LABEL:
682             TRACE("l%u", reg);
683             break;
684         case WINED3DSPR_LOOP:
685             TRACE("aL");
686             break;
687         case WINED3DSPR_SAMPLER:
688             TRACE("s%u", reg);
689             break;
690         case WINED3DSPR_MISCTYPE:
691             if (reg > 1) {
692                 FIXME("Unhandled misctype register %d\n", reg);
693             } else {
694                 TRACE("%s", misctype_reg_names[reg]);
695             }
696             break;
697         case WINED3DSPR_PREDICATE:
698             TRACE("p%u", reg);
699             break;
700         default:
701             TRACE("unhandled_rtype(%#x)", regtype);
702             break;
703    }
704
705    if (!input) {
706        /* operand output (for modifiers and shift, see dump_ins_modifiers) */
707
708        if ((param & WINED3DSP_WRITEMASK_ALL) != WINED3DSP_WRITEMASK_ALL) {
709            TRACE(".");
710            if (param & WINED3DSP_WRITEMASK_0) TRACE("%c", swizzle_reg_chars[0]);
711            if (param & WINED3DSP_WRITEMASK_1) TRACE("%c", swizzle_reg_chars[1]);
712            if (param & WINED3DSP_WRITEMASK_2) TRACE("%c", swizzle_reg_chars[2]);
713            if (param & WINED3DSP_WRITEMASK_3) TRACE("%c", swizzle_reg_chars[3]);
714        }
715
716    } else {
717         /** operand input */
718         DWORD swizzle = (param & WINED3DSP_SWIZZLE_MASK) >> WINED3DSP_SWIZZLE_SHIFT;
719         DWORD swizzle_r = swizzle & 0x03;
720         DWORD swizzle_g = (swizzle >> 2) & 0x03;
721         DWORD swizzle_b = (swizzle >> 4) & 0x03;
722         DWORD swizzle_a = (swizzle >> 6) & 0x03;
723
724         if (0 != modifier) {
725             switch (modifier) {
726                 case WINED3DSPSM_NONE:    break;
727                 case WINED3DSPSM_NEG:     break;
728                 case WINED3DSPSM_NOT:     break;
729                 case WINED3DSPSM_BIAS:    TRACE("_bias"); break;
730                 case WINED3DSPSM_BIASNEG: TRACE("_bias"); break;
731                 case WINED3DSPSM_SIGN:    TRACE("_bx2"); break;
732                 case WINED3DSPSM_SIGNNEG: TRACE("_bx2"); break;
733                 case WINED3DSPSM_COMP:    break;
734                 case WINED3DSPSM_X2:      TRACE("_x2"); break;
735                 case WINED3DSPSM_X2NEG:   TRACE("_x2"); break;
736                 case WINED3DSPSM_DZ:      TRACE("_dz"); break;
737                 case WINED3DSPSM_DW:      TRACE("_dw"); break;
738                 case WINED3DSPSM_ABSNEG:  TRACE(")"); break;
739                 case WINED3DSPSM_ABS:     TRACE(")"); break;
740                 default:
741                     TRACE("_unknown_modifier(%#x)", modifier >> WINED3DSP_SRCMOD_SHIFT);
742             }
743         }
744
745         /**
746         * swizzle bits fields:
747         *  RRGGBBAA
748         */
749         if ((WINED3DVS_NOSWIZZLE >> WINED3DVS_SWIZZLE_SHIFT) != swizzle) {
750             if (swizzle_r == swizzle_g &&
751                 swizzle_r == swizzle_b &&
752                 swizzle_r == swizzle_a) {
753                     TRACE(".%c", swizzle_reg_chars[swizzle_r]);
754             } else {
755                 TRACE(".%c%c%c%c",
756                 swizzle_reg_chars[swizzle_r],
757                 swizzle_reg_chars[swizzle_g],
758                 swizzle_reg_chars[swizzle_b],
759                 swizzle_reg_chars[swizzle_a]);
760             }
761         }
762     }
763 }
764
765 static void shader_color_correction(IWineD3DBaseShaderImpl *shader,
766         IWineD3DDeviceImpl *device, const struct SHADER_OPCODE_ARG *arg, DWORD shader_version)
767 {
768     IWineD3DBaseTextureImpl *texture;
769     struct color_fixup_desc fixup;
770     BOOL recorded = FALSE;
771     DWORD sampler_idx;
772     UINT i;
773
774     switch(arg->opcode->opcode)
775     {
776         case WINED3DSIO_TEX:
777             if (WINED3DSHADER_VERSION_MAJOR(shader_version) < 2) sampler_idx = arg->dst & WINED3DSP_REGNUM_MASK;
778             else sampler_idx = arg->src[1] & WINED3DSP_REGNUM_MASK;
779             break;
780
781         case WINED3DSIO_TEXLDL:
782             FIXME("Add color fixup for vertex texture WINED3DSIO_TEXLDL\n");
783             return;
784
785         case WINED3DSIO_TEXDP3TEX:
786         case WINED3DSIO_TEXM3x3TEX:
787         case WINED3DSIO_TEXM3x3SPEC:
788         case WINED3DSIO_TEXM3x3VSPEC:
789         case WINED3DSIO_TEXBEM:
790         case WINED3DSIO_TEXREG2AR:
791         case WINED3DSIO_TEXREG2GB:
792         case WINED3DSIO_TEXREG2RGB:
793             sampler_idx = arg->dst & WINED3DSP_REGNUM_MASK;
794             break;
795
796         default:
797             /* Not a texture sampling instruction, nothing to do */
798             return;
799     };
800
801     texture = (IWineD3DBaseTextureImpl *)device->stateBlock->textures[sampler_idx];
802     if (texture) fixup = texture->baseTexture.shader_color_fixup;
803     else fixup = COLOR_FIXUP_IDENTITY;
804
805     /* before doing anything, record the sampler with the format in the format conversion list,
806      * but check if it's not there already */
807     for (i = 0; i < shader->baseShader.num_sampled_samplers; ++i)
808     {
809         if (shader->baseShader.sampled_samplers[i] == sampler_idx)
810         {
811             recorded = TRUE;
812             break;
813         }
814     }
815
816     if (!recorded)
817     {
818         shader->baseShader.sampled_samplers[shader->baseShader.num_sampled_samplers] = sampler_idx;
819         ++shader->baseShader.num_sampled_samplers;
820     }
821
822     device->shader_backend->shader_color_correction(arg, fixup);
823 }
824
825 /* Shared code in order to generate the bulk of the shader string.
826  * NOTE: A description of how to parse tokens can be found on msdn */
827 void shader_generate_main(IWineD3DBaseShader *iface, SHADER_BUFFER* buffer,
828         const shader_reg_maps* reg_maps, CONST DWORD* pFunction)
829 {
830     IWineD3DBaseShaderImpl* This = (IWineD3DBaseShaderImpl*) iface;
831     IWineD3DDeviceImpl *device = (IWineD3DDeviceImpl *) This->baseShader.device; /* To access shader backend callbacks */
832     const SHADER_OPCODE *opcode_table = This->baseShader.shader_ins;
833     const SHADER_HANDLER *handler_table = device->shader_backend->shader_instruction_handler_table;
834     DWORD shader_version = reg_maps->shader_version;
835     const DWORD *pToken = pFunction;
836     const SHADER_OPCODE *curOpcode;
837     SHADER_HANDLER hw_fct;
838     DWORD i;
839     SHADER_OPCODE_ARG hw_arg;
840
841     /* Initialize current parsing state */
842     hw_arg.shader = iface;
843     hw_arg.buffer = buffer;
844     hw_arg.reg_maps = reg_maps;
845     This->baseShader.parse_state.current_row = 0;
846
847     if (!pToken) return;
848
849     while (WINED3DPS_END() != *pToken)
850     {
851         /* Skip version token */
852         if (shader_is_version_token(*pToken))
853         {
854             ++pToken;
855             continue;
856         }
857
858         /* Skip comment tokens */
859         if (shader_is_comment(*pToken))
860         {
861             pToken += (*pToken & WINED3DSI_COMMENTSIZE_MASK) >> WINED3DSI_COMMENTSIZE_SHIFT;
862             ++pToken;
863             continue;
864         }
865
866         /* Read opcode */
867         hw_arg.opcode_token = *pToken++;
868         curOpcode = shader_get_opcode(opcode_table, shader_version, hw_arg.opcode_token);
869
870         /* Unknown opcode and its parameters */
871         if (!curOpcode)
872         {
873             FIXME("Unrecognized opcode: token=0x%08x\n", hw_arg.opcode_token);
874             pToken += shader_skip_unrecognized(pToken, shader_version);
875             continue;
876         }
877
878         /* Nothing to do */
879         if (WINED3DSIO_DCL == curOpcode->opcode
880                 || WINED3DSIO_NOP == curOpcode->opcode
881                 || WINED3DSIO_DEF == curOpcode->opcode
882                 || WINED3DSIO_DEFI == curOpcode->opcode
883                 || WINED3DSIO_DEFB == curOpcode->opcode
884                 || WINED3DSIO_PHASE == curOpcode->opcode
885                 || WINED3DSIO_RET == curOpcode->opcode)
886         {
887             pToken += shader_skip_opcode(curOpcode, hw_arg.opcode_token, shader_version);
888             continue;
889         }
890
891         /* Select handler */
892         hw_fct = handler_table[curOpcode->handler_idx];
893
894         /* Unhandled opcode */
895         if (!hw_fct)
896         {
897             FIXME("Can't handle opcode %s in hwShader\n", curOpcode->name);
898             pToken += shader_skip_opcode(curOpcode, hw_arg.opcode_token, shader_version);
899             continue;
900         }
901
902         hw_arg.opcode = curOpcode;
903
904         /* Destination token */
905         if (curOpcode->dst_token)
906         {
907             DWORD param, addr_token = 0;
908             pToken += shader_get_param(pToken, shader_version, &param, &addr_token);
909             hw_arg.dst = param;
910             hw_arg.dst_addr = addr_token;
911         }
912
913         /* Predication token */
914         if (hw_arg.opcode_token & WINED3DSHADER_INSTRUCTION_PREDICATED) hw_arg.predicate = *pToken++;
915
916         /* Other source tokens */
917         for (i = 0; i < (curOpcode->num_params - curOpcode->dst_token); ++i)
918         {
919             DWORD param, addr_token = 0;
920             pToken += shader_get_param(pToken, shader_version, &param, &addr_token);
921             hw_arg.src[i] = param;
922             hw_arg.src_addr[i] = addr_token;
923         }
924
925         /* Call appropriate function for output target */
926         hw_fct(&hw_arg);
927
928         /* Add color correction if needed */
929         shader_color_correction(This, device, &hw_arg, shader_version);
930
931         /* Process instruction modifiers for GLSL apps ( _sat, etc. ) */
932         /* FIXME: This should be internal to the shader backend.
933          * Also, right now this is the only reason "shader_mode" exists. */
934         if (This->baseShader.shader_mode == SHADER_GLSL) shader_glsl_add_instruction_modifiers(&hw_arg);
935     }
936 }
937
938 static void shader_dump_ins_modifiers(const DWORD output)
939 {
940     DWORD shift = (output & WINED3DSP_DSTSHIFT_MASK) >> WINED3DSP_DSTSHIFT_SHIFT;
941     DWORD mmask = output & WINED3DSP_DSTMOD_MASK;
942
943     switch (shift) {
944         case 0: break;
945         case 13: TRACE("_d8"); break;
946         case 14: TRACE("_d4"); break;
947         case 15: TRACE("_d2"); break;
948         case 1: TRACE("_x2"); break;
949         case 2: TRACE("_x4"); break;
950         case 3: TRACE("_x8"); break;
951         default: TRACE("_unhandled_shift(%d)", shift); break;
952     }
953
954     if (mmask & WINED3DSPDM_SATURATE)         TRACE("_sat");
955     if (mmask & WINED3DSPDM_PARTIALPRECISION) TRACE("_pp");
956     if (mmask & WINED3DSPDM_MSAMPCENTROID)    TRACE("_centroid");
957
958     mmask &= ~(WINED3DSPDM_SATURATE | WINED3DSPDM_PARTIALPRECISION | WINED3DSPDM_MSAMPCENTROID);
959     if (mmask)
960         FIXME("_unrecognized_modifier(%#x)", mmask >> WINED3DSP_DSTMOD_SHIFT);
961 }
962
963 void shader_trace_init(const DWORD *pFunction, const SHADER_OPCODE *opcode_table)
964 {
965     const DWORD* pToken = pFunction;
966     const SHADER_OPCODE* curOpcode = NULL;
967     DWORD shader_version;
968     DWORD opcode_token;
969     DWORD i;
970
971     TRACE("Parsing %p\n", pFunction);
972
973     if (!pFunction)
974     {
975         WARN("Got a NULL pFunction, returning.\n");
976         return;
977     }
978
979     /* The version token is supposed to be the first token */
980     if (!shader_is_version_token(*pToken))
981     {
982         FIXME("First token is not a version token, invalid shader.\n");
983         return;
984     }
985     shader_version = *pToken++;
986     TRACE("%s_%u_%u\n", shader_is_pshader_version(shader_version) ? "ps": "vs",
987             WINED3DSHADER_VERSION_MAJOR(shader_version), WINED3DSHADER_VERSION_MINOR(shader_version));
988
989     while (WINED3DVS_END() != *pToken)
990     {
991         if (shader_is_comment(*pToken)) /* comment */
992         {
993             DWORD comment_len = (*pToken & WINED3DSI_COMMENTSIZE_MASK) >> WINED3DSI_COMMENTSIZE_SHIFT;
994             ++pToken;
995             TRACE("//%s\n", (const char*)pToken);
996             pToken += comment_len;
997             continue;
998         }
999         opcode_token = *pToken++;
1000         curOpcode = shader_get_opcode(opcode_table, shader_version, opcode_token);
1001
1002         if (!curOpcode)
1003         {
1004             int tokens_read;
1005             FIXME("Unrecognized opcode: token=0x%08x\n", opcode_token);
1006             tokens_read = shader_skip_unrecognized(pToken, shader_version);
1007             pToken += tokens_read;
1008         }
1009         else
1010         {
1011             if (curOpcode->opcode == WINED3DSIO_DCL)
1012             {
1013                 DWORD usage = *pToken;
1014                 DWORD param = *(pToken + 1);
1015
1016                 shader_dump_decl_usage(usage, param, shader_version);
1017                 shader_dump_ins_modifiers(param);
1018                 TRACE(" ");
1019                 shader_dump_param(param, 0, 0, shader_version);
1020                 pToken += 2;
1021             }
1022             else if (curOpcode->opcode == WINED3DSIO_DEF)
1023             {
1024                 unsigned int offset = shader_get_float_offset(*pToken);
1025
1026                 TRACE("def c%u = %f, %f, %f, %f", offset,
1027                         *(const float *)(pToken + 1),
1028                         *(const float *)(pToken + 2),
1029                         *(const float *)(pToken + 3),
1030                         *(const float *)(pToken + 4));
1031                 pToken += 5;
1032             }
1033             else if (curOpcode->opcode == WINED3DSIO_DEFI)
1034             {
1035                 TRACE("defi i%u = %d, %d, %d, %d", *pToken & WINED3DSP_REGNUM_MASK,
1036                         *(pToken + 1),
1037                         *(pToken + 2),
1038                         *(pToken + 3),
1039                         *(pToken + 4));
1040                 pToken += 5;
1041             }
1042             else if (curOpcode->opcode == WINED3DSIO_DEFB)
1043             {
1044                 TRACE("defb b%u = %s", *pToken & WINED3DSP_REGNUM_MASK,
1045                         *(pToken + 1)? "true": "false");
1046                 pToken += 2;
1047             }
1048             else
1049             {
1050                 DWORD param, addr_token;
1051                 int tokens_read;
1052
1053                 /* Print out predication source token first - it follows
1054                  * the destination token. */
1055                 if (opcode_token & WINED3DSHADER_INSTRUCTION_PREDICATED)
1056                 {
1057                     TRACE("(");
1058                     shader_dump_param(*(pToken + 2), 0, 1, shader_version);
1059                     TRACE(") ");
1060                 }
1061                 if (opcode_token & WINED3DSI_COISSUE)
1062                 {
1063                     /* PixWin marks instructions with the coissue flag with a '+' */
1064                     TRACE("+");
1065                 }
1066
1067                 TRACE("%s", curOpcode->name);
1068
1069                 if (curOpcode->opcode == WINED3DSIO_IFC
1070                         || curOpcode->opcode == WINED3DSIO_BREAKC)
1071                 {
1072                     DWORD op = (opcode_token & INST_CONTROLS_MASK) >> INST_CONTROLS_SHIFT;
1073
1074                     switch (op)
1075                     {
1076                         case COMPARISON_GT: TRACE("_gt"); break;
1077                         case COMPARISON_EQ: TRACE("_eq"); break;
1078                         case COMPARISON_GE: TRACE("_ge"); break;
1079                         case COMPARISON_LT: TRACE("_lt"); break;
1080                         case COMPARISON_NE: TRACE("_ne"); break;
1081                         case COMPARISON_LE: TRACE("_le"); break;
1082                         default: TRACE("_(%u)", op);
1083                     }
1084                 }
1085                 else if (curOpcode->opcode == WINED3DSIO_TEX
1086                         && shader_version >= WINED3DPS_VERSION(2,0)
1087                         && (opcode_token & WINED3DSI_TEXLD_PROJECT))
1088                 {
1089                     TRACE("p");
1090                 }
1091
1092                 /* Destination token */
1093                 if (curOpcode->dst_token)
1094                 {
1095                     tokens_read = shader_get_param(pToken, shader_version, &param, &addr_token);
1096                     pToken += tokens_read;
1097
1098                     shader_dump_ins_modifiers(param);
1099                     TRACE(" ");
1100                     shader_dump_param(param, addr_token, 0, shader_version);
1101                 }
1102
1103                 /* Predication token - already printed out, just skip it */
1104                 if (opcode_token & WINED3DSHADER_INSTRUCTION_PREDICATED)
1105                 {
1106                     pToken++;
1107                 }
1108
1109                 /* Other source tokens */
1110                 for (i = curOpcode->dst_token; i < curOpcode->num_params; ++i)
1111                 {
1112                     tokens_read = shader_get_param(pToken, shader_version, &param, &addr_token);
1113                     pToken += tokens_read;
1114
1115                     TRACE((i == 0)? " " : ", ");
1116                     shader_dump_param(param, addr_token, 1, shader_version);
1117                 }
1118             }
1119             TRACE("\n");
1120         }
1121     }
1122 }
1123
1124 void shader_cleanup(IWineD3DBaseShader *iface)
1125 {
1126     IWineD3DBaseShaderImpl *This = (IWineD3DBaseShaderImpl *)iface;
1127
1128     ((IWineD3DDeviceImpl *)This->baseShader.device)->shader_backend->shader_destroy(iface);
1129     HeapFree(GetProcessHeap(), 0, This->baseShader.function);
1130     shader_delete_constant_list(&This->baseShader.constantsF);
1131     shader_delete_constant_list(&This->baseShader.constantsB);
1132     shader_delete_constant_list(&This->baseShader.constantsI);
1133     list_remove(&This->baseShader.shader_list_entry);
1134 }
1135
1136 static const SHADER_HANDLER shader_none_instruction_handler_table[WINED3DSIH_TABLE_SIZE] = {0};
1137 static void shader_none_select(IWineD3DDevice *iface, BOOL usePS, BOOL useVS) {}
1138 static void shader_none_select_depth_blt(IWineD3DDevice *iface, enum tex_types tex_type) {}
1139 static void shader_none_deselect_depth_blt(IWineD3DDevice *iface) {}
1140 static void shader_none_load_constants(IWineD3DDevice *iface, char usePS, char useVS) {}
1141 static void shader_none_cleanup(IWineD3DDevice *iface) {}
1142 static void shader_none_color_correction(const struct SHADER_OPCODE_ARG *arg, struct color_fixup_desc fixup) {}
1143 static void shader_none_destroy(IWineD3DBaseShader *iface) {}
1144 static HRESULT shader_none_alloc(IWineD3DDevice *iface) {return WINED3D_OK;}
1145 static void shader_none_free(IWineD3DDevice *iface) {}
1146 static BOOL shader_none_dirty_const(IWineD3DDevice *iface) {return FALSE;}
1147 static GLuint shader_none_generate_pshader(IWineD3DPixelShader *iface, SHADER_BUFFER *buffer) {
1148     FIXME("NONE shader backend asked to generate a pixel shader\n");
1149     return 0;
1150 }
1151 static void shader_none_generate_vshader(IWineD3DVertexShader *iface, SHADER_BUFFER *buffer) {
1152     FIXME("NONE shader backend asked to generate a vertex shader\n");
1153 }
1154
1155 #define GLINFO_LOCATION      (*gl_info)
1156 static void shader_none_get_caps(WINED3DDEVTYPE devtype, const WineD3D_GL_Info *gl_info, struct shader_caps *pCaps)
1157 {
1158     /* Set the shader caps to 0 for the none shader backend */
1159     pCaps->VertexShaderVersion  = 0;
1160     pCaps->PixelShaderVersion    = 0;
1161     pCaps->PixelShader1xMaxValue = 0.0;
1162 }
1163 #undef GLINFO_LOCATION
1164 static BOOL shader_none_color_fixup_supported(struct color_fixup_desc fixup)
1165 {
1166     if (TRACE_ON(d3d_shader) && TRACE_ON(d3d))
1167     {
1168         TRACE("Checking support for fixup:\n");
1169         dump_color_fixup_desc(fixup);
1170     }
1171
1172     /* Faked to make some apps happy. */
1173     if (!is_yuv_fixup(fixup))
1174     {
1175         TRACE("[OK]\n");
1176         return TRUE;
1177     }
1178
1179     TRACE("[FAILED]\n");
1180     return FALSE;
1181 }
1182
1183 const shader_backend_t none_shader_backend = {
1184     shader_none_instruction_handler_table,
1185     shader_none_select,
1186     shader_none_select_depth_blt,
1187     shader_none_deselect_depth_blt,
1188     shader_none_load_constants,
1189     shader_none_cleanup,
1190     shader_none_color_correction,
1191     shader_none_destroy,
1192     shader_none_alloc,
1193     shader_none_free,
1194     shader_none_dirty_const,
1195     shader_none_generate_pshader,
1196     shader_none_generate_vshader,
1197     shader_none_get_caps,
1198     shader_none_color_fixup_supported,
1199 };