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
12 * This library is free software; you can redistribute it and/or
13 * modify it under the terms of the GNU Lesser General Public
14 * License as published by the Free Software Foundation; either
15 * version 2.1 of the License, or (at your option) any later version.
17 * This library is distributed in the hope that it will be useful,
18 * but WITHOUT ANY WARRANTY; without even the implied warranty of
19 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
20 * Lesser General Public License for more details.
22 * You should have received a copy of the GNU Lesser General Public
23 * License along with this library; if not, write to the Free Software
24 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
32 #include "wined3d_private.h"
34 WINE_DEFAULT_DEBUG_CHANNEL(d3d_shader
);
36 #define GLINFO_LOCATION (*gl_info)
38 /********************************************************
39 * ARB_[vertex/fragment]_program helper functions follow
40 ********************************************************/
43 * Loads floating point constants into the currently set ARB_vertex/fragment_program.
44 * When @constants_set == NULL, it will load all the constants.
46 * @target_type should be either GL_VERTEX_PROGRAM_ARB (for vertex shaders)
47 * or GL_FRAGMENT_PROGRAM_ARB (for pixel shaders)
49 void shader_arb_load_constantsF(
50 IWineD3DBaseShaderImpl
* This
,
51 WineD3D_GL_Info
*gl_info
,
53 unsigned max_constants
,
55 BOOL
* constants_set
) {
60 for (i
=0; i
<max_constants
; ++i
) {
61 if (NULL
== constants_set
|| constants_set
[i
]) {
62 TRACE("Loading constants %i: %f, %f, %f, %f\n", i
,
63 constants
[i
* 4 + 0], constants
[i
* 4 + 1],
64 constants
[i
* 4 + 2], constants
[i
* 4 + 3]);
66 GL_EXTCALL(glProgramEnvParameter4fvARB(target_type
, i
, &constants
[i
* 4]));
67 checkGLcall("glProgramEnvParameter4fvARB");
71 /* Load immediate constants */
72 ptr
= list_head(&This
->baseShader
.constantsF
);
75 local_constant
* lconst
= LIST_ENTRY(ptr
, struct local_constant
, entry
);
76 unsigned int idx
= lconst
->idx
;
77 GLfloat
* values
= (GLfloat
*) lconst
->value
;
79 TRACE("Loading local constants %i: %f, %f, %f, %f\n", idx
,
80 values
[0], values
[1], values
[2], values
[3]);
82 GL_EXTCALL(glProgramEnvParameter4fvARB(target_type
, idx
, values
));
83 checkGLcall("glProgramEnvParameter4fvARB");
84 ptr
= list_next(&This
->baseShader
.constantsF
, ptr
);
89 * Loads the app-supplied constants into the currently set ARB_[vertex/fragment]_programs.
91 * We only support float constants in ARB at the moment, so don't
92 * worry about the Integers or Booleans
94 void shader_arb_load_constants(
95 IWineD3DStateBlock
* iface
,
97 char useVertexShader
) {
99 IWineD3DStateBlockImpl
* stateBlock
= (IWineD3DStateBlockImpl
*) iface
;
100 WineD3D_GL_Info
*gl_info
= &((IWineD3DImpl
*)stateBlock
->wineD3DDevice
->wineD3D
)->gl_info
;
102 if (useVertexShader
) {
103 IWineD3DBaseShaderImpl
* vshader
= (IWineD3DBaseShaderImpl
*) stateBlock
->vertexShader
;
104 IWineD3DVertexShaderImpl
* vshader_impl
= (IWineD3DVertexShaderImpl
*) stateBlock
->vertexShader
;
105 IWineD3DVertexDeclarationImpl
* vertexDeclaration
=
106 (IWineD3DVertexDeclarationImpl
*) vshader_impl
->vertexDeclaration
;
108 if (NULL
!= vertexDeclaration
&& NULL
!= vertexDeclaration
->constants
) {
109 /* Load DirectX 8 float constants for vertex shader */
110 shader_arb_load_constantsF(vshader
, gl_info
, GL_VERTEX_PROGRAM_ARB
,
111 GL_LIMITS(vshader_constantsF
),
112 vertexDeclaration
->constants
, NULL
);
115 /* Load DirectX 9 float constants for vertex shader */
116 shader_arb_load_constantsF(vshader
, gl_info
, GL_VERTEX_PROGRAM_ARB
,
117 GL_LIMITS(vshader_constantsF
),
118 stateBlock
->vertexShaderConstantF
,
119 stateBlock
->set
.vertexShaderConstantsF
);
122 if (usePixelShader
) {
124 IWineD3DBaseShaderImpl
* pshader
= (IWineD3DBaseShaderImpl
*) stateBlock
->pixelShader
;
126 /* Load DirectX 9 float constants for pixel shader */
127 shader_arb_load_constantsF(pshader
, gl_info
, GL_FRAGMENT_PROGRAM_ARB
,
128 GL_LIMITS(pshader_constantsF
),
129 stateBlock
->pixelShaderConstantF
,
130 stateBlock
->set
.pixelShaderConstantsF
);
134 /* Generate the variable & register declarations for the ARB_vertex_program output target */
135 void shader_generate_arb_declarations(
136 IWineD3DBaseShader
*iface
,
137 shader_reg_maps
* reg_maps
,
138 SHADER_BUFFER
* buffer
,
139 WineD3D_GL_Info
* gl_info
) {
141 IWineD3DBaseShaderImpl
* This
= (IWineD3DBaseShaderImpl
*) iface
;
143 char pshader
= shader_is_pshader_version(This
->baseShader
.hex_version
);
144 unsigned max_constantsF
= min(This
->baseShader
.limits
.constant_float
,
145 (pshader
? GL_LIMITS(pshader_constantsF
) : GL_LIMITS(vshader_constantsF
)));
147 /* Temporary Output register */
148 shader_addline(buffer
, "TEMP TMP_OUT;\n");
150 for(i
= 0; i
< This
->baseShader
.limits
.temporary
; i
++) {
151 if (reg_maps
->temporary
[i
])
152 shader_addline(buffer
, "TEMP R%lu;\n", i
);
155 for (i
= 0; i
< This
->baseShader
.limits
.address
; i
++) {
156 if (reg_maps
->address
[i
])
157 shader_addline(buffer
, "ADDRESS A%ld;\n", i
);
160 for(i
= 0; i
< This
->baseShader
.limits
.texcoord
; i
++) {
161 if (reg_maps
->texcoord
[i
])
162 shader_addline(buffer
,"TEMP T%lu;\n", i
);
165 /* Texture coordinate registers must be pre-loaded */
166 for (i
= 0; i
< This
->baseShader
.limits
.texcoord
; i
++) {
167 if (reg_maps
->texcoord
[i
])
168 shader_addline(buffer
, "MOV T%lu, fragment.texcoord[%lu];\n", i
, i
);
171 /* Need to PARAM the environment parameters (constants) so we can use relative addressing */
172 shader_addline(buffer
, "PARAM C[%d] = { program.env[0..%d] };\n",
173 max_constantsF
, max_constantsF
- 1);
176 static const char* shift_tab
[] = {
177 "dummy", /* 0 (none) */
178 "coefmul.x", /* 1 (x2) */
179 "coefmul.y", /* 2 (x4) */
180 "coefmul.z", /* 3 (x8) */
181 "coefmul.w", /* 4 (x16) */
182 "dummy", /* 5 (x32) */
183 "dummy", /* 6 (x64) */
184 "dummy", /* 7 (x128) */
185 "dummy", /* 8 (d256) */
186 "dummy", /* 9 (d128) */
187 "dummy", /* 10 (d64) */
188 "dummy", /* 11 (d32) */
189 "coefdiv.w", /* 12 (d16) */
190 "coefdiv.z", /* 13 (d8) */
191 "coefdiv.y", /* 14 (d4) */
192 "coefdiv.x" /* 15 (d2) */
195 static void pshader_get_write_mask(const DWORD output_reg
, char *write_mask
) {
197 if ((output_reg
& D3DSP_WRITEMASK_ALL
) != D3DSP_WRITEMASK_ALL
) {
198 strcat(write_mask
, ".");
199 if (output_reg
& D3DSP_WRITEMASK_0
) strcat(write_mask
, "r");
200 if (output_reg
& D3DSP_WRITEMASK_1
) strcat(write_mask
, "g");
201 if (output_reg
& D3DSP_WRITEMASK_2
) strcat(write_mask
, "b");
202 if (output_reg
& D3DSP_WRITEMASK_3
) strcat(write_mask
, "a");
206 /* TODO: merge with pixel shader */
207 static void vshader_program_add_output_param_swizzle(const DWORD param
, int is_color
, char *hwLine
) {
208 /** operand output */
209 if ((param
& D3DSP_WRITEMASK_ALL
) != D3DSP_WRITEMASK_ALL
) {
211 if (param
& D3DSP_WRITEMASK_0
) { strcat(hwLine
, "x"); }
212 if (param
& D3DSP_WRITEMASK_1
) { strcat(hwLine
, "y"); }
213 if (param
& D3DSP_WRITEMASK_2
) { strcat(hwLine
, "z"); }
214 if (param
& D3DSP_WRITEMASK_3
) { strcat(hwLine
, "w"); }
218 static void pshader_get_input_register_swizzle(const DWORD instr
, char *swzstring
) {
219 static const char swizzle_reg_chars
[] = "rgba";
220 DWORD swizzle
= (instr
& D3DSP_SWIZZLE_MASK
) >> D3DSP_SWIZZLE_SHIFT
;
221 DWORD swizzle_x
= swizzle
& 0x03;
222 DWORD swizzle_y
= (swizzle
>> 2) & 0x03;
223 DWORD swizzle_z
= (swizzle
>> 4) & 0x03;
224 DWORD swizzle_w
= (swizzle
>> 6) & 0x03;
226 * swizzle bits fields:
230 if ((D3DSP_NOSWIZZLE
>> D3DSP_SWIZZLE_SHIFT
) != swizzle
) { /* ! D3DVS_NOSWIZZLE == 0xE4 << D3DVS_SWIZZLE_SHIFT */
231 if (swizzle_x
== swizzle_y
&&
232 swizzle_x
== swizzle_z
&&
233 swizzle_x
== swizzle_w
) {
234 sprintf(swzstring
, ".%c", swizzle_reg_chars
[swizzle_x
]);
236 sprintf(swzstring
, ".%c%c%c%c",
237 swizzle_reg_chars
[swizzle_x
],
238 swizzle_reg_chars
[swizzle_y
],
239 swizzle_reg_chars
[swizzle_z
],
240 swizzle_reg_chars
[swizzle_w
]);
245 /* TODO: merge with pixel shader */
246 static void vshader_program_add_input_param_swizzle(const DWORD param
, int is_color
, char *hwLine
) {
247 static const char swizzle_reg_chars_color_fix
[] = "zyxw";
248 static const char swizzle_reg_chars
[] = "xyzw";
249 const char* swizzle_regs
= NULL
;
253 DWORD swizzle
= (param
& D3DVS_SWIZZLE_MASK
) >> D3DVS_SWIZZLE_SHIFT
;
254 DWORD swizzle_x
= swizzle
& 0x03;
255 DWORD swizzle_y
= (swizzle
>> 2) & 0x03;
256 DWORD swizzle_z
= (swizzle
>> 4) & 0x03;
257 DWORD swizzle_w
= (swizzle
>> 6) & 0x03;
260 swizzle_regs
= swizzle_reg_chars_color_fix
;
262 swizzle_regs
= swizzle_reg_chars
;
266 * swizzle bits fields:
269 if ((D3DVS_NOSWIZZLE
>> D3DVS_SWIZZLE_SHIFT
) == swizzle
) { /* D3DVS_NOSWIZZLE == 0xE4 << D3DVS_SWIZZLE_SHIFT */
271 sprintf(tmpReg
, ".%c%c%c%c",
272 swizzle_regs
[swizzle_x
],
273 swizzle_regs
[swizzle_y
],
274 swizzle_regs
[swizzle_z
],
275 swizzle_regs
[swizzle_w
]);
276 strcat(hwLine
, tmpReg
);
280 if (swizzle_x
== swizzle_y
&&
281 swizzle_x
== swizzle_z
&&
282 swizzle_x
== swizzle_w
)
284 sprintf(tmpReg
, ".%c", swizzle_regs
[swizzle_x
]);
285 strcat(hwLine
, tmpReg
);
287 sprintf(tmpReg
, ".%c%c%c%c",
288 swizzle_regs
[swizzle_x
],
289 swizzle_regs
[swizzle_y
],
290 swizzle_regs
[swizzle_z
],
291 swizzle_regs
[swizzle_w
]);
292 strcat(hwLine
, tmpReg
);
296 static void pshader_get_register_name(
297 const DWORD param
, char* regstr
) {
299 DWORD reg
= param
& D3DSP_REGNUM_MASK
;
300 DWORD regtype
= shader_get_regtype(param
);
304 sprintf(regstr
, "R%lu", reg
);
308 strcpy(regstr
, "fragment.color.primary");
310 strcpy(regstr
, "fragment.color.secondary");
314 sprintf(regstr
, "C[%lu]", reg
);
316 case D3DSPR_TEXTURE
: /* case D3DSPR_ADDR: */
317 sprintf(regstr
,"T%lu", reg
);
319 case D3DSPR_COLOROUT
:
321 sprintf(regstr
, "result.color");
323 /* TODO: See GL_ARB_draw_buffers */
324 FIXME("Unsupported write to render target %lu\n", reg
);
325 sprintf(regstr
, "unsupported_register");
328 case D3DSPR_DEPTHOUT
:
329 sprintf(regstr
, "result.depth");
332 sprintf(regstr
, "oD[%lu]", reg
);
334 case D3DSPR_TEXCRDOUT
:
335 sprintf(regstr
, "oT[%lu]", reg
);
338 FIXME("Unhandled register name Type(%ld)\n", regtype
);
339 sprintf(regstr
, "unrecognized_register");
344 /* TODO: merge with pixel shader */
345 static void vshader_program_add_param(SHADER_OPCODE_ARG
*arg
, const DWORD param
, BOOL is_input
, char *hwLine
) {
347 IWineD3DVertexShaderImpl
* This
= (IWineD3DVertexShaderImpl
*) arg
->shader
;
349 /* oPos, oFog and oPts in D3D */
350 static const char* hwrastout_reg_names
[] = { "TMP_OUT", "TMP_FOG", "result.pointsize" };
352 DWORD reg
= param
& D3DSP_REGNUM_MASK
;
353 DWORD regtype
= shader_get_regtype(param
);
355 BOOL is_color
= FALSE
;
357 if ((param
& D3DSP_SRCMOD_MASK
) == D3DSPSM_NEG
) {
358 strcat(hwLine
, " -");
365 sprintf(tmpReg
, "R%lu", reg
);
366 strcat(hwLine
, tmpReg
);
370 if (vshader_input_is_color((IWineD3DVertexShader
*) This
, reg
))
373 sprintf(tmpReg
, "vertex.attrib[%lu]", reg
);
374 strcat(hwLine
, tmpReg
);
377 sprintf(tmpReg
, "C[%s%lu]", (param
& D3DVS_ADDRMODE_RELATIVE
) ? "A0.x + " : "", reg
);
378 strcat(hwLine
, tmpReg
);
380 case D3DSPR_ADDR
: /*case D3DSPR_TEXTURE:*/
381 sprintf(tmpReg
, "A%lu", reg
);
382 strcat(hwLine
, tmpReg
);
385 sprintf(tmpReg
, "%s", hwrastout_reg_names
[reg
]);
386 strcat(hwLine
, tmpReg
);
390 strcat(hwLine
, "result.color.primary");
392 strcat(hwLine
, "result.color.secondary");
395 case D3DSPR_TEXCRDOUT
:
396 sprintf(tmpReg
, "result.texcoord[%lu]", reg
);
397 strcat(hwLine
, tmpReg
);
400 FIXME("Unknown reg type %ld %ld\n", regtype
, reg
);
401 strcat(hwLine
, "unrecognized_register");
406 vshader_program_add_output_param_swizzle(param
, is_color
, hwLine
);
408 vshader_program_add_input_param_swizzle(param
, is_color
, hwLine
);
412 static void pshader_gen_input_modifier_line (
413 SHADER_BUFFER
* buffer
,
418 /* Generate a line that does the input modifier computation and return the input register to use */
423 /* Assume a new line will be added */
426 /* Get register name */
427 pshader_get_register_name(instr
, regstr
);
428 pshader_get_input_register_swizzle(instr
, swzstr
);
430 switch (instr
& D3DSP_SRCMOD_MASK
) {
432 sprintf(outregstr
, "%s%s", regstr
, swzstr
);
436 sprintf(outregstr
, "-%s%s", regstr
, swzstr
);
440 shader_addline(buffer
, "ADD T%c, %s, -coefdiv.x;\n", 'A' + tmpreg
, regstr
);
442 case D3DSPSM_BIASNEG
:
443 shader_addline(buffer
, "ADD T%c, -%s, coefdiv.x;\n", 'A' + tmpreg
, regstr
);
446 shader_addline(buffer
, "MAD T%c, %s, coefmul.x, -one.x;\n", 'A' + tmpreg
, regstr
);
448 case D3DSPSM_SIGNNEG
:
449 shader_addline(buffer
, "MAD T%c, %s, -coefmul.x, one.x;\n", 'A' + tmpreg
, regstr
);
452 shader_addline(buffer
, "SUB T%c, one.x, %s;\n", 'A' + tmpreg
, regstr
);
455 shader_addline(buffer
, "ADD T%c, %s, %s;\n", 'A' + tmpreg
, regstr
, regstr
);
458 shader_addline(buffer
, "ADD T%c, -%s, -%s;\n", 'A' + tmpreg
, regstr
, regstr
);
461 shader_addline(buffer
, "RCP T%c, %s.z;\n", 'A' + tmpreg
, regstr
);
462 shader_addline(buffer
, "MUL T%c, %s, T%c;\n", 'A' + tmpreg
, regstr
, 'A' + tmpreg
);
465 shader_addline(buffer
, "RCP T%c, %s.w;\n", 'A' + tmpreg
, regstr
);
466 shader_addline(buffer
, "MUL T%c, %s, T%c;\n", 'A' + tmpreg
, regstr
, 'A' + tmpreg
);
469 sprintf(outregstr
, "%s%s", regstr
, swzstr
);
473 /* Return modified or original register, with swizzle */
475 sprintf(outregstr
, "T%c%s", 'A' + tmpreg
, swzstr
);
478 inline static void pshader_gen_output_modifier_line(
479 SHADER_BUFFER
* buffer
,
485 /* Generate a line that does the output modifier computation */
486 shader_addline(buffer
, "MUL%s %s%s, %s, %s;\n", saturate
? "_SAT" : "",
487 regstr
, write_mask
, regstr
, shift_tab
[shift
]);
490 void pshader_hw_cnd(SHADER_OPCODE_ARG
* arg
) {
492 SHADER_BUFFER
* buffer
= arg
->buffer
;
495 char src_name
[3][50];
497 /* FIXME: support output modifiers */
499 /* Handle output register */
500 pshader_get_register_name(arg
->dst
, dst_name
);
501 pshader_get_write_mask(arg
->dst
, dst_wmask
);
502 strcat(dst_name
, dst_wmask
);
504 /* Generate input register names (with modifiers) */
505 pshader_gen_input_modifier_line(buffer
, arg
->src
[0], 0, src_name
[0]);
506 pshader_gen_input_modifier_line(buffer
, arg
->src
[1], 1, src_name
[1]);
507 pshader_gen_input_modifier_line(buffer
, arg
->src
[2], 2, src_name
[2]);
509 shader_addline(buffer
, "ADD TMP, -%s, coefdiv.x;\n", src_name
[0]);
510 shader_addline(buffer
, "CMP %s, TMP, %s, %s;\n", dst_name
, src_name
[1], src_name
[2]);
513 void pshader_hw_cmp(SHADER_OPCODE_ARG
* arg
) {
515 SHADER_BUFFER
* buffer
= arg
->buffer
;
518 char src_name
[3][50];
520 /* FIXME: support output modifiers */
522 /* Handle output register */
523 pshader_get_register_name(arg
->dst
, dst_name
);
524 pshader_get_write_mask(arg
->dst
, dst_wmask
);
525 strcat(dst_name
, dst_wmask
);
527 /* Generate input register names (with modifiers) */
528 pshader_gen_input_modifier_line(buffer
, arg
->src
[0], 0, src_name
[0]);
529 pshader_gen_input_modifier_line(buffer
, arg
->src
[1], 1, src_name
[1]);
530 pshader_gen_input_modifier_line(buffer
, arg
->src
[2], 2, src_name
[2]);
532 shader_addline(buffer
, "CMP %s, %s, %s, %s;\n", dst_name
,
533 src_name
[0], src_name
[2], src_name
[1]);
536 /* Map the opcode 1-to-1 to the GL code */
537 void pshader_hw_map2gl(SHADER_OPCODE_ARG
* arg
) {
539 CONST SHADER_OPCODE
* curOpcode
= arg
->opcode
;
540 SHADER_BUFFER
* buffer
= arg
->buffer
;
541 DWORD dst
= arg
->dst
;
542 DWORD
* src
= arg
->src
;
547 /* Output token related */
548 char output_rname
[256];
549 char output_wmask
[20];
550 BOOL saturate
= FALSE
;
551 BOOL centroid
= FALSE
;
552 BOOL partialprecision
= FALSE
;
555 strcpy(tmpLine
, curOpcode
->glname
);
557 /* Process modifiers */
558 if (0 != (dst
& D3DSP_DSTMOD_MASK
)) {
559 DWORD mask
= dst
& D3DSP_DSTMOD_MASK
;
561 saturate
= mask
& D3DSPDM_SATURATE
;
562 centroid
= mask
& D3DSPDM_MSAMPCENTROID
;
563 partialprecision
= mask
& D3DSPDM_PARTIALPRECISION
;
564 mask
&= ~(D3DSPDM_MSAMPCENTROID
| D3DSPDM_PARTIALPRECISION
| D3DSPDM_SATURATE
);
566 FIXME("Unrecognized modifier(0x%#lx)\n", mask
>> D3DSP_DSTMOD_SHIFT
);
569 FIXME("Unhandled modifier(0x%#lx)\n", mask
>> D3DSP_DSTMOD_SHIFT
);
571 shift
= (dst
& D3DSP_DSTSHIFT_MASK
) >> D3DSP_DSTSHIFT_SHIFT
;
573 /* Generate input and output registers */
574 if (curOpcode
->num_params
> 0) {
575 char operands
[4][100];
577 /* Generate input register names (with modifiers) */
578 for (i
= 1; i
< curOpcode
->num_params
; ++i
)
579 pshader_gen_input_modifier_line(buffer
, src
[i
-1], i
-1, operands
[i
]);
581 /* Handle output register */
582 pshader_get_register_name(dst
, output_rname
);
583 strcpy(operands
[0], output_rname
);
584 pshader_get_write_mask(dst
, output_wmask
);
585 strcat(operands
[0], output_wmask
);
587 if (saturate
&& (shift
== 0))
588 strcat(tmpLine
, "_SAT");
589 strcat(tmpLine
, " ");
590 strcat(tmpLine
, operands
[0]);
591 for (i
= 1; i
< curOpcode
->num_params
; i
++) {
592 strcat(tmpLine
, ", ");
593 strcat(tmpLine
, operands
[i
]);
595 strcat(tmpLine
,";\n");
596 shader_addline(buffer
, tmpLine
);
598 /* A shift requires another line. */
600 pshader_gen_output_modifier_line(buffer
, saturate
, output_wmask
, shift
, output_rname
);
604 void pshader_hw_tex(SHADER_OPCODE_ARG
* arg
) {
606 IWineD3DPixelShaderImpl
* This
= (IWineD3DPixelShaderImpl
*) arg
->shader
;
607 DWORD dst
= arg
->dst
;
608 DWORD
* src
= arg
->src
;
609 SHADER_BUFFER
* buffer
= arg
->buffer
;
610 DWORD hex_version
= This
->baseShader
.hex_version
;
615 DWORD reg_sampler_code
;
617 /* All versions have a destination register */
618 reg_dest_code
= dst
& D3DSP_REGNUM_MASK
;
619 pshader_get_register_name(dst
, reg_dest
);
621 /* 1.0-1.3: Use destination register as coordinate source.
622 1.4+: Use provided coordinate source register. */
623 if (hex_version
< D3DPS_VERSION(1,4))
624 strcpy(reg_coord
, reg_dest
);
626 pshader_gen_input_modifier_line(buffer
, src
[0], 0, reg_coord
);
628 /* 1.0-1.4: Use destination register number as texture code.
629 2.0+: Use provided sampler number as texure code. */
630 if (hex_version
< D3DPS_VERSION(2,0))
631 reg_sampler_code
= reg_dest_code
;
633 reg_sampler_code
= src
[1] & D3DSP_REGNUM_MASK
;
635 shader_addline(buffer
, "TEX %s, %s, texture[%lu], 2D;\n",
636 reg_dest
, reg_coord
, reg_sampler_code
);
639 void pshader_hw_texcoord(SHADER_OPCODE_ARG
* arg
) {
641 IWineD3DPixelShaderImpl
* This
= (IWineD3DPixelShaderImpl
*) arg
->shader
;
642 DWORD dst
= arg
->dst
;
643 DWORD
* src
= arg
->src
;
644 SHADER_BUFFER
* buffer
= arg
->buffer
;
645 DWORD hex_version
= This
->baseShader
.hex_version
;
648 pshader_get_write_mask(dst
, tmp
);
649 if (hex_version
!= D3DPS_VERSION(1,4)) {
650 DWORD reg
= dst
& D3DSP_REGNUM_MASK
;
651 shader_addline(buffer
, "MOV_SAT T%lu%s, fragment.texcoord[%lu];\n", reg
, tmp
, reg
);
653 DWORD reg1
= dst
& D3DSP_REGNUM_MASK
;
654 DWORD reg2
= src
[0] & D3DSP_REGNUM_MASK
;
655 shader_addline(buffer
, "MOV R%lu%s, fragment.texcoord[%lu];\n", reg1
, tmp
, reg2
);
659 void pshader_hw_texreg2ar(SHADER_OPCODE_ARG
* arg
) {
661 SHADER_BUFFER
* buffer
= arg
->buffer
;
663 DWORD reg1
= arg
->dst
& D3DSP_REGNUM_MASK
;
664 DWORD reg2
= arg
->src
[0] & D3DSP_REGNUM_MASK
;
665 shader_addline(buffer
, "MOV TMP.r, T%lu.a;\n", reg2
);
666 shader_addline(buffer
, "MOV TMP.g, T%lu.r;\n", reg2
);
667 shader_addline(buffer
, "TEX T%lu, TMP, texture[%lu], 2D;\n", reg1
, reg1
);
670 void pshader_hw_texreg2gb(SHADER_OPCODE_ARG
* arg
) {
672 SHADER_BUFFER
* buffer
= arg
->buffer
;
674 DWORD reg1
= arg
->dst
& D3DSP_REGNUM_MASK
;
675 DWORD reg2
= arg
->src
[0] & D3DSP_REGNUM_MASK
;
676 shader_addline(buffer
, "MOV TMP.r, T%lu.g;\n", reg2
);
677 shader_addline(buffer
, "MOV TMP.g, T%lu.b;\n", reg2
);
678 shader_addline(buffer
, "TEX T%lu, TMP, texture[%lu], 2D;\n", reg1
, reg1
);
681 void pshader_hw_texbem(SHADER_OPCODE_ARG
* arg
) {
683 SHADER_BUFFER
* buffer
= arg
->buffer
;
684 DWORD reg1
= arg
->dst
& D3DSP_REGNUM_MASK
;
685 DWORD reg2
= arg
->src
[0] & D3DSP_REGNUM_MASK
;
687 /* FIXME: Should apply the BUMPMAPENV matrix */
688 shader_addline(buffer
, "ADD TMP.rg, fragment.texcoord[%lu], T%lu;\n", reg1
, reg2
);
689 shader_addline(buffer
, "TEX T%lu, TMP, texture[%lu], 2D;\n", reg1
, reg1
);
692 void pshader_hw_texm3x2pad(SHADER_OPCODE_ARG
* arg
) {
694 DWORD reg
= arg
->dst
& D3DSP_REGNUM_MASK
;
695 SHADER_BUFFER
* buffer
= arg
->buffer
;
698 pshader_gen_input_modifier_line(buffer
, arg
->src
[0], 0, src0_name
);
699 shader_addline(buffer
, "DP3 TMP.x, T%lu, %s;\n", reg
, src0_name
);
702 void pshader_hw_texm3x2tex(SHADER_OPCODE_ARG
* arg
) {
704 DWORD reg
= arg
->dst
& D3DSP_REGNUM_MASK
;
705 SHADER_BUFFER
* buffer
= arg
->buffer
;
708 pshader_gen_input_modifier_line(buffer
, arg
->src
[0], 0, src0_name
);
709 shader_addline(buffer
, "DP3 TMP.y, T%lu, %s;\n", reg
, src0_name
);
710 shader_addline(buffer
, "TEX T%lu, TMP, texture[%lu], 2D;\n", reg
, reg
);
713 void pshader_hw_texm3x3pad(SHADER_OPCODE_ARG
* arg
) {
715 IWineD3DPixelShaderImpl
* This
= (IWineD3DPixelShaderImpl
*) arg
->shader
;
716 DWORD reg
= arg
->dst
& D3DSP_REGNUM_MASK
;
717 SHADER_BUFFER
* buffer
= arg
->buffer
;
718 SHADER_PARSE_STATE
* current_state
= &This
->baseShader
.parse_state
;
721 pshader_gen_input_modifier_line(buffer
, arg
->src
[0], 0, src0_name
);
722 shader_addline(buffer
, "DP3 TMP.%c, T%lu, %s;\n", 'x' + current_state
->current_row
, reg
, src0_name
);
723 current_state
->texcoord_w
[current_state
->current_row
++] = reg
;
726 void pshader_hw_texm3x3tex(SHADER_OPCODE_ARG
* arg
) {
728 IWineD3DPixelShaderImpl
* This
= (IWineD3DPixelShaderImpl
*) arg
->shader
;
729 DWORD reg
= arg
->dst
& D3DSP_REGNUM_MASK
;
730 SHADER_BUFFER
* buffer
= arg
->buffer
;
731 SHADER_PARSE_STATE
* current_state
= &This
->baseShader
.parse_state
;
734 pshader_gen_input_modifier_line(buffer
, arg
->src
[0], 0, src0_name
);
735 shader_addline(buffer
, "DP3 TMP.z, T%lu, %s;\n", reg
, src0_name
);
737 /* Cubemap textures will be more used than 3D ones. */
738 shader_addline(buffer
, "TEX T%lu, TMP, texture[%lu], CUBE;\n", reg
, reg
);
739 current_state
->current_row
= 0;
742 void pshader_hw_texm3x3vspec(SHADER_OPCODE_ARG
* arg
) {
744 IWineD3DPixelShaderImpl
* This
= (IWineD3DPixelShaderImpl
*) arg
->shader
;
745 DWORD reg
= arg
->dst
& D3DSP_REGNUM_MASK
;
746 SHADER_BUFFER
* buffer
= arg
->buffer
;
747 SHADER_PARSE_STATE
* current_state
= &This
->baseShader
.parse_state
;
750 pshader_gen_input_modifier_line(buffer
, arg
->src
[0], 0, src0_name
);
751 shader_addline(buffer
, "DP3 TMP.z, T%lu, %s;\n", reg
, src0_name
);
753 /* Construct the eye-ray vector from w coordinates */
754 shader_addline(buffer
, "MOV TMP2.x, fragment.texcoord[%lu].w;\n", current_state
->texcoord_w
[0]);
755 shader_addline(buffer
, "MOV TMP2.y, fragment.texcoord[%lu].w;\n", current_state
->texcoord_w
[1]);
756 shader_addline(buffer
, "MOV TMP2.z, fragment.texcoord[%lu].w;\n", reg
);
758 /* Calculate reflection vector (Assume normal is normalized): RF = 2*(N.E)*N -E */
759 shader_addline(buffer
, "DP3 TMP.w, TMP, TMP2;\n");
760 shader_addline(buffer
, "MUL TMP, TMP.w, TMP;\n");
761 shader_addline(buffer
, "MAD TMP, coefmul.x, TMP, -TMP2;\n");
763 /* Cubemap textures will be more used than 3D ones. */
764 shader_addline(buffer
, "TEX T%lu, TMP, texture[%lu], CUBE;\n", reg
, reg
);
765 current_state
->current_row
= 0;
768 void pshader_hw_texm3x3spec(SHADER_OPCODE_ARG
* arg
) {
770 IWineD3DPixelShaderImpl
* This
= (IWineD3DPixelShaderImpl
*) arg
->shader
;
771 DWORD reg
= arg
->dst
& D3DSP_REGNUM_MASK
;
772 DWORD reg3
= arg
->src
[1] & D3DSP_REGNUM_MASK
;
773 SHADER_PARSE_STATE
* current_state
= &This
->baseShader
.parse_state
;
774 SHADER_BUFFER
* buffer
= arg
->buffer
;
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 /* Calculate reflection vector (Assume normal is normalized): RF = 2*(N.E)*N -E */
781 shader_addline(buffer
, "DP3 TMP.w, TMP, C[%lu];\n", reg3
);
782 shader_addline(buffer
, "MUL TMP, TMP.w, TMP;\n");
783 shader_addline(buffer
, "MAD TMP, coefmul.x, TMP, -C[%lu];\n", reg3
);
785 /* Cubemap textures will be more used than 3D ones. */
786 shader_addline(buffer
, "TEX T%lu, TMP, texture[%lu], CUBE;\n", reg
, reg
);
787 current_state
->current_row
= 0;
790 /** Handles transforming all D3DSIO_M?x? opcodes for
791 Vertex shaders to ARB_vertex_program codes */
792 void vshader_hw_mnxn(SHADER_OPCODE_ARG
* arg
) {
796 SHADER_OPCODE_ARG tmpArg
;
798 memset(&tmpArg
, 0, sizeof(SHADER_OPCODE_ARG
));
800 /* Set constants for the temporary argument */
801 tmpArg
.shader
= arg
->shader
;
802 tmpArg
.buffer
= arg
->buffer
;
803 tmpArg
.src
[0] = arg
->src
[0];
804 tmpArg
.src_addr
[0] = arg
->src_addr
[0];
805 tmpArg
.src_addr
[1] = arg
->src_addr
[1];
806 tmpArg
.reg_maps
= arg
->reg_maps
;
808 switch(arg
->opcode
->opcode
) {
811 tmpArg
.opcode
= &IWineD3DVertexShaderImpl_shader_ins
[D3DSIO_DP4
];
815 tmpArg
.opcode
= &IWineD3DVertexShaderImpl_shader_ins
[D3DSIO_DP4
];
819 tmpArg
.opcode
= &IWineD3DVertexShaderImpl_shader_ins
[D3DSIO_DP3
];
823 tmpArg
.opcode
= &IWineD3DVertexShaderImpl_shader_ins
[D3DSIO_DP3
];
827 tmpArg
.opcode
= &IWineD3DVertexShaderImpl_shader_ins
[D3DSIO_DP3
];
833 for (i
= 0; i
< nComponents
; i
++) {
834 tmpArg
.dst
= ((arg
->dst
) & ~D3DSP_WRITEMASK_ALL
)|(D3DSP_WRITEMASK_0
<<i
);
835 tmpArg
.src
[1] = arg
->src
[1]+i
;
836 vshader_hw_map2gl(&tmpArg
);
840 /* TODO: merge with pixel shader */
841 /* Map the opcode 1-to-1 to the GL code */
842 void vshader_hw_map2gl(SHADER_OPCODE_ARG
* arg
) {
844 CONST SHADER_OPCODE
* curOpcode
= arg
->opcode
;
845 SHADER_BUFFER
* buffer
= arg
->buffer
;
846 DWORD dst
= arg
->dst
;
847 DWORD
* src
= arg
->src
;
849 DWORD dst_regtype
= shader_get_regtype(dst
);
853 if (curOpcode
->opcode
== D3DSIO_MOV
&& dst_regtype
== D3DSPR_ADDR
)
854 strcpy(tmpLine
, "ARL");
856 strcpy(tmpLine
, curOpcode
->glname
);
858 if (curOpcode
->num_params
> 0) {
859 vshader_program_add_param(arg
, dst
, FALSE
, tmpLine
);
860 for (i
= 1; i
< curOpcode
->num_params
; ++i
) {
861 strcat(tmpLine
, ",");
862 vshader_program_add_param(arg
, src
[i
-1], TRUE
, tmpLine
);
865 shader_addline(buffer
, "%s;\n", tmpLine
);