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