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);
132 if (usePixelShader) {
134 IWineD3DBaseShaderImpl* pshader = (IWineD3DBaseShaderImpl*) stateBlock->pixelShader;
136 /* Load DirectX 9 float constants for pixel shader */
137 shader_arb_load_constantsF(pshader, gl_info, GL_FRAGMENT_PROGRAM_ARB,
138 GL_LIMITS(pshader_constantsF),
139 stateBlock->pixelShaderConstantF,
140 &stateBlock->set_pconstantsF);
144 /* Generate the variable & register declarations for the ARB_vertex_program output target */
145 void shader_generate_arb_declarations(
146 IWineD3DBaseShader *iface,
147 shader_reg_maps* reg_maps,
148 SHADER_BUFFER* buffer,
149 WineD3D_GL_Info* gl_info) {
151 IWineD3DBaseShaderImpl* This = (IWineD3DBaseShaderImpl*) iface;
153 char pshader = shader_is_pshader_version(This->baseShader.hex_version);
154 unsigned max_constantsF = min(This->baseShader.limits.constant_float,
155 (pshader ? GL_LIMITS(pshader_constantsF) : GL_LIMITS(vshader_constantsF)));
157 /* Temporary Output register */
158 shader_addline(buffer, "TEMP TMP_OUT;\n");
160 for(i = 0; i < This->baseShader.limits.temporary; i++) {
161 if (reg_maps->temporary[i])
162 shader_addline(buffer, "TEMP R%lu;\n", i);
165 for (i = 0; i < This->baseShader.limits.address; i++) {
166 if (reg_maps->address[i])
167 shader_addline(buffer, "ADDRESS A%ld;\n", i);
170 for(i = 0; i < This->baseShader.limits.texcoord; i++) {
171 if (reg_maps->texcoord[i])
172 shader_addline(buffer,"TEMP T%lu;\n", i);
175 /* Texture coordinate registers must be pre-loaded */
176 for (i = 0; i < This->baseShader.limits.texcoord; i++) {
177 if (reg_maps->texcoord[i])
178 shader_addline(buffer, "MOV T%lu, fragment.texcoord[%lu];\n", i, i);
181 /* Need to PARAM the environment parameters (constants) so we can use relative addressing */
182 shader_addline(buffer, "PARAM C[%d] = { program.env[0..%d] };\n",
183 max_constantsF, max_constantsF - 1);
186 static const char* shift_tab[] = {
187 "dummy", /* 0 (none) */
188 "coefmul.x", /* 1 (x2) */
189 "coefmul.y", /* 2 (x4) */
190 "coefmul.z", /* 3 (x8) */
191 "coefmul.w", /* 4 (x16) */
192 "dummy", /* 5 (x32) */
193 "dummy", /* 6 (x64) */
194 "dummy", /* 7 (x128) */
195 "dummy", /* 8 (d256) */
196 "dummy", /* 9 (d128) */
197 "dummy", /* 10 (d64) */
198 "dummy", /* 11 (d32) */
199 "coefdiv.w", /* 12 (d16) */
200 "coefdiv.z", /* 13 (d8) */
201 "coefdiv.y", /* 14 (d4) */
202 "coefdiv.x" /* 15 (d2) */
205 static void pshader_get_write_mask(const DWORD output_reg, char *write_mask) {
207 if ((output_reg & D3DSP_WRITEMASK_ALL) != D3DSP_WRITEMASK_ALL) {
208 strcat(write_mask, ".");
209 if (output_reg & D3DSP_WRITEMASK_0) strcat(write_mask, "r");
210 if (output_reg & D3DSP_WRITEMASK_1) strcat(write_mask, "g");
211 if (output_reg & D3DSP_WRITEMASK_2) strcat(write_mask, "b");
212 if (output_reg & D3DSP_WRITEMASK_3) strcat(write_mask, "a");
216 /* TODO: merge with pixel shader */
217 static void vshader_program_add_output_param_swizzle(const DWORD param, int is_color, char *hwLine) {
218 /** operand output */
219 if ((param & D3DSP_WRITEMASK_ALL) != D3DSP_WRITEMASK_ALL) {
221 if (param & D3DSP_WRITEMASK_0) { strcat(hwLine, "x"); }
222 if (param & D3DSP_WRITEMASK_1) { strcat(hwLine, "y"); }
223 if (param & D3DSP_WRITEMASK_2) { strcat(hwLine, "z"); }
224 if (param & D3DSP_WRITEMASK_3) { strcat(hwLine, "w"); }
228 static void pshader_get_input_register_swizzle(const DWORD instr, char *swzstring) {
229 static const char swizzle_reg_chars[] = "rgba";
230 DWORD swizzle = (instr & D3DSP_SWIZZLE_MASK) >> D3DSP_SWIZZLE_SHIFT;
231 DWORD swizzle_x = swizzle & 0x03;
232 DWORD swizzle_y = (swizzle >> 2) & 0x03;
233 DWORD swizzle_z = (swizzle >> 4) & 0x03;
234 DWORD swizzle_w = (swizzle >> 6) & 0x03;
236 * swizzle bits fields:
240 if ((D3DSP_NOSWIZZLE >> D3DSP_SWIZZLE_SHIFT) != swizzle) { /* ! D3DVS_NOSWIZZLE == 0xE4 << D3DVS_SWIZZLE_SHIFT */
241 if (swizzle_x == swizzle_y &&
242 swizzle_x == swizzle_z &&
243 swizzle_x == swizzle_w) {
244 sprintf(swzstring, ".%c", swizzle_reg_chars[swizzle_x]);
246 sprintf(swzstring, ".%c%c%c%c",
247 swizzle_reg_chars[swizzle_x],
248 swizzle_reg_chars[swizzle_y],
249 swizzle_reg_chars[swizzle_z],
250 swizzle_reg_chars[swizzle_w]);
255 /* TODO: merge with pixel shader */
256 static void vshader_program_add_input_param_swizzle(const DWORD param, int is_color, char *hwLine) {
257 static const char swizzle_reg_chars_color_fix[] = "zyxw";
258 static const char swizzle_reg_chars[] = "xyzw";
259 const char* swizzle_regs = NULL;
263 DWORD swizzle = (param & D3DVS_SWIZZLE_MASK) >> D3DVS_SWIZZLE_SHIFT;
264 DWORD swizzle_x = swizzle & 0x03;
265 DWORD swizzle_y = (swizzle >> 2) & 0x03;
266 DWORD swizzle_z = (swizzle >> 4) & 0x03;
267 DWORD swizzle_w = (swizzle >> 6) & 0x03;
270 swizzle_regs = swizzle_reg_chars_color_fix;
272 swizzle_regs = swizzle_reg_chars;
276 * swizzle bits fields:
279 if ((D3DVS_NOSWIZZLE >> D3DVS_SWIZZLE_SHIFT) == swizzle) { /* D3DVS_NOSWIZZLE == 0xE4 << D3DVS_SWIZZLE_SHIFT */
281 sprintf(tmpReg, ".%c%c%c%c",
282 swizzle_regs[swizzle_x],
283 swizzle_regs[swizzle_y],
284 swizzle_regs[swizzle_z],
285 swizzle_regs[swizzle_w]);
286 strcat(hwLine, tmpReg);
290 if (swizzle_x == swizzle_y &&
291 swizzle_x == swizzle_z &&
292 swizzle_x == swizzle_w)
294 sprintf(tmpReg, ".%c", swizzle_regs[swizzle_x]);
295 strcat(hwLine, tmpReg);
297 sprintf(tmpReg, ".%c%c%c%c",
298 swizzle_regs[swizzle_x],
299 swizzle_regs[swizzle_y],
300 swizzle_regs[swizzle_z],
301 swizzle_regs[swizzle_w]);
302 strcat(hwLine, tmpReg);
306 static void pshader_get_register_name(
307 const DWORD param, char* regstr) {
309 DWORD reg = param & D3DSP_REGNUM_MASK;
310 DWORD regtype = shader_get_regtype(param);
314 sprintf(regstr, "R%lu", reg);
318 strcpy(regstr, "fragment.color.primary");
320 strcpy(regstr, "fragment.color.secondary");
324 sprintf(regstr, "C[%lu]", reg);
326 case D3DSPR_TEXTURE: /* case D3DSPR_ADDR: */
327 sprintf(regstr,"T%lu", reg);
329 case D3DSPR_COLOROUT:
331 sprintf(regstr, "result.color");
333 /* TODO: See GL_ARB_draw_buffers */
334 FIXME("Unsupported write to render target %lu\n", reg);
335 sprintf(regstr, "unsupported_register");
338 case D3DSPR_DEPTHOUT:
339 sprintf(regstr, "result.depth");
342 sprintf(regstr, "oD[%lu]", reg);
344 case D3DSPR_TEXCRDOUT:
345 sprintf(regstr, "oT[%lu]", reg);
348 FIXME("Unhandled register name Type(%ld)\n", regtype);
349 sprintf(regstr, "unrecognized_register");
354 /* TODO: merge with pixel shader */
355 static void vshader_program_add_param(SHADER_OPCODE_ARG *arg, const DWORD param, BOOL is_input, char *hwLine) {
357 IWineD3DVertexShaderImpl* This = (IWineD3DVertexShaderImpl*) arg->shader;
359 /* oPos, oFog and oPts in D3D */
360 static const char* hwrastout_reg_names[] = { "TMP_OUT", "TMP_FOG", "result.pointsize" };
362 DWORD reg = param & D3DSP_REGNUM_MASK;
363 DWORD regtype = shader_get_regtype(param);
365 BOOL is_color = FALSE;
367 if ((param & D3DSP_SRCMOD_MASK) == D3DSPSM_NEG) {
368 strcat(hwLine, " -");
375 sprintf(tmpReg, "R%lu", reg);
376 strcat(hwLine, tmpReg);
380 if (vshader_input_is_color((IWineD3DVertexShader*) This, reg))
383 sprintf(tmpReg, "vertex.attrib[%lu]", reg);
384 strcat(hwLine, tmpReg);
387 sprintf(tmpReg, "C[%s%lu]", (param & D3DVS_ADDRMODE_RELATIVE) ? "A0.x + " : "", reg);
388 strcat(hwLine, tmpReg);
390 case D3DSPR_ADDR: /*case D3DSPR_TEXTURE:*/
391 sprintf(tmpReg, "A%lu", reg);
392 strcat(hwLine, tmpReg);
395 sprintf(tmpReg, "%s", hwrastout_reg_names[reg]);
396 strcat(hwLine, tmpReg);
400 strcat(hwLine, "result.color.primary");
402 strcat(hwLine, "result.color.secondary");
405 case D3DSPR_TEXCRDOUT:
406 sprintf(tmpReg, "result.texcoord[%lu]", reg);
407 strcat(hwLine, tmpReg);
410 FIXME("Unknown reg type %ld %ld\n", regtype, reg);
411 strcat(hwLine, "unrecognized_register");
416 vshader_program_add_output_param_swizzle(param, is_color, hwLine);
418 vshader_program_add_input_param_swizzle(param, is_color, hwLine);
422 static void pshader_gen_input_modifier_line (
423 SHADER_BUFFER* buffer,
428 /* Generate a line that does the input modifier computation and return the input register to use */
433 /* Assume a new line will be added */
436 /* Get register name */
437 pshader_get_register_name(instr, regstr);
438 pshader_get_input_register_swizzle(instr, swzstr);
440 switch (instr & D3DSP_SRCMOD_MASK) {
442 sprintf(outregstr, "%s%s", regstr, swzstr);
446 sprintf(outregstr, "-%s%s", regstr, swzstr);
450 shader_addline(buffer, "ADD T%c, %s, -coefdiv.x;\n", 'A' + tmpreg, regstr);
452 case D3DSPSM_BIASNEG:
453 shader_addline(buffer, "ADD T%c, -%s, coefdiv.x;\n", 'A' + tmpreg, regstr);
456 shader_addline(buffer, "MAD T%c, %s, coefmul.x, -one.x;\n", 'A' + tmpreg, regstr);
458 case D3DSPSM_SIGNNEG:
459 shader_addline(buffer, "MAD T%c, %s, -coefmul.x, one.x;\n", 'A' + tmpreg, regstr);
462 shader_addline(buffer, "SUB T%c, one.x, %s;\n", 'A' + tmpreg, regstr);
465 shader_addline(buffer, "ADD T%c, %s, %s;\n", 'A' + tmpreg, regstr, regstr);
468 shader_addline(buffer, "ADD T%c, -%s, -%s;\n", 'A' + tmpreg, regstr, regstr);
471 shader_addline(buffer, "RCP T%c, %s.z;\n", 'A' + tmpreg, regstr);
472 shader_addline(buffer, "MUL T%c, %s, T%c;\n", 'A' + tmpreg, regstr, 'A' + tmpreg);
475 shader_addline(buffer, "RCP T%c, %s.w;\n", 'A' + tmpreg, regstr);
476 shader_addline(buffer, "MUL T%c, %s, T%c;\n", 'A' + tmpreg, regstr, 'A' + tmpreg);
479 sprintf(outregstr, "%s%s", regstr, swzstr);
483 /* Return modified or original register, with swizzle */
485 sprintf(outregstr, "T%c%s", 'A' + tmpreg, swzstr);
488 inline static void pshader_gen_output_modifier_line(
489 SHADER_BUFFER* buffer,
495 /* Generate a line that does the output modifier computation */
496 shader_addline(buffer, "MUL%s %s%s, %s, %s;\n", saturate ? "_SAT" : "",
497 regstr, write_mask, regstr, shift_tab[shift]);
500 void pshader_hw_cnd(SHADER_OPCODE_ARG* arg) {
502 SHADER_BUFFER* buffer = arg->buffer;
505 char src_name[3][50];
507 /* FIXME: support output modifiers */
509 /* Handle output register */
510 pshader_get_register_name(arg->dst, dst_name);
511 pshader_get_write_mask(arg->dst, dst_wmask);
512 strcat(dst_name, dst_wmask);
514 /* Generate input register names (with modifiers) */
515 pshader_gen_input_modifier_line(buffer, arg->src[0], 0, src_name[0]);
516 pshader_gen_input_modifier_line(buffer, arg->src[1], 1, src_name[1]);
517 pshader_gen_input_modifier_line(buffer, arg->src[2], 2, src_name[2]);
519 shader_addline(buffer, "ADD TMP, -%s, coefdiv.x;\n", src_name[0]);
520 shader_addline(buffer, "CMP %s, TMP, %s, %s;\n", dst_name, src_name[1], src_name[2]);
523 void pshader_hw_cmp(SHADER_OPCODE_ARG* arg) {
525 SHADER_BUFFER* buffer = arg->buffer;
528 char src_name[3][50];
530 /* FIXME: support output modifiers */
532 /* Handle output register */
533 pshader_get_register_name(arg->dst, dst_name);
534 pshader_get_write_mask(arg->dst, dst_wmask);
535 strcat(dst_name, dst_wmask);
537 /* Generate input register names (with modifiers) */
538 pshader_gen_input_modifier_line(buffer, arg->src[0], 0, src_name[0]);
539 pshader_gen_input_modifier_line(buffer, arg->src[1], 1, src_name[1]);
540 pshader_gen_input_modifier_line(buffer, arg->src[2], 2, src_name[2]);
542 shader_addline(buffer, "CMP %s, %s, %s, %s;\n", dst_name,
543 src_name[0], src_name[2], src_name[1]);
546 /* Map the opcode 1-to-1 to the GL code */
547 void pshader_hw_map2gl(SHADER_OPCODE_ARG* arg) {
549 CONST SHADER_OPCODE* curOpcode = arg->opcode;
550 SHADER_BUFFER* buffer = arg->buffer;
551 DWORD dst = arg->dst;
552 DWORD* src = arg->src;
557 /* Output token related */
558 char output_rname[256];
559 char output_wmask[20];
560 BOOL saturate = FALSE;
561 BOOL centroid = FALSE;
562 BOOL partialprecision = FALSE;
565 strcpy(tmpLine, curOpcode->glname);
567 /* Process modifiers */
568 if (0 != (dst & D3DSP_DSTMOD_MASK)) {
569 DWORD mask = dst & D3DSP_DSTMOD_MASK;
571 saturate = mask & D3DSPDM_SATURATE;
572 centroid = mask & D3DSPDM_MSAMPCENTROID;
573 partialprecision = mask & D3DSPDM_PARTIALPRECISION;
574 mask &= ~(D3DSPDM_MSAMPCENTROID | D3DSPDM_PARTIALPRECISION | D3DSPDM_SATURATE);
576 FIXME("Unrecognized modifier(0x%#lx)\n", mask >> D3DSP_DSTMOD_SHIFT);
579 FIXME("Unhandled modifier(0x%#lx)\n", mask >> D3DSP_DSTMOD_SHIFT);
581 shift = (dst & D3DSP_DSTSHIFT_MASK) >> D3DSP_DSTSHIFT_SHIFT;
583 /* Generate input and output registers */
584 if (curOpcode->num_params > 0) {
585 char operands[4][100];
587 /* Generate input register names (with modifiers) */
588 for (i = 1; i < curOpcode->num_params; ++i)
589 pshader_gen_input_modifier_line(buffer, src[i-1], i-1, operands[i]);
591 /* Handle output register */
592 pshader_get_register_name(dst, output_rname);
593 strcpy(operands[0], output_rname);
594 pshader_get_write_mask(dst, output_wmask);
595 strcat(operands[0], output_wmask);
597 if (saturate && (shift == 0))
598 strcat(tmpLine, "_SAT");
599 strcat(tmpLine, " ");
600 strcat(tmpLine, operands[0]);
601 for (i = 1; i < curOpcode->num_params; i++) {
602 strcat(tmpLine, ", ");
603 strcat(tmpLine, operands[i]);
605 strcat(tmpLine,";\n");
606 shader_addline(buffer, tmpLine);
608 /* A shift requires another line. */
610 pshader_gen_output_modifier_line(buffer, saturate, output_wmask, shift, output_rname);
614 void pshader_hw_tex(SHADER_OPCODE_ARG* arg) {
616 IWineD3DPixelShaderImpl* This = (IWineD3DPixelShaderImpl*) arg->shader;
617 DWORD dst = arg->dst;
618 DWORD* src = arg->src;
619 SHADER_BUFFER* buffer = arg->buffer;
620 DWORD hex_version = This->baseShader.hex_version;
624 const char *tex_type;
626 DWORD reg_sampler_code;
629 /* All versions have a destination register */
630 reg_dest_code = dst & D3DSP_REGNUM_MASK;
631 pshader_get_register_name(dst, reg_dest);
633 /* 1.0-1.3: Use destination register as coordinate source.
634 1.4+: Use provided coordinate source register. */
635 if (hex_version < D3DPS_VERSION(1,4))
636 strcpy(reg_coord, reg_dest);
638 pshader_gen_input_modifier_line(buffer, src[0], 0, reg_coord);
640 /* 1.0-1.4: Use destination register number as texture code.
641 2.0+: Use provided sampler number as texure code. */
642 if (hex_version < D3DPS_VERSION(2,0))
643 reg_sampler_code = reg_dest_code;
645 reg_sampler_code = src[1] & D3DSP_REGNUM_MASK;
647 sampler_type = arg->reg_maps->samplers[reg_sampler_code] & WINED3DSP_TEXTURETYPE_MASK;
648 switch(sampler_type) {
657 case WINED3DSTT_VOLUME:
661 case WINED3DSTT_CUBE:
666 ERR("Unexpected texture type %ld\n", sampler_type);
670 if(This->wineD3DDevice->stateBlock->textureState[reg_sampler_code][D3DTSS_TEXTURETRANSFORMFLAGS] & D3DTTFF_PROJECTED) {
671 shader_addline(buffer, "TXP %s, %s, texture[%lu], %s;\n",
672 reg_dest, reg_coord, reg_sampler_code, tex_type);
674 shader_addline(buffer, "TEX %s, %s, texture[%lu], %s;\n",
675 reg_dest, reg_coord, reg_sampler_code, tex_type);
679 void pshader_hw_texcoord(SHADER_OPCODE_ARG* arg) {
681 IWineD3DPixelShaderImpl* This = (IWineD3DPixelShaderImpl*) arg->shader;
682 DWORD dst = arg->dst;
683 DWORD* src = arg->src;
684 SHADER_BUFFER* buffer = arg->buffer;
685 DWORD hex_version = This->baseShader.hex_version;
688 pshader_get_write_mask(dst, tmp);
689 if (hex_version != D3DPS_VERSION(1,4)) {
690 DWORD reg = dst & D3DSP_REGNUM_MASK;
691 shader_addline(buffer, "MOV_SAT T%lu%s, fragment.texcoord[%lu];\n", reg, tmp, reg);
693 DWORD reg1 = dst & D3DSP_REGNUM_MASK;
694 DWORD reg2 = src[0] & D3DSP_REGNUM_MASK;
695 shader_addline(buffer, "MOV R%lu%s, fragment.texcoord[%lu];\n", reg1, tmp, reg2);
699 void pshader_hw_texreg2ar(SHADER_OPCODE_ARG* arg) {
701 SHADER_BUFFER* buffer = arg->buffer;
703 DWORD reg1 = arg->dst & D3DSP_REGNUM_MASK;
704 DWORD reg2 = arg->src[0] & D3DSP_REGNUM_MASK;
705 shader_addline(buffer, "MOV TMP.r, T%lu.a;\n", reg2);
706 shader_addline(buffer, "MOV TMP.g, T%lu.r;\n", reg2);
707 shader_addline(buffer, "TEX T%lu, TMP, texture[%lu], 2D;\n", reg1, reg1);
710 void pshader_hw_texreg2gb(SHADER_OPCODE_ARG* arg) {
712 SHADER_BUFFER* buffer = arg->buffer;
714 DWORD reg1 = arg->dst & D3DSP_REGNUM_MASK;
715 DWORD reg2 = arg->src[0] & D3DSP_REGNUM_MASK;
716 shader_addline(buffer, "MOV TMP.r, T%lu.g;\n", reg2);
717 shader_addline(buffer, "MOV TMP.g, T%lu.b;\n", reg2);
718 shader_addline(buffer, "TEX T%lu, TMP, texture[%lu], 2D;\n", reg1, reg1);
721 void pshader_hw_texbem(SHADER_OPCODE_ARG* arg) {
723 SHADER_BUFFER* buffer = arg->buffer;
724 DWORD reg1 = arg->dst & D3DSP_REGNUM_MASK;
725 DWORD reg2 = arg->src[0] & D3DSP_REGNUM_MASK;
727 /* FIXME: Should apply the BUMPMAPENV matrix */
728 shader_addline(buffer, "ADD TMP.rg, fragment.texcoord[%lu], T%lu;\n", reg1, reg2);
729 shader_addline(buffer, "TEX T%lu, TMP, texture[%lu], 2D;\n", reg1, reg1);
732 void pshader_hw_texm3x2pad(SHADER_OPCODE_ARG* arg) {
734 DWORD reg = arg->dst & D3DSP_REGNUM_MASK;
735 SHADER_BUFFER* buffer = arg->buffer;
738 pshader_gen_input_modifier_line(buffer, arg->src[0], 0, src0_name);
739 shader_addline(buffer, "DP3 TMP.x, T%lu, %s;\n", reg, src0_name);
742 void pshader_hw_texm3x2tex(SHADER_OPCODE_ARG* arg) {
744 DWORD reg = arg->dst & D3DSP_REGNUM_MASK;
745 SHADER_BUFFER* buffer = arg->buffer;
748 pshader_gen_input_modifier_line(buffer, arg->src[0], 0, src0_name);
749 shader_addline(buffer, "DP3 TMP.y, T%lu, %s;\n", reg, src0_name);
750 shader_addline(buffer, "TEX T%lu, TMP, texture[%lu], 2D;\n", reg, reg);
753 void pshader_hw_texm3x3pad(SHADER_OPCODE_ARG* arg) {
755 IWineD3DPixelShaderImpl* This = (IWineD3DPixelShaderImpl*) arg->shader;
756 DWORD reg = arg->dst & D3DSP_REGNUM_MASK;
757 SHADER_BUFFER* buffer = arg->buffer;
758 SHADER_PARSE_STATE* current_state = &This->baseShader.parse_state;
761 pshader_gen_input_modifier_line(buffer, arg->src[0], 0, src0_name);
762 shader_addline(buffer, "DP3 TMP.%c, T%lu, %s;\n", 'x' + current_state->current_row, reg, src0_name);
763 current_state->texcoord_w[current_state->current_row++] = reg;
766 void pshader_hw_texm3x3tex(SHADER_OPCODE_ARG* arg) {
768 IWineD3DPixelShaderImpl* This = (IWineD3DPixelShaderImpl*) arg->shader;
769 DWORD reg = arg->dst & D3DSP_REGNUM_MASK;
770 SHADER_BUFFER* buffer = arg->buffer;
771 SHADER_PARSE_STATE* current_state = &This->baseShader.parse_state;
774 pshader_gen_input_modifier_line(buffer, arg->src[0], 0, src0_name);
775 shader_addline(buffer, "DP3 TMP.z, T%lu, %s;\n", reg, src0_name);
777 /* Cubemap textures will be more used than 3D ones. */
778 shader_addline(buffer, "TEX T%lu, TMP, texture[%lu], CUBE;\n", reg, reg);
779 current_state->current_row = 0;
782 void pshader_hw_texm3x3vspec(SHADER_OPCODE_ARG* arg) {
784 IWineD3DPixelShaderImpl* This = (IWineD3DPixelShaderImpl*) arg->shader;
785 DWORD reg = arg->dst & D3DSP_REGNUM_MASK;
786 SHADER_BUFFER* buffer = arg->buffer;
787 SHADER_PARSE_STATE* current_state = &This->baseShader.parse_state;
790 pshader_gen_input_modifier_line(buffer, arg->src[0], 0, src0_name);
791 shader_addline(buffer, "DP3 TMP.z, T%lu, %s;\n", reg, src0_name);
793 /* Construct the eye-ray vector from w coordinates */
794 shader_addline(buffer, "MOV TMP2.x, fragment.texcoord[%lu].w;\n", current_state->texcoord_w[0]);
795 shader_addline(buffer, "MOV TMP2.y, fragment.texcoord[%lu].w;\n", current_state->texcoord_w[1]);
796 shader_addline(buffer, "MOV TMP2.z, fragment.texcoord[%lu].w;\n", reg);
798 /* Calculate reflection vector (Assume normal is normalized): RF = 2*(N.E)*N -E */
799 shader_addline(buffer, "DP3 TMP.w, TMP, TMP2;\n");
800 shader_addline(buffer, "MUL TMP, TMP.w, TMP;\n");
801 shader_addline(buffer, "MAD TMP, coefmul.x, TMP, -TMP2;\n");
803 /* Cubemap textures will be more used than 3D ones. */
804 shader_addline(buffer, "TEX T%lu, TMP, texture[%lu], CUBE;\n", reg, reg);
805 current_state->current_row = 0;
808 void pshader_hw_texm3x3spec(SHADER_OPCODE_ARG* arg) {
810 IWineD3DPixelShaderImpl* This = (IWineD3DPixelShaderImpl*) arg->shader;
811 DWORD reg = arg->dst & D3DSP_REGNUM_MASK;
812 DWORD reg3 = arg->src[1] & D3DSP_REGNUM_MASK;
813 SHADER_PARSE_STATE* current_state = &This->baseShader.parse_state;
814 SHADER_BUFFER* buffer = arg->buffer;
817 pshader_gen_input_modifier_line(buffer, arg->src[0], 0, src0_name);
818 shader_addline(buffer, "DP3 TMP.z, T%lu, %s;\n", reg, src0_name);
820 /* Calculate reflection vector (Assume normal is normalized): RF = 2*(N.E)*N -E */
821 shader_addline(buffer, "DP3 TMP.w, TMP, C[%lu];\n", reg3);
822 shader_addline(buffer, "MUL TMP, TMP.w, TMP;\n");
823 shader_addline(buffer, "MAD TMP, coefmul.x, TMP, -C[%lu];\n", reg3);
825 /* Cubemap textures will be more used than 3D ones. */
826 shader_addline(buffer, "TEX T%lu, TMP, texture[%lu], CUBE;\n", reg, reg);
827 current_state->current_row = 0;
830 /** Handles transforming all D3DSIO_M?x? opcodes for
831 Vertex shaders to ARB_vertex_program codes */
832 void vshader_hw_mnxn(SHADER_OPCODE_ARG* arg) {
836 SHADER_OPCODE_ARG tmpArg;
838 memset(&tmpArg, 0, sizeof(SHADER_OPCODE_ARG));
840 /* Set constants for the temporary argument */
841 tmpArg.shader = arg->shader;
842 tmpArg.buffer = arg->buffer;
843 tmpArg.src[0] = arg->src[0];
844 tmpArg.src_addr[0] = arg->src_addr[0];
845 tmpArg.src_addr[1] = arg->src_addr[1];
846 tmpArg.reg_maps = arg->reg_maps;
848 switch(arg->opcode->opcode) {
851 tmpArg.opcode = &IWineD3DVertexShaderImpl_shader_ins[D3DSIO_DP4];
855 tmpArg.opcode = &IWineD3DVertexShaderImpl_shader_ins[D3DSIO_DP4];
859 tmpArg.opcode = &IWineD3DVertexShaderImpl_shader_ins[D3DSIO_DP3];
863 tmpArg.opcode = &IWineD3DVertexShaderImpl_shader_ins[D3DSIO_DP3];
867 tmpArg.opcode = &IWineD3DVertexShaderImpl_shader_ins[D3DSIO_DP3];
873 for (i = 0; i < nComponents; i++) {
874 tmpArg.dst = ((arg->dst) & ~D3DSP_WRITEMASK_ALL)|(D3DSP_WRITEMASK_0<<i);
875 tmpArg.src[1] = arg->src[1]+i;
876 vshader_hw_map2gl(&tmpArg);
880 /* TODO: merge with pixel shader */
881 /* Map the opcode 1-to-1 to the GL code */
882 void vshader_hw_map2gl(SHADER_OPCODE_ARG* arg) {
884 CONST SHADER_OPCODE* curOpcode = arg->opcode;
885 SHADER_BUFFER* buffer = arg->buffer;
886 DWORD dst = arg->dst;
887 DWORD* src = arg->src;
889 DWORD dst_regtype = shader_get_regtype(dst);
893 if (curOpcode->opcode == D3DSIO_MOV && dst_regtype == D3DSPR_ADDR)
894 strcpy(tmpLine, "ARL");
896 strcpy(tmpLine, curOpcode->glname);
898 if (curOpcode->num_params > 0) {
899 vshader_program_add_param(arg, dst, FALSE, tmpLine);
900 for (i = 1; i < curOpcode->num_params; ++i) {
901 strcat(tmpLine, ",");
902 vshader_program_add_param(arg, src[i-1], TRUE, tmpLine);
905 shader_addline(buffer, "%s;\n", tmpLine);