mshtml: Added put_backgroundImage implementation.
[wine] / dlls / wined3d / arb_program_shader.c
1 /*
2  * Pixel and vertex shaders implementation using ARB_vertex_program
3  * and ARB_fragment_program GL extensions.
4  *
5  * Copyright 2002-2003 Jason Edmeades
6  * Copyright 2002-2003 Raphael Junqueira
7  * Copyright 2004 Christian Costa
8  * Copyright 2005 Oliver Stieber
9  * Copyright 2006 Ivan Gyurdiev
10  * Copyright 2006 Jason Green
11  * Copyright 2006 Henri Verbeet
12  * Copyright 2007-2008 Stefan Dösinger for CodeWeavers
13  *
14  * This library is free software; you can redistribute it and/or
15  * modify it under the terms of the GNU Lesser General Public
16  * License as published by the Free Software Foundation; either
17  * version 2.1 of the License, or (at your option) any later version.
18  *
19  * This library is distributed in the hope that it will be useful,
20  * but WITHOUT ANY WARRANTY; without even the implied warranty of
21  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
22  * Lesser General Public License for more details.
23  *
24  * You should have received a copy of the GNU Lesser General Public
25  * License along with this library; if not, write to the Free Software
26  * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
27  */
28
29 #include "config.h"
30
31 #include <math.h>
32 #include <stdio.h>
33
34 #include "wined3d_private.h"
35
36 WINE_DEFAULT_DEBUG_CHANNEL(d3d_shader);
37 WINE_DECLARE_DEBUG_CHANNEL(d3d_constants);
38 WINE_DECLARE_DEBUG_CHANNEL(d3d_caps);
39
40 #define GLINFO_LOCATION      (*gl_info)
41
42 /********************************************************
43  * ARB_[vertex/fragment]_program helper functions follow
44  ********************************************************/
45
46 /** 
47  * Loads floating point constants into the currently set ARB_vertex/fragment_program.
48  * When constant_list == NULL, it will load all the constants.
49  *  
50  * @target_type should be either GL_VERTEX_PROGRAM_ARB (for vertex shaders)
51  *  or GL_FRAGMENT_PROGRAM_ARB (for pixel shaders)
52  */
53 static unsigned int shader_arb_load_constantsF(IWineD3DBaseShaderImpl* This, WineD3D_GL_Info *gl_info, GLuint target_type,
54         unsigned int max_constants, float* constants, char *dirty_consts) {
55     local_constant* lconst;
56     DWORD i, j;
57     unsigned int ret;
58
59     if (TRACE_ON(d3d_shader)) {
60         for(i = 0; i < max_constants; i++) {
61             if(!dirty_consts[i]) continue;
62             TRACE_(d3d_constants)("Loading constants %i: %f, %f, %f, %f\n", i,
63                         constants[i * 4 + 0], constants[i * 4 + 1],
64                         constants[i * 4 + 2], constants[i * 4 + 3]);
65         }
66     }
67     /* In 1.X pixel shaders constants are implicitly clamped in the range [-1;1] */
68     if(target_type == GL_FRAGMENT_PROGRAM_ARB &&
69        WINED3DSHADER_VERSION_MAJOR(This->baseShader.hex_version) == 1) {
70         float lcl_const[4];
71         for(i = 0; i < max_constants; i++) {
72             if(!dirty_consts[i]) continue;
73             dirty_consts[i] = 0;
74
75             j = 4 * i;
76             if(constants[j + 0] > 1.0) lcl_const[0] = 1.0;
77             else if(constants[j + 0] < -1.0) lcl_const[0] = -1.0;
78             else lcl_const[0] = constants[j + 0];
79
80             if(constants[j + 1] > 1.0) lcl_const[1] = 1.0;
81             else if(constants[j + 1] < -1.0) lcl_const[1] = -1.0;
82             else lcl_const[1] = constants[j + 1];
83
84             if(constants[j + 2] > 1.0) lcl_const[2] = 1.0;
85             else if(constants[j + 2] < -1.0) lcl_const[2] = -1.0;
86             else lcl_const[2] = constants[j + 2];
87
88             if(constants[j + 3] > 1.0) lcl_const[3] = 1.0;
89             else if(constants[j + 3] < -1.0) lcl_const[3] = -1.0;
90             else lcl_const[3] = constants[j + 3];
91
92             GL_EXTCALL(glProgramEnvParameter4fvARB(target_type, i, lcl_const));
93         }
94     } else {
95         if(GL_SUPPORT(EXT_GPU_PROGRAM_PARAMETERS)) {
96             /* TODO: Benchmark if we're better of with finding the dirty constants ourselves,
97              * or just reloading *all* constants at once
98              *
99             GL_EXTCALL(glProgramEnvParameters4fvEXT(target_type, 0, max_constants, constants));
100              */
101             for(i = 0; i < max_constants; i++) {
102                 if(!dirty_consts[i]) continue;
103
104                 /* Find the next block of dirty constants */
105                 dirty_consts[i] = 0;
106                 j = i;
107                 for(i++; (i < max_constants) && dirty_consts[i]; i++) {
108                     dirty_consts[i] = 0;
109                 }
110
111                 GL_EXTCALL(glProgramEnvParameters4fvEXT(target_type, j, i - j, constants + (j * 4)));
112             }
113         } else {
114             for(i = 0; i < max_constants; i++) {
115                 if(dirty_consts[i]) {
116                     dirty_consts[i] = 0;
117                     GL_EXTCALL(glProgramEnvParameter4fvARB(target_type, i, constants + (i * 4)));
118                 }
119             }
120         }
121     }
122     checkGLcall("glProgramEnvParameter4fvARB()");
123
124     /* Load immediate constants */
125     if(This->baseShader.load_local_constsF) {
126         if (TRACE_ON(d3d_shader)) {
127             LIST_FOR_EACH_ENTRY(lconst, &This->baseShader.constantsF, local_constant, entry) {
128                 GLfloat* values = (GLfloat*)lconst->value;
129                 TRACE_(d3d_constants)("Loading local constants %i: %f, %f, %f, %f\n", lconst->idx,
130                         values[0], values[1], values[2], values[3]);
131             }
132         }
133         /* Immediate constants are clamped for 1.X shaders at loading times */
134         ret = 0;
135         LIST_FOR_EACH_ENTRY(lconst, &This->baseShader.constantsF, local_constant, entry) {
136             dirty_consts[lconst->idx] = 1; /* Dirtify so the non-immediate constant overwrites it next time */
137             ret = max(ret, lconst->idx);
138             GL_EXTCALL(glProgramEnvParameter4fvARB(target_type, lconst->idx, (GLfloat*)lconst->value));
139         }
140         checkGLcall("glProgramEnvParameter4fvARB()");
141         return ret; /* The loaded immediate constants need reloading for the next shader */
142     } else {
143         return 0; /* No constants are dirty now */
144     }
145 }
146
147 /**
148  * Loads the app-supplied constants into the currently set ARB_[vertex/fragment]_programs.
149  * 
150  * We only support float constants in ARB at the moment, so don't 
151  * worry about the Integers or Booleans
152  */
153 void shader_arb_load_constants(
154     IWineD3DDevice* device,
155     char usePixelShader,
156     char useVertexShader) {
157    
158     IWineD3DDeviceImpl* deviceImpl = (IWineD3DDeviceImpl*) device; 
159     IWineD3DStateBlockImpl* stateBlock = deviceImpl->stateBlock;
160     WineD3D_GL_Info *gl_info = &deviceImpl->adapter->gl_info;
161     unsigned char i;
162
163     if (useVertexShader) {
164         IWineD3DBaseShaderImpl* vshader = (IWineD3DBaseShaderImpl*) stateBlock->vertexShader;
165
166         /* Load DirectX 9 float constants for vertex shader */
167         deviceImpl->highest_dirty_vs_const = shader_arb_load_constantsF(
168                 vshader, gl_info, GL_VERTEX_PROGRAM_ARB,
169                 deviceImpl->highest_dirty_vs_const,
170                 stateBlock->vertexShaderConstantF,
171                 deviceImpl->activeContext->vshader_const_dirty);
172
173         /* Upload the position fixup */
174         GL_EXTCALL(glProgramEnvParameter4fvARB(GL_VERTEX_PROGRAM_ARB, ARB_SHADER_PRIVCONST_POS, deviceImpl->posFixup));
175     }
176
177     if (usePixelShader) {
178
179         IWineD3DBaseShaderImpl* pshader = (IWineD3DBaseShaderImpl*) stateBlock->pixelShader;
180         IWineD3DPixelShaderImpl *psi = (IWineD3DPixelShaderImpl *) pshader;
181
182         /* Load DirectX 9 float constants for pixel shader */
183         deviceImpl->highest_dirty_ps_const = shader_arb_load_constantsF(
184                 pshader, gl_info, GL_FRAGMENT_PROGRAM_ARB,
185                 deviceImpl->highest_dirty_ps_const,
186                 stateBlock->pixelShaderConstantF,
187                 deviceImpl->activeContext->pshader_const_dirty);
188
189         for(i = 0; i < psi->numbumpenvmatconsts; i++) {
190             /* The state manager takes care that this function is always called if the bump env matrix changes
191              */
192             float *data = (float *) &stateBlock->textureState[(int) psi->bumpenvmatconst[i].texunit][WINED3DTSS_BUMPENVMAT00];
193             GL_EXTCALL(glProgramEnvParameter4fvARB(GL_FRAGMENT_PROGRAM_ARB, psi->bumpenvmatconst[i].const_num, data));
194             deviceImpl->activeContext->pshader_const_dirty[psi->bumpenvmatconst[i].const_num] = 1;
195
196             if(psi->luminanceconst[i].const_num != -1) {
197                 /* WINED3DTSS_BUMPENVLSCALE and WINED3DTSS_BUMPENVLOFFSET are next to each other.
198                  * point gl to the scale, and load 4 floats. x = scale, y = offset, z and w are junk, we
199                  * don't care about them. The pointers are valid for sure because the stateblock is bigger.
200                  * (they're WINED3DTSS_TEXTURETRANSFORMFLAGS and WINED3DTSS_ADDRESSW, so most likely 0 or NaN
201                  */
202                 float *scale = (float *) &stateBlock->textureState[(int) psi->luminanceconst[i].texunit][WINED3DTSS_BUMPENVLSCALE];
203                 GL_EXTCALL(glProgramEnvParameter4fvARB(GL_FRAGMENT_PROGRAM_ARB, psi->luminanceconst[i].const_num, scale));
204                 deviceImpl->activeContext->pshader_const_dirty[psi->luminanceconst[i].const_num] = 1;
205             }
206         }
207
208         if(((IWineD3DPixelShaderImpl *) pshader)->srgb_enabled &&
209            !((IWineD3DPixelShaderImpl *) pshader)->srgb_mode_hardcoded) {
210             float comparison[4];
211             float mul_low[4];
212
213             if(stateBlock->renderState[WINED3DRS_SRGBWRITEENABLE]) {
214                 comparison[0] = srgb_cmp; comparison[1] = srgb_cmp;
215                 comparison[2] = srgb_cmp; comparison[3] = srgb_cmp;
216
217                 mul_low[0] = srgb_mul_low; mul_low[1] = srgb_mul_low;
218                 mul_low[2] = srgb_mul_low; mul_low[3] = srgb_mul_low;
219             } else {
220                 comparison[0] = 1.0 / 0.0; comparison[1] = 1.0 / 0.0;
221                 comparison[2] = 1.0 / 0.0; comparison[3] = 1.0 / 0.0;
222
223                 mul_low[0] = 1.0; mul_low[1] = 1.0;
224                 mul_low[2] = 1.0; mul_low[3] = 1.0;
225             }
226             GL_EXTCALL(glProgramEnvParameter4fvARB(GL_FRAGMENT_PROGRAM_ARB, psi->srgb_cmp_const, comparison));
227             GL_EXTCALL(glProgramEnvParameter4fvARB(GL_FRAGMENT_PROGRAM_ARB, psi->srgb_low_const, mul_low));
228             checkGLcall("Load sRGB correction constants\n");
229             deviceImpl->activeContext->pshader_const_dirty[psi->srgb_low_const] = 1;
230             deviceImpl->activeContext->pshader_const_dirty[psi->srgb_cmp_const] = 1;
231
232         }
233     }
234 }
235
236 /* Generate the variable & register declarations for the ARB_vertex_program output target */
237 void shader_generate_arb_declarations(
238     IWineD3DBaseShader *iface,
239     shader_reg_maps* reg_maps,
240     SHADER_BUFFER* buffer,
241     WineD3D_GL_Info* gl_info) {
242
243     IWineD3DBaseShaderImpl* This = (IWineD3DBaseShaderImpl*) iface;
244     IWineD3DDeviceImpl *device = (IWineD3DDeviceImpl *) This->baseShader.device;
245     DWORD i, cur;
246     char pshader = shader_is_pshader_version(This->baseShader.hex_version);
247     unsigned max_constantsF = min(This->baseShader.limits.constant_float, 
248             (pshader ? GL_LIMITS(pshader_constantsF) : GL_LIMITS(vshader_constantsF)));
249     UINT extra_constants_needed = 0;
250     local_constant* lconst;
251
252     /* Temporary Output register */
253     shader_addline(buffer, "TEMP TMP_OUT;\n");
254
255     for(i = 0; i < This->baseShader.limits.temporary; i++) {
256         if (reg_maps->temporary[i])
257             shader_addline(buffer, "TEMP R%u;\n", i);
258     }
259
260     for (i = 0; i < This->baseShader.limits.address; i++) {
261         if (reg_maps->address[i])
262             shader_addline(buffer, "ADDRESS A%d;\n", i);
263     }
264
265     for(i = 0; i < This->baseShader.limits.texcoord; i++) {
266         if (reg_maps->texcoord[i])
267             shader_addline(buffer,"TEMP T%u;\n", i);
268     }
269
270     /* Texture coordinate registers must be pre-loaded */
271     for (i = 0; i < This->baseShader.limits.texcoord; i++) {
272         if (reg_maps->texcoord[i])
273             shader_addline(buffer, "MOV T%u, fragment.texcoord[%u];\n", i, i);
274     }
275
276     for(i = 0; i < (sizeof(reg_maps->bumpmat) / sizeof(reg_maps->bumpmat[0])); i++) {
277         IWineD3DPixelShaderImpl *ps = (IWineD3DPixelShaderImpl *) This;
278         if(!reg_maps->bumpmat[i]) continue;
279
280         cur = ps->numbumpenvmatconsts;
281         ps->bumpenvmatconst[cur].const_num = -1;
282         ps->bumpenvmatconst[cur].texunit = i;
283         ps->luminanceconst[cur].const_num = -1;
284         ps->luminanceconst[cur].texunit = i;
285
286         /* If the shader does not use all available constants, use the next free constant to load the bump mapping environment matrix from
287          * the stateblock into the shader. If no constant is available don't load, texbem will then just sample the texture without applying
288          * bump mapping.
289          */
290         if(max_constantsF + extra_constants_needed < GL_LIMITS(pshader_constantsF)) {
291             ps->bumpenvmatconst[cur].const_num = max_constantsF + extra_constants_needed;
292             shader_addline(buffer, "PARAM bumpenvmat%d = program.env[%d];\n",
293                            i, ps->bumpenvmatconst[cur].const_num);
294             extra_constants_needed++;
295
296             if(reg_maps->luminanceparams && max_constantsF + extra_constants_needed < GL_LIMITS(pshader_constantsF)) {
297                 ((IWineD3DPixelShaderImpl *)This)->luminanceconst[cur].const_num = max_constantsF + extra_constants_needed;
298                 shader_addline(buffer, "PARAM luminance%d = program.env[%d];\n",
299                                i, ps->luminanceconst[cur].const_num);
300                 extra_constants_needed++;
301             } else if(reg_maps->luminanceparams) {
302                 FIXME("No free constant to load the luminance parameters\n");
303             }
304         } else {
305             FIXME("No free constant found to load environemnt bump mapping matrix into the shader. texbem instruction will not apply bump mapping\n");
306         }
307
308         ps->numbumpenvmatconsts = cur + 1;
309     }
310
311     if(device->stateBlock->renderState[WINED3DRS_SRGBWRITEENABLE] && pshader) {
312         IWineD3DPixelShaderImpl *ps_impl = (IWineD3DPixelShaderImpl *) This;
313         /* If there are 2 constants left to use, use them to pass the sRGB correction values in. This way
314          * srgb write correction can be turned on and off dynamically without recompilation. Otherwise
315          * hardcode them. The drawback of hardcoding is that the shader needs recompilation to turn sRGB
316          * off again
317          */
318         if(max_constantsF + extra_constants_needed + 1 < GL_LIMITS(pshader_constantsF) && FALSE) {
319             /* The idea is that if srgb is enabled, then disabled, the constant loading code
320              * can effectively disable sRGB correction by passing 1.0 and INF as the multiplication
321              * and comparison constants. If it disables it that way, the shader won't be recompiled
322              * and the code will stay in, so sRGB writing can be turned on again by setting the
323              * constants from the spec
324              */
325             ps_impl->srgb_mode_hardcoded = 0;
326             ps_impl->srgb_low_const = GL_LIMITS(pshader_constantsF) - extra_constants_needed;
327             ps_impl->srgb_cmp_const = GL_LIMITS(pshader_constantsF) - extra_constants_needed - 1;
328             shader_addline(buffer, "PARAM srgb_mul_low = program.env[%d];\n", ps_impl->srgb_low_const);
329             shader_addline(buffer, "PARAM srgb_comparison = program.env[%d];\n", ps_impl->srgb_cmp_const);
330         } else {
331             shader_addline(buffer, "PARAM srgb_mul_low = {%f, %f, %f, 1.0};\n",
332                            srgb_mul_low, srgb_mul_low, srgb_mul_low);
333             shader_addline(buffer, "PARAM srgb_comparison =  {%f, %f, %f, %f};\n",
334                            srgb_cmp, srgb_cmp, srgb_cmp, srgb_cmp);
335             ps_impl->srgb_mode_hardcoded = 1;
336         }
337         /* These can be hardcoded, they do not cause any harm because no fragment will enter the high
338          * path if the comparison value is set to INF
339          */
340         shader_addline(buffer, "PARAM srgb_pow =  {%f, %f, %f, 1.0};\n",
341                        srgb_pow, srgb_pow, srgb_pow);
342         shader_addline(buffer, "PARAM srgb_mul_hi =  {%f, %f, %f, 1.0};\n",
343                        srgb_mul_high, srgb_mul_high, srgb_mul_high);
344         shader_addline(buffer, "PARAM srgb_sub_hi =  {%f, %f, %f, 0.0};\n",
345                        srgb_sub_high, srgb_sub_high, srgb_sub_high);
346         ps_impl->srgb_enabled = 1;
347     } else if(pshader) {
348         IWineD3DPixelShaderImpl *ps_impl = (IWineD3DPixelShaderImpl *) This;
349
350         /* Do not write any srgb fixup into the shader to save shader size and processing time.
351          * As a consequence, we can't toggle srgb write on without recompilation
352          */
353         ps_impl->srgb_enabled = 0;
354         ps_impl->srgb_mode_hardcoded = 1;
355     }
356
357     /* Hardcodable local constants */
358     if(!This->baseShader.load_local_constsF) {
359         LIST_FOR_EACH_ENTRY(lconst, &This->baseShader.constantsF, local_constant, entry) {
360             float *value = (float *) lconst->value;
361             shader_addline(buffer, "PARAM C%u = {%f, %f, %f, %f};\n", lconst->idx,
362                            value[0], value[1], value[2], value[3]);
363         }
364     }
365
366     /* we use the array-based constants array if the local constants are marked for loading,
367      * because then we use indirect addressing, or when the local constant list is empty,
368      * because then we don't know if we're using indirect addressing or not. If we're hardcoding
369      * local constants do not declare the loaded constants as an array because ARB compilers usually
370      * do not optimize unused constants away
371      */
372     if(This->baseShader.load_local_constsF || list_empty(&This->baseShader.constantsF)) {
373         /* Need to PARAM the environment parameters (constants) so we can use relative addressing */
374         shader_addline(buffer, "PARAM C[%d] = { program.env[0..%d] };\n",
375                     max_constantsF, max_constantsF - 1);
376     } else {
377         for(i = 0; i < max_constantsF; i++) {
378             if(!shader_constant_is_local(This, i)) {
379                 shader_addline(buffer, "PARAM C%d = program.env[%d];\n",i, i);
380             }
381         }
382     }
383 }
384
385 static const char * const shift_tab[] = {
386     "dummy",     /*  0 (none) */
387     "coefmul.x", /*  1 (x2)   */
388     "coefmul.y", /*  2 (x4)   */
389     "coefmul.z", /*  3 (x8)   */
390     "coefmul.w", /*  4 (x16)  */
391     "dummy",     /*  5 (x32)  */
392     "dummy",     /*  6 (x64)  */
393     "dummy",     /*  7 (x128) */
394     "dummy",     /*  8 (d256) */
395     "dummy",     /*  9 (d128) */
396     "dummy",     /* 10 (d64)  */
397     "dummy",     /* 11 (d32)  */
398     "coefdiv.w", /* 12 (d16)  */
399     "coefdiv.z", /* 13 (d8)   */
400     "coefdiv.y", /* 14 (d4)   */
401     "coefdiv.x"  /* 15 (d2)   */
402 };
403
404 static void shader_arb_get_write_mask(SHADER_OPCODE_ARG* arg, const DWORD param, char *write_mask) {
405     IWineD3DBaseShaderImpl *This = (IWineD3DBaseShaderImpl *) arg->shader;
406     char *ptr = write_mask;
407     char vshader = shader_is_vshader_version(This->baseShader.hex_version);
408
409     if(vshader && shader_get_regtype(param) == WINED3DSPR_ADDR) {
410         *ptr++ = '.';
411         *ptr++ = 'x';
412     } else if ((param & WINED3DSP_WRITEMASK_ALL) != WINED3DSP_WRITEMASK_ALL) {
413         *ptr++ = '.';
414         if (param & WINED3DSP_WRITEMASK_0) *ptr++ = 'x';
415         if (param & WINED3DSP_WRITEMASK_1) *ptr++ = 'y';
416         if (param & WINED3DSP_WRITEMASK_2) *ptr++ = 'z';
417         if (param & WINED3DSP_WRITEMASK_3) *ptr++ = 'w';
418     }
419
420     *ptr = '\0';
421 }
422
423 static void shader_arb_get_swizzle(const DWORD param, BOOL fixup, char *swizzle_str) {
424     /* For registers of type WINED3DDECLTYPE_D3DCOLOR, data is stored as "bgra",
425      * but addressed as "rgba". To fix this we need to swap the register's x
426      * and z components. */
427     const char *swizzle_chars = fixup ? "zyxw" : "xyzw";
428     char *ptr = swizzle_str;
429
430     /* swizzle bits fields: wwzzyyxx */
431     DWORD swizzle = (param & WINED3DSP_SWIZZLE_MASK) >> WINED3DSP_SWIZZLE_SHIFT;
432     DWORD swizzle_x = swizzle & 0x03;
433     DWORD swizzle_y = (swizzle >> 2) & 0x03;
434     DWORD swizzle_z = (swizzle >> 4) & 0x03;
435     DWORD swizzle_w = (swizzle >> 6) & 0x03;
436
437     /* If the swizzle is the default swizzle (ie, "xyzw"), we don't need to
438      * generate a swizzle string. Unless we need to our own swizzling. */
439     if ((WINED3DSP_NOSWIZZLE >> WINED3DSP_SWIZZLE_SHIFT) != swizzle || fixup) {
440         *ptr++ = '.';
441         if (swizzle_x == swizzle_y && swizzle_x == swizzle_z && swizzle_x == swizzle_w) {
442             *ptr++ = swizzle_chars[swizzle_x];
443         } else {
444             *ptr++ = swizzle_chars[swizzle_x];
445             *ptr++ = swizzle_chars[swizzle_y];
446             *ptr++ = swizzle_chars[swizzle_z];
447             *ptr++ = swizzle_chars[swizzle_w];
448         }
449     }
450
451     *ptr = '\0';
452 }
453
454 static void pshader_get_register_name(IWineD3DBaseShader* iface,
455     const DWORD param, char* regstr) {
456
457     DWORD reg = param & WINED3DSP_REGNUM_MASK;
458     DWORD regtype = shader_get_regtype(param);
459     IWineD3DBaseShaderImpl *This = (IWineD3DBaseShaderImpl *) iface;
460
461     switch (regtype) {
462     case WINED3DSPR_TEMP:
463         sprintf(regstr, "R%u", reg);
464     break;
465     case WINED3DSPR_INPUT:
466         if (reg==0) {
467             strcpy(regstr, "fragment.color.primary");
468         } else {
469             strcpy(regstr, "fragment.color.secondary");
470         }
471     break;
472     case WINED3DSPR_CONST:
473         if(This->baseShader.load_local_constsF || list_empty(&This->baseShader.constantsF)) {
474             sprintf(regstr, "C[%u]", reg);
475         } else {
476             sprintf(regstr, "C%u", reg);
477         }
478     break;
479     case WINED3DSPR_TEXTURE: /* case WINED3DSPR_ADDR: */
480         sprintf(regstr,"T%u", reg);
481     break;
482     case WINED3DSPR_COLOROUT:
483         if (reg == 0)
484             sprintf(regstr, "TMP_COLOR");
485         else {
486             /* TODO: See GL_ARB_draw_buffers */
487             FIXME("Unsupported write to render target %u\n", reg);
488             sprintf(regstr, "unsupported_register");
489         }
490     break;
491     case WINED3DSPR_DEPTHOUT:
492         sprintf(regstr, "result.depth");
493     break;
494     case WINED3DSPR_ATTROUT:
495         sprintf(regstr, "oD[%u]", reg);
496     break;
497     case WINED3DSPR_TEXCRDOUT:
498         sprintf(regstr, "oT[%u]", reg);
499     break;
500     default:
501         FIXME("Unhandled register name Type(%d)\n", regtype);
502         sprintf(regstr, "unrecognized_register");
503     break;
504     }
505 }
506
507 /* TODO: merge with pixel shader */
508 static void vshader_program_add_param(SHADER_OPCODE_ARG *arg, const DWORD param, BOOL is_input, char *hwLine) {
509
510   IWineD3DVertexShaderImpl* This = (IWineD3DVertexShaderImpl*) arg->shader;
511
512   /* oPos, oFog and oPts in D3D */
513   static const char * const hwrastout_reg_names[] = { "TMP_OUT", "result.fogcoord", "result.pointsize" };
514
515   DWORD reg = param & WINED3DSP_REGNUM_MASK;
516   DWORD regtype = shader_get_regtype(param);
517   char  tmpReg[255];
518   BOOL is_color = FALSE;
519
520   if ((param & WINED3DSP_SRCMOD_MASK) == WINED3DSPSM_NEG) {
521       strcat(hwLine, " -");
522   } else {
523       strcat(hwLine, " ");
524   }
525
526   switch (regtype) {
527   case WINED3DSPR_TEMP:
528     sprintf(tmpReg, "R%u", reg);
529     strcat(hwLine, tmpReg);
530     break;
531   case WINED3DSPR_INPUT:
532
533     if (vshader_input_is_color((IWineD3DVertexShader*) This, reg))
534         is_color = TRUE;
535
536     sprintf(tmpReg, "vertex.attrib[%u]", reg);
537     strcat(hwLine, tmpReg);
538     break;
539   case WINED3DSPR_CONST:
540       if(param & WINED3DSHADER_ADDRMODE_RELATIVE) {
541           if(reg >= This->rel_offset) {
542               sprintf(tmpReg, "C[A0.x + %u]", reg - This->rel_offset);
543           } else {
544               sprintf(tmpReg, "C[A0.x - %u]", -reg + This->rel_offset);
545           }
546       } else {
547           if(This->baseShader.load_local_constsF || list_empty(&This->baseShader.constantsF)) {
548               sprintf(tmpReg, "C[%u]", reg);
549           } else {
550               sprintf(tmpReg, "C%u", reg);
551           }
552       }
553     strcat(hwLine, tmpReg);
554     break;
555   case WINED3DSPR_ADDR: /*case D3DSPR_TEXTURE:*/
556     sprintf(tmpReg, "A%u", reg);
557     strcat(hwLine, tmpReg);
558     break;
559   case WINED3DSPR_RASTOUT:
560     sprintf(tmpReg, "%s", hwrastout_reg_names[reg]);
561     strcat(hwLine, tmpReg);
562     break;
563   case WINED3DSPR_ATTROUT:
564     if (reg==0) {
565        strcat(hwLine, "result.color.primary");
566     } else {
567        strcat(hwLine, "result.color.secondary");
568     }
569     break;
570   case WINED3DSPR_TEXCRDOUT:
571     sprintf(tmpReg, "result.texcoord[%u]", reg);
572     strcat(hwLine, tmpReg);
573     break;
574   default:
575     FIXME("Unknown reg type %d %d\n", regtype, reg);
576     strcat(hwLine, "unrecognized_register");
577     break;
578   }
579
580   if (!is_input) {
581     char write_mask[6];
582     shader_arb_get_write_mask(arg, param, write_mask);
583     strcat(hwLine, write_mask);
584   } else {
585     char swizzle[6];
586     shader_arb_get_swizzle(param, is_color, swizzle);
587     strcat(hwLine, swizzle);
588   }
589 }
590
591 static void shader_hw_sample(SHADER_OPCODE_ARG* arg, DWORD sampler_idx, const char *dst_str, const char *coord_reg, BOOL projected, BOOL bias) {
592     SHADER_BUFFER* buffer = arg->buffer;
593     DWORD sampler_type = arg->reg_maps->samplers[sampler_idx] & WINED3DSP_TEXTURETYPE_MASK;
594     const char *tex_type;
595
596     switch(sampler_type) {
597         case WINED3DSTT_1D:
598             tex_type = "1D";
599             break;
600
601         case WINED3DSTT_2D:
602         {
603             IWineD3DBaseShaderImpl *This = (IWineD3DBaseShaderImpl *) arg->shader;
604             IWineD3DDeviceImpl *device = (IWineD3DDeviceImpl *) This->baseShader.device;
605             if(device->stateBlock->textures[sampler_idx] &&
606                IWineD3DBaseTexture_GetTextureDimensions(device->stateBlock->textures[sampler_idx]) == GL_TEXTURE_RECTANGLE_ARB) {
607                 tex_type = "RECT";
608             } else {
609                 tex_type = "2D";
610             }
611             break;
612         }
613
614         case WINED3DSTT_VOLUME:
615             tex_type = "3D";
616             break;
617
618         case WINED3DSTT_CUBE:
619             tex_type = "CUBE";
620             break;
621
622         default:
623             ERR("Unexpected texture type %d\n", sampler_type);
624             tex_type = "";
625     }
626
627     if (bias) {
628         /* Shouldn't be possible, but let's check for it */
629         if(projected) FIXME("Biased and Projected texture sampling\n");
630         /* TXB takes the 4th component of the source vector automatically, as d3d. Nothing more to do */
631         shader_addline(buffer, "TXB %s, %s, texture[%u], %s;\n", dst_str, coord_reg, sampler_idx, tex_type);
632     } else if (projected) {
633         shader_addline(buffer, "TXP %s, %s, texture[%u], %s;\n", dst_str, coord_reg, sampler_idx, tex_type);
634     } else {
635         shader_addline(buffer, "TEX %s, %s, texture[%u], %s;\n", dst_str, coord_reg, sampler_idx, tex_type);
636     }
637 }
638
639 static void shader_arb_color_correction(SHADER_OPCODE_ARG* arg) {
640     IWineD3DBaseShaderImpl* shader = (IWineD3DBaseShaderImpl*) arg->shader;
641     IWineD3DDeviceImpl* deviceImpl = (IWineD3DDeviceImpl*) shader->baseShader.device;
642     WineD3D_GL_Info *gl_info = &deviceImpl->adapter->gl_info;
643     WINED3DFORMAT fmt;
644     WINED3DFORMAT conversion_group;
645     IWineD3DBaseTextureImpl *texture;
646     UINT i;
647     BOOL recorded = FALSE;
648     DWORD sampler_idx;
649     DWORD hex_version = shader->baseShader.hex_version;
650     char reg[256];
651     char writemask[6];
652
653     switch(arg->opcode->opcode) {
654         case WINED3DSIO_TEX:
655             if (hex_version < WINED3DPS_VERSION(2,0)) {
656                 sampler_idx = arg->dst & WINED3DSP_REGNUM_MASK;
657             } else {
658                 sampler_idx = arg->src[1] & WINED3DSP_REGNUM_MASK;
659             }
660             break;
661
662         case WINED3DSIO_TEXLDL:
663             FIXME("Add color fixup for vertex texture WINED3DSIO_TEXLDL\n");
664             return;
665
666         case WINED3DSIO_TEXDP3TEX:
667         case WINED3DSIO_TEXM3x3TEX:
668         case WINED3DSIO_TEXM3x3SPEC:
669         case WINED3DSIO_TEXM3x3VSPEC:
670         case WINED3DSIO_TEXBEM:
671         case WINED3DSIO_TEXREG2AR:
672         case WINED3DSIO_TEXREG2GB:
673         case WINED3DSIO_TEXREG2RGB:
674             sampler_idx = arg->dst & WINED3DSP_REGNUM_MASK;
675             break;
676
677         default:
678             /* Not a texture sampling instruction, nothing to do */
679             return;
680     };
681
682     texture = (IWineD3DBaseTextureImpl *) deviceImpl->stateBlock->textures[sampler_idx];
683     if(texture) {
684         fmt = texture->resource.format;
685         conversion_group = texture->baseTexture.shader_conversion_group;
686     } else {
687         fmt = WINED3DFMT_UNKNOWN;
688         conversion_group = WINED3DFMT_UNKNOWN;
689     }
690
691     /* before doing anything, record the sampler with the format in the format conversion list,
692      * but check if it's not there already
693      */
694     for(i = 0; i < shader->baseShader.num_sampled_samplers; i++) {
695         if(shader->baseShader.sampled_samplers[i] == sampler_idx) {
696             recorded = TRUE;
697         }
698     }
699     if(!recorded) {
700         shader->baseShader.sampled_samplers[shader->baseShader.num_sampled_samplers] = sampler_idx;
701         shader->baseShader.num_sampled_samplers++;
702         shader->baseShader.sampled_format[sampler_idx] = conversion_group;
703     }
704
705     pshader_get_register_name(arg->shader, arg->dst, reg);
706     shader_arb_get_write_mask(arg, arg->dst, writemask);
707     if(strlen(writemask) == 0) strcpy(writemask, ".xyzw");
708
709     switch(fmt) {
710         case WINED3DFMT_V8U8:
711         case WINED3DFMT_V16U16:
712             if(GL_SUPPORT(NV_TEXTURE_SHADER) ||
713                (GL_SUPPORT(ATI_ENVMAP_BUMPMAP) && fmt == WINED3DFMT_V8U8)) {
714 #if 0
715                 /* The 3rd channel returns 1.0 in d3d, but 0.0 in gl. Fix this while we're at it :-)
716                  * disabled until an application that needs it is found because it causes unneeded
717                  * shader recompilation in some game
718                  */
719                 if(strlen(writemask) >= 4) {
720                     shader_addline(arg->buffer, "MOV %s.%c, one.z;\n", reg, writemask[3]);
721                 }
722 #endif
723             } else {
724                 /* Correct the sign, but leave the blue as it is - it was loaded correctly already
725                  * ARB shaders are a bit picky wrt writemasks and swizzles. If we're free to scale
726                  * all registers, do so, this saves an instruction.
727                  */
728                 if(strlen(writemask) >= 5) {
729                     shader_addline(arg->buffer, "MAD %s, %s, coefmul.x, -one;\n", reg, reg);
730                 } else if(strlen(writemask) >= 3) {
731                     shader_addline(arg->buffer, "MAD %s.%c, %s.%c, coefmul.x, -one;\n",
732                                    reg, writemask[1],
733                                    reg, writemask[1]);
734                     shader_addline(arg->buffer, "MAD %s.%c, %s.%c, coefmul.x, -one;\n",
735                                    reg, writemask[2],
736                                    reg, writemask[2]);
737                 } else if(strlen(writemask) == 2) {
738                     shader_addline(arg->buffer, "MAD %s.%c, %s.%c, coefmul.x, -one;\n", reg, writemask[1],
739                                    reg, writemask[1]);
740                 }
741             }
742             break;
743
744         case WINED3DFMT_X8L8V8U8:
745             if(!GL_SUPPORT(NV_TEXTURE_SHADER)) {
746                 /* Red and blue are the signed channels, fix them up; Blue(=L) is correct already,
747                  * and a(X) is always 1.0. Cannot do a full conversion due to L(blue)
748                  */
749                 if(strlen(writemask) >= 3) {
750                     shader_addline(arg->buffer, "MAD %s.%c, %s.%c, coefmul.x, -one;\n",
751                                    reg, writemask[1],
752                                    reg, writemask[1]);
753                     shader_addline(arg->buffer, "MAD %s.%c, %s.%c, coefmul.x, -one;\n",
754                                    reg, writemask[2],
755                                    reg, writemask[2]);
756                 } else if(strlen(writemask) == 2) {
757                     shader_addline(arg->buffer, "MAD %s.%c, %s.%c, coefmul.x, -one;\n",
758                                    reg, writemask[1],
759                                    reg, writemask[1]);
760                 }
761             }
762             break;
763
764         case WINED3DFMT_L6V5U5:
765             if(!GL_SUPPORT(NV_TEXTURE_SHADER)) {
766                 if(strlen(writemask) >= 4) {
767                     /* Swap y and z (U and L), and do a sign conversion on x and the new y(V and U) */
768                     shader_addline(arg->buffer, "MOV TMP.g, %s.%c;\n",
769                                    reg, writemask[2]);
770                     shader_addline(arg->buffer, "MAD %s.%c%c, %s.%c%c, coefmul.x, -one;\n",
771                                    reg, writemask[1], writemask[1],
772                                    reg, writemask[1], writemask[3]);
773                     shader_addline(arg->buffer, "MOV %s.%c, TMP.g;\n", reg,
774                                    writemask[3]);
775                 } else if(strlen(writemask) == 3) {
776                     /* This is bad: We have VL, but we need VU */
777                     FIXME("2 components sampled from a converted L6V5U5 texture\n");
778                 } else {
779                     shader_addline(arg->buffer, "MAD %s.%c, %s.%c, coefmul.x, -one;\n",
780                                    reg, writemask[1],
781                                    reg, writemask[1]);
782                 }
783             }
784             break;
785
786         case WINED3DFMT_Q8W8V8U8:
787             if(!GL_SUPPORT(NV_TEXTURE_SHADER)) {
788                 /* Correct the sign in all channels */
789                 switch(strlen(writemask)) {
790                     case 4:
791                         shader_addline(arg->buffer, "MAD %s.%c, %s.%c, coefmul.x, -one;\n",
792                                        reg, writemask[3],
793                                        reg, writemask[3]);
794                         /* drop through */
795                     case 3:
796                         shader_addline(arg->buffer, "MAD %s.%c, %s.%c, coefmul.x, -one;\n",
797                                        reg, writemask[2],
798                                        reg, writemask[2]);
799                         /* drop through */
800                     case 2:
801                         shader_addline(arg->buffer, "MAD %s.%c, %s.%c, coefmul.x, -one;\n",
802                                        reg, writemask[1],
803                                        reg, writemask[1]);
804                         break;
805
806                         /* Should not occur, since it's at minimum '.' and a letter */
807                     case 1:
808                         ERR("Unexpected writemask: \"%s\"\n", writemask);
809                         break;
810
811                     case 5:
812                     default:
813                         shader_addline(arg->buffer, "MAD %s, %s, coefmul.x, -one;\n", reg, reg);
814                 }
815             }
816             break;
817
818             /* stupid compiler */
819         default:
820             break;
821     }
822 }
823
824
825 static void pshader_gen_input_modifier_line (
826     IWineD3DBaseShader *iface,
827     SHADER_BUFFER* buffer,
828     const DWORD instr,
829     int tmpreg,
830     char *outregstr) {
831
832     /* Generate a line that does the input modifier computation and return the input register to use */
833     char regstr[256];
834     char swzstr[20];
835     int insert_line;
836
837     /* Assume a new line will be added */
838     insert_line = 1;
839
840     /* Get register name */
841     pshader_get_register_name(iface, instr, regstr);
842     shader_arb_get_swizzle(instr, FALSE, swzstr);
843
844     switch (instr & WINED3DSP_SRCMOD_MASK) {
845     case WINED3DSPSM_NONE:
846         sprintf(outregstr, "%s%s", regstr, swzstr);
847         insert_line = 0;
848         break;
849     case WINED3DSPSM_NEG:
850         sprintf(outregstr, "-%s%s", regstr, swzstr);
851         insert_line = 0;
852         break;
853     case WINED3DSPSM_BIAS:
854         shader_addline(buffer, "ADD T%c, %s, -coefdiv.x;\n", 'A' + tmpreg, regstr);
855         break;
856     case WINED3DSPSM_BIASNEG:
857         shader_addline(buffer, "ADD T%c, -%s, coefdiv.x;\n", 'A' + tmpreg, regstr);
858         break;
859     case WINED3DSPSM_SIGN:
860         shader_addline(buffer, "MAD T%c, %s, coefmul.x, -one.x;\n", 'A' + tmpreg, regstr);
861         break;
862     case WINED3DSPSM_SIGNNEG:
863         shader_addline(buffer, "MAD T%c, %s, -coefmul.x, one.x;\n", 'A' + tmpreg, regstr);
864         break;
865     case WINED3DSPSM_COMP:
866         shader_addline(buffer, "SUB T%c, one.x, %s;\n", 'A' + tmpreg, regstr);
867         break;
868     case WINED3DSPSM_X2:
869         shader_addline(buffer, "ADD T%c, %s, %s;\n", 'A' + tmpreg, regstr, regstr);
870         break;
871     case WINED3DSPSM_X2NEG:
872         shader_addline(buffer, "ADD T%c, -%s, -%s;\n", 'A' + tmpreg, regstr, regstr);
873         break;
874     case WINED3DSPSM_DZ:
875         shader_addline(buffer, "RCP T%c, %s.z;\n", 'A' + tmpreg, regstr);
876         shader_addline(buffer, "MUL T%c, %s, T%c;\n", 'A' + tmpreg, regstr, 'A' + tmpreg);
877         break;
878     case WINED3DSPSM_DW:
879         shader_addline(buffer, "RCP T%c, %s.w;\n", 'A' + tmpreg, regstr);
880         shader_addline(buffer, "MUL T%c, %s, T%c;\n", 'A' + tmpreg, regstr, 'A' + tmpreg);
881         break;
882     default:
883         sprintf(outregstr, "%s%s", regstr, swzstr);
884         insert_line = 0;
885     }
886
887     /* Return modified or original register, with swizzle */
888     if (insert_line)
889         sprintf(outregstr, "T%c%s", 'A' + tmpreg, swzstr);
890 }
891
892 static inline void pshader_gen_output_modifier_line(
893     SHADER_BUFFER* buffer,
894     int saturate,
895     char *write_mask,
896     int shift,
897     char *regstr) {
898
899     /* Generate a line that does the output modifier computation */
900     shader_addline(buffer, "MUL%s %s%s, %s, %s;\n", saturate ? "_SAT" : "",
901         regstr, write_mask, regstr, shift_tab[shift]);
902 }
903
904 void pshader_hw_bem(SHADER_OPCODE_ARG* arg) {
905     IWineD3DPixelShaderImpl* This = (IWineD3DPixelShaderImpl*) arg->shader;
906
907     SHADER_BUFFER* buffer = arg->buffer;
908     char dst_name[50];
909     char src_name[2][50];
910     char dst_wmask[20];
911     DWORD sampler_code = arg->dst & WINED3DSP_REGNUM_MASK;
912     BOOL has_bumpmat = FALSE;
913     int i;
914
915     for(i = 0; i < This->numbumpenvmatconsts; i++) {
916         if(This->bumpenvmatconst[i].const_num != -1 && This->bumpenvmatconst[i].texunit == sampler_code) {
917             has_bumpmat = TRUE;
918             break;
919         }
920     }
921
922     pshader_get_register_name(arg->shader, arg->dst, dst_name);
923     shader_arb_get_write_mask(arg, arg->dst, dst_wmask);
924     strcat(dst_name, dst_wmask);
925
926     pshader_gen_input_modifier_line(arg->shader, buffer, arg->src[0], 0, src_name[0]);
927     pshader_gen_input_modifier_line(arg->shader, buffer, arg->src[1], 1, src_name[1]);
928
929     if(has_bumpmat) {
930         /* Sampling the perturbation map in Tsrc was done already, including the signedness correction if needed */
931         shader_addline(buffer, "SWZ TMP2, bumpenvmat%d, x, z, 0, 0;\n", sampler_code);
932         shader_addline(buffer, "DP3 TMP.r, TMP2, %s;\n", src_name[1]);
933         shader_addline(buffer, "SWZ TMP2, bumpenvmat%d, y, w, 0, 0;\n", sampler_code);
934         shader_addline(buffer, "DP3 TMP.g, TMP2, %s;\n", src_name[1]);
935
936         shader_addline(buffer, "ADD %s, %s, TMP;\n", dst_name, src_name[0]);
937     } else {
938         shader_addline(buffer, "MOV %s, %s;\n", dst_name, src_name[0]);
939     }
940 }
941
942 void pshader_hw_cnd(SHADER_OPCODE_ARG* arg) {
943
944     IWineD3DBaseShaderImpl* shader = (IWineD3DBaseShaderImpl*) arg->shader;
945     SHADER_BUFFER* buffer = arg->buffer;
946     char dst_wmask[20];
947     char dst_name[50];
948     char src_name[3][50];
949     BOOL sat = (arg->dst & WINED3DSP_DSTMOD_MASK) & WINED3DSPDM_SATURATE;
950     DWORD shift = (arg->dst & WINED3DSP_DSTSHIFT_MASK) >> WINED3DSP_DSTSHIFT_SHIFT;
951
952     /* FIXME: support output modifiers */
953
954     /* Handle output register */
955     pshader_get_register_name(arg->shader, arg->dst, dst_name);
956     shader_arb_get_write_mask(arg, arg->dst, dst_wmask);
957
958     /* Generate input register names (with modifiers) */
959     pshader_gen_input_modifier_line(arg->shader, buffer, arg->src[0], 0, src_name[0]);
960     pshader_gen_input_modifier_line(arg->shader, buffer, arg->src[1], 1, src_name[1]);
961     pshader_gen_input_modifier_line(arg->shader, buffer, arg->src[2], 2, src_name[2]);
962
963     /* The coissue flag changes the semantic of the cnd instruction in <= 1.3 shaders */
964     if (shader->baseShader.hex_version <= WINED3DPS_VERSION(1, 3) &&
965         arg->opcode_token & WINED3DSI_COISSUE) {
966         shader_addline(buffer, "MOV%s %s%s, %s;\n", sat ? "_SAT" : "", dst_name, dst_wmask, src_name[1]);
967     } else {
968         shader_addline(buffer, "ADD TMP, -%s, coefdiv.x;\n", src_name[0]);
969         shader_addline(buffer, "CMP%s %s%s, TMP, %s, %s;\n",
970                                 sat ? "_SAT" : "", dst_name, dst_wmask, src_name[1], src_name[2]);
971     }
972     if (shift != 0)
973         pshader_gen_output_modifier_line(buffer, FALSE, dst_wmask, shift, dst_name);
974 }
975
976 void pshader_hw_cmp(SHADER_OPCODE_ARG* arg) {
977
978     SHADER_BUFFER* buffer = arg->buffer;
979     char dst_wmask[20];
980     char dst_name[50];
981     char src_name[3][50];
982     DWORD shift = (arg->dst & WINED3DSP_DSTSHIFT_MASK) >> WINED3DSP_DSTSHIFT_SHIFT;
983     BOOL sat = (arg->dst & WINED3DSP_DSTMOD_MASK) & WINED3DSPDM_SATURATE;
984
985     /* FIXME: support output modifiers */
986
987     /* Handle output register */
988     pshader_get_register_name(arg->shader, arg->dst, dst_name);
989     shader_arb_get_write_mask(arg, arg->dst, dst_wmask);
990
991     /* Generate input register names (with modifiers) */
992     pshader_gen_input_modifier_line(arg->shader, buffer, arg->src[0], 0, src_name[0]);
993     pshader_gen_input_modifier_line(arg->shader, buffer, arg->src[1], 1, src_name[1]);
994     pshader_gen_input_modifier_line(arg->shader, buffer, arg->src[2], 2, src_name[2]);
995
996     shader_addline(buffer, "CMP%s %s%s, %s, %s, %s;\n", sat ? "_SAT" : "", dst_name, dst_wmask,
997                    src_name[0], src_name[2], src_name[1]);
998
999     if (shift != 0)
1000         pshader_gen_output_modifier_line(buffer, FALSE, dst_wmask, shift, dst_name);
1001 }
1002
1003 /** Process the WINED3DSIO_DP2ADD instruction in ARB.
1004  * dst = dot2(src0, src1) + src2 */
1005 void pshader_hw_dp2add(SHADER_OPCODE_ARG* arg) {
1006     SHADER_BUFFER* buffer = arg->buffer;
1007     char dst_wmask[20];
1008     char dst_name[50];
1009     char src_name[3][50];
1010     DWORD shift = (arg->dst & WINED3DSP_DSTSHIFT_MASK) >> WINED3DSP_DSTSHIFT_SHIFT;
1011     BOOL sat = (arg->dst & WINED3DSP_DSTMOD_MASK) & WINED3DSPDM_SATURATE;
1012
1013     pshader_get_register_name(arg->shader, arg->dst, dst_name);
1014     shader_arb_get_write_mask(arg, arg->dst, dst_wmask);
1015
1016     pshader_gen_input_modifier_line(arg->shader, buffer, arg->src[0], 0, src_name[0]);
1017     pshader_gen_input_modifier_line(arg->shader, buffer, arg->src[1], 1, src_name[1]);
1018     pshader_gen_input_modifier_line(arg->shader, buffer, arg->src[2], 2, src_name[2]);
1019
1020     /* Emulate a DP2 with a DP3 and 0.0 */
1021     shader_addline(buffer, "MOV TMP, %s;\n", src_name[0]);
1022     shader_addline(buffer, "MOV TMP.z, 0.0;\n");
1023     shader_addline(buffer, "DP3 TMP2, TMP, %s;\n", src_name[1]);
1024     shader_addline(buffer, "ADD%s %s%s, TMP2, %s;\n", sat ? "_SAT" : "", dst_name, dst_wmask, src_name[2]);
1025
1026     if (shift != 0)
1027         pshader_gen_output_modifier_line(buffer, FALSE, dst_wmask, shift, dst_name);
1028 }
1029
1030 /* Map the opcode 1-to-1 to the GL code */
1031 void pshader_hw_map2gl(SHADER_OPCODE_ARG* arg) {
1032
1033      CONST SHADER_OPCODE* curOpcode = arg->opcode;
1034      SHADER_BUFFER* buffer = arg->buffer;
1035      DWORD dst = arg->dst;
1036      DWORD* src = arg->src;
1037
1038      unsigned int i;
1039      char tmpLine[256];
1040
1041      /* Output token related */
1042      char output_rname[256];
1043      char output_wmask[20];
1044      BOOL saturate = FALSE;
1045      BOOL centroid = FALSE;
1046      BOOL partialprecision = FALSE;
1047      DWORD shift;
1048
1049      strcpy(tmpLine, curOpcode->glname);
1050
1051      /* Process modifiers */
1052      if (0 != (dst & WINED3DSP_DSTMOD_MASK)) {
1053          DWORD mask = dst & WINED3DSP_DSTMOD_MASK;
1054
1055          saturate = mask & WINED3DSPDM_SATURATE;
1056          centroid = mask & WINED3DSPDM_MSAMPCENTROID;
1057          partialprecision = mask & WINED3DSPDM_PARTIALPRECISION;
1058          mask &= ~(WINED3DSPDM_MSAMPCENTROID | WINED3DSPDM_PARTIALPRECISION | WINED3DSPDM_SATURATE);
1059          if (mask)
1060             FIXME("Unrecognized modifier(%#x)\n", mask >> WINED3DSP_DSTMOD_SHIFT);
1061
1062          if (centroid)
1063              FIXME("Unhandled modifier(%#x)\n", mask >> WINED3DSP_DSTMOD_SHIFT);
1064      }
1065      shift = (dst & WINED3DSP_DSTSHIFT_MASK) >> WINED3DSP_DSTSHIFT_SHIFT;
1066
1067       /* Generate input and output registers */
1068       if (curOpcode->num_params > 0) {
1069           char operands[4][100];
1070
1071           /* Generate input register names (with modifiers) */
1072           for (i = 1; i < curOpcode->num_params; ++i)
1073               pshader_gen_input_modifier_line(arg->shader, buffer, src[i-1], i-1, operands[i]);
1074
1075           /* Handle output register */
1076           pshader_get_register_name(arg->shader, dst, output_rname);
1077           strcpy(operands[0], output_rname);
1078           shader_arb_get_write_mask(arg, dst, output_wmask);
1079           strcat(operands[0], output_wmask);
1080
1081           if (saturate && (shift == 0))
1082              strcat(tmpLine, "_SAT");
1083           strcat(tmpLine, " ");
1084           strcat(tmpLine, operands[0]);
1085           for (i = 1; i < curOpcode->num_params; i++) {
1086               strcat(tmpLine, ", ");
1087               strcat(tmpLine, operands[i]);
1088           }
1089           strcat(tmpLine,";\n");
1090           shader_addline(buffer, tmpLine);
1091
1092           /* A shift requires another line. */
1093           if (shift != 0)
1094               pshader_gen_output_modifier_line(buffer, saturate, output_wmask, shift, output_rname);
1095       }
1096 }
1097
1098 void pshader_hw_texkill(SHADER_OPCODE_ARG* arg) {
1099     IWineD3DPixelShaderImpl* This = (IWineD3DPixelShaderImpl*) arg->shader;
1100     DWORD hex_version = This->baseShader.hex_version;
1101     SHADER_BUFFER* buffer = arg->buffer;
1102     char reg_dest[40];
1103
1104     /* No swizzles are allowed in d3d's texkill. PS 1.x ignores the 4th component as documented,
1105      * but >= 2.0 honors it(undocumented, but tested by the d3d9 testsuit)
1106      */
1107     pshader_get_register_name(arg->shader, arg->dst, reg_dest);
1108
1109     if(hex_version >= WINED3DPS_VERSION(2,0)) {
1110         /* The arb backend doesn't claim ps 2.0 support, but try to eat what the app feeds to us */
1111         shader_addline(buffer, "KIL %s;\n", reg_dest);
1112     } else {
1113         /* ARB fp doesn't like swizzles on the parameter of the KIL instruction. To mask the 4th component,
1114          * copy the register into our general purpose TMP variable, overwrite .w and pass TMP to KIL
1115          */
1116         shader_addline(buffer, "MOV TMP, %s;\n", reg_dest);
1117         shader_addline(buffer, "MOV TMP.w, one.w;\n");
1118         shader_addline(buffer, "KIL TMP;\n");
1119     }
1120 }
1121
1122 void pshader_hw_tex(SHADER_OPCODE_ARG* arg) {
1123     IWineD3DPixelShaderImpl* This = (IWineD3DPixelShaderImpl*) arg->shader;
1124     IWineD3DDeviceImpl* deviceImpl = (IWineD3DDeviceImpl*) This->baseShader.device;
1125
1126     DWORD dst = arg->dst;
1127     DWORD* src = arg->src;
1128     SHADER_BUFFER* buffer = arg->buffer;
1129     DWORD hex_version = This->baseShader.hex_version;
1130     BOOL projected = FALSE, bias = FALSE;
1131
1132     char reg_dest[40];
1133     char reg_coord[40];
1134     DWORD reg_dest_code;
1135     DWORD reg_sampler_code;
1136
1137     /* All versions have a destination register */
1138     reg_dest_code = dst & WINED3DSP_REGNUM_MASK;
1139     pshader_get_register_name(arg->shader, dst, reg_dest);
1140
1141     /* 1.0-1.3: Use destination register as coordinate source.
1142        1.4+: Use provided coordinate source register. */
1143    if (hex_version < WINED3DPS_VERSION(1,4))
1144       strcpy(reg_coord, reg_dest);
1145    else
1146       pshader_gen_input_modifier_line(arg->shader, buffer, src[0], 0, reg_coord);
1147
1148   /* 1.0-1.4: Use destination register number as texture code.
1149      2.0+: Use provided sampler number as texure code. */
1150   if (hex_version < WINED3DPS_VERSION(2,0))
1151      reg_sampler_code = reg_dest_code;
1152   else
1153      reg_sampler_code = src[1] & WINED3DSP_REGNUM_MASK;
1154
1155   /* projection flag:
1156    * 1.1, 1.2, 1.3: Use WINED3DTSS_TEXTURETRANSFORMFLAGS
1157    * 1.4: Use WINED3DSPSM_DZ or WINED3DSPSM_DW on src[0]
1158    * 2.0+: Use WINED3DSI_TEXLD_PROJECT on the opcode
1159    */
1160   if(hex_version < WINED3DPS_VERSION(1,4)) {
1161       DWORD flags = 0;
1162       if(reg_sampler_code < MAX_TEXTURES) {
1163         flags = deviceImpl->stateBlock->textureState[reg_sampler_code][WINED3DTSS_TEXTURETRANSFORMFLAGS];
1164       }
1165       if (flags & WINED3DTTFF_PROJECTED) {
1166           projected = TRUE;
1167       }
1168   } else if(hex_version < WINED3DPS_VERSION(2,0)) {
1169       DWORD src_mod = arg->src[0] & WINED3DSP_SRCMOD_MASK;
1170       if (src_mod == WINED3DSPSM_DZ) {
1171           projected = TRUE;
1172       } else if(src_mod == WINED3DSPSM_DW) {
1173           projected = TRUE;
1174       }
1175   } else {
1176       if(arg->opcode_token & WINED3DSI_TEXLD_PROJECT) {
1177           projected = TRUE;
1178       }
1179       if(arg->opcode_token & WINED3DSI_TEXLD_BIAS) {
1180           bias = TRUE;
1181       }
1182   }
1183   shader_hw_sample(arg, reg_sampler_code, reg_dest, reg_coord, projected, bias);
1184 }
1185
1186 void pshader_hw_texcoord(SHADER_OPCODE_ARG* arg) {
1187
1188     IWineD3DPixelShaderImpl* This = (IWineD3DPixelShaderImpl*) arg->shader;
1189     DWORD dst = arg->dst;
1190     SHADER_BUFFER* buffer = arg->buffer;
1191     DWORD hex_version = This->baseShader.hex_version;
1192
1193     char tmp[20];
1194     shader_arb_get_write_mask(arg, dst, tmp);
1195     if (hex_version != WINED3DPS_VERSION(1,4)) {
1196         DWORD reg = dst & WINED3DSP_REGNUM_MASK;
1197         shader_addline(buffer, "MOV_SAT T%u%s, fragment.texcoord[%u];\n", reg, tmp, reg);
1198     } else {
1199         DWORD reg1 = dst & WINED3DSP_REGNUM_MASK;
1200         char reg_src[40];
1201
1202         pshader_gen_input_modifier_line(arg->shader, buffer, arg->src[0], 0, reg_src);
1203         shader_addline(buffer, "MOV R%u%s, %s;\n", reg1, tmp, reg_src);
1204    }
1205 }
1206
1207 void pshader_hw_texreg2ar(SHADER_OPCODE_ARG* arg) {
1208
1209      SHADER_BUFFER* buffer = arg->buffer;
1210      IWineD3DPixelShaderImpl* This = (IWineD3DPixelShaderImpl*) arg->shader;
1211      IWineD3DDeviceImpl* deviceImpl = (IWineD3DDeviceImpl*) This->baseShader.device;
1212      DWORD flags;
1213
1214      DWORD reg1 = arg->dst & WINED3DSP_REGNUM_MASK;
1215      char dst_str[8];
1216      char src_str[50];
1217
1218      sprintf(dst_str, "T%u", reg1);
1219      pshader_gen_input_modifier_line(arg->shader, buffer, arg->src[0], 0, src_str);
1220      shader_addline(buffer, "MOV TMP.r, %s.a;\n", src_str);
1221      shader_addline(buffer, "MOV TMP.g, %s.r;\n", src_str);
1222      flags = reg1 < MAX_TEXTURES ? deviceImpl->stateBlock->textureState[reg1][WINED3DTSS_TEXTURETRANSFORMFLAGS] : 0;
1223      shader_hw_sample(arg, reg1, dst_str, "TMP", flags & WINED3DTTFF_PROJECTED, FALSE);
1224 }
1225
1226 void pshader_hw_texreg2gb(SHADER_OPCODE_ARG* arg) {
1227
1228      SHADER_BUFFER* buffer = arg->buffer;
1229      IWineD3DPixelShaderImpl* This = (IWineD3DPixelShaderImpl*) arg->shader;
1230      IWineD3DDeviceImpl* deviceImpl = (IWineD3DDeviceImpl*) This->baseShader.device;
1231      DWORD flags;
1232
1233      DWORD reg1 = arg->dst & WINED3DSP_REGNUM_MASK;
1234      char dst_str[8];
1235      char src_str[50];
1236
1237      sprintf(dst_str, "T%u", reg1);
1238      pshader_gen_input_modifier_line(arg->shader, buffer, arg->src[0], 0, src_str);
1239      shader_addline(buffer, "MOV TMP.r, %s.g;\n", src_str);
1240      shader_addline(buffer, "MOV TMP.g, %s.b;\n", src_str);
1241      flags = reg1 < MAX_TEXTURES ? deviceImpl->stateBlock->textureState[reg1][WINED3DTSS_TEXTURETRANSFORMFLAGS] : 0;
1242      shader_hw_sample(arg, reg1, dst_str, "TMP", FALSE, FALSE);
1243 }
1244
1245 void pshader_hw_texreg2rgb(SHADER_OPCODE_ARG* arg) {
1246
1247     SHADER_BUFFER* buffer = arg->buffer;
1248     IWineD3DPixelShaderImpl* This = (IWineD3DPixelShaderImpl*) arg->shader;
1249     IWineD3DDeviceImpl* deviceImpl = (IWineD3DDeviceImpl*) This->baseShader.device;
1250     DWORD flags;
1251     DWORD reg1 = arg->dst & WINED3DSP_REGNUM_MASK;
1252     char dst_str[8];
1253     char src_str[50];
1254
1255     sprintf(dst_str, "T%u", reg1);
1256     pshader_gen_input_modifier_line(arg->shader, buffer, arg->src[0], 0, src_str);
1257     flags = reg1 < MAX_TEXTURES ? deviceImpl->stateBlock->textureState[reg1][WINED3DTSS_TEXTURETRANSFORMFLAGS] : 0;
1258     shader_hw_sample(arg, reg1, dst_str, src_str, FALSE, FALSE);
1259 }
1260
1261 void pshader_hw_texbem(SHADER_OPCODE_ARG* arg) {
1262     IWineD3DPixelShaderImpl* This = (IWineD3DPixelShaderImpl*) arg->shader;
1263     BOOL has_bumpmat = FALSE;
1264     BOOL has_luminance = FALSE;
1265     int i;
1266
1267     DWORD dst = arg->dst;
1268     DWORD src = arg->src[0] & WINED3DSP_REGNUM_MASK;
1269     SHADER_BUFFER* buffer = arg->buffer;
1270
1271     char reg_coord[40];
1272     DWORD reg_dest_code;
1273
1274     /* All versions have a destination register */
1275     reg_dest_code = dst & WINED3DSP_REGNUM_MASK;
1276     /* Can directly use the name because texbem is only valid for <= 1.3 shaders */
1277     pshader_get_register_name(arg->shader, dst, reg_coord);
1278
1279     for(i = 0; i < This->numbumpenvmatconsts; i++) {
1280         if(This->bumpenvmatconst[i].const_num != -1 && reg_dest_code == This->bumpenvmatconst[i].texunit) {
1281             has_bumpmat = TRUE;
1282             break;
1283         }
1284     }
1285     for(i = 0; i < This->numbumpenvmatconsts; i++) {
1286         if(This->luminanceconst[i].const_num != -1 && reg_dest_code == This->luminanceconst[i].texunit) {
1287             has_luminance = TRUE;
1288             break;
1289         }
1290     }
1291
1292     if(has_bumpmat) {
1293         /* Sampling the perturbation map in Tsrc was done already, including the signedness correction if needed */
1294
1295         shader_addline(buffer, "SWZ TMP2, bumpenvmat%d, x, z, 0, 0;\n", reg_dest_code);
1296         shader_addline(buffer, "DP3 TMP.r, TMP2, T%u;\n", src);
1297         shader_addline(buffer, "SWZ TMP2, bumpenvmat%d, y, w, 0, 0;\n", reg_dest_code);
1298         shader_addline(buffer, "DP3 TMP.g, TMP2, T%u;\n", src);
1299
1300         /* with projective textures, texbem only divides the static texture coord, not the displacement,
1301          * so we can't let the GL handle this.
1302          */
1303         if (((IWineD3DDeviceImpl*) This->baseShader.device)->stateBlock->textureState[reg_dest_code][WINED3DTSS_TEXTURETRANSFORMFLAGS]
1304               & WINED3DTTFF_PROJECTED) {
1305             shader_addline(buffer, "RCP TMP2.a, %s.a;\n", reg_coord);
1306             shader_addline(buffer, "MUL TMP2.rg, %s, TMP2.a;\n", reg_coord);
1307             shader_addline(buffer, "ADD TMP.rg, TMP, TMP2;\n");
1308         } else {
1309             shader_addline(buffer, "ADD TMP.rg, TMP, %s;\n", reg_coord);
1310         }
1311
1312         shader_hw_sample(arg, reg_dest_code, reg_coord, "TMP", FALSE, FALSE);
1313
1314         if(arg->opcode->opcode == WINED3DSIO_TEXBEML && has_luminance) {
1315             shader_addline(buffer, "MAD TMP, T%u.z, luminance%d.x, luminance%d.y;\n",
1316                            src, reg_dest_code, reg_dest_code);
1317             shader_addline(buffer, "MUL %s, %s, TMP;\n", reg_coord, reg_coord);
1318         }
1319
1320     } else {
1321         DWORD tf;
1322         if(reg_dest_code < MAX_TEXTURES) {
1323             tf = ((IWineD3DDeviceImpl*) This->baseShader.device)->stateBlock->textureState[reg_dest_code][WINED3DTSS_TEXTURETRANSFORMFLAGS];
1324         } else {
1325             tf = 0;
1326         }
1327         /* Without a bump matrix loaded, just sample with the unmodified coordinates */
1328         shader_hw_sample(arg, reg_dest_code, reg_coord, reg_coord, tf & WINED3DTTFF_PROJECTED, FALSE);
1329     }
1330 }
1331
1332 void pshader_hw_texm3x2pad(SHADER_OPCODE_ARG* arg) {
1333
1334     DWORD reg = arg->dst & WINED3DSP_REGNUM_MASK;
1335     SHADER_BUFFER* buffer = arg->buffer;
1336     char src0_name[50];
1337
1338     pshader_gen_input_modifier_line(arg->shader, buffer, arg->src[0], 0, src0_name);
1339     shader_addline(buffer, "DP3 TMP.x, T%u, %s;\n", reg, src0_name);
1340 }
1341
1342 void pshader_hw_texm3x2tex(SHADER_OPCODE_ARG* arg) {
1343
1344     IWineD3DPixelShaderImpl* This = (IWineD3DPixelShaderImpl*) arg->shader;
1345     IWineD3DDeviceImpl* deviceImpl = (IWineD3DDeviceImpl*) This->baseShader.device;
1346     DWORD flags;
1347     DWORD reg = arg->dst & WINED3DSP_REGNUM_MASK;
1348     SHADER_BUFFER* buffer = arg->buffer;
1349     char dst_str[8];
1350     char src0_name[50];
1351
1352     sprintf(dst_str, "T%u", reg);
1353     pshader_gen_input_modifier_line(arg->shader, buffer, arg->src[0], 0, src0_name);
1354     shader_addline(buffer, "DP3 TMP.y, T%u, %s;\n", reg, src0_name);
1355     flags = reg < MAX_TEXTURES ? deviceImpl->stateBlock->textureState[reg][WINED3DTSS_TEXTURETRANSFORMFLAGS] : 0;
1356     shader_hw_sample(arg, reg, dst_str, "TMP", flags & WINED3DTTFF_PROJECTED, FALSE);
1357 }
1358
1359 void pshader_hw_texm3x3pad(SHADER_OPCODE_ARG* arg) {
1360
1361     IWineD3DPixelShaderImpl* This = (IWineD3DPixelShaderImpl*) arg->shader;
1362     DWORD reg = arg->dst & WINED3DSP_REGNUM_MASK;
1363     SHADER_BUFFER* buffer = arg->buffer;
1364     SHADER_PARSE_STATE* current_state = &This->baseShader.parse_state;
1365     char src0_name[50];
1366
1367     pshader_gen_input_modifier_line(arg->shader, buffer, arg->src[0], 0, src0_name);
1368     shader_addline(buffer, "DP3 TMP.%c, T%u, %s;\n", 'x' + current_state->current_row, reg, src0_name);
1369     current_state->texcoord_w[current_state->current_row++] = reg;
1370 }
1371
1372 void pshader_hw_texm3x3tex(SHADER_OPCODE_ARG* arg) {
1373
1374     IWineD3DPixelShaderImpl* This = (IWineD3DPixelShaderImpl*) arg->shader;
1375     IWineD3DDeviceImpl* deviceImpl = (IWineD3DDeviceImpl*) This->baseShader.device;
1376     DWORD flags;
1377     DWORD reg = arg->dst & WINED3DSP_REGNUM_MASK;
1378     SHADER_BUFFER* buffer = arg->buffer;
1379     SHADER_PARSE_STATE* current_state = &This->baseShader.parse_state;
1380     char dst_str[8];
1381     char src0_name[50];
1382
1383     pshader_gen_input_modifier_line(arg->shader, buffer, arg->src[0], 0, src0_name);
1384     shader_addline(buffer, "DP3 TMP.z, T%u, %s;\n", reg, src0_name);
1385
1386     /* Sample the texture using the calculated coordinates */
1387     sprintf(dst_str, "T%u", reg);
1388     flags = reg < MAX_TEXTURES ? deviceImpl->stateBlock->textureState[reg][WINED3DTSS_TEXTURETRANSFORMFLAGS] : 0;
1389     shader_hw_sample(arg, reg, dst_str, "TMP", flags & WINED3DTTFF_PROJECTED, FALSE);
1390     current_state->current_row = 0;
1391 }
1392
1393 void pshader_hw_texm3x3vspec(SHADER_OPCODE_ARG* arg) {
1394
1395     IWineD3DPixelShaderImpl* This = (IWineD3DPixelShaderImpl*) arg->shader;
1396     IWineD3DDeviceImpl* deviceImpl = (IWineD3DDeviceImpl*) This->baseShader.device;
1397     DWORD flags;
1398     DWORD reg = arg->dst & WINED3DSP_REGNUM_MASK;
1399     SHADER_BUFFER* buffer = arg->buffer;
1400     SHADER_PARSE_STATE* current_state = &This->baseShader.parse_state;
1401     char dst_str[8];
1402     char src0_name[50];
1403
1404     pshader_gen_input_modifier_line(arg->shader, buffer, arg->src[0], 0, src0_name);
1405     shader_addline(buffer, "DP3 TMP.z, T%u, %s;\n", reg, src0_name);
1406
1407     /* Construct the eye-ray vector from w coordinates */
1408     shader_addline(buffer, "MOV TMP2.x, fragment.texcoord[%u].w;\n", current_state->texcoord_w[0]);
1409     shader_addline(buffer, "MOV TMP2.y, fragment.texcoord[%u].w;\n", current_state->texcoord_w[1]);
1410     shader_addline(buffer, "MOV TMP2.z, fragment.texcoord[%u].w;\n", reg);
1411
1412     /* Calculate reflection vector
1413      */
1414     shader_addline(buffer, "DP3 TMP.w, TMP, TMP2;\n");
1415     /* The .w is ignored when sampling, so I can use TMP2.w to calculate dot(N, N) */
1416     shader_addline(buffer, "DP3 TMP2.w, TMP, TMP;\n");
1417     shader_addline(buffer, "RCP TMP2.w, TMP2.w;\n");
1418     shader_addline(buffer, "MUL TMP.w, TMP.w, TMP2.w;\n");
1419     shader_addline(buffer, "MUL TMP, TMP.w, TMP;\n");
1420     shader_addline(buffer, "MAD TMP, coefmul.x, TMP, -TMP2;\n");
1421
1422     /* Sample the texture using the calculated coordinates */
1423     sprintf(dst_str, "T%u", reg);
1424     flags = reg < MAX_TEXTURES ? deviceImpl->stateBlock->textureState[reg][WINED3DTSS_TEXTURETRANSFORMFLAGS] : 0;
1425     shader_hw_sample(arg, reg, dst_str, "TMP", flags & WINED3DTTFF_PROJECTED, FALSE);
1426     current_state->current_row = 0;
1427 }
1428
1429 void pshader_hw_texm3x3spec(SHADER_OPCODE_ARG* arg) {
1430
1431     IWineD3DPixelShaderImpl* This = (IWineD3DPixelShaderImpl*) arg->shader;
1432     IWineD3DDeviceImpl* deviceImpl = (IWineD3DDeviceImpl*) This->baseShader.device;
1433     DWORD flags;
1434     DWORD reg = arg->dst & WINED3DSP_REGNUM_MASK;
1435     DWORD reg3 = arg->src[1] & WINED3DSP_REGNUM_MASK;
1436     SHADER_PARSE_STATE* current_state = &This->baseShader.parse_state;
1437     SHADER_BUFFER* buffer = arg->buffer;
1438     char dst_str[8];
1439     char src0_name[50];
1440
1441     pshader_gen_input_modifier_line(arg->shader, buffer, arg->src[0], 0, src0_name);
1442     shader_addline(buffer, "DP3 TMP.z, T%u, %s;\n", reg, src0_name);
1443
1444     /* Calculate reflection vector.
1445      *
1446      *               dot(N, E)
1447      * TMP.xyz = 2 * --------- * N - E
1448      *               dot(N, N)
1449      *
1450      * Which normalizes the normal vector
1451      */
1452     shader_addline(buffer, "DP3 TMP.w, TMP, C[%u];\n", reg3);
1453     shader_addline(buffer, "DP3 TMP2.w, TMP, TMP;\n");
1454     shader_addline(buffer, "RCP TMP2.w, TMP2.w;\n");
1455     shader_addline(buffer, "MUL TMP.w, TMP.w, TMP2.w;\n");
1456     shader_addline(buffer, "MUL TMP, TMP.w, TMP;\n");
1457     shader_addline(buffer, "MAD TMP, coefmul.x, TMP, -C[%u];\n", reg3);
1458
1459     /* Sample the texture using the calculated coordinates */
1460     sprintf(dst_str, "T%u", reg);
1461     flags = reg < MAX_TEXTURES ? deviceImpl->stateBlock->textureState[reg][WINED3DTSS_TEXTURETRANSFORMFLAGS] : 0;
1462     shader_hw_sample(arg, reg, dst_str, "TMP", flags & WINED3DTTFF_PROJECTED, FALSE);
1463     current_state->current_row = 0;
1464 }
1465
1466 void pshader_hw_texdepth(SHADER_OPCODE_ARG* arg) {
1467     SHADER_BUFFER* buffer = arg->buffer;
1468     char dst_name[50];
1469
1470     /* texdepth has an implicit destination, the fragment depth value. It's only parameter,
1471      * which is essentially an input, is the destination register because it is the first
1472      * parameter. According to the msdn, this must be register r5, but let's keep it more flexible
1473      * here
1474      */
1475     pshader_get_register_name(arg->shader, arg->dst, dst_name);
1476
1477     /* According to the msdn, the source register(must be r5) is unusable after
1478      * the texdepth instruction, so we're free to modify it
1479      */
1480     shader_addline(buffer, "MIN %s.g, %s.g, one.g;\n", dst_name, dst_name);
1481
1482     /* How to deal with the special case dst_name.g == 0? if r != 0, then
1483      * the r * (1 / 0) will give infinity, which is clamped to 1.0, the correct
1484      * result. But if r = 0.0, then 0 * inf = 0, which is incorrect.
1485      */
1486     shader_addline(buffer, "RCP %s.g, %s.g;\n", dst_name, dst_name);
1487     shader_addline(buffer, "MUL TMP.x, %s.r, %s.g;\n", dst_name, dst_name);
1488     shader_addline(buffer, "MIN TMP.x, TMP.x, one.r;\n");
1489     shader_addline(buffer, "MAX result.depth, TMP.x, 0.0;\n");
1490 }
1491
1492 /** Process the WINED3DSIO_TEXDP3TEX instruction in ARB:
1493  * Take a 3-component dot product of the TexCoord[dstreg] and src,
1494  * then perform a 1D texture lookup from stage dstregnum, place into dst. */
1495 void pshader_hw_texdp3tex(SHADER_OPCODE_ARG* arg) {
1496     SHADER_BUFFER* buffer = arg->buffer;
1497     DWORD sampler_idx = arg->dst & WINED3DSP_REGNUM_MASK;
1498     char src0[50];
1499     char dst_str[8];
1500
1501     pshader_gen_input_modifier_line(arg->shader, buffer, arg->src[0], 0, src0);
1502     shader_addline(buffer, "MOV TMP, 0.0;\n");
1503     shader_addline(buffer, "DP3 TMP.x, T%u, %s;\n", sampler_idx, src0);
1504
1505     sprintf(dst_str, "T%u", sampler_idx);
1506     shader_hw_sample(arg, sampler_idx, dst_str, "TMP", FALSE /* Only one coord, can't be projected */, FALSE);
1507 }
1508
1509 /** Process the WINED3DSIO_TEXDP3 instruction in ARB:
1510  * Take a 3-component dot product of the TexCoord[dstreg] and src. */
1511 void pshader_hw_texdp3(SHADER_OPCODE_ARG* arg) {
1512     char src0[50];
1513     char dst_str[50];
1514     char dst_mask[6];
1515     DWORD dstreg = arg->dst & WINED3DSP_REGNUM_MASK;
1516     SHADER_BUFFER* buffer = arg->buffer;
1517
1518     /* Handle output register */
1519     pshader_get_register_name(arg->shader, arg->dst, dst_str);
1520     shader_arb_get_write_mask(arg, arg->dst, dst_mask);
1521
1522     pshader_gen_input_modifier_line(arg->shader, buffer, arg->src[0], 0, src0);
1523     shader_addline(buffer, "DP3 %s%s, T%u, %s;\n", dst_str, dst_mask, dstreg, src0);
1524
1525     /* TODO: Handle output modifiers */
1526 }
1527
1528 /** Process the WINED3DSIO_TEXM3X3 instruction in ARB
1529  * Perform the 3rd row of a 3x3 matrix multiply */
1530 void pshader_hw_texm3x3(SHADER_OPCODE_ARG* arg) {
1531     SHADER_BUFFER* buffer = arg->buffer;
1532     char dst_str[50];
1533     char dst_mask[6];
1534     char src0[50];
1535     DWORD dst_reg = arg->dst & WINED3DSP_REGNUM_MASK;
1536
1537     pshader_get_register_name(arg->shader, arg->dst, dst_str);
1538     shader_arb_get_write_mask(arg, arg->dst, dst_mask);
1539
1540     pshader_gen_input_modifier_line(arg->shader, buffer, arg->src[0], 0, src0);
1541     shader_addline(buffer, "DP3 TMP.z, T%u, %s;\n", dst_reg, src0);
1542     shader_addline(buffer, "MOV %s%s, TMP;\n", dst_str, dst_mask);
1543
1544     /* TODO: Handle output modifiers */
1545 }
1546
1547 /** Process the WINED3DSIO_TEXM3X2DEPTH instruction in ARB:
1548  * Last row of a 3x2 matrix multiply, use the result to calculate the depth:
1549  * Calculate tmp0.y = TexCoord[dstreg] . src.xyz;  (tmp0.x has already been calculated)
1550  * depth = (tmp0.y == 0.0) ? 1.0 : tmp0.x / tmp0.y
1551  */
1552 void pshader_hw_texm3x2depth(SHADER_OPCODE_ARG* arg) {
1553     SHADER_BUFFER* buffer = arg->buffer;
1554     DWORD dst_reg = arg->dst & WINED3DSP_REGNUM_MASK;
1555     char src0[50];
1556
1557     pshader_gen_input_modifier_line(arg->shader, buffer, arg->src[0], 0, src0);
1558     shader_addline(buffer, "DP3 TMP.y, T%u, %s;\n", dst_reg, src0);
1559
1560     /* How to deal with the special case dst_name.g == 0? if r != 0, then
1561      * the r * (1 / 0) will give infinity, which is clamped to 1.0, the correct
1562      * result. But if r = 0.0, then 0 * inf = 0, which is incorrect.
1563      */
1564     shader_addline(buffer, "RCP TMP.y, TMP.y;\n");
1565     shader_addline(buffer, "MUL TMP.x, TMP.x, TMP.y;\n");
1566     shader_addline(buffer, "MIN TMP.x, TMP.x, one.r;\n");
1567     shader_addline(buffer, "MAX result.depth, TMP.x, 0.0;\n");
1568 }
1569
1570 /** Handles transforming all WINED3DSIO_M?x? opcodes for
1571     Vertex/Pixel shaders to ARB_vertex_program codes */
1572 void shader_hw_mnxn(SHADER_OPCODE_ARG* arg) {
1573
1574     int i;
1575     int nComponents = 0;
1576     SHADER_OPCODE_ARG tmpArg;
1577
1578     memset(&tmpArg, 0, sizeof(SHADER_OPCODE_ARG));
1579
1580     /* Set constants for the temporary argument */
1581     tmpArg.shader      = arg->shader;
1582     tmpArg.buffer      = arg->buffer;
1583     tmpArg.src[0]      = arg->src[0];
1584     tmpArg.src_addr[0] = arg->src_addr[0];
1585     tmpArg.src_addr[1] = arg->src_addr[1];
1586     tmpArg.reg_maps = arg->reg_maps;
1587
1588     switch(arg->opcode->opcode) {
1589     case WINED3DSIO_M4x4:
1590         nComponents = 4;
1591         tmpArg.opcode = shader_get_opcode(arg->shader, WINED3DSIO_DP4);
1592         break;
1593     case WINED3DSIO_M4x3:
1594         nComponents = 3;
1595         tmpArg.opcode = shader_get_opcode(arg->shader, WINED3DSIO_DP4);
1596         break;
1597     case WINED3DSIO_M3x4:
1598         nComponents = 4;
1599         tmpArg.opcode = shader_get_opcode(arg->shader, WINED3DSIO_DP3);
1600         break;
1601     case WINED3DSIO_M3x3:
1602         nComponents = 3;
1603         tmpArg.opcode = shader_get_opcode(arg->shader, WINED3DSIO_DP3);
1604         break;
1605     case WINED3DSIO_M3x2:
1606         nComponents = 2;
1607         tmpArg.opcode = shader_get_opcode(arg->shader, WINED3DSIO_DP3);
1608         break;
1609     default:
1610         break;
1611     }
1612
1613     for (i = 0; i < nComponents; i++) {
1614         tmpArg.dst = ((arg->dst) & ~WINED3DSP_WRITEMASK_ALL)|(WINED3DSP_WRITEMASK_0<<i);
1615         tmpArg.src[1] = arg->src[1]+i;
1616         vshader_hw_map2gl(&tmpArg);
1617     }
1618 }
1619
1620 void vshader_hw_rsq_rcp(SHADER_OPCODE_ARG* arg) {
1621     CONST SHADER_OPCODE* curOpcode = arg->opcode;
1622     SHADER_BUFFER* buffer = arg->buffer;
1623     DWORD dst = arg->dst;
1624     DWORD src = arg->src[0];
1625     DWORD swizzle = (src & WINED3DSP_SWIZZLE_MASK) >> WINED3DSP_SWIZZLE_SHIFT;
1626
1627     char tmpLine[256];
1628
1629     strcpy(tmpLine, curOpcode->glname); /* Opcode */
1630     vshader_program_add_param(arg, dst, FALSE, tmpLine); /* Destination */
1631     strcat(tmpLine, ",");
1632     vshader_program_add_param(arg, src, TRUE, tmpLine);
1633     if ((WINED3DSP_NOSWIZZLE >> WINED3DSP_SWIZZLE_SHIFT) == swizzle) {
1634         /* Dx sdk says .x is used if no swizzle is given, but our test shows that
1635          * .w is used
1636          */
1637         strcat(tmpLine, ".w");
1638     }
1639
1640     shader_addline(buffer, "%s;\n", tmpLine);
1641 }
1642
1643 void shader_hw_nrm(SHADER_OPCODE_ARG* arg) {
1644     SHADER_BUFFER* buffer = arg->buffer;
1645     char dst_name[50];
1646     char src_name[50];
1647     char dst_wmask[20];
1648     DWORD shift = (arg->dst & WINED3DSP_DSTSHIFT_MASK) >> WINED3DSP_DSTSHIFT_SHIFT;
1649     BOOL sat = (arg->dst & WINED3DSP_DSTMOD_MASK) & WINED3DSPDM_SATURATE;
1650
1651     pshader_get_register_name(arg->shader, arg->dst, dst_name);
1652     shader_arb_get_write_mask(arg, arg->dst, dst_wmask);
1653
1654     pshader_gen_input_modifier_line(arg->shader, buffer, arg->src[0], 0, src_name);
1655     shader_addline(buffer, "DP3 TMP, %s, %s;\n", src_name, src_name);
1656     shader_addline(buffer, "RSQ TMP, TMP.x;\n");
1657     /* dst.w = src[0].w * 1 / (src.x^2 + src.y^2 + src.z^2)^(1/2) according to msdn*/
1658     shader_addline(buffer, "MUL%s %s%s, %s, TMP;\n", sat ? "_SAT" : "", dst_name, dst_wmask,
1659                    src_name);
1660
1661     if (shift != 0)
1662         pshader_gen_output_modifier_line(buffer, FALSE, dst_wmask, shift, dst_name);
1663 }
1664
1665 void shader_hw_sincos(SHADER_OPCODE_ARG* arg) {
1666     /* This instruction exists in ARB, but the d3d instruction takes two extra parameters which
1667      * must contain fixed constants. So we need a separate function to filter those constants and
1668      * can't use map2gl
1669      */
1670     SHADER_BUFFER* buffer = arg->buffer;
1671     char dst_name[50];
1672     char src_name[50];
1673     char dst_wmask[20];
1674     DWORD shift = (arg->dst & WINED3DSP_DSTSHIFT_MASK) >> WINED3DSP_DSTSHIFT_SHIFT;
1675     BOOL sat = (arg->dst & WINED3DSP_DSTMOD_MASK) & WINED3DSPDM_SATURATE;
1676
1677     pshader_get_register_name(arg->shader, arg->dst, dst_name);
1678     shader_arb_get_write_mask(arg, arg->dst, dst_wmask);
1679
1680     pshader_gen_input_modifier_line(arg->shader, buffer, arg->src[0], 0, src_name);
1681     shader_addline(buffer, "SCS%s %s%s, %s;\n", sat ? "_SAT" : "", dst_name, dst_wmask,
1682                    src_name);
1683
1684     if (shift != 0)
1685         pshader_gen_output_modifier_line(buffer, FALSE, dst_wmask, shift, dst_name);
1686
1687 }
1688
1689 /* TODO: merge with pixel shader */
1690 /* Map the opcode 1-to-1 to the GL code */
1691 void vshader_hw_map2gl(SHADER_OPCODE_ARG* arg) {
1692
1693     IWineD3DVertexShaderImpl *shader = (IWineD3DVertexShaderImpl*) arg->shader;
1694     CONST SHADER_OPCODE* curOpcode = arg->opcode;
1695     SHADER_BUFFER* buffer = arg->buffer;
1696     DWORD dst = arg->dst;
1697     DWORD* src = arg->src;
1698
1699     DWORD dst_regtype = shader_get_regtype(dst);
1700     char tmpLine[256];
1701     unsigned int i;
1702
1703     if ((curOpcode->opcode == WINED3DSIO_MOV && dst_regtype == WINED3DSPR_ADDR) || curOpcode->opcode == WINED3DSIO_MOVA) {
1704         if(shader->rel_offset) {
1705             memset(tmpLine, 0, sizeof(tmpLine));
1706             vshader_program_add_param(arg, src[0], TRUE, tmpLine);
1707             shader_addline(buffer, "ADD TMP.x, %s, helper_const.z;\n", tmpLine);
1708             shader_addline(buffer, "ARL A0.x, TMP.x;\n");
1709             return;
1710         } else {
1711             strcpy(tmpLine, "ARL");
1712         }
1713     } else
1714         strcpy(tmpLine, curOpcode->glname);
1715
1716     if (curOpcode->num_params > 0) {
1717         vshader_program_add_param(arg, dst, FALSE, tmpLine);
1718         for (i = 1; i < curOpcode->num_params; ++i) {
1719            strcat(tmpLine, ",");
1720            vshader_program_add_param(arg, src[i-1], TRUE, tmpLine);
1721         }
1722     }
1723    shader_addline(buffer, "%s;\n", tmpLine);
1724 }
1725
1726 static GLuint create_arb_blt_vertex_program(WineD3D_GL_Info *gl_info) {
1727     GLuint program_id = 0;
1728     const char *blt_vprogram =
1729         "!!ARBvp1.0\n"
1730         "PARAM c[1] = { { 1, 0.5 } };\n"
1731         "MOV result.position, vertex.position;\n"
1732         "MOV result.color, c[0].x;\n"
1733         "MAD result.texcoord[0].y, -vertex.position, c[0], c[0];\n"
1734         "MAD result.texcoord[0].x, vertex.position, c[0].y, c[0].y;\n"
1735         "END\n";
1736
1737     GL_EXTCALL(glGenProgramsARB(1, &program_id));
1738     GL_EXTCALL(glBindProgramARB(GL_VERTEX_PROGRAM_ARB, program_id));
1739     GL_EXTCALL(glProgramStringARB(GL_VERTEX_PROGRAM_ARB, GL_PROGRAM_FORMAT_ASCII_ARB, strlen(blt_vprogram), blt_vprogram));
1740
1741     if (glGetError() == GL_INVALID_OPERATION) {
1742         GLint pos;
1743         glGetIntegerv(GL_PROGRAM_ERROR_POSITION_ARB, &pos);
1744         FIXME("Vertex program error at position %d: %s\n", pos,
1745             debugstr_a((const char *)glGetString(GL_PROGRAM_ERROR_STRING_ARB)));
1746     }
1747
1748     return program_id;
1749 }
1750
1751 static GLuint create_arb_blt_fragment_program(WineD3D_GL_Info *gl_info) {
1752     GLuint program_id = 0;
1753     const char *blt_fprogram =
1754         "!!ARBfp1.0\n"
1755         "TEMP R0;\n"
1756         "TEX R0.x, fragment.texcoord[0], texture[0], 2D;\n"
1757         "MOV result.depth.z, R0.x;\n"
1758         "END\n";
1759
1760     GL_EXTCALL(glGenProgramsARB(1, &program_id));
1761     GL_EXTCALL(glBindProgramARB(GL_FRAGMENT_PROGRAM_ARB, program_id));
1762     GL_EXTCALL(glProgramStringARB(GL_FRAGMENT_PROGRAM_ARB, GL_PROGRAM_FORMAT_ASCII_ARB, strlen(blt_fprogram), blt_fprogram));
1763
1764     if (glGetError() == GL_INVALID_OPERATION) {
1765         GLint pos;
1766         glGetIntegerv(GL_PROGRAM_ERROR_POSITION_ARB, &pos);
1767         FIXME("Fragment program error at position %d: %s\n", pos,
1768             debugstr_a((const char *)glGetString(GL_PROGRAM_ERROR_STRING_ARB)));
1769     }
1770
1771     return program_id;
1772 }
1773
1774 static void shader_arb_select(IWineD3DDevice *iface, BOOL usePS, BOOL useVS) {
1775     IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
1776     WineD3D_GL_Info *gl_info = &This->adapter->gl_info;
1777
1778     if (useVS) {
1779         TRACE("Using vertex shader\n");
1780
1781         /* Bind the vertex program */
1782         GL_EXTCALL(glBindProgramARB(GL_VERTEX_PROGRAM_ARB,
1783             ((IWineD3DVertexShaderImpl *)This->stateBlock->vertexShader)->baseShader.prgId));
1784         checkGLcall("glBindProgramARB(GL_VERTEX_PROGRAM_ARB, vertexShader->prgId);");
1785
1786         /* Enable OpenGL vertex programs */
1787         glEnable(GL_VERTEX_PROGRAM_ARB);
1788         checkGLcall("glEnable(GL_VERTEX_PROGRAM_ARB);");
1789         TRACE("(%p) : Bound vertex program %u and enabled GL_VERTEX_PROGRAM_ARB\n",
1790             This, ((IWineD3DVertexShaderImpl *)This->stateBlock->vertexShader)->baseShader.prgId);
1791     } else if(GL_SUPPORT(ARB_VERTEX_PROGRAM)) {
1792         glDisable(GL_VERTEX_PROGRAM_ARB);
1793         checkGLcall("glDisable(GL_VERTEX_PROGRAM_ARB)");
1794     }
1795
1796     if (usePS) {
1797         TRACE("Using pixel shader\n");
1798
1799         /* Bind the fragment program */
1800         GL_EXTCALL(glBindProgramARB(GL_FRAGMENT_PROGRAM_ARB,
1801             ((IWineD3DPixelShaderImpl *)This->stateBlock->pixelShader)->baseShader.prgId));
1802         checkGLcall("glBindProgramARB(GL_FRAGMENT_PROGRAM_ARB, pixelShader->prgId);");
1803
1804         /* Enable OpenGL fragment programs */
1805         glEnable(GL_FRAGMENT_PROGRAM_ARB);
1806         checkGLcall("glEnable(GL_FRAGMENT_PROGRAM_ARB);");
1807         TRACE("(%p) : Bound fragment program %u and enabled GL_FRAGMENT_PROGRAM_ARB\n",
1808             This, ((IWineD3DPixelShaderImpl *)This->stateBlock->pixelShader)->baseShader.prgId);
1809     } else if(GL_SUPPORT(ARB_FRAGMENT_PROGRAM)) {
1810         glDisable(GL_FRAGMENT_PROGRAM_ARB);
1811         checkGLcall("glDisable(GL_FRAGMENT_PROGRAM_ARB)");
1812     }
1813 }
1814
1815 static void shader_arb_select_depth_blt(IWineD3DDevice *iface) {
1816     IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
1817     struct shader_arb_priv *priv = (struct shader_arb_priv *) This->shader_priv;
1818     WineD3D_GL_Info *gl_info = &This->adapter->gl_info;
1819
1820     if (!priv->depth_blt_vprogram_id) priv->depth_blt_vprogram_id = create_arb_blt_vertex_program(gl_info);
1821     GL_EXTCALL(glBindProgramARB(GL_VERTEX_PROGRAM_ARB, priv->depth_blt_vprogram_id));
1822     glEnable(GL_VERTEX_PROGRAM_ARB);
1823
1824     if (!priv->depth_blt_fprogram_id) priv->depth_blt_fprogram_id = create_arb_blt_fragment_program(gl_info);
1825     GL_EXTCALL(glBindProgramARB(GL_FRAGMENT_PROGRAM_ARB, priv->depth_blt_fprogram_id));
1826     glEnable(GL_FRAGMENT_PROGRAM_ARB);
1827 }
1828
1829 static void shader_arb_destroy_depth_blt(IWineD3DDevice *iface) {
1830     IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
1831     struct shader_arb_priv *priv = (struct shader_arb_priv *) This->shader_priv;
1832     WineD3D_GL_Info *gl_info = &This->adapter->gl_info;
1833
1834     if(priv->depth_blt_vprogram_id) {
1835         GL_EXTCALL(glDeleteProgramsARB(1, &priv->depth_blt_vprogram_id));
1836         priv->depth_blt_vprogram_id = 0;
1837     }
1838     if(priv->depth_blt_fprogram_id) {
1839         GL_EXTCALL(glDeleteProgramsARB(1, &priv->depth_blt_fprogram_id));
1840         priv->depth_blt_fprogram_id = 0;
1841     }
1842 }
1843
1844 static void shader_arb_cleanup(IWineD3DDevice *iface) {
1845     IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
1846     WineD3D_GL_Info *gl_info = &This->adapter->gl_info;
1847     if (GL_SUPPORT(ARB_VERTEX_PROGRAM)) glDisable(GL_VERTEX_PROGRAM_ARB);
1848     if (GL_SUPPORT(ARB_FRAGMENT_PROGRAM)) glDisable(GL_FRAGMENT_PROGRAM_ARB);
1849 }
1850
1851 static void shader_arb_destroy(IWineD3DBaseShader *iface) {
1852     IWineD3DBaseShaderImpl *This = (IWineD3DBaseShaderImpl *) iface;
1853     WineD3D_GL_Info *gl_info = &((IWineD3DDeviceImpl *) This->baseShader.device)->adapter->gl_info;
1854
1855     ENTER_GL();
1856     GL_EXTCALL(glDeleteProgramsARB(1, &This->baseShader.prgId));
1857     checkGLcall("GL_EXTCALL(glDeleteProgramsARB(1, &This->baseShader.prgId))");
1858     LEAVE_GL();
1859     This->baseShader.prgId = 0;
1860     This->baseShader.is_compiled = FALSE;
1861 }
1862
1863 static HRESULT shader_arb_alloc(IWineD3DDevice *iface) {
1864     IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
1865     This->shader_priv = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(struct shader_arb_priv));
1866     return WINED3D_OK;
1867 }
1868
1869 static void shader_arb_free(IWineD3DDevice *iface) {
1870     IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
1871     HeapFree(GetProcessHeap(), 0, This->shader_priv);
1872 }
1873
1874 static BOOL shader_arb_dirty_const(IWineD3DDevice *iface) {
1875     return TRUE;
1876 }
1877
1878 static void shader_arb_generate_pshader(IWineD3DPixelShader *iface, SHADER_BUFFER *buffer) {
1879     IWineD3DPixelShaderImpl *This = (IWineD3DPixelShaderImpl *)iface;
1880     shader_reg_maps* reg_maps = &This->baseShader.reg_maps;
1881     CONST DWORD *function = This->baseShader.function;
1882     const char *fragcolor;
1883     WineD3D_GL_Info *gl_info = &((IWineD3DDeviceImpl *)This->baseShader.device)->adapter->gl_info;
1884
1885     /*  Create the hw ARB shader */
1886     shader_addline(buffer, "!!ARBfp1.0\n");
1887
1888     shader_addline(buffer, "TEMP TMP;\n");     /* Used in matrix ops */
1889     shader_addline(buffer, "TEMP TMP2;\n");    /* Used in matrix ops */
1890     shader_addline(buffer, "TEMP TA;\n");      /* Used for modifiers */
1891     shader_addline(buffer, "TEMP TB;\n");      /* Used for modifiers */
1892     shader_addline(buffer, "TEMP TC;\n");      /* Used for modifiers */
1893     shader_addline(buffer, "PARAM coefdiv = { 0.5, 0.25, 0.125, 0.0625 };\n");
1894     shader_addline(buffer, "PARAM coefmul = { 2, 4, 8, 16 };\n");
1895     shader_addline(buffer, "PARAM one = { 1.0, 1.0, 1.0, 1.0 };\n");
1896
1897     /* Base Declarations */
1898     shader_generate_arb_declarations( (IWineD3DBaseShader*) This, reg_maps, buffer, &GLINFO_LOCATION);
1899
1900     /* We need two variables for fog blending */
1901     shader_addline(buffer, "TEMP TMP_FOG;\n");
1902     if (This->baseShader.hex_version >= WINED3DPS_VERSION(2,0)) {
1903         shader_addline(buffer, "TEMP TMP_COLOR;\n");
1904     }
1905
1906     /* Base Shader Body */
1907     shader_generate_main( (IWineD3DBaseShader*) This, buffer, reg_maps, function);
1908
1909     /* calculate fog and blend it
1910      * NOTE: state.fog.params.y and state.fog.params.z don't hold fog start s and end e but
1911      * -1/(e-s) and e/(e-s) respectively.
1912      */
1913     shader_addline(buffer, "MAD_SAT TMP_FOG, fragment.fogcoord, state.fog.params.y, state.fog.params.z;\n");
1914
1915     if (This->baseShader.hex_version < WINED3DPS_VERSION(2,0)) {
1916         fragcolor = "R0";
1917     } else {
1918         fragcolor = "TMP_COLOR";
1919     }
1920     if(This->srgb_enabled) {
1921         /* Perform sRGB write correction. See GLX_EXT_framebuffer_sRGB */
1922
1923         /* Calculate the > 0.0031308 case */
1924         shader_addline(buffer, "POW TMP.x, %s.x, srgb_pow.x;\n", fragcolor);
1925         shader_addline(buffer, "POW TMP.y, %s.y, srgb_pow.y;\n", fragcolor);
1926         shader_addline(buffer, "POW TMP.z, %s.z, srgb_pow.z;\n", fragcolor);
1927         shader_addline(buffer, "MUL TMP, TMP, srgb_mul_hi;\n");
1928         shader_addline(buffer, "SUB TMP, TMP, srgb_sub_hi;\n");
1929         /* Calculate the < case */
1930         shader_addline(buffer, "MUL TMP2, srgb_mul_low, %s;\n", fragcolor);
1931         /* Get 1.0 / 0.0 masks for > 0.0031308 and < 0.0031308 */
1932         shader_addline(buffer, "SLT TA, srgb_comparison, %s;\n", fragcolor);
1933         shader_addline(buffer, "SGE TB, srgb_comparison, %s;\n", fragcolor);
1934         /* Store the components > 0.0031308 in the destination */
1935         shader_addline(buffer, "MUL %s, TMP, TA;\n", fragcolor);
1936         /* Add the components that are < 0.0031308 */
1937         shader_addline(buffer, "MAD result.color.xyz, TMP2, TB, %s;\n", fragcolor);
1938         /* [0.0;1.0] clamping. Not needed, this is done implicitly */
1939     }
1940     if (This->baseShader.hex_version < WINED3DPS_VERSION(3,0)) {
1941         shader_addline(buffer, "LRP result.color.rgb, TMP_FOG.x, %s, state.fog.color;\n", fragcolor);
1942         shader_addline(buffer, "MOV result.color.a, %s.a;\n", fragcolor);
1943     }
1944
1945     shader_addline(buffer, "END\n");
1946
1947     /* TODO: change to resource.glObjectHandle or something like that */
1948     GL_EXTCALL(glGenProgramsARB(1, &This->baseShader.prgId));
1949
1950     TRACE("Creating a hw pixel shader, prg=%d\n", This->baseShader.prgId);
1951     GL_EXTCALL(glBindProgramARB(GL_FRAGMENT_PROGRAM_ARB, This->baseShader.prgId));
1952
1953     TRACE("Created hw pixel shader, prg=%d\n", This->baseShader.prgId);
1954     /* Create the program and check for errors */
1955     GL_EXTCALL(glProgramStringARB(GL_FRAGMENT_PROGRAM_ARB, GL_PROGRAM_FORMAT_ASCII_ARB,
1956                buffer->bsize, buffer->buffer));
1957
1958     if (glGetError() == GL_INVALID_OPERATION) {
1959         GLint errPos;
1960         glGetIntegerv(GL_PROGRAM_ERROR_POSITION_ARB, &errPos);
1961         FIXME("HW PixelShader Error at position %d: %s\n",
1962               errPos, debugstr_a((const char *)glGetString(GL_PROGRAM_ERROR_STRING_ARB)));
1963         This->baseShader.prgId = -1;
1964     }
1965 }
1966
1967 static void shader_arb_generate_vshader(IWineD3DVertexShader *iface, SHADER_BUFFER *buffer) {
1968     IWineD3DVertexShaderImpl *This = (IWineD3DVertexShaderImpl *)iface;
1969     shader_reg_maps* reg_maps = &This->baseShader.reg_maps;
1970     CONST DWORD *function = This->baseShader.function;
1971     WineD3D_GL_Info *gl_info = &((IWineD3DDeviceImpl *)This->baseShader.device)->adapter->gl_info;
1972
1973     /*  Create the hw ARB shader */
1974     shader_addline(buffer, "!!ARBvp1.0\n");
1975     shader_addline(buffer, "PARAM helper_const = { 2.0, -1.0, %d.0, 0.0 };\n", This->rel_offset);
1976
1977     /* Mesa supports only 95 constants */
1978     if (GL_VEND(MESA) || GL_VEND(WINE))
1979         This->baseShader.limits.constant_float =
1980                 min(95, This->baseShader.limits.constant_float);
1981
1982     shader_addline(buffer, "TEMP TMP;\n");
1983
1984     /* Base Declarations */
1985     shader_generate_arb_declarations( (IWineD3DBaseShader*) This, reg_maps, buffer, &GLINFO_LOCATION);
1986
1987     /* We need a constant to fixup the final position */
1988     shader_addline(buffer, "PARAM posFixup = program.env[%d];\n", ARB_SHADER_PRIVCONST_POS);
1989
1990     /* Initialize output parameters. GL_ARB_vertex_program does not require special initialization values
1991      * for output parameters. D3D in theory does not do that either, but some applications depend on a
1992      * proper initialization of the secondary color, and programs using the fixed function pipeline without
1993      * a replacement shader depend on the texcoord.w being set properly.
1994      *
1995      * GL_NV_vertex_program defines that all output values are initialized to {0.0, 0.0, 0.0, 1.0}. This
1996      * assertion is in effect even when using GL_ARB_vertex_program without any NV specific additions. So
1997      * skip this if NV_vertex_program is supported. Otherwise, initialize the secondary color. For the tex-
1998      * coords, we have a flag in the opengl caps. Many cards do not require the texcoord being set, and
1999      * this can eat a number of instructions, so skip it unless this cap is set as well
2000      */
2001     if(!GL_SUPPORT(NV_VERTEX_PROGRAM)) {
2002         shader_addline(buffer, "MOV result.color.secondary, -helper_const.wwwy;\n");
2003
2004         if((GLINFO_LOCATION).set_texcoord_w) {
2005             int i;
2006             for(i = 0; i < min(8, MAX_REG_TEXCRD); i++) {
2007                 if(This->baseShader.reg_maps.texcoord_mask[i] != 0 &&
2008                 This->baseShader.reg_maps.texcoord_mask[i] != WINED3DSP_WRITEMASK_ALL) {
2009                     shader_addline(buffer, "MOV result.texcoord[%u].w, -helper_const.y;\n", i);
2010                 }
2011             }
2012         }
2013     }
2014
2015     /* Base Shader Body */
2016     shader_generate_main( (IWineD3DBaseShader*) This, buffer, reg_maps, function);
2017
2018     /* If this shader doesn't use fog copy the z coord to the fog coord so that we can use table fog */
2019     if (!reg_maps->fog)
2020         shader_addline(buffer, "MOV result.fogcoord, TMP_OUT.z;\n");
2021
2022     /* Write the final position.
2023      *
2024      * OpenGL coordinates specify the center of the pixel while d3d coords specify
2025      * the corner. The offsets are stored in z and w in posFixup. posFixup.y contains
2026      * 1.0 or -1.0 to turn the rendering upside down for offscreen rendering. PosFixup.x
2027      * contains 1.0 to allow a mad, but arb vs swizzles are too restricted for that.
2028      */
2029     shader_addline(buffer, "MUL TMP, posFixup, TMP_OUT.w;\n");
2030     shader_addline(buffer, "ADD TMP_OUT.x, TMP_OUT.x, TMP.z;\n");
2031     shader_addline(buffer, "MAD TMP_OUT.y, TMP_OUT.y, posFixup.y, TMP.w;\n");
2032
2033     /* Z coord [0;1]->[-1;1] mapping, see comment in transform_projection in state.c
2034      * and the glsl equivalent
2035      */
2036     shader_addline(buffer, "MAD TMP_OUT.z, TMP_OUT.z, helper_const.x, -TMP_OUT.w;\n");
2037
2038     shader_addline(buffer, "MOV result.position, TMP_OUT;\n");
2039
2040     shader_addline(buffer, "END\n");
2041
2042     /* TODO: change to resource.glObjectHandle or something like that */
2043     GL_EXTCALL(glGenProgramsARB(1, &This->baseShader.prgId));
2044
2045     TRACE("Creating a hw vertex shader, prg=%d\n", This->baseShader.prgId);
2046     GL_EXTCALL(glBindProgramARB(GL_VERTEX_PROGRAM_ARB, This->baseShader.prgId));
2047
2048     TRACE("Created hw vertex shader, prg=%d\n", This->baseShader.prgId);
2049     /* Create the program and check for errors */
2050     GL_EXTCALL(glProgramStringARB(GL_VERTEX_PROGRAM_ARB, GL_PROGRAM_FORMAT_ASCII_ARB,
2051                buffer->bsize, buffer->buffer));
2052
2053     if (glGetError() == GL_INVALID_OPERATION) {
2054         GLint errPos;
2055         glGetIntegerv(GL_PROGRAM_ERROR_POSITION_ARB, &errPos);
2056         FIXME("HW VertexShader Error at position %d: %s\n",
2057               errPos, debugstr_a((const char *)glGetString(GL_PROGRAM_ERROR_STRING_ARB)));
2058         This->baseShader.prgId = -1;
2059     }
2060 }
2061
2062 static void shader_arb_get_caps(WINED3DDEVTYPE devtype, WineD3D_GL_Info *gl_info, struct shader_caps *pCaps) {
2063     /* We don't have an ARB fixed function pipeline yet, so let the none backend set its caps,
2064      * then overwrite the shader specific ones
2065      */
2066     none_shader_backend.shader_get_caps(devtype, gl_info, pCaps);
2067
2068     if(GL_SUPPORT(ARB_VERTEX_PROGRAM)) {
2069         pCaps->VertexShaderVersion = WINED3DVS_VERSION(1,1);
2070         TRACE_(d3d_caps)("Hardware vertex shader version 1.1 enabled (ARB_PROGRAM)\n");
2071         pCaps->MaxVertexShaderConst = GL_LIMITS(vshader_constantsF);
2072     }
2073
2074     if(GL_SUPPORT(ARB_FRAGMENT_PROGRAM)) {
2075         pCaps->PixelShaderVersion    = WINED3DPS_VERSION(1,4);
2076         pCaps->PixelShader1xMaxValue = 8.0;
2077         TRACE_(d3d_caps)("Hardware pixel shader version 1.4 enabled (ARB_PROGRAM)\n");
2078     }
2079 }
2080
2081 static void shader_arb_load_init(void) {
2082 }
2083
2084 static void shader_arb_fragment_enable(IWineD3DDevice *iface, BOOL enable) {
2085     none_shader_backend.shader_fragment_enable(iface, enable);
2086 }
2087
2088 const shader_backend_t arb_program_shader_backend = {
2089     &shader_arb_select,
2090     &shader_arb_select_depth_blt,
2091     &shader_arb_destroy_depth_blt,
2092     &shader_arb_load_constants,
2093     &shader_arb_cleanup,
2094     &shader_arb_color_correction,
2095     &shader_arb_destroy,
2096     &shader_arb_alloc,
2097     &shader_arb_free,
2098     &shader_arb_dirty_const,
2099     &shader_arb_generate_pshader,
2100     &shader_arb_generate_vshader,
2101     &shader_arb_get_caps,
2102     &shader_arb_load_init,
2103     &shader_arb_fragment_enable,
2104     FFPStateTable
2105 };