2 * Pixel and vertex shaders implementation using ARB_vertex_program
3 * and ARB_fragment_program GL extensions.
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
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.
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.
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
33 #include "wined3d_private.h"
35 WINE_DEFAULT_DEBUG_CHANNEL(d3d_shader);
37 #define GLINFO_LOCATION (*gl_info)
39 /********************************************************
40 * ARB_[vertex/fragment]_program helper functions follow
41 ********************************************************/
44 * Loads floating point constants into the currently set ARB_vertex/fragment_program.
45 * When constant_list == NULL, it will load all the constants.
47 * @target_type should be either GL_VERTEX_PROGRAM_ARB (for vertex shaders)
48 * or GL_FRAGMENT_PROGRAM_ARB (for pixel shaders)
50 static void shader_arb_load_constantsF(IWineD3DBaseShaderImpl* This, WineD3D_GL_Info *gl_info, GLuint target_type,
51 unsigned int max_constants, float* constants, struct list *constant_list) {
52 constant_entry *constant;
53 local_constant* lconst;
57 if (TRACE_ON(d3d_shader)) {
58 for (i = 0; i < max_constants; ++i) {
59 TRACE("Loading constants %i: %f, %f, %f, %f\n", i,
60 constants[i * 4 + 0], constants[i * 4 + 1],
61 constants[i * 4 + 2], constants[i * 4 + 3]);
64 for (i = 0; i < max_constants; ++i) {
65 GL_EXTCALL(glProgramEnvParameter4fvARB(target_type, i, constants + (i * 4)));
67 checkGLcall("glProgramEnvParameter4fvARB()");
69 if (TRACE_ON(d3d_shader)) {
70 LIST_FOR_EACH_ENTRY(constant, constant_list, constant_entry, entry) {
72 TRACE("Loading constants %i: %f, %f, %f, %f\n", i,
73 constants[i * 4 + 0], constants[i * 4 + 1],
74 constants[i * 4 + 2], constants[i * 4 + 3]);
77 LIST_FOR_EACH_ENTRY(constant, constant_list, constant_entry, entry) {
79 GL_EXTCALL(glProgramEnvParameter4fvARB(target_type, i, constants + (i * 4)));
81 checkGLcall("glProgramEnvParameter4fvARB()");
84 /* Load immediate constants */
85 if (TRACE_ON(d3d_shader)) {
86 LIST_FOR_EACH_ENTRY(lconst, &This->baseShader.constantsF, local_constant, entry) {
87 GLfloat* values = (GLfloat*)lconst->value;
88 TRACE("Loading local constants %i: %f, %f, %f, %f\n", lconst->idx,
89 values[0], values[1], values[2], values[3]);
92 LIST_FOR_EACH_ENTRY(lconst, &This->baseShader.constantsF, local_constant, entry) {
93 GL_EXTCALL(glProgramEnvParameter4fvARB(target_type, lconst->idx, (GLfloat*)lconst->value));
95 checkGLcall("glProgramEnvParameter4fvARB()");
99 * Loads the app-supplied constants into the currently set ARB_[vertex/fragment]_programs.
101 * We only support float constants in ARB at the moment, so don't
102 * worry about the Integers or Booleans
104 void shader_arb_load_constants(
105 IWineD3DStateBlock* iface,
107 char useVertexShader) {
109 IWineD3DStateBlockImpl* stateBlock = (IWineD3DStateBlockImpl*) iface;
110 WineD3D_GL_Info *gl_info = &((IWineD3DImpl*)stateBlock->wineD3DDevice->wineD3D)->gl_info;
112 if (useVertexShader) {
113 IWineD3DBaseShaderImpl* vshader = (IWineD3DBaseShaderImpl*) stateBlock->vertexShader;
114 IWineD3DVertexShaderImpl* vshader_impl = (IWineD3DVertexShaderImpl*) stateBlock->vertexShader;
115 IWineD3DVertexDeclarationImpl* vertexDeclaration =
116 (IWineD3DVertexDeclarationImpl*) vshader_impl->vertexDeclaration;
118 if (NULL != vertexDeclaration && NULL != vertexDeclaration->constants) {
119 /* Load DirectX 8 float constants for vertex shader */
120 shader_arb_load_constantsF(vshader, gl_info, GL_VERTEX_PROGRAM_ARB,
121 GL_LIMITS(vshader_constantsF),
122 vertexDeclaration->constants, NULL);
125 /* Load DirectX 9 float constants for vertex shader */
126 shader_arb_load_constantsF(vshader, gl_info, GL_VERTEX_PROGRAM_ARB,
127 GL_LIMITS(vshader_constantsF),
128 stateBlock->vertexShaderConstantF,
129 &stateBlock->set_vconstantsF);
131 /* Upload the position fixup */
132 GL_EXTCALL(glProgramEnvParameter4fvARB(GL_VERTEX_PROGRAM_ARB, ARB_SHADER_PRIVCONST_POS, vshader_impl->wineD3DDevice->posFixup));
135 if (usePixelShader) {
137 IWineD3DBaseShaderImpl* pshader = (IWineD3DBaseShaderImpl*) stateBlock->pixelShader;
139 /* Load DirectX 9 float constants for pixel shader */
140 shader_arb_load_constantsF(pshader, gl_info, GL_FRAGMENT_PROGRAM_ARB,
141 GL_LIMITS(pshader_constantsF),
142 stateBlock->pixelShaderConstantF,
143 &stateBlock->set_pconstantsF);
147 /* Generate the variable & register declarations for the ARB_vertex_program output target */
148 void shader_generate_arb_declarations(
149 IWineD3DBaseShader *iface,
150 shader_reg_maps* reg_maps,
151 SHADER_BUFFER* buffer,
152 WineD3D_GL_Info* gl_info) {
154 IWineD3DBaseShaderImpl* This = (IWineD3DBaseShaderImpl*) iface;
156 char pshader = shader_is_pshader_version(This->baseShader.hex_version);
157 unsigned max_constantsF = min(This->baseShader.limits.constant_float,
158 (pshader ? GL_LIMITS(pshader_constantsF) : GL_LIMITS(vshader_constantsF)));
160 /* Temporary Output register */
161 shader_addline(buffer, "TEMP TMP_OUT;\n");
163 for(i = 0; i < This->baseShader.limits.temporary; i++) {
164 if (reg_maps->temporary[i])
165 shader_addline(buffer, "TEMP R%lu;\n", i);
168 for (i = 0; i < This->baseShader.limits.address; i++) {
169 if (reg_maps->address[i])
170 shader_addline(buffer, "ADDRESS A%ld;\n", i);
173 for(i = 0; i < This->baseShader.limits.texcoord; i++) {
174 if (reg_maps->texcoord[i])
175 shader_addline(buffer,"TEMP T%lu;\n", i);
178 /* Texture coordinate registers must be pre-loaded */
179 for (i = 0; i < This->baseShader.limits.texcoord; i++) {
180 if (reg_maps->texcoord[i])
181 shader_addline(buffer, "MOV T%lu, fragment.texcoord[%lu];\n", i, i);
184 /* Need to PARAM the environment parameters (constants) so we can use relative addressing */
185 shader_addline(buffer, "PARAM C[%d] = { program.env[0..%d] };\n",
186 max_constantsF, max_constantsF - 1);
189 static const char* shift_tab[] = {
190 "dummy", /* 0 (none) */
191 "coefmul.x", /* 1 (x2) */
192 "coefmul.y", /* 2 (x4) */
193 "coefmul.z", /* 3 (x8) */
194 "coefmul.w", /* 4 (x16) */
195 "dummy", /* 5 (x32) */
196 "dummy", /* 6 (x64) */
197 "dummy", /* 7 (x128) */
198 "dummy", /* 8 (d256) */
199 "dummy", /* 9 (d128) */
200 "dummy", /* 10 (d64) */
201 "dummy", /* 11 (d32) */
202 "coefdiv.w", /* 12 (d16) */
203 "coefdiv.z", /* 13 (d8) */
204 "coefdiv.y", /* 14 (d4) */
205 "coefdiv.x" /* 15 (d2) */
208 static void pshader_get_write_mask(const DWORD output_reg, char *write_mask) {
210 if ((output_reg & D3DSP_WRITEMASK_ALL) != D3DSP_WRITEMASK_ALL) {
211 strcat(write_mask, ".");
212 if (output_reg & D3DSP_WRITEMASK_0) strcat(write_mask, "r");
213 if (output_reg & D3DSP_WRITEMASK_1) strcat(write_mask, "g");
214 if (output_reg & D3DSP_WRITEMASK_2) strcat(write_mask, "b");
215 if (output_reg & D3DSP_WRITEMASK_3) strcat(write_mask, "a");
219 /* TODO: merge with pixel shader */
220 static void vshader_program_add_output_param_swizzle(const DWORD param, int is_color, char *hwLine) {
221 /** operand output */
222 if ((param & D3DSP_WRITEMASK_ALL) != D3DSP_WRITEMASK_ALL) {
224 if (param & D3DSP_WRITEMASK_0) { strcat(hwLine, "x"); }
225 if (param & D3DSP_WRITEMASK_1) { strcat(hwLine, "y"); }
226 if (param & D3DSP_WRITEMASK_2) { strcat(hwLine, "z"); }
227 if (param & D3DSP_WRITEMASK_3) { strcat(hwLine, "w"); }
231 static void pshader_get_input_register_swizzle(const DWORD instr, char *swzstring) {
232 static const char swizzle_reg_chars[] = "rgba";
233 DWORD swizzle = (instr & D3DSP_SWIZZLE_MASK) >> D3DSP_SWIZZLE_SHIFT;
234 DWORD swizzle_x = swizzle & 0x03;
235 DWORD swizzle_y = (swizzle >> 2) & 0x03;
236 DWORD swizzle_z = (swizzle >> 4) & 0x03;
237 DWORD swizzle_w = (swizzle >> 6) & 0x03;
239 * swizzle bits fields:
243 if ((D3DSP_NOSWIZZLE >> D3DSP_SWIZZLE_SHIFT) != swizzle) { /* ! D3DVS_NOSWIZZLE == 0xE4 << D3DVS_SWIZZLE_SHIFT */
244 if (swizzle_x == swizzle_y &&
245 swizzle_x == swizzle_z &&
246 swizzle_x == swizzle_w) {
247 sprintf(swzstring, ".%c", swizzle_reg_chars[swizzle_x]);
249 sprintf(swzstring, ".%c%c%c%c",
250 swizzle_reg_chars[swizzle_x],
251 swizzle_reg_chars[swizzle_y],
252 swizzle_reg_chars[swizzle_z],
253 swizzle_reg_chars[swizzle_w]);
258 /* TODO: merge with pixel shader */
259 static void vshader_program_add_input_param_swizzle(const DWORD param, int is_color, char *hwLine) {
260 static const char swizzle_reg_chars_color_fix[] = "zyxw";
261 static const char swizzle_reg_chars[] = "xyzw";
262 const char* swizzle_regs = NULL;
266 DWORD swizzle = (param & D3DVS_SWIZZLE_MASK) >> D3DVS_SWIZZLE_SHIFT;
267 DWORD swizzle_x = swizzle & 0x03;
268 DWORD swizzle_y = (swizzle >> 2) & 0x03;
269 DWORD swizzle_z = (swizzle >> 4) & 0x03;
270 DWORD swizzle_w = (swizzle >> 6) & 0x03;
273 swizzle_regs = swizzle_reg_chars_color_fix;
275 swizzle_regs = swizzle_reg_chars;
279 * swizzle bits fields:
282 if ((D3DVS_NOSWIZZLE >> D3DVS_SWIZZLE_SHIFT) == swizzle) { /* D3DVS_NOSWIZZLE == 0xE4 << D3DVS_SWIZZLE_SHIFT */
284 sprintf(tmpReg, ".%c%c%c%c",
285 swizzle_regs[swizzle_x],
286 swizzle_regs[swizzle_y],
287 swizzle_regs[swizzle_z],
288 swizzle_regs[swizzle_w]);
289 strcat(hwLine, tmpReg);
293 if (swizzle_x == swizzle_y &&
294 swizzle_x == swizzle_z &&
295 swizzle_x == swizzle_w)
297 sprintf(tmpReg, ".%c", swizzle_regs[swizzle_x]);
298 strcat(hwLine, tmpReg);
300 sprintf(tmpReg, ".%c%c%c%c",
301 swizzle_regs[swizzle_x],
302 swizzle_regs[swizzle_y],
303 swizzle_regs[swizzle_z],
304 swizzle_regs[swizzle_w]);
305 strcat(hwLine, tmpReg);
309 static void pshader_get_register_name(
310 const DWORD param, char* regstr) {
312 DWORD reg = param & D3DSP_REGNUM_MASK;
313 DWORD regtype = shader_get_regtype(param);
317 sprintf(regstr, "R%lu", reg);
321 strcpy(regstr, "fragment.color.primary");
323 strcpy(regstr, "fragment.color.secondary");
327 sprintf(regstr, "C[%lu]", reg);
329 case D3DSPR_TEXTURE: /* case D3DSPR_ADDR: */
330 sprintf(regstr,"T%lu", reg);
332 case D3DSPR_COLOROUT:
334 sprintf(regstr, "result.color");
336 /* TODO: See GL_ARB_draw_buffers */
337 FIXME("Unsupported write to render target %lu\n", reg);
338 sprintf(regstr, "unsupported_register");
341 case D3DSPR_DEPTHOUT:
342 sprintf(regstr, "result.depth");
345 sprintf(regstr, "oD[%lu]", reg);
347 case D3DSPR_TEXCRDOUT:
348 sprintf(regstr, "oT[%lu]", reg);
351 FIXME("Unhandled register name Type(%ld)\n", regtype);
352 sprintf(regstr, "unrecognized_register");
357 /* TODO: merge with pixel shader */
358 static void vshader_program_add_param(SHADER_OPCODE_ARG *arg, const DWORD param, BOOL is_input, char *hwLine) {
360 IWineD3DVertexShaderImpl* This = (IWineD3DVertexShaderImpl*) arg->shader;
362 /* oPos, oFog and oPts in D3D */
363 static const char* hwrastout_reg_names[] = { "TMP_OUT", "TMP_FOG", "result.pointsize" };
365 DWORD reg = param & D3DSP_REGNUM_MASK;
366 DWORD regtype = shader_get_regtype(param);
368 BOOL is_color = FALSE;
370 if ((param & D3DSP_SRCMOD_MASK) == D3DSPSM_NEG) {
371 strcat(hwLine, " -");
378 sprintf(tmpReg, "R%lu", reg);
379 strcat(hwLine, tmpReg);
383 if (vshader_input_is_color((IWineD3DVertexShader*) This, reg))
386 sprintf(tmpReg, "vertex.attrib[%lu]", reg);
387 strcat(hwLine, tmpReg);
390 sprintf(tmpReg, "C[%s%lu]", (param & D3DVS_ADDRMODE_RELATIVE) ? "A0.x + " : "", reg);
391 strcat(hwLine, tmpReg);
393 case D3DSPR_ADDR: /*case D3DSPR_TEXTURE:*/
394 sprintf(tmpReg, "A%lu", reg);
395 strcat(hwLine, tmpReg);
398 sprintf(tmpReg, "%s", hwrastout_reg_names[reg]);
399 strcat(hwLine, tmpReg);
403 strcat(hwLine, "result.color.primary");
405 strcat(hwLine, "result.color.secondary");
408 case D3DSPR_TEXCRDOUT:
409 sprintf(tmpReg, "result.texcoord[%lu]", reg);
410 strcat(hwLine, tmpReg);
413 FIXME("Unknown reg type %ld %ld\n", regtype, reg);
414 strcat(hwLine, "unrecognized_register");
419 vshader_program_add_output_param_swizzle(param, is_color, hwLine);
421 vshader_program_add_input_param_swizzle(param, is_color, hwLine);
425 static void pshader_gen_input_modifier_line (
426 SHADER_BUFFER* buffer,
431 /* Generate a line that does the input modifier computation and return the input register to use */
436 /* Assume a new line will be added */
439 /* Get register name */
440 pshader_get_register_name(instr, regstr);
441 pshader_get_input_register_swizzle(instr, swzstr);
443 switch (instr & D3DSP_SRCMOD_MASK) {
445 sprintf(outregstr, "%s%s", regstr, swzstr);
449 sprintf(outregstr, "-%s%s", regstr, swzstr);
453 shader_addline(buffer, "ADD T%c, %s, -coefdiv.x;\n", 'A' + tmpreg, regstr);
455 case D3DSPSM_BIASNEG:
456 shader_addline(buffer, "ADD T%c, -%s, coefdiv.x;\n", 'A' + tmpreg, regstr);
459 shader_addline(buffer, "MAD T%c, %s, coefmul.x, -one.x;\n", 'A' + tmpreg, regstr);
461 case D3DSPSM_SIGNNEG:
462 shader_addline(buffer, "MAD T%c, %s, -coefmul.x, one.x;\n", 'A' + tmpreg, regstr);
465 shader_addline(buffer, "SUB T%c, one.x, %s;\n", 'A' + tmpreg, regstr);
468 shader_addline(buffer, "ADD T%c, %s, %s;\n", 'A' + tmpreg, regstr, regstr);
471 shader_addline(buffer, "ADD T%c, -%s, -%s;\n", 'A' + tmpreg, regstr, regstr);
474 shader_addline(buffer, "RCP T%c, %s.z;\n", 'A' + tmpreg, regstr);
475 shader_addline(buffer, "MUL T%c, %s, T%c;\n", 'A' + tmpreg, regstr, 'A' + tmpreg);
478 shader_addline(buffer, "RCP T%c, %s.w;\n", 'A' + tmpreg, regstr);
479 shader_addline(buffer, "MUL T%c, %s, T%c;\n", 'A' + tmpreg, regstr, 'A' + tmpreg);
482 sprintf(outregstr, "%s%s", regstr, swzstr);
486 /* Return modified or original register, with swizzle */
488 sprintf(outregstr, "T%c%s", 'A' + tmpreg, swzstr);
491 inline static void pshader_gen_output_modifier_line(
492 SHADER_BUFFER* buffer,
498 /* Generate a line that does the output modifier computation */
499 shader_addline(buffer, "MUL%s %s%s, %s, %s;\n", saturate ? "_SAT" : "",
500 regstr, write_mask, regstr, shift_tab[shift]);
503 void pshader_hw_cnd(SHADER_OPCODE_ARG* arg) {
505 SHADER_BUFFER* buffer = arg->buffer;
508 char src_name[3][50];
510 /* FIXME: support output modifiers */
512 /* Handle output register */
513 pshader_get_register_name(arg->dst, dst_name);
514 pshader_get_write_mask(arg->dst, dst_wmask);
515 strcat(dst_name, dst_wmask);
517 /* Generate input register names (with modifiers) */
518 pshader_gen_input_modifier_line(buffer, arg->src[0], 0, src_name[0]);
519 pshader_gen_input_modifier_line(buffer, arg->src[1], 1, src_name[1]);
520 pshader_gen_input_modifier_line(buffer, arg->src[2], 2, src_name[2]);
522 shader_addline(buffer, "ADD TMP, -%s, coefdiv.x;\n", src_name[0]);
523 shader_addline(buffer, "CMP %s, TMP, %s, %s;\n", dst_name, src_name[1], src_name[2]);
526 void pshader_hw_cmp(SHADER_OPCODE_ARG* arg) {
528 SHADER_BUFFER* buffer = arg->buffer;
531 char src_name[3][50];
533 /* FIXME: support output modifiers */
535 /* Handle output register */
536 pshader_get_register_name(arg->dst, dst_name);
537 pshader_get_write_mask(arg->dst, dst_wmask);
538 strcat(dst_name, dst_wmask);
540 /* Generate input register names (with modifiers) */
541 pshader_gen_input_modifier_line(buffer, arg->src[0], 0, src_name[0]);
542 pshader_gen_input_modifier_line(buffer, arg->src[1], 1, src_name[1]);
543 pshader_gen_input_modifier_line(buffer, arg->src[2], 2, src_name[2]);
545 shader_addline(buffer, "CMP %s, %s, %s, %s;\n", dst_name,
546 src_name[0], src_name[2], src_name[1]);
549 /* Map the opcode 1-to-1 to the GL code */
550 void pshader_hw_map2gl(SHADER_OPCODE_ARG* arg) {
552 CONST SHADER_OPCODE* curOpcode = arg->opcode;
553 SHADER_BUFFER* buffer = arg->buffer;
554 DWORD dst = arg->dst;
555 DWORD* src = arg->src;
560 /* Output token related */
561 char output_rname[256];
562 char output_wmask[20];
563 BOOL saturate = FALSE;
564 BOOL centroid = FALSE;
565 BOOL partialprecision = FALSE;
568 strcpy(tmpLine, curOpcode->glname);
570 /* Process modifiers */
571 if (0 != (dst & D3DSP_DSTMOD_MASK)) {
572 DWORD mask = dst & D3DSP_DSTMOD_MASK;
574 saturate = mask & D3DSPDM_SATURATE;
575 centroid = mask & D3DSPDM_MSAMPCENTROID;
576 partialprecision = mask & D3DSPDM_PARTIALPRECISION;
577 mask &= ~(D3DSPDM_MSAMPCENTROID | D3DSPDM_PARTIALPRECISION | D3DSPDM_SATURATE);
579 FIXME("Unrecognized modifier(0x%#lx)\n", mask >> D3DSP_DSTMOD_SHIFT);
582 FIXME("Unhandled modifier(0x%#lx)\n", mask >> D3DSP_DSTMOD_SHIFT);
584 shift = (dst & D3DSP_DSTSHIFT_MASK) >> D3DSP_DSTSHIFT_SHIFT;
586 /* Generate input and output registers */
587 if (curOpcode->num_params > 0) {
588 char operands[4][100];
590 /* Generate input register names (with modifiers) */
591 for (i = 1; i < curOpcode->num_params; ++i)
592 pshader_gen_input_modifier_line(buffer, src[i-1], i-1, operands[i]);
594 /* Handle output register */
595 pshader_get_register_name(dst, output_rname);
596 strcpy(operands[0], output_rname);
597 pshader_get_write_mask(dst, output_wmask);
598 strcat(operands[0], output_wmask);
600 if (saturate && (shift == 0))
601 strcat(tmpLine, "_SAT");
602 strcat(tmpLine, " ");
603 strcat(tmpLine, operands[0]);
604 for (i = 1; i < curOpcode->num_params; i++) {
605 strcat(tmpLine, ", ");
606 strcat(tmpLine, operands[i]);
608 strcat(tmpLine,";\n");
609 shader_addline(buffer, tmpLine);
611 /* A shift requires another line. */
613 pshader_gen_output_modifier_line(buffer, saturate, output_wmask, shift, output_rname);
617 void pshader_hw_tex(SHADER_OPCODE_ARG* arg) {
619 IWineD3DPixelShaderImpl* This = (IWineD3DPixelShaderImpl*) arg->shader;
620 DWORD dst = arg->dst;
621 DWORD* src = arg->src;
622 SHADER_BUFFER* buffer = arg->buffer;
623 DWORD hex_version = This->baseShader.hex_version;
627 const char *tex_type;
629 DWORD reg_sampler_code;
632 /* All versions have a destination register */
633 reg_dest_code = dst & D3DSP_REGNUM_MASK;
634 pshader_get_register_name(dst, reg_dest);
636 /* 1.0-1.3: Use destination register as coordinate source.
637 1.4+: Use provided coordinate source register. */
638 if (hex_version < D3DPS_VERSION(1,4))
639 strcpy(reg_coord, reg_dest);
641 pshader_gen_input_modifier_line(buffer, src[0], 0, reg_coord);
643 /* 1.0-1.4: Use destination register number as texture code.
644 2.0+: Use provided sampler number as texure code. */
645 if (hex_version < D3DPS_VERSION(2,0))
646 reg_sampler_code = reg_dest_code;
648 reg_sampler_code = src[1] & D3DSP_REGNUM_MASK;
650 sampler_type = arg->reg_maps->samplers[reg_sampler_code] & WINED3DSP_TEXTURETYPE_MASK;
651 switch(sampler_type) {
660 case WINED3DSTT_VOLUME:
664 case WINED3DSTT_CUBE:
669 ERR("Unexpected texture type %ld\n", sampler_type);
673 if(This->wineD3DDevice->stateBlock->textureState[reg_sampler_code][D3DTSS_TEXTURETRANSFORMFLAGS] & D3DTTFF_PROJECTED) {
674 shader_addline(buffer, "TXP %s, %s, texture[%lu], %s;\n",
675 reg_dest, reg_coord, reg_sampler_code, tex_type);
677 shader_addline(buffer, "TEX %s, %s, texture[%lu], %s;\n",
678 reg_dest, reg_coord, reg_sampler_code, tex_type);
682 void pshader_hw_texcoord(SHADER_OPCODE_ARG* arg) {
684 IWineD3DPixelShaderImpl* This = (IWineD3DPixelShaderImpl*) arg->shader;
685 DWORD dst = arg->dst;
686 DWORD* src = arg->src;
687 SHADER_BUFFER* buffer = arg->buffer;
688 DWORD hex_version = This->baseShader.hex_version;
691 pshader_get_write_mask(dst, tmp);
692 if (hex_version != D3DPS_VERSION(1,4)) {
693 DWORD reg = dst & D3DSP_REGNUM_MASK;
694 shader_addline(buffer, "MOV_SAT T%lu%s, fragment.texcoord[%lu];\n", reg, tmp, reg);
696 DWORD reg1 = dst & D3DSP_REGNUM_MASK;
697 DWORD reg2 = src[0] & D3DSP_REGNUM_MASK;
698 shader_addline(buffer, "MOV R%lu%s, fragment.texcoord[%lu];\n", reg1, tmp, reg2);
702 void pshader_hw_texreg2ar(SHADER_OPCODE_ARG* arg) {
704 SHADER_BUFFER* buffer = arg->buffer;
706 DWORD reg1 = arg->dst & D3DSP_REGNUM_MASK;
707 DWORD reg2 = arg->src[0] & D3DSP_REGNUM_MASK;
708 shader_addline(buffer, "MOV TMP.r, T%lu.a;\n", reg2);
709 shader_addline(buffer, "MOV TMP.g, T%lu.r;\n", reg2);
710 shader_addline(buffer, "TEX T%lu, TMP, texture[%lu], 2D;\n", reg1, reg1);
713 void pshader_hw_texreg2gb(SHADER_OPCODE_ARG* arg) {
715 SHADER_BUFFER* buffer = arg->buffer;
717 DWORD reg1 = arg->dst & D3DSP_REGNUM_MASK;
718 DWORD reg2 = arg->src[0] & D3DSP_REGNUM_MASK;
719 shader_addline(buffer, "MOV TMP.r, T%lu.g;\n", reg2);
720 shader_addline(buffer, "MOV TMP.g, T%lu.b;\n", reg2);
721 shader_addline(buffer, "TEX T%lu, TMP, texture[%lu], 2D;\n", reg1, reg1);
724 void pshader_hw_texbem(SHADER_OPCODE_ARG* arg) {
726 SHADER_BUFFER* buffer = arg->buffer;
727 DWORD reg1 = arg->dst & D3DSP_REGNUM_MASK;
728 DWORD reg2 = arg->src[0] & D3DSP_REGNUM_MASK;
730 /* FIXME: Should apply the BUMPMAPENV matrix */
731 shader_addline(buffer, "ADD TMP.rg, fragment.texcoord[%lu], T%lu;\n", reg1, reg2);
732 shader_addline(buffer, "TEX T%lu, TMP, texture[%lu], 2D;\n", reg1, reg1);
735 void pshader_hw_texm3x2pad(SHADER_OPCODE_ARG* arg) {
737 DWORD reg = arg->dst & D3DSP_REGNUM_MASK;
738 SHADER_BUFFER* buffer = arg->buffer;
741 pshader_gen_input_modifier_line(buffer, arg->src[0], 0, src0_name);
742 shader_addline(buffer, "DP3 TMP.x, T%lu, %s;\n", reg, src0_name);
745 void pshader_hw_texm3x2tex(SHADER_OPCODE_ARG* arg) {
747 DWORD reg = arg->dst & D3DSP_REGNUM_MASK;
748 SHADER_BUFFER* buffer = arg->buffer;
751 pshader_gen_input_modifier_line(buffer, arg->src[0], 0, src0_name);
752 shader_addline(buffer, "DP3 TMP.y, T%lu, %s;\n", reg, src0_name);
753 shader_addline(buffer, "TEX T%lu, TMP, texture[%lu], 2D;\n", reg, reg);
756 void pshader_hw_texm3x3pad(SHADER_OPCODE_ARG* arg) {
758 IWineD3DPixelShaderImpl* This = (IWineD3DPixelShaderImpl*) arg->shader;
759 DWORD reg = arg->dst & D3DSP_REGNUM_MASK;
760 SHADER_BUFFER* buffer = arg->buffer;
761 SHADER_PARSE_STATE* current_state = &This->baseShader.parse_state;
764 pshader_gen_input_modifier_line(buffer, arg->src[0], 0, src0_name);
765 shader_addline(buffer, "DP3 TMP.%c, T%lu, %s;\n", 'x' + current_state->current_row, reg, src0_name);
766 current_state->texcoord_w[current_state->current_row++] = reg;
769 void pshader_hw_texm3x3tex(SHADER_OPCODE_ARG* arg) {
771 IWineD3DPixelShaderImpl* This = (IWineD3DPixelShaderImpl*) arg->shader;
772 DWORD reg = arg->dst & D3DSP_REGNUM_MASK;
773 SHADER_BUFFER* buffer = arg->buffer;
774 SHADER_PARSE_STATE* current_state = &This->baseShader.parse_state;
777 pshader_gen_input_modifier_line(buffer, arg->src[0], 0, src0_name);
778 shader_addline(buffer, "DP3 TMP.z, T%lu, %s;\n", reg, src0_name);
780 /* Cubemap textures will be more used than 3D ones. */
781 shader_addline(buffer, "TEX T%lu, TMP, texture[%lu], CUBE;\n", reg, reg);
782 current_state->current_row = 0;
785 void pshader_hw_texm3x3vspec(SHADER_OPCODE_ARG* arg) {
787 IWineD3DPixelShaderImpl* This = (IWineD3DPixelShaderImpl*) arg->shader;
788 DWORD reg = arg->dst & D3DSP_REGNUM_MASK;
789 SHADER_BUFFER* buffer = arg->buffer;
790 SHADER_PARSE_STATE* current_state = &This->baseShader.parse_state;
793 pshader_gen_input_modifier_line(buffer, arg->src[0], 0, src0_name);
794 shader_addline(buffer, "DP3 TMP.z, T%lu, %s;\n", reg, src0_name);
796 /* Construct the eye-ray vector from w coordinates */
797 shader_addline(buffer, "MOV TMP2.x, fragment.texcoord[%lu].w;\n", current_state->texcoord_w[0]);
798 shader_addline(buffer, "MOV TMP2.y, fragment.texcoord[%lu].w;\n", current_state->texcoord_w[1]);
799 shader_addline(buffer, "MOV TMP2.z, fragment.texcoord[%lu].w;\n", reg);
801 /* Calculate reflection vector (Assume normal is normalized): RF = 2*(N.E)*N -E */
802 shader_addline(buffer, "DP3 TMP.w, TMP, TMP2;\n");
803 shader_addline(buffer, "MUL TMP, TMP.w, TMP;\n");
804 shader_addline(buffer, "MAD TMP, coefmul.x, TMP, -TMP2;\n");
806 /* Cubemap textures will be more used than 3D ones. */
807 shader_addline(buffer, "TEX T%lu, TMP, texture[%lu], CUBE;\n", reg, reg);
808 current_state->current_row = 0;
811 void pshader_hw_texm3x3spec(SHADER_OPCODE_ARG* arg) {
813 IWineD3DPixelShaderImpl* This = (IWineD3DPixelShaderImpl*) arg->shader;
814 DWORD reg = arg->dst & D3DSP_REGNUM_MASK;
815 DWORD reg3 = arg->src[1] & D3DSP_REGNUM_MASK;
816 SHADER_PARSE_STATE* current_state = &This->baseShader.parse_state;
817 SHADER_BUFFER* buffer = arg->buffer;
820 pshader_gen_input_modifier_line(buffer, arg->src[0], 0, src0_name);
821 shader_addline(buffer, "DP3 TMP.z, T%lu, %s;\n", reg, src0_name);
823 /* Calculate reflection vector (Assume normal is normalized): RF = 2*(N.E)*N -E */
824 shader_addline(buffer, "DP3 TMP.w, TMP, C[%lu];\n", reg3);
825 shader_addline(buffer, "MUL TMP, TMP.w, TMP;\n");
826 shader_addline(buffer, "MAD TMP, coefmul.x, TMP, -C[%lu];\n", reg3);
828 /* Cubemap textures will be more used than 3D ones. */
829 shader_addline(buffer, "TEX T%lu, TMP, texture[%lu], CUBE;\n", reg, reg);
830 current_state->current_row = 0;
833 /** Handles transforming all D3DSIO_M?x? opcodes for
834 Vertex shaders to ARB_vertex_program codes */
835 void vshader_hw_mnxn(SHADER_OPCODE_ARG* arg) {
839 SHADER_OPCODE_ARG tmpArg;
841 memset(&tmpArg, 0, sizeof(SHADER_OPCODE_ARG));
843 /* Set constants for the temporary argument */
844 tmpArg.shader = arg->shader;
845 tmpArg.buffer = arg->buffer;
846 tmpArg.src[0] = arg->src[0];
847 tmpArg.src_addr[0] = arg->src_addr[0];
848 tmpArg.src_addr[1] = arg->src_addr[1];
849 tmpArg.reg_maps = arg->reg_maps;
851 switch(arg->opcode->opcode) {
854 tmpArg.opcode = &IWineD3DVertexShaderImpl_shader_ins[D3DSIO_DP4];
858 tmpArg.opcode = &IWineD3DVertexShaderImpl_shader_ins[D3DSIO_DP4];
862 tmpArg.opcode = &IWineD3DVertexShaderImpl_shader_ins[D3DSIO_DP3];
866 tmpArg.opcode = &IWineD3DVertexShaderImpl_shader_ins[D3DSIO_DP3];
870 tmpArg.opcode = &IWineD3DVertexShaderImpl_shader_ins[D3DSIO_DP3];
876 for (i = 0; i < nComponents; i++) {
877 tmpArg.dst = ((arg->dst) & ~D3DSP_WRITEMASK_ALL)|(D3DSP_WRITEMASK_0<<i);
878 tmpArg.src[1] = arg->src[1]+i;
879 vshader_hw_map2gl(&tmpArg);
883 /* TODO: merge with pixel shader */
884 /* Map the opcode 1-to-1 to the GL code */
885 void vshader_hw_map2gl(SHADER_OPCODE_ARG* arg) {
887 CONST SHADER_OPCODE* curOpcode = arg->opcode;
888 SHADER_BUFFER* buffer = arg->buffer;
889 DWORD dst = arg->dst;
890 DWORD* src = arg->src;
892 DWORD dst_regtype = shader_get_regtype(dst);
896 if (curOpcode->opcode == D3DSIO_MOV && dst_regtype == D3DSPR_ADDR)
897 strcpy(tmpLine, "ARL");
899 strcpy(tmpLine, curOpcode->glname);
901 if (curOpcode->num_params > 0) {
902 vshader_program_add_param(arg, dst, FALSE, tmpLine);
903 for (i = 1; i < curOpcode->num_params; ++i) {
904 strcat(tmpLine, ",");
905 vshader_program_add_param(arg, src[i-1], TRUE, tmpLine);
908 shader_addline(buffer, "%s;\n", tmpLine);