mshtml: Call OnStopRequest in OnStopBinding.
[wine] / dlls / wined3d / baseshader.c
1 /*
2  * shaders implementation
3  *
4  * Copyright 2002-2003 Jason Edmeades
5  * Copyright 2002-2003 Raphael Junqueira
6  * Copyright 2005 Oliver Stieber
7  * Copyright 2006 Ivan Gyurdiev
8  *
9  * This library is free software; you can redistribute it and/or
10  * modify it under the terms of the GNU Lesser General Public
11  * License as published by the Free Software Foundation; either
12  * version 2.1 of the License, or (at your option) any later version.
13  *
14  * This library is distributed in the hope that it will be useful,
15  * but WITHOUT ANY WARRANTY; without even the implied warranty of
16  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
17  * Lesser General Public License for more details.
18  *
19  * You should have received a copy of the GNU Lesser General Public
20  * License along with this library; if not, write to the Free Software
21  * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
22  */
23
24 #include "config.h"
25 #include <string.h>
26 #include <stdio.h>
27 #include "wined3d_private.h"
28
29 WINE_DEFAULT_DEBUG_CHANNEL(d3d_shader);
30
31 #define GLNAME_REQUIRE_GLSL  ((const char *)1)
32
33 inline static BOOL shader_is_version_token(DWORD token) {
34     return shader_is_pshader_version(token) ||
35            shader_is_vshader_version(token);
36 }
37
38 int shader_addline(
39     SHADER_BUFFER* buffer,  
40     const char *format, ...) {
41
42     char* base = buffer->buffer + buffer->bsize;
43     int rc;
44
45     va_list args;
46     va_start(args, format);
47     rc = vsnprintf(base, SHADER_PGMSIZE - 1 - buffer->bsize, format, args);
48     va_end(args);
49
50     if (rc < 0 ||                                   /* C89 */ 
51         rc > SHADER_PGMSIZE - 1 - buffer->bsize) {  /* C99 */
52
53         ERR("The buffer allocated for the shader program string "
54             "is too small at %d bytes.\n", SHADER_PGMSIZE);
55         buffer->bsize = SHADER_PGMSIZE - 1;
56         return -1;
57     }
58
59     buffer->bsize += rc;
60     buffer->lineNo++;
61     TRACE("GL HW (%u, %u) : %s", buffer->lineNo, buffer->bsize, base); 
62     return 0;
63 }
64
65 const SHADER_OPCODE* shader_get_opcode(
66     IWineD3DBaseShader *iface, const DWORD code) {
67
68     IWineD3DBaseShaderImpl *This = (IWineD3DBaseShaderImpl*) iface;
69
70     DWORD i = 0;
71     DWORD hex_version = This->baseShader.hex_version;
72     const SHADER_OPCODE *shader_ins = This->baseShader.shader_ins;
73
74     /** TODO: use dichotomic search */
75     while (NULL != shader_ins[i].name) {
76         if (((code & D3DSI_OPCODE_MASK) == shader_ins[i].opcode) &&
77             (((hex_version >= shader_ins[i].min_version) && (hex_version <= shader_ins[i].max_version)) ||
78             ((shader_ins[i].min_version == 0) && (shader_ins[i].max_version == 0)))) {
79             return &shader_ins[i];
80         }
81         ++i;
82     }
83     FIXME("Unsupported opcode %#lx(%ld) masked %#lx, shader version %#lx\n", 
84        code, code, code & D3DSI_OPCODE_MASK, hex_version);
85     return NULL;
86 }
87
88 /* Read a parameter opcode from the input stream,
89  * and possibly a relative addressing token.
90  * Return the number of tokens read */
91 int shader_get_param(
92     IWineD3DBaseShader* iface,
93     const DWORD* pToken,
94     DWORD* param,
95     DWORD* addr_token) {
96
97     /* PS >= 3.0 have relative addressing (with token)
98      * VS >= 2.0 have relative addressing (with token)
99      * VS >= 1.0 < 2.0 have relative addressing (without token)
100      * The version check below should work in general */
101
102     IWineD3DBaseShaderImpl* This = (IWineD3DBaseShaderImpl*) iface;
103     char rel_token = D3DSHADER_VERSION_MAJOR(This->baseShader.hex_version) >= 2 &&
104         ((*pToken & D3DSHADER_ADDRESSMODE_MASK) == D3DSHADER_ADDRMODE_RELATIVE);
105
106     *param = *pToken;
107     *addr_token = rel_token? *(pToken + 1): 0;
108     return rel_token? 2:1;
109 }
110
111 /* Return the number of parameters to skip for an opcode */
112 static inline int shader_skip_opcode(
113     IWineD3DBaseShaderImpl* This,
114     const SHADER_OPCODE* curOpcode,
115     DWORD opcode_token) {
116
117    /* Shaders >= 2.0 may contain address tokens, but fortunately they
118     * have a useful legnth mask - use it here. Shaders 1.0 contain no such tokens */
119
120     return (D3DSHADER_VERSION_MAJOR(This->baseShader.hex_version) >= 2)?
121         ((opcode_token & D3DSI_INSTLENGTH_MASK) >> D3DSI_INSTLENGTH_SHIFT):
122         curOpcode->num_params;
123 }
124
125 /* Read the parameters of an unrecognized opcode from the input stream
126  * Return the number of tokens read. 
127  * 
128  * Note: This function assumes source or destination token format.
129  * It will not work with specially-formatted tokens like DEF or DCL, 
130  * but hopefully those would be recognized */
131
132 int shader_skip_unrecognized(
133     IWineD3DBaseShader* iface,
134     const DWORD* pToken) {
135
136     int tokens_read = 0;
137     int i = 0;
138
139     /* TODO: Think of a good name for 0x80000000 and replace it with a constant */
140     while (*pToken & 0x80000000) {
141
142         DWORD param, addr_token;
143         tokens_read += shader_get_param(iface, pToken, &param, &addr_token);
144         pToken += tokens_read;
145
146         FIXME("Unrecognized opcode param: token=%08lX "
147             "addr_token=%08lX name=", param, addr_token);
148         shader_dump_param(iface, param, addr_token, i);
149         FIXME("\n");
150         ++i;
151     }
152     return tokens_read;
153 }
154
155 /* Convert floating point offset relative
156  * to a register file to an absolute offset for float constants */
157
158 unsigned int shader_get_float_offset(const DWORD reg) {
159
160      unsigned int regnum = reg & D3DSP_REGNUM_MASK;
161      int regtype = shader_get_regtype(reg);
162
163      switch (regtype) {
164         case D3DSPR_CONST: return regnum;
165         case D3DSPR_CONST2: return 2048 + regnum;
166         case D3DSPR_CONST3: return 4096 + regnum;
167         case D3DSPR_CONST4: return 6144 + regnum;
168         default:
169             FIXME("Unsupported register type: %d\n", regtype);
170             return regnum;
171      }
172 }
173
174 static void shader_parse_decl_usage(
175     DWORD *semantics_map,
176     DWORD usage_token, DWORD param) {
177
178     unsigned int usage = (usage_token & D3DSP_DCL_USAGE_MASK) >> D3DSP_DCL_USAGE_SHIFT;
179     unsigned int usage_idx = (usage_token & D3DSP_DCL_USAGEINDEX_MASK) >> D3DSP_DCL_USAGEINDEX_SHIFT;
180     unsigned int regnum = param & D3DSP_REGNUM_MASK;
181
182     switch(usage) {
183         case D3DDECLUSAGE_POSITION:
184             if (usage_idx == 0) { /* tween data */
185                 TRACE("Setting position to %d\n", regnum);
186                 semantics_map[WINED3DSHADERDECLUSAGE_POSITION] = param;
187             } else {
188                 /* TODO: position indexes go from 0-8!!*/
189                 TRACE("Setting position 2 to %d because usage_idx = %d\n", regnum, usage_idx);
190                 /* robots uses positions up to 8, the position arrays are just packed.*/
191                 if (usage_idx > 1) {
192                     TRACE("Loaded for position %d (greater than 2)\n", usage_idx);
193                 }
194                 semantics_map[WINED3DSHADERDECLUSAGE_POSITION2 + usage_idx-1] = param;
195             }
196             break;
197
198         case D3DDECLUSAGE_BLENDINDICES:
199             TRACE("Setting BLENDINDICES to %d\n", regnum);
200             semantics_map[WINED3DSHADERDECLUSAGE_BLENDINDICES] = param;
201             if (usage_idx != 0) FIXME("Extended BLENDINDICES\n");
202             break;
203
204         case D3DDECLUSAGE_BLENDWEIGHT:
205             TRACE("Setting BLENDWEIGHT to %d\n", regnum);
206             semantics_map[WINED3DSHADERDECLUSAGE_BLENDWEIGHT] = param;
207             if (usage_idx != 0) FIXME("Extended blend weights\n");
208             break;
209
210         case D3DDECLUSAGE_NORMAL:
211             if (usage_idx == 0) { /* tween data */
212                 TRACE("Setting normal to %d\n", regnum);
213                 semantics_map[WINED3DSHADERDECLUSAGE_NORMAL] = param;
214             } else {
215                 TRACE("Setting normal 2 to %d because usage = %d\n", regnum, usage_idx);
216                 semantics_map[WINED3DSHADERDECLUSAGE_NORMAL2] = param;
217             }
218             break;
219
220         case D3DDECLUSAGE_PSIZE:
221             TRACE("Setting PSIZE to %d\n", regnum);
222             semantics_map[WINED3DSHADERDECLUSAGE_PSIZE] = param;
223             if (usage_idx != 0) FIXME("Extended PSIZE\n");
224             break;
225
226         case D3DDECLUSAGE_COLOR:
227             if (usage_idx == 0)  {
228                 TRACE("Setting DIFFUSE to %d\n", regnum);
229                 semantics_map[WINED3DSHADERDECLUSAGE_DIFFUSE] = param;
230             } else {
231                 TRACE("Setting SPECULAR to %d\n", regnum);
232                 semantics_map[WINED3DSHADERDECLUSAGE_SPECULAR] = param;
233             }
234             break;
235
236         case D3DDECLUSAGE_TEXCOORD:
237             if (usage_idx > 7) {
238                 FIXME("Program uses texture coordinate %d but only 0-7 have been "
239                     "implemented\n", usage_idx);
240             } else {
241                 TRACE("Setting TEXCOORD %d  to %d\n", usage_idx, regnum);
242                 semantics_map[WINED3DSHADERDECLUSAGE_TEXCOORD0 + usage_idx] = param;
243             }
244             break;
245
246         case D3DDECLUSAGE_TANGENT:
247             TRACE("Setting TANGENT to %d\n", regnum);
248             semantics_map[WINED3DSHADERDECLUSAGE_TANGENT] = param;
249             break;
250
251         case D3DDECLUSAGE_BINORMAL:
252             TRACE("Setting BINORMAL to %d\n", regnum);
253             semantics_map[WINED3DSHADERDECLUSAGE_BINORMAL] = param;
254             break;
255
256         case D3DDECLUSAGE_TESSFACTOR:
257             TRACE("Setting TESSFACTOR to %d\n", regnum);
258             semantics_map[WINED3DSHADERDECLUSAGE_TESSFACTOR] = param;
259             break;
260
261         case D3DDECLUSAGE_POSITIONT:
262             if (usage_idx == 0) { /* tween data */
263                 FIXME("Setting positiont to %d\n", regnum);
264                 semantics_map[WINED3DSHADERDECLUSAGE_POSITIONT] = param;
265             } else {
266                 FIXME("Setting positiont 2 to %d because usage = %d\n", regnum, usage_idx);
267                 semantics_map[WINED3DSHADERDECLUSAGE_POSITIONT2] = param;
268                 if (usage_idx != 0) FIXME("Extended positiont\n");
269             }
270             break;
271
272         case D3DDECLUSAGE_FOG:
273             TRACE("Setting FOG to %d\n", regnum);
274             semantics_map[WINED3DSHADERDECLUSAGE_FOG] = param;
275             break;
276
277         case D3DDECLUSAGE_DEPTH:
278             TRACE("Setting DEPTH to %d\n", regnum);
279             semantics_map[WINED3DSHADERDECLUSAGE_DEPTH] = param;
280             break;
281
282         case D3DDECLUSAGE_SAMPLE:
283             TRACE("Setting SAMPLE to %d\n", regnum);
284             semantics_map[WINED3DSHADERDECLUSAGE_SAMPLE] = param;
285             break;
286
287         default:
288             FIXME("Unrecognised dcl %#x", usage);
289     }
290 }
291
292 /* Note that this does not count the loop register
293  * as an address register. */
294
295 void shader_get_registers_used(
296     IWineD3DBaseShader *iface,
297     shader_reg_maps* reg_maps,
298     CONST DWORD* pToken) {
299
300     IWineD3DBaseShaderImpl* This = (IWineD3DBaseShaderImpl*) iface;
301
302     /* There are some minor differences between pixel and vertex shaders */
303     char pshader = shader_is_pshader_version(This->baseShader.hex_version);
304
305     if (pToken == NULL)
306         return;
307
308     while (D3DVS_END() != *pToken) {
309         CONST SHADER_OPCODE* curOpcode;
310         DWORD opcode_token;
311
312         /* Skip version */
313         if (shader_is_version_token(*pToken)) {
314              ++pToken;
315              continue;
316
317         /* Skip comments */
318         } else if (shader_is_comment(*pToken)) {
319              DWORD comment_len = (*pToken & D3DSI_COMMENTSIZE_MASK) >> D3DSI_COMMENTSIZE_SHIFT;
320              ++pToken;
321              pToken += comment_len;
322              continue;
323         }
324
325         /* Fetch opcode */
326         opcode_token = *pToken++;
327         curOpcode = shader_get_opcode(iface, opcode_token);
328
329         /* Unhandled opcode, and its parameters */
330         if (NULL == curOpcode) {
331            while (*pToken & 0x80000000)
332                ++pToken;
333
334         /* Handle declarations */
335         } else if (D3DSIO_DCL == curOpcode->opcode) {
336
337             DWORD usage = *pToken++;
338             DWORD param = *pToken++;
339             DWORD regtype = shader_get_regtype(param);
340             unsigned int regnum = param & D3DSP_REGNUM_MASK;
341
342             /* Vshader: mark attributes used
343                Pshader: mark 3.0 input registers used, save token */
344             if (D3DSPR_INPUT == regtype) {
345
346                 if (!pshader)
347                     reg_maps->attributes[regnum] = 1;
348                 else
349                     reg_maps->packed_input[regnum] = 1;
350
351                 shader_parse_decl_usage(reg_maps->semantics_in, usage, param);
352
353             /* Vshader: mark 3.0 output registers used, save token */
354             } else if (D3DSPR_OUTPUT == regtype) {
355                 reg_maps->packed_output[regnum] = 1;
356                 shader_parse_decl_usage(reg_maps->semantics_out, usage, param);
357
358             /* Save sampler usage token */
359             } else if (D3DSPR_SAMPLER == regtype)
360                 reg_maps->samplers[regnum] = usage;
361
362         /* Skip definitions (for now) */
363         } else if (D3DSIO_DEF == curOpcode->opcode) {
364             pToken += curOpcode->num_params;
365
366         /* If there's a loop in the shader */
367         } else if (D3DSIO_LOOP == curOpcode->opcode) {
368             reg_maps->loop = 1;
369             pToken += curOpcode->num_params;
370         
371         /* Set texture, address, temporary registers */
372         } else {
373             int i, limit;
374
375             /* Declare 1.X samplers implicitly, based on the destination reg. number */
376             if (D3DSHADER_VERSION_MAJOR(This->baseShader.hex_version) == 1 && 
377                 (D3DSIO_TEX == curOpcode->opcode ||
378                  D3DSIO_TEXM3x2TEX == curOpcode->opcode ||
379                  D3DSIO_TEXM3x3TEX == curOpcode->opcode ||
380                  D3DSIO_TEXM3x3SPEC == curOpcode->opcode ||
381                  D3DSIO_TEXM3x3VSPEC == curOpcode->opcode)) {
382
383                 /* Fake sampler usage, only set reserved bit and ttype */
384                 DWORD sampler_code = *pToken & D3DSP_REGNUM_MASK;
385                 reg_maps->samplers[sampler_code] = (0x1 << 31) | D3DSTT_2D;
386             }
387
388             /* This will loop over all the registers and try to
389              * make a bitmask of the ones we're interested in. 
390              *
391              * Relative addressing tokens are ignored, but that's 
392              * okay, since we'll catch any address registers when 
393              * they are initialized (required by spec) */
394
395             limit = (opcode_token & D3DSHADER_INSTRUCTION_PREDICATED)?
396                 curOpcode->num_params + 1: curOpcode->num_params;
397
398             for (i = 0; i < limit; ++i) {
399
400                 DWORD param, addr_token, reg, regtype;
401                 pToken += shader_get_param(iface, pToken, &param, &addr_token);
402
403                 regtype = (param & D3DSP_REGTYPE_MASK) >> D3DSP_REGTYPE_SHIFT;
404                 reg = param & D3DSP_REGNUM_MASK;
405
406                 if (D3DSPR_TEXTURE == regtype) { /* vs: D3DSPR_ADDR */
407
408                     if (pshader)
409                         reg_maps->texcoord[reg] = 1;
410                     else
411                         reg_maps->address[reg] = 1;
412                 }
413
414                 else if (D3DSPR_TEMP == regtype)
415                     reg_maps->temporary[reg] = 1;
416
417                 else if (D3DSPR_INPUT == regtype && !pshader)
418                     reg_maps->attributes[reg] = 1;
419              }
420         }
421     }
422 }
423
424 static void shader_dump_decl_usage(
425     DWORD decl, 
426     DWORD param) {
427
428     DWORD regtype = shader_get_regtype(param);
429     TRACE("dcl_");
430
431     if (regtype == D3DSPR_SAMPLER) {
432         DWORD ttype = decl & D3DSP_TEXTURETYPE_MASK;
433
434         switch (ttype) {
435             case D3DSTT_2D: TRACE("2d"); break;
436             case D3DSTT_CUBE: TRACE("cube"); break;
437             case D3DSTT_VOLUME: TRACE("volume"); break;
438             default: TRACE("unknown_ttype(%08lx)", ttype); 
439        }
440
441     } else { 
442
443         DWORD usage = decl & D3DSP_DCL_USAGE_MASK;
444         DWORD idx = (decl & D3DSP_DCL_USAGEINDEX_MASK) >> D3DSP_DCL_USAGEINDEX_SHIFT;
445
446         switch(usage) {
447         case D3DDECLUSAGE_POSITION:
448             TRACE("%s%ld", "position", idx);
449             break;
450         case D3DDECLUSAGE_BLENDINDICES:
451             TRACE("%s", "blend");
452             break;
453         case D3DDECLUSAGE_BLENDWEIGHT:
454             TRACE("%s", "weight");
455             break;
456         case D3DDECLUSAGE_NORMAL:
457             TRACE("%s%ld", "normal", idx);
458             break;
459         case D3DDECLUSAGE_PSIZE:
460             TRACE("%s", "psize");
461             break;
462         case D3DDECLUSAGE_COLOR:
463             if(idx == 0)  {
464                 TRACE("%s", "color");
465             } else {
466                 TRACE("%s%ld", "specular", (idx - 1));
467             }
468             break;
469         case D3DDECLUSAGE_TEXCOORD:
470             TRACE("%s%ld", "texture", idx);
471             break;
472         case D3DDECLUSAGE_TANGENT:
473             TRACE("%s", "tangent");
474             break;
475         case D3DDECLUSAGE_BINORMAL:
476             TRACE("%s", "binormal");
477             break;
478         case D3DDECLUSAGE_TESSFACTOR:
479             TRACE("%s", "tessfactor");
480             break;
481         case D3DDECLUSAGE_POSITIONT:
482             TRACE("%s%ld", "positionT", idx);
483             break;
484         case D3DDECLUSAGE_FOG:
485             TRACE("%s", "fog");
486             break;
487         case D3DDECLUSAGE_DEPTH:
488             TRACE("%s", "depth");
489             break;
490         case D3DDECLUSAGE_SAMPLE:
491             TRACE("%s", "sample");
492             break;
493         default:
494             FIXME("unknown_semantics(%08lx)", usage);
495         }
496     }
497 }
498
499 static void shader_dump_arr_entry(
500     IWineD3DBaseShader *iface,
501     const DWORD param,
502     const DWORD addr_token,
503     unsigned int reg,
504     int input) {
505
506     char relative =
507         ((param & D3DSHADER_ADDRESSMODE_MASK) == D3DSHADER_ADDRMODE_RELATIVE);
508
509     if (relative) {
510         TRACE("[");
511         if (addr_token)
512             shader_dump_param(iface, addr_token, 0, input);
513         else
514             TRACE("a0.x");
515         TRACE(" + ");
516      }
517      TRACE("%u", reg);
518      if (relative)
519          TRACE("]");
520 }
521
522 void shader_dump_param(
523     IWineD3DBaseShader *iface,
524     const DWORD param, 
525     const DWORD addr_token,
526     int input) {
527
528     IWineD3DBaseShaderImpl* This = (IWineD3DBaseShaderImpl*) iface;
529     static const char* rastout_reg_names[] = { "oPos", "oFog", "oPts" };
530     char swizzle_reg_chars[4];
531
532     DWORD reg = param & D3DSP_REGNUM_MASK;
533     DWORD regtype = shader_get_regtype(param);
534
535     /* There are some minor differences between pixel and vertex shaders */
536     char pshader = shader_is_pshader_version(This->baseShader.hex_version);
537
538     /* For one, we'd prefer color components to be shown for pshaders.
539      * FIXME: use the swizzle function for this */
540
541     swizzle_reg_chars[0] = pshader? 'r': 'x';
542     swizzle_reg_chars[1] = pshader? 'g': 'y';
543     swizzle_reg_chars[2] = pshader? 'b': 'z';
544     swizzle_reg_chars[3] = pshader? 'a': 'w';
545
546     if (input) {
547         if ( ((param & D3DSP_SRCMOD_MASK) == D3DSPSM_NEG) ||
548              ((param & D3DSP_SRCMOD_MASK) == D3DSPSM_BIASNEG) ||
549              ((param & D3DSP_SRCMOD_MASK) == D3DSPSM_SIGNNEG) ||
550              ((param & D3DSP_SRCMOD_MASK) == D3DSPSM_X2NEG) )
551             TRACE("-");
552         else if ((param & D3DSP_SRCMOD_MASK) == D3DSPSM_COMP)
553             TRACE("1-");
554         else if ((param & D3DSP_SRCMOD_MASK) == D3DSPSM_NOT)
555             TRACE("!");
556     }
557
558     switch (regtype) {
559         case D3DSPR_TEMP:
560             TRACE("r%lu", reg);
561             break;
562         case D3DSPR_INPUT:
563             TRACE("v");
564             shader_dump_arr_entry(iface, param, addr_token, reg, input);
565             break;
566         case D3DSPR_CONST:
567         case D3DSPR_CONST2:
568         case D3DSPR_CONST3:
569         case D3DSPR_CONST4:
570             TRACE("c");
571             shader_dump_arr_entry(iface, param, addr_token, shader_get_float_offset(param), input);
572             break;
573         case D3DSPR_TEXTURE: /* vs: case D3DSPR_ADDR */
574             TRACE("%c%lu", (pshader? 't':'a'), reg);
575             break;        
576         case D3DSPR_RASTOUT:
577             TRACE("%s", rastout_reg_names[reg]);
578             break;
579         case D3DSPR_COLOROUT:
580             TRACE("oC%lu", reg);
581             break;
582         case D3DSPR_DEPTHOUT:
583             TRACE("oDepth");
584             break;
585         case D3DSPR_ATTROUT:
586             TRACE("oD%lu", reg);
587             break;
588         case D3DSPR_TEXCRDOUT: 
589
590             /* Vertex shaders >= 3.0 use general purpose output registers
591              * (D3DSPR_OUTPUT), which can include an address token */
592
593             if (D3DSHADER_VERSION_MAJOR(This->baseShader.hex_version) >= 3) {
594                 TRACE("o");
595                 shader_dump_arr_entry(iface, param, addr_token, reg, input);
596             }
597             else 
598                TRACE("oT%lu", reg);
599             break;
600         case D3DSPR_CONSTINT:
601             TRACE("i");
602             shader_dump_arr_entry(iface, param, addr_token, reg, input);
603             break;
604         case D3DSPR_CONSTBOOL:
605             TRACE("b");
606             shader_dump_arr_entry(iface, param, addr_token, reg, input);
607             break;
608         case D3DSPR_LABEL:
609             TRACE("l%lu", reg);
610             break;
611         case D3DSPR_LOOP:
612             TRACE("aL");
613             break;
614         case D3DSPR_SAMPLER:
615             TRACE("s%lu", reg);
616             break;
617         case D3DSPR_PREDICATE:
618             TRACE("p%lu", reg);
619             break;
620         default:
621             TRACE("unhandled_rtype(%#lx)", regtype);
622             break;
623    }
624
625    if (!input) {
626        /* operand output (for modifiers and shift, see dump_ins_modifiers) */
627
628        if ((param & D3DSP_WRITEMASK_ALL) != D3DSP_WRITEMASK_ALL) {
629            TRACE(".");
630            if (param & D3DSP_WRITEMASK_0) TRACE("%c", swizzle_reg_chars[0]);
631            if (param & D3DSP_WRITEMASK_1) TRACE("%c", swizzle_reg_chars[1]);
632            if (param & D3DSP_WRITEMASK_2) TRACE("%c", swizzle_reg_chars[2]);
633            if (param & D3DSP_WRITEMASK_3) TRACE("%c", swizzle_reg_chars[3]);
634        }
635
636    } else {
637         /** operand input */
638         DWORD swizzle = (param & D3DSP_SWIZZLE_MASK) >> D3DSP_SWIZZLE_SHIFT;
639         DWORD swizzle_r = swizzle & 0x03;
640         DWORD swizzle_g = (swizzle >> 2) & 0x03;
641         DWORD swizzle_b = (swizzle >> 4) & 0x03;
642         DWORD swizzle_a = (swizzle >> 6) & 0x03;
643
644         if (0 != (param & D3DSP_SRCMOD_MASK)) {
645             DWORD mask = param & D3DSP_SRCMOD_MASK;
646             switch (mask) {
647                 case D3DSPSM_NONE:    break;
648                 case D3DSPSM_NEG:     break;
649                 case D3DSPSM_NOT:     break;
650                 case D3DSPSM_BIAS:    TRACE("_bias"); break;
651                 case D3DSPSM_BIASNEG: TRACE("_bias"); break;
652                 case D3DSPSM_SIGN:    TRACE("_bx2"); break;
653                 case D3DSPSM_SIGNNEG: TRACE("_bx2"); break;
654                 case D3DSPSM_COMP:    break;
655                 case D3DSPSM_X2:      TRACE("_x2"); break;
656                 case D3DSPSM_X2NEG:   TRACE("_x2"); break;
657                 case D3DSPSM_DZ:      TRACE("_dz"); break;
658                 case D3DSPSM_DW:      TRACE("_dw"); break;
659                 default:
660                     TRACE("_unknown_modifier(%#lx)", mask >> D3DSP_SRCMOD_SHIFT);
661             }
662         }
663
664         /**
665         * swizzle bits fields:
666         *  RRGGBBAA
667         */
668         if ((D3DVS_NOSWIZZLE >> D3DVS_SWIZZLE_SHIFT) != swizzle) { /* ! D3DVS_NOSWIZZLE == 0xE4 << D3DVS_SWIZZLE_SHIFT */
669             if (swizzle_r == swizzle_g &&
670                 swizzle_r == swizzle_b &&
671                 swizzle_r == swizzle_a) {
672                     TRACE(".%c", swizzle_reg_chars[swizzle_r]);
673             } else {
674                 TRACE(".%c%c%c%c",
675                 swizzle_reg_chars[swizzle_r],
676                 swizzle_reg_chars[swizzle_g],
677                 swizzle_reg_chars[swizzle_b],
678                 swizzle_reg_chars[swizzle_a]);
679             }
680         }
681     }
682 }
683
684 /** Shared code in order to generate the bulk of the shader string.
685     Use the shader_header_fct & shader_footer_fct to add strings
686     that are specific to pixel or vertex functions
687     NOTE: A description of how to parse tokens can be found at:
688           http://msdn.microsoft.com/library/default.asp?url=/library/en-us/graphics/hh/graphics/usermodedisplaydriver_shader_cc8e4e05-f5c3-4ec0-8853-8ce07c1551b2.xml.asp */
689 void shader_generate_main(
690     IWineD3DBaseShader *iface,
691     SHADER_BUFFER* buffer,
692     shader_reg_maps* reg_maps,
693     CONST DWORD* pFunction) {
694
695     IWineD3DBaseShaderImpl* This = (IWineD3DBaseShaderImpl*) iface;
696     const DWORD *pToken = pFunction;
697     const SHADER_OPCODE *curOpcode = NULL;
698     SHADER_HANDLER hw_fct = NULL;
699     DWORD opcode_token;
700     DWORD i;
701     SHADER_OPCODE_ARG hw_arg;
702
703     /* Initialize current parsing state */
704     hw_arg.shader = iface;
705     hw_arg.buffer = buffer;
706     hw_arg.reg_maps = reg_maps;
707     This->baseShader.parse_state.current_row = 0;
708
709     /* Second pass, process opcodes */
710     if (NULL != pToken) {
711         while (D3DPS_END() != *pToken) {
712
713             /* Skip version token */
714             if (shader_is_version_token(*pToken)) {
715                 ++pToken;
716                 continue;
717             }
718
719             /* Skip comment tokens */
720             if (shader_is_comment(*pToken)) {
721                 DWORD comment_len = (*pToken & D3DSI_COMMENTSIZE_MASK) >> D3DSI_COMMENTSIZE_SHIFT;
722                 ++pToken;
723                 TRACE("#%s\n", (char*)pToken);
724                 pToken += comment_len;
725                 continue;
726             }
727
728             /* Read opcode */
729             opcode_token = *pToken++;
730             curOpcode = shader_get_opcode(iface, opcode_token);
731             hw_fct = (curOpcode == NULL)? NULL:
732                      (wined3d_settings.shader_mode == SHADER_GLSL)?
733                          curOpcode->hw_glsl_fct : curOpcode->hw_fct;
734
735             /* Unknown opcode and its parameters */
736             if (NULL == curOpcode) {
737                 FIXME("Unrecognized opcode: token=%08lX\n", opcode_token);
738                 pToken += shader_skip_unrecognized(iface, pToken); 
739
740             /* Nothing to do */
741             } else if (D3DSIO_DCL == curOpcode->opcode ||
742                        D3DSIO_NOP == curOpcode->opcode) {
743
744                 pToken += shader_skip_opcode(This, curOpcode, opcode_token);
745
746             /* If a generator function is set for current shader target, use it */
747             } else if (hw_fct != NULL) {
748
749                 hw_arg.opcode = curOpcode;
750
751                 /* Destination token */
752                 if (curOpcode->dst_token) {
753
754                     DWORD param, addr_token = 0;
755                     pToken += shader_get_param(iface, pToken, &param, &addr_token);
756                     hw_arg.dst = param;
757                     hw_arg.dst_addr = addr_token;
758                 }
759
760                 /* Predication token */
761                 if (opcode_token & D3DSHADER_INSTRUCTION_PREDICATED) 
762                     hw_arg.predicate = *pToken++;
763
764                 /* Other source tokens */
765                 for (i = curOpcode->dst_token; i < curOpcode->num_params; i++) {
766
767                     DWORD param, addr_token = 0; 
768
769                     /* DEF* instructions have constant src parameters, not registers */
770                     if (curOpcode->opcode == D3DSIO_DEF || 
771                         curOpcode->opcode == D3DSIO_DEFI || 
772                         curOpcode->opcode == D3DSIO_DEFB) {
773                         param = *pToken++;
774
775                     } else
776                         pToken += shader_get_param(iface, pToken, &param, &addr_token);
777
778                     hw_arg.src[i-1] = param;
779                     hw_arg.src_addr[i-1] = addr_token;
780                 }
781
782                 /* Call appropriate function for output target */
783                 hw_fct(&hw_arg);
784
785                 /* Process instruction modifiers for GLSL apps ( _sat, etc. ) */
786                 if (wined3d_settings.shader_mode == SHADER_GLSL)
787                     shader_glsl_add_instruction_modifiers(&hw_arg);
788
789             /* Unhandled opcode */
790             } else {
791
792                 FIXME("Can't handle opcode %s in hwShader\n", curOpcode->name);
793                 pToken += shader_skip_opcode(This, curOpcode, opcode_token);
794             }
795         }
796         /* TODO: What about result.depth? */
797
798     }
799 }
800
801 void shader_dump_ins_modifiers(const DWORD output) {
802
803     DWORD shift = (output & D3DSP_DSTSHIFT_MASK) >> D3DSP_DSTSHIFT_SHIFT;
804     DWORD mmask = output & D3DSP_DSTMOD_MASK;
805
806     switch (shift) {
807         case 0: break;
808         case 13: TRACE("_d8"); break;
809         case 14: TRACE("_d4"); break;
810         case 15: TRACE("_d2"); break;
811         case 1: TRACE("_x2"); break;
812         case 2: TRACE("_x4"); break;
813         case 3: TRACE("_x8"); break;
814         default: TRACE("_unhandled_shift(%ld)", shift); break;
815     }
816
817     if (mmask & D3DSPDM_SATURATE)         TRACE("_sat");
818     if (mmask & D3DSPDM_PARTIALPRECISION) TRACE("_pp");
819     if (mmask & D3DSPDM_MSAMPCENTROID)    TRACE("_centroid");
820
821     mmask &= ~(D3DSPDM_SATURATE | D3DSPDM_PARTIALPRECISION | D3DSPDM_MSAMPCENTROID);
822     if (mmask)
823         FIXME("_unrecognized_modifier(%#lx)", mmask >> D3DSP_DSTMOD_SHIFT);
824 }
825
826 /* First pass: trace shader, initialize length and version */
827 void shader_trace_init(
828     IWineD3DBaseShader *iface,
829     const DWORD* pFunction) {
830
831     IWineD3DBaseShaderImpl *This =(IWineD3DBaseShaderImpl *)iface;
832
833     const DWORD* pToken = pFunction;
834     const SHADER_OPCODE* curOpcode = NULL;
835     DWORD opcode_token;
836     unsigned int len = 0;
837     DWORD i;
838
839     TRACE("(%p) : Parsing programme\n", This);
840
841     if (NULL != pToken) {
842         while (D3DVS_END() != *pToken) {
843             if (shader_is_version_token(*pToken)) { /** version */
844                 This->baseShader.hex_version = *pToken;
845                 TRACE("%s_%lu_%lu\n", shader_is_pshader_version(This->baseShader.hex_version)? "ps": "vs",
846                     D3DSHADER_VERSION_MAJOR(This->baseShader.hex_version),
847                     D3DSHADER_VERSION_MINOR(This->baseShader.hex_version));
848                 ++pToken;
849                 ++len;
850                 continue;
851             }
852             if (shader_is_comment(*pToken)) { /** comment */
853                 DWORD comment_len = (*pToken & D3DSI_COMMENTSIZE_MASK) >> D3DSI_COMMENTSIZE_SHIFT;
854                 ++pToken;
855                 TRACE("//%s\n", (char*)pToken);
856                 pToken += comment_len;
857                 len += comment_len + 1;
858                 continue;
859             }
860             opcode_token = *pToken++;
861             curOpcode = shader_get_opcode(iface, opcode_token);
862             len++;
863
864             if (NULL == curOpcode) {
865                 int tokens_read;
866                 FIXME("Unrecognized opcode: token=%08lX\n", opcode_token);
867                 tokens_read = shader_skip_unrecognized(iface, pToken);
868                 pToken += tokens_read;
869                 len += tokens_read;
870
871             } else {
872                 if (curOpcode->opcode == D3DSIO_DCL) {
873
874                     DWORD usage = *pToken;
875                     DWORD param = *(pToken + 1);
876
877                     shader_dump_decl_usage(usage, param);
878                     shader_dump_ins_modifiers(param);
879                     TRACE(" ");
880                     shader_dump_param(iface, param, 0, 0);
881                     pToken += 2;
882                     len += 2;
883
884                 } else if (curOpcode->opcode == D3DSIO_DEF) {
885
886                         unsigned int offset = shader_get_float_offset(*pToken);
887
888                         TRACE("def c%u = %f, %f, %f, %f", offset,
889                             *(float *)(pToken + 1),
890                             *(float *)(pToken + 2),
891                             *(float *)(pToken + 3),
892                             *(float *)(pToken + 4));
893
894                         pToken += 5;
895                         len += 5;
896                 } else if (curOpcode->opcode == D3DSIO_DEFI) {
897
898                         TRACE("defi i%lu = %ld, %ld, %ld, %ld", *pToken & D3DSP_REGNUM_MASK,
899                             (long) *(pToken + 1),
900                             (long) *(pToken + 2),
901                             (long) *(pToken + 3),
902                             (long) *(pToken + 4));
903
904                         pToken += 5;
905                         len += 5;
906
907                 } else if (curOpcode->opcode == D3DSIO_DEFB) {
908
909                         TRACE("defb b%lu = %s", *pToken & D3DSP_REGNUM_MASK,
910                             *(pToken + 1)? "true": "false");
911
912                         pToken += 2;
913                         len += 2;
914
915                 } else {
916
917                     DWORD param, addr_token;
918                     int tokens_read;
919
920                     /* Print out predication source token first - it follows
921                      * the destination token. */
922                     if (opcode_token & D3DSHADER_INSTRUCTION_PREDICATED) {
923                         TRACE("(");
924                         shader_dump_param(iface, *(pToken + 2), 0, 1);
925                         TRACE(") ");
926                     }
927
928                     TRACE("%s", curOpcode->name);
929
930                     /* Destination token */
931                     if (curOpcode->dst_token) {
932
933                         /* Destination token */
934                         tokens_read = shader_get_param(iface, pToken, &param, &addr_token);
935                         pToken += tokens_read;
936                         len += tokens_read;
937
938                         shader_dump_ins_modifiers(param);
939                         TRACE(" ");
940                         shader_dump_param(iface, param, addr_token, 0);
941                     }
942
943                     /* Predication token - already printed out, just skip it */
944                     if (opcode_token & D3DSHADER_INSTRUCTION_PREDICATED) {
945                         pToken++;
946                         len++;
947                     }
948
949                     /* Other source tokens */
950                     for (i = curOpcode->dst_token; i < curOpcode->num_params; ++i) {
951
952                         tokens_read = shader_get_param(iface, pToken, &param, &addr_token);
953                         pToken += tokens_read;
954                         len += tokens_read;
955
956                         TRACE((i == 0)? " " : ", ");
957                         shader_dump_param(iface, param, addr_token, 1);
958                     }
959                 }
960                 TRACE("\n");
961             }
962         }
963         This->baseShader.functionLength = (len + 1) * sizeof(DWORD);
964     } else {
965         This->baseShader.functionLength = 1; /* no Function defined use fixed function vertex processing */
966     }
967 }
968
969 /* TODO: Move other shared code here */