2 * GLSL pixel and vertex shader implementation
4 * Copyright 2006 Jason Green
6 * This library is free software; you can redistribute it and/or
7 * modify it under the terms of the GNU Lesser General Public
8 * License as published by the Free Software Foundation; either
9 * version 2.1 of the License, or (at your option) any later version.
11 * This library is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 * Lesser General Public License for more details.
16 * You should have received a copy of the GNU Lesser General Public
17 * License along with this library; if not, write to the Free Software
18 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
23 #include "wined3d_private.h"
25 WINE_DEFAULT_DEBUG_CHANNEL(d3d_shader
);
27 #define GLINFO_LOCATION (*gl_info)
29 /** Prints the GLSL info log which will contain error messages if they exist */
30 void print_glsl_info_log(WineD3D_GL_Info
*gl_info
, GLhandleARB obj
) {
32 int infologLength
= 0;
35 GL_EXTCALL(glGetObjectParameterivARB(obj
,
36 GL_OBJECT_INFO_LOG_LENGTH_ARB
,
39 /* A size of 1 is just a null-terminated string, so the log should be bigger than
40 * that if there are errors. */
41 if (infologLength
> 1)
43 infoLog
= (char *)HeapAlloc(GetProcessHeap(), 0, infologLength
);
44 GL_EXTCALL(glGetInfoLogARB(obj
, infologLength
, NULL
, infoLog
));
45 FIXME("Error received from GLSL shader #%u: %s\n", obj
, debugstr_a(infoLog
));
46 HeapFree(GetProcessHeap(), 0, infoLog
);
51 * Loads (pixel shader) samplers
53 void shader_glsl_load_psamplers(
54 WineD3D_GL_Info
*gl_info
,
55 IWineD3DStateBlock
* iface
) {
57 IWineD3DStateBlockImpl
* stateBlock
= (IWineD3DStateBlockImpl
*) iface
;
58 GLhandleARB programId
= stateBlock
->shaderPrgId
;
61 char sampler_name
[20];
63 for (i
=0; i
< GL_LIMITS(samplers
); ++i
) {
64 if (stateBlock
->textures
[i
] != NULL
) {
65 snprintf(sampler_name
, sizeof(sampler_name
), "Psampler%d", i
);
66 name_loc
= GL_EXTCALL(glGetUniformLocationARB(programId
, sampler_name
));
68 TRACE_(d3d_shader
)("Loading %s for texture %d\n", sampler_name
, i
);
69 GL_EXTCALL(glUniform1iARB(name_loc
, i
));
70 checkGLcall("glUniform1iARB");
77 * Loads floating point constants (aka uniforms) into the currently set GLSL program.
78 * When @constants_set == NULL, it will load all the constants.
80 void shader_glsl_load_constantsF(
81 IWineD3DBaseShaderImpl
* This
,
82 WineD3D_GL_Info
*gl_info
,
83 GLhandleARB programId
,
84 unsigned max_constants
,
86 BOOL
* constants_set
) {
91 char is_pshader
= shader_is_pshader_version(This
->baseShader
.hex_version
);
92 const char* prefix
= is_pshader
? "PC":"VC";
95 for (i
=0; i
<max_constants
; ++i
) {
96 if (NULL
== constants_set
|| constants_set
[i
]) {
98 TRACE("Loading constants %i: %f, %f, %f, %f\n", i
,
99 constants
[i
* sizeof(float) + 0], constants
[i
* sizeof(float) + 1],
100 constants
[i
* sizeof(float) + 2], constants
[i
* sizeof(float) + 3]);
102 /* TODO: Benchmark and see if it would be beneficial to store the
103 * locations of the constants to avoid looking up each time */
104 snprintf(tmp_name
, sizeof(tmp_name
), "%s[%i]", prefix
, i
);
105 tmp_loc
= GL_EXTCALL(glGetUniformLocationARB(programId
, tmp_name
));
107 /* We found this uniform name in the program - go ahead and send the data */
108 GL_EXTCALL(glUniform4fvARB(tmp_loc
, 1, &constants
[i
* sizeof(float)]));
109 checkGLcall("glUniform4fvARB");
114 /* Load immediate constants */
115 ptr
= list_head(&This
->baseShader
.constantsF
);
117 local_constant
* lconst
= LIST_ENTRY(ptr
, struct local_constant
, entry
);
118 unsigned int idx
= lconst
->idx
;
119 GLfloat
* values
= (GLfloat
*) lconst
->value
;
121 TRACE("Loading local constants %i: %f, %f, %f, %f\n", idx
,
122 values
[0], values
[1], values
[2], values
[3]);
124 snprintf(tmp_name
, sizeof(tmp_name
), "%s[%i]", prefix
, idx
);
125 tmp_loc
= GL_EXTCALL(glGetUniformLocationARB(programId
, tmp_name
));
127 /* We found this uniform name in the program - go ahead and send the data */
128 GL_EXTCALL(glUniform4fvARB(tmp_loc
, 1, values
));
129 checkGLcall("glUniform4fvARB");
131 ptr
= list_next(&This
->baseShader
.constantsF
, ptr
);
136 * Loads integer constants (aka uniforms) into the currently set GLSL program.
137 * When @constants_set == NULL, it will load all the constants.
139 void shader_glsl_load_constantsI(
140 IWineD3DBaseShaderImpl
* This
,
141 WineD3D_GL_Info
*gl_info
,
142 GLhandleARB programId
,
143 unsigned max_constants
,
145 BOOL
* constants_set
) {
150 char is_pshader
= shader_is_pshader_version(This
->baseShader
.hex_version
);
151 const char* prefix
= is_pshader
? "PI":"VI";
154 for (i
=0; i
<max_constants
; ++i
) {
155 if (NULL
== constants_set
|| constants_set
[i
]) {
157 TRACE("Loading constants %i: %i, %i, %i, %i\n",
158 i
, constants
[i
*4], constants
[i
*4+1], constants
[i
*4+2], constants
[i
*4+3]);
160 /* TODO: Benchmark and see if it would be beneficial to store the
161 * locations of the constants to avoid looking up each time */
162 snprintf(tmp_name
, sizeof(tmp_name
), "%s[%i]", prefix
, i
);
163 tmp_loc
= GL_EXTCALL(glGetUniformLocationARB(programId
, tmp_name
));
165 /* We found this uniform name in the program - go ahead and send the data */
166 GL_EXTCALL(glUniform4ivARB(tmp_loc
, 1, &constants
[i
*4]));
167 checkGLcall("glUniform4ivARB");
172 /* Load immediate constants */
173 ptr
= list_head(&This
->baseShader
.constantsI
);
175 local_constant
* lconst
= LIST_ENTRY(ptr
, struct local_constant
, entry
);
176 unsigned int idx
= lconst
->idx
;
177 GLint
* values
= (GLint
*) lconst
->value
;
179 TRACE("Loading local constants %i: %i, %i, %i, %i\n", idx
,
180 values
[0], values
[1], values
[2], values
[3]);
182 snprintf(tmp_name
, sizeof(tmp_name
), "%s[%i]", prefix
, idx
);
183 tmp_loc
= GL_EXTCALL(glGetUniformLocationARB(programId
, tmp_name
));
185 /* We found this uniform name in the program - go ahead and send the data */
186 GL_EXTCALL(glUniform4ivARB(tmp_loc
, 1, values
));
187 checkGLcall("glUniform4ivARB");
189 ptr
= list_next(&This
->baseShader
.constantsI
, ptr
);
194 * Loads boolean constants (aka uniforms) into the currently set GLSL program.
195 * When @constants_set == NULL, it will load all the constants.
197 void shader_glsl_load_constantsB(
198 IWineD3DBaseShaderImpl
* This
,
199 WineD3D_GL_Info
*gl_info
,
200 GLhandleARB programId
,
201 unsigned max_constants
,
203 BOOL
* constants_set
) {
208 char is_pshader
= shader_is_pshader_version(This
->baseShader
.hex_version
);
209 const char* prefix
= is_pshader
? "PB":"VB";
212 for (i
=0; i
<max_constants
; ++i
) {
213 if (NULL
== constants_set
|| constants_set
[i
]) {
215 TRACE("Loading constants %i: %i;\n", i
, constants
[i
*4]);
217 /* TODO: Benchmark and see if it would be beneficial to store the
218 * locations of the constants to avoid looking up each time */
219 snprintf(tmp_name
, sizeof(tmp_name
), "%s[%i]", prefix
, i
);
220 tmp_loc
= GL_EXTCALL(glGetUniformLocationARB(programId
, tmp_name
));
222 /* We found this uniform name in the program - go ahead and send the data */
223 GL_EXTCALL(glUniform1ivARB(tmp_loc
, 1, &constants
[i
*4]));
224 checkGLcall("glUniform1ivARB");
229 /* Load immediate constants */
230 ptr
= list_head(&This
->baseShader
.constantsB
);
232 local_constant
* lconst
= LIST_ENTRY(ptr
, struct local_constant
, entry
);
233 unsigned int idx
= lconst
->idx
;
234 GLint
* values
= (GLint
*) lconst
->value
;
236 TRACE("Loading local constants %i: %i\n", idx
, values
[0]);
238 snprintf(tmp_name
, sizeof(tmp_name
), "%s[%i]", prefix
, idx
);
239 tmp_loc
= GL_EXTCALL(glGetUniformLocationARB(programId
, tmp_name
));
241 /* We found this uniform name in the program - go ahead and send the data */
242 GL_EXTCALL(glUniform1ivARB(tmp_loc
, 1, values
));
243 checkGLcall("glUniform1ivARB");
245 ptr
= list_next(&This
->baseShader
.constantsB
, ptr
);
252 * Loads the app-supplied constants into the currently set GLSL program.
254 void shader_glsl_load_constants(
255 IWineD3DStateBlock
* iface
,
257 char useVertexShader
) {
259 IWineD3DStateBlockImpl
* stateBlock
= (IWineD3DStateBlockImpl
*) iface
;
260 WineD3D_GL_Info
*gl_info
= &((IWineD3DImpl
*)stateBlock
->wineD3DDevice
->wineD3D
)->gl_info
;
261 GLhandleARB programId
= stateBlock
->shaderPrgId
;
263 if (programId
== 0) {
264 /* No GLSL program set - nothing to do. */
268 if (useVertexShader
) {
269 IWineD3DBaseShaderImpl
* vshader
= (IWineD3DBaseShaderImpl
*) stateBlock
->vertexShader
;
270 IWineD3DVertexShaderImpl
* vshader_impl
= (IWineD3DVertexShaderImpl
*) vshader
;
272 IWineD3DVertexDeclarationImpl
* vertexDeclaration
=
273 (IWineD3DVertexDeclarationImpl
*) vshader_impl
->vertexDeclaration
;
275 if (NULL
!= vertexDeclaration
&& NULL
!= vertexDeclaration
->constants
) {
276 /* Load DirectX 8 float constants/uniforms for vertex shader */
277 shader_glsl_load_constantsF(vshader
, gl_info
, programId
, GL_LIMITS(vshader_constantsF
),
278 vertexDeclaration
->constants
, NULL
);
281 /* Load DirectX 9 float constants/uniforms for vertex shader */
282 shader_glsl_load_constantsF(vshader
, gl_info
, programId
, GL_LIMITS(vshader_constantsF
),
283 stateBlock
->vertexShaderConstantF
,
284 stateBlock
->set
.vertexShaderConstantsF
);
286 /* Load DirectX 9 integer constants/uniforms for vertex shader */
287 shader_glsl_load_constantsI(vshader
, gl_info
, programId
, MAX_CONST_I
,
288 stateBlock
->vertexShaderConstantI
,
289 stateBlock
->set
.vertexShaderConstantsI
);
291 /* Load DirectX 9 boolean constants/uniforms for vertex shader */
292 shader_glsl_load_constantsB(vshader
, gl_info
, programId
, MAX_CONST_B
,
293 stateBlock
->vertexShaderConstantB
,
294 stateBlock
->set
.vertexShaderConstantsB
);
297 if (usePixelShader
) {
299 IWineD3DBaseShaderImpl
* pshader
= (IWineD3DBaseShaderImpl
*) stateBlock
->pixelShader
;
301 /* Load pixel shader samplers */
302 shader_glsl_load_psamplers(gl_info
, iface
);
304 /* Load DirectX 9 float constants/uniforms for pixel shader */
305 shader_glsl_load_constantsF(pshader
, gl_info
, programId
, GL_LIMITS(pshader_constantsF
),
306 stateBlock
->pixelShaderConstantF
,
307 stateBlock
->set
.pixelShaderConstantsF
);
309 /* Load DirectX 9 integer constants/uniforms for pixel shader */
310 shader_glsl_load_constantsI(pshader
, gl_info
, programId
, MAX_CONST_I
,
311 stateBlock
->pixelShaderConstantI
,
312 stateBlock
->set
.pixelShaderConstantsI
);
314 /* Load DirectX 9 boolean constants/uniforms for pixel shader */
315 shader_glsl_load_constantsB(pshader
, gl_info
, programId
, MAX_CONST_B
,
316 stateBlock
->pixelShaderConstantB
,
317 stateBlock
->set
.pixelShaderConstantsB
);
321 /** Generate the variable & register declarations for the GLSL output target */
322 void shader_generate_glsl_declarations(
323 IWineD3DBaseShader
*iface
,
324 shader_reg_maps
* reg_maps
,
325 SHADER_BUFFER
* buffer
,
326 WineD3D_GL_Info
* gl_info
) {
328 IWineD3DBaseShaderImpl
* This
= (IWineD3DBaseShaderImpl
*) iface
;
331 /* There are some minor differences between pixel and vertex shaders */
332 char pshader
= shader_is_pshader_version(This
->baseShader
.hex_version
);
333 char prefix
= pshader
? 'P' : 'V';
335 /* Prototype the subroutines */
336 for (i
= 0; i
< This
->baseShader
.limits
.label
; i
++) {
337 if (reg_maps
->labels
[i
])
338 shader_addline(buffer
, "void subroutine%lu();\n", i
);
341 /* Declare the constants (aka uniforms) */
342 if (This
->baseShader
.limits
.constant_float
> 0) {
343 unsigned max_constantsF
= min(This
->baseShader
.limits
.constant_float
,
344 (pshader
? GL_LIMITS(pshader_constantsF
) : GL_LIMITS(vshader_constantsF
)));
345 shader_addline(buffer
, "uniform vec4 %cC[%u];\n", prefix
, max_constantsF
);
348 if (This
->baseShader
.limits
.constant_int
> 0)
349 shader_addline(buffer
, "uniform ivec4 %cI[%u];\n", prefix
, This
->baseShader
.limits
.constant_int
);
351 if (This
->baseShader
.limits
.constant_bool
> 0)
352 shader_addline(buffer
, "uniform bool %cB[%u];\n", prefix
, This
->baseShader
.limits
.constant_bool
);
354 /* Declare texture samplers */
355 for (i
= 0; i
< This
->baseShader
.limits
.sampler
; i
++) {
356 if (reg_maps
->samplers
[i
]) {
358 DWORD stype
= reg_maps
->samplers
[i
] & WINED3DSP_TEXTURETYPE_MASK
;
362 shader_addline(buffer
, "uniform sampler1D %csampler%lu;\n", prefix
, i
);
365 shader_addline(buffer
, "uniform sampler2D %csampler%lu;\n", prefix
, i
);
367 case WINED3DSTT_CUBE
:
368 shader_addline(buffer
, "uniform samplerCube %csampler%lu;\n", prefix
, i
);
370 case WINED3DSTT_VOLUME
:
371 shader_addline(buffer
, "uniform sampler3D %csampler%lu;\n", prefix
, i
);
374 shader_addline(buffer
, "uniform unsupported_sampler %csampler%lu;\n", prefix
, i
);
375 FIXME("Unrecognized sampler type: %#lx\n", stype
);
381 /* Declare address variables */
382 for (i
= 0; i
< This
->baseShader
.limits
.address
; i
++) {
383 if (reg_maps
->address
[i
])
384 shader_addline(buffer
, "ivec4 A%ld;\n", i
);
387 /* Declare texture coordinate temporaries and initialize them */
388 for (i
= 0; i
< This
->baseShader
.limits
.texcoord
; i
++) {
389 if (reg_maps
->texcoord
[i
])
390 shader_addline(buffer
, "vec4 T%lu = gl_TexCoord[%lu];\n", i
, i
);
393 /* Declare input register temporaries */
394 for (i
=0; i
< This
->baseShader
.limits
.packed_input
; i
++) {
395 if (reg_maps
->packed_input
[i
])
396 shader_addline(buffer
, "vec4 IN%lu;\n", i
);
399 /* Declare output register temporaries */
400 for (i
= 0; i
< This
->baseShader
.limits
.packed_output
; i
++) {
401 if (reg_maps
->packed_output
[i
])
402 shader_addline(buffer
, "vec4 OUT%lu;\n", i
);
405 /* Declare temporary variables */
406 for(i
= 0; i
< This
->baseShader
.limits
.temporary
; i
++) {
407 if (reg_maps
->temporary
[i
])
408 shader_addline(buffer
, "vec4 R%lu;\n", i
);
411 /* Declare attributes */
412 for (i
= 0; i
< This
->baseShader
.limits
.attributes
; i
++) {
413 if (reg_maps
->attributes
[i
])
414 shader_addline(buffer
, "attribute vec4 attrib%i;\n", i
);
417 /* Declare loop register aL */
418 if (reg_maps
->loop
) {
419 shader_addline(buffer
, "int aL;\n");
420 shader_addline(buffer
, "int tmpInt;\n");
423 /* Temporary variables for matrix operations */
424 shader_addline(buffer
, "vec4 tmp0;\n");
425 shader_addline(buffer
, "vec4 tmp1;\n");
427 /* Start the main program */
428 shader_addline(buffer
, "void main() {\n");
431 /*****************************************************************************
432 * Functions to generate GLSL strings from DirectX Shader bytecode begin here.
434 * For more information, see http://wiki.winehq.org/DirectX-Shaders
435 ****************************************************************************/
438 static void shader_glsl_add_param(
439 SHADER_OPCODE_ARG
* arg
,
441 const DWORD addr_token
,
447 /** Used for opcode modifiers - They multiply the result by the specified amount */
448 static const char* shift_glsl_tab
[] = {
450 "2.0 * ", /* 1 (x2) */
451 "4.0 * ", /* 2 (x4) */
452 "8.0 * ", /* 3 (x8) */
453 "16.0 * ", /* 4 (x16) */
454 "32.0 * ", /* 5 (x32) */
461 "0.0625 * ", /* 12 (d16) */
462 "0.125 * ", /* 13 (d8) */
463 "0.25 * ", /* 14 (d4) */
464 "0.5 * " /* 15 (d2) */
467 /** Print the beginning of the generated GLSL string. example: "reg_name.xyzw = vec4("
468 * Will also change the reg_mask if necessary (not all register types are equal in DX vs GL) */
469 static void shader_glsl_add_dst(DWORD param
, const char* reg_name
, char* reg_mask
, char* outStr
) {
471 int shift
= (param
& D3DSP_DSTSHIFT_MASK
) >> D3DSP_DSTSHIFT_SHIFT
;
474 if ((shader_get_regtype(param
) == D3DSPR_RASTOUT
)
475 && ((param
& D3DSP_REGNUM_MASK
) != 0)) {
476 /* gl_FogFragCoord or glPointSize - both floats */
477 strcpy(cast
, "float");
478 strcpy(reg_mask
, "");
480 } else if (reg_name
[0] == 'A') {
481 /* Address register for vertex shaders (ivec4) */
482 strcpy(cast
, "ivec4");
485 /* Everything else should be a 4 component float vector */
486 strcpy(cast
, "vec4");
489 sprintf(outStr
, "%s%s = %s%s(", reg_name
, reg_mask
, shift_glsl_tab
[shift
], cast
);
492 /* Generate a GLSL parameter that does the input modifier computation and return the input register/mask to use */
493 static void shader_glsl_gen_modifier (
496 const char *in_regswizzle
,
501 if (instr
== D3DSIO_TEXKILL
)
504 switch (instr
& D3DSP_SRCMOD_MASK
) {
506 sprintf(out_str
, "%s%s", in_reg
, in_regswizzle
);
509 sprintf(out_str
, "-%s%s", in_reg
, in_regswizzle
);
512 sprintf(out_str
, "!%s%s", in_reg
, in_regswizzle
);
515 sprintf(out_str
, "(%s%s - vec4(0.5)%s)", in_reg
, in_regswizzle
, in_regswizzle
);
517 case D3DSPSM_BIASNEG
:
518 sprintf(out_str
, "-(%s%s - vec4(0.5)%s)", in_reg
, in_regswizzle
, in_regswizzle
);
521 sprintf(out_str
, "(2.0 * (%s%s - 0.5))", in_reg
, in_regswizzle
);
523 case D3DSPSM_SIGNNEG
:
524 sprintf(out_str
, "-(2.0 * (%s%s - 0.5))", in_reg
, in_regswizzle
);
527 sprintf(out_str
, "(1.0 - %s%s)", in_reg
, in_regswizzle
);
530 sprintf(out_str
, "(2.0 * %s%s)", in_reg
, in_regswizzle
);
533 sprintf(out_str
, "-(2.0 * %s%s)", in_reg
, in_regswizzle
);
535 case D3DSPSM_DZ
: /* reg1_db = { reg1.r/b, reg1.g/b, ...} The g & a components are undefined, so we'll leave them alone */
536 sprintf(out_str
, "vec4(%s.r / %s.b, %s.g / %s.b, %s.b, %s.a)", in_reg
, in_reg
, in_reg
, in_reg
, in_reg
, in_reg
);
539 sprintf(out_str
, "vec4(%s.r / %s.a, %s.g / %s.a, %s.b, %s.a)", in_reg
, in_reg
, in_reg
, in_reg
, in_reg
, in_reg
);
542 sprintf(out_str
, "abs(%s%s)", in_reg
, in_regswizzle
);
545 sprintf(out_str
, "-abs(%s%s)", in_reg
, in_regswizzle
);
548 FIXME("Unhandled modifier %lu\n", (instr
& D3DSP_SRCMOD_MASK
));
549 sprintf(out_str
, "%s%s", in_reg
, in_regswizzle
);
553 /** Writes the GLSL variable name that corresponds to the register that the
554 * DX opcode parameter is trying to access */
555 static void shader_glsl_get_register_name(
557 const DWORD addr_token
,
560 SHADER_OPCODE_ARG
* arg
) {
562 /* oPos, oFog and oPts in D3D */
563 const char* hwrastout_reg_names
[] = { "gl_Position", "gl_FogFragCoord", "gl_PointSize" };
565 DWORD reg
= param
& D3DSP_REGNUM_MASK
;
566 DWORD regtype
= shader_get_regtype(param
);
567 IWineD3DBaseShaderImpl
* This
= (IWineD3DBaseShaderImpl
*) arg
->shader
;
568 char pshader
= shader_is_pshader_version(This
->baseShader
.hex_version
);
575 sprintf(tmpStr
, "R%lu", reg
);
579 /* Pixel shaders >= 3.0 */
580 if (D3DSHADER_VERSION_MAJOR(This
->baseShader
.hex_version
) >= 3)
581 sprintf(tmpStr
, "IN%lu", reg
);
584 strcpy(tmpStr
, "gl_Color");
586 strcpy(tmpStr
, "gl_SecondaryColor");
589 if (vshader_input_is_color((IWineD3DVertexShader
*) This
, reg
))
591 sprintf(tmpStr
, "attrib%lu", reg
);
596 const char* prefix
= pshader
? "PC":"VC";
598 /* Relative addressing */
599 if (param
& D3DVS_ADDRMODE_RELATIVE
) {
601 /* Relative addressing on shaders 2.0+ have a relative address token,
602 * prior to that, it was hard-coded as "A0.x" because there's only 1 register */
603 if (D3DSHADER_VERSION_MAJOR(This
->baseShader
.hex_version
) >= 2) {
604 char relStr
[100], relReg
[50], relMask
[6];
605 shader_glsl_add_param(arg
, addr_token
, 0, TRUE
, relReg
, relMask
, relStr
);
606 sprintf(tmpStr
, "%s[%s + %lu]", prefix
, relStr
, reg
);
608 sprintf(tmpStr
, "%s[A0.x + %lu]", prefix
, reg
);
611 sprintf(tmpStr
, "%s[%lu]", prefix
, reg
);
615 case D3DSPR_CONSTINT
:
617 sprintf(tmpStr
, "PI[%lu]", reg
);
619 sprintf(tmpStr
, "VI[%lu]", reg
);
621 case D3DSPR_CONSTBOOL
:
623 sprintf(tmpStr
, "PB[%lu]", reg
);
625 sprintf(tmpStr
, "VB[%lu]", reg
);
627 case D3DSPR_TEXTURE
: /* case D3DSPR_ADDR: */
629 sprintf(tmpStr
, "T%lu", reg
);
631 sprintf(tmpStr
, "A%lu", reg
);
635 sprintf(tmpStr
, "aL");
639 sprintf(tmpStr
, "Psampler%lu", reg
);
641 sprintf(tmpStr
, "Vsampler%lu", reg
);
643 case D3DSPR_COLOROUT
:
644 sprintf(tmpStr
, "gl_FragData[%lu]", reg
);
646 /* TODO: See GL_ARB_draw_buffers */
647 FIXME("Unsupported write to render target %lu\n", reg
);
651 sprintf(tmpStr
, "%s", hwrastout_reg_names
[reg
]);
653 case D3DSPR_DEPTHOUT
:
654 sprintf(tmpStr
, "gl_FragDepth");
658 sprintf(tmpStr
, "gl_FrontColor");
660 sprintf(tmpStr
, "gl_FrontSecondaryColor");
663 case D3DSPR_TEXCRDOUT
:
664 /* Vertex shaders >= 3.0: D3DSPR_OUTPUT */
665 if (D3DSHADER_VERSION_MAJOR(This
->baseShader
.hex_version
) >= 3)
666 sprintf(tmpStr
, "OUT%lu", reg
);
668 sprintf(tmpStr
, "gl_TexCoord[%lu]", reg
);
671 FIXME("Unhandled register name Type(%ld)\n", regtype
);
672 sprintf(tmpStr
, "unrecognized_register");
676 strcat(regstr
, tmpStr
);
679 /* Writes the GLSL writemask for the destination register */
680 static void shader_glsl_get_output_register_swizzle(
685 if ((param
& D3DSP_WRITEMASK_ALL
) != D3DSP_WRITEMASK_ALL
) {
686 strcat(write_mask
, ".");
687 if (param
& D3DSP_WRITEMASK_0
) strcat(write_mask
, "x");
688 if (param
& D3DSP_WRITEMASK_1
) strcat(write_mask
, "y");
689 if (param
& D3DSP_WRITEMASK_2
) strcat(write_mask
, "z");
690 if (param
& D3DSP_WRITEMASK_3
) strcat(write_mask
, "w");
694 static void shader_glsl_get_input_register_swizzle(
699 const char swizzle_reg_chars_color_fix
[] = "zyxw";
700 const char swizzle_reg_chars
[] = "xyzw";
701 const char* swizzle_regs
= NULL
;
704 DWORD swizzle
= (param
& D3DVS_SWIZZLE_MASK
) >> D3DVS_SWIZZLE_SHIFT
;
705 DWORD swizzle_x
= swizzle
& 0x03;
706 DWORD swizzle_y
= (swizzle
>> 2) & 0x03;
707 DWORD swizzle_z
= (swizzle
>> 4) & 0x03;
708 DWORD swizzle_w
= (swizzle
>> 6) & 0x03;
711 swizzle_regs
= swizzle_reg_chars_color_fix
;
713 swizzle_regs
= swizzle_reg_chars
;
717 * swizzle bits fields:
720 if ((D3DVS_NOSWIZZLE
>> D3DVS_SWIZZLE_SHIFT
) == swizzle
) { /* D3DVS_NOSWIZZLE == 0xE4 << D3DVS_SWIZZLE_SHIFT */
722 sprintf(reg_mask
, ".%c%c%c%c",
723 swizzle_regs
[swizzle_x
],
724 swizzle_regs
[swizzle_y
],
725 swizzle_regs
[swizzle_z
],
726 swizzle_regs
[swizzle_w
]);
730 if (swizzle_x
== swizzle_y
&&
731 swizzle_x
== swizzle_z
&&
732 swizzle_x
== swizzle_w
)
734 sprintf(reg_mask
, ".%c", swizzle_regs
[swizzle_x
]);
736 sprintf(reg_mask
, ".%c%c%c%c",
737 swizzle_regs
[swizzle_x
],
738 swizzle_regs
[swizzle_y
],
739 swizzle_regs
[swizzle_z
],
740 swizzle_regs
[swizzle_w
]);
744 /** From a given parameter token, generate the corresponding GLSL string.
745 * Also, return the actual register name and swizzle in case the
746 * caller needs this information as well. */
747 static void shader_glsl_add_param(
748 SHADER_OPCODE_ARG
* arg
,
750 const DWORD addr_token
,
756 BOOL is_color
= FALSE
;
757 reg_mask
[0] = reg_name
[0] = out_str
[0] = 0;
759 shader_glsl_get_register_name(param
, addr_token
, reg_name
, &is_color
, arg
);
762 shader_glsl_get_input_register_swizzle(param
, is_color
, reg_mask
);
763 shader_glsl_gen_modifier(param
, reg_name
, reg_mask
, out_str
);
765 shader_glsl_get_output_register_swizzle(param
, reg_mask
);
766 sprintf(out_str
, "%s%s", reg_name
, reg_mask
);
770 /** Process GLSL instruction modifiers */
771 void shader_glsl_add_instruction_modifiers(SHADER_OPCODE_ARG
* arg
) {
773 DWORD mask
= arg
->dst
& D3DSP_DSTMOD_MASK
;
775 if (arg
->opcode
->dst_token
&& mask
!= 0) {
780 shader_glsl_add_param(arg
, arg
->dst
, 0, FALSE
, dst_reg
, dst_mask
, dst_str
);
782 if (mask
& D3DSPDM_SATURATE
) {
783 /* _SAT means to clamp the value of the register to between 0 and 1 */
784 shader_addline(arg
->buffer
, "%s%s = clamp(%s%s, 0.0, 1.0);\n", dst_reg
, dst_mask
, dst_reg
, dst_mask
);
786 if (mask
& D3DSPDM_MSAMPCENTROID
) {
787 FIXME("_centroid modifier not handled\n");
789 if (mask
& D3DSPDM_PARTIALPRECISION
) {
790 /* MSDN says this modifier can be safely ignored, so that's what we'll do. */
795 static inline const char* shader_get_comp_op(
796 const DWORD opcode
) {
798 DWORD op
= (opcode
& INST_CONTROLS_MASK
) >> INST_CONTROLS_SHIFT
;
800 case COMPARISON_GT
: return ">";
801 case COMPARISON_EQ
: return "==";
802 case COMPARISON_GE
: return ">=";
803 case COMPARISON_LT
: return "<";
804 case COMPARISON_NE
: return "!=";
805 case COMPARISON_LE
: return "<=";
807 FIXME("Unrecognized comparison value: %lu\n", op
);
812 /*****************************************************************************
814 * Begin processing individual instruction opcodes
816 ****************************************************************************/
818 /* Generate GLSL arithmetic functions (dst = src1 + src2) */
819 void shader_glsl_arith(SHADER_OPCODE_ARG
* arg
) {
821 CONST SHADER_OPCODE
* curOpcode
= arg
->opcode
;
822 SHADER_BUFFER
* buffer
= arg
->buffer
;
824 char dst_reg
[50], src0_reg
[50], src1_reg
[50];
825 char dst_mask
[6], src0_mask
[6], src1_mask
[6];
826 char dst_str
[100], src0_str
[100], src1_str
[100];
828 shader_glsl_add_param(arg
, arg
->dst
, 0, FALSE
, dst_reg
, dst_mask
, dst_str
);
829 shader_glsl_add_param(arg
, arg
->src
[0], arg
->src_addr
[0], TRUE
, src0_reg
, src0_mask
, src0_str
);
830 shader_glsl_add_param(arg
, arg
->src
[1], arg
->src_addr
[1], TRUE
, src1_reg
, src1_mask
, src1_str
);
831 shader_glsl_add_dst(arg
->dst
, dst_reg
, dst_mask
, tmpLine
);
832 strcat(tmpLine
, "vec4(");
833 strcat(tmpLine
, src0_str
);
834 strcat(tmpLine
, ")");
836 /* Determine the GLSL operator to use based on the opcode */
837 switch (curOpcode
->opcode
) {
838 case D3DSIO_MUL
: strcat(tmpLine
, " * "); break;
839 case D3DSIO_ADD
: strcat(tmpLine
, " + "); break;
840 case D3DSIO_SUB
: strcat(tmpLine
, " - "); break;
842 FIXME("Opcode %s not yet handled in GLSL\n", curOpcode
->name
);
845 shader_addline(buffer
, "%svec4(%s))%s;\n", tmpLine
, src1_str
, dst_mask
);
848 /* Process the D3DSIO_MOV opcode using GLSL (dst = src) */
849 void shader_glsl_mov(SHADER_OPCODE_ARG
* arg
) {
851 SHADER_BUFFER
* buffer
= arg
->buffer
;
853 char dst_str
[100], src0_str
[100];
854 char dst_reg
[50], src0_reg
[50];
855 char dst_mask
[6], src0_mask
[6];
857 shader_glsl_add_param(arg
, arg
->dst
, 0, FALSE
, dst_reg
, dst_mask
, dst_str
);
858 shader_glsl_add_param(arg
, arg
->src
[0], arg
->src_addr
[0], TRUE
, src0_reg
, src0_mask
, src0_str
);
859 shader_glsl_add_dst(arg
->dst
, dst_reg
, dst_mask
, tmpLine
);
860 shader_addline(buffer
, "%s%s)%s;\n", tmpLine
, src0_str
, dst_mask
);
863 /* Process the dot product operators DP3 and DP4 in GLSL (dst = dot(src0, src1)) */
864 void shader_glsl_dot(SHADER_OPCODE_ARG
* arg
) {
866 CONST SHADER_OPCODE
* curOpcode
= arg
->opcode
;
867 SHADER_BUFFER
* buffer
= arg
->buffer
;
869 char dst_str
[100], src0_str
[100], src1_str
[100];
870 char dst_reg
[50], src0_reg
[50], src1_reg
[50];
871 char dst_mask
[6], src0_mask
[6], src1_mask
[6];
874 shader_glsl_add_param(arg
, arg
->dst
, 0, FALSE
, dst_reg
, dst_mask
, dst_str
);
875 shader_glsl_add_param(arg
, arg
->src
[0], arg
->src_addr
[0], TRUE
, src0_reg
, src0_mask
, src0_str
);
876 shader_glsl_add_param(arg
, arg
->src
[1], arg
->src_addr
[1], TRUE
, src1_reg
, src1_mask
, src1_str
);
878 shader_glsl_add_dst(arg
->dst
, dst_reg
, dst_mask
, tmpDest
);
880 /* Need to cast the src vectors to vec3 for dp3, and vec4 for dp4 */
881 if (curOpcode
->opcode
== D3DSIO_DP4
)
882 strcpy(cast
, "vec4(");
884 strcpy(cast
, "vec3(");
886 shader_addline(buffer
, "%sdot(%s%s), %s%s)))%s;\n",
887 tmpDest
, cast
, src0_str
, cast
, src1_str
, dst_mask
);
890 /* Map the opcode 1-to-1 to the GL code (arg->dst = instruction(src0, src1, ...) */
891 void shader_glsl_map2gl(SHADER_OPCODE_ARG
* arg
) {
893 CONST SHADER_OPCODE
* curOpcode
= arg
->opcode
;
894 SHADER_BUFFER
* buffer
= arg
->buffer
;
896 char dst_str
[100], src_str
[100];
897 char dst_reg
[50], src_reg
[50];
898 char dst_mask
[6], src_mask
[6];
901 shader_glsl_add_param(arg
, arg
->dst
, 0, FALSE
, dst_reg
, dst_mask
, dst_str
);
903 shader_glsl_add_dst(arg
->dst
, dst_reg
, dst_mask
, tmpLine
);
905 /* Determine the GLSL function to use based on the opcode */
906 /* TODO: Possibly make this a table for faster lookups */
907 switch (curOpcode
->opcode
) {
908 case D3DSIO_MIN
: strcat(tmpLine
, "min"); break;
909 case D3DSIO_MAX
: strcat(tmpLine
, "max"); break;
910 case D3DSIO_RSQ
: strcat(tmpLine
, "inversesqrt"); break;
911 case D3DSIO_ABS
: strcat(tmpLine
, "abs"); break;
912 case D3DSIO_FRC
: strcat(tmpLine
, "fract"); break;
913 case D3DSIO_POW
: strcat(tmpLine
, "pow"); break;
914 case D3DSIO_CRS
: strcat(tmpLine
, "cross"); break;
915 case D3DSIO_NRM
: strcat(tmpLine
, "normalize"); break;
917 case D3DSIO_LOG
: strcat(tmpLine
, "log2"); break;
918 case D3DSIO_EXP
: strcat(tmpLine
, "exp2"); break;
919 case D3DSIO_SGE
: strcat(tmpLine
, "greaterThanEqual"); break;
920 case D3DSIO_SLT
: strcat(tmpLine
, "lessThan"); break;
921 case D3DSIO_SGN
: strcat(tmpLine
, "sign"); break;
923 FIXME("Opcode %s not yet handled in GLSL\n", curOpcode
->name
);
927 strcat(tmpLine
, "(");
929 if (curOpcode
->num_params
> 0) {
930 strcat(tmpLine
, "vec4(");
931 shader_glsl_add_param(arg
, arg
->src
[0], arg
->src_addr
[0], TRUE
, src_reg
, src_mask
, src_str
);
932 strcat(tmpLine
, src_str
);
933 strcat(tmpLine
, ")");
934 for (i
= 2; i
< curOpcode
->num_params
; ++i
) {
935 strcat(tmpLine
, ", vec4(");
936 shader_glsl_add_param(arg
, arg
->src
[i
-1], arg
->src_addr
[i
-1], TRUE
, src_reg
, src_mask
, src_str
);
937 strcat(tmpLine
, src_str
);
938 strcat(tmpLine
, ")");
941 shader_addline(buffer
, "%s))%s;\n", tmpLine
, dst_mask
);
945 /** Process the D3DSIO_EXPP instruction in GLSL:
946 * For shader model 1.x, do the following (and honor the writemask, so use a temporary variable):
947 * dst.x = 2^(floor(src))
948 * dst.y = src - floor(src)
949 * dst.z = 2^src (partial precision is allowed, but optional)
951 * For 2.0 shaders, just do this (honoring writemask and swizzle):
952 * dst = 2^src; (partial precision is allowed, but optional)
954 void shader_glsl_expp(SHADER_OPCODE_ARG
* arg
) {
957 char dst_str
[100], src_str
[100];
958 char dst_reg
[50], src_reg
[50];
959 char dst_mask
[6], src_mask
[6];
960 IWineD3DPixelShaderImpl
* This
= (IWineD3DPixelShaderImpl
*) arg
->shader
;
961 DWORD hex_version
= This
->baseShader
.hex_version
;
963 shader_glsl_add_param(arg
, arg
->dst
, 0, FALSE
, dst_reg
, dst_mask
, dst_str
);
964 shader_glsl_add_param(arg
, arg
->src
[0], arg
->src_addr
[0], TRUE
, src_reg
, src_mask
, src_str
);
965 shader_glsl_add_dst(arg
->dst
, dst_reg
, dst_mask
, tmpLine
);
967 if (hex_version
< D3DPS_VERSION(2,0)) {
968 shader_addline(arg
->buffer
, "tmp0.x = vec4(exp2(floor(%s))).x;\n", src_str
);
969 shader_addline(arg
->buffer
, "tmp0.y = vec4(%s - floor(%s)).y;\n", src_str
, src_str
);
970 shader_addline(arg
->buffer
, "tmp0.z = vec4(exp2(%s)).x;\n", src_str
);
971 shader_addline(arg
->buffer
, "tmp0.w = 1.0;\n");
972 shader_addline(arg
->buffer
, "%svec4(tmp0))%s;\n", tmpLine
, dst_mask
);
974 shader_addline(arg
->buffer
, "%svec4(exp2(%s)))%s;\n", tmpLine
, src_str
, dst_mask
);
978 /** Process the RCP (reciprocal or inverse) opcode in GLSL (dst = 1 / src) */
979 void shader_glsl_rcp(SHADER_OPCODE_ARG
* arg
) {
982 char dst_str
[100], src_str
[100];
983 char dst_reg
[50], src_reg
[50];
984 char dst_mask
[6], src_mask
[6];
986 shader_glsl_add_param(arg
, arg
->dst
, 0, FALSE
, dst_reg
, dst_mask
, dst_str
);
987 shader_glsl_add_param(arg
, arg
->src
[0], arg
->src_addr
[0], TRUE
, src_reg
, src_mask
, src_str
);
988 shader_glsl_add_dst(arg
->dst
, dst_reg
, dst_mask
, tmpLine
);
989 strcat(tmpLine
, "1.0 / ");
990 shader_addline(arg
->buffer
, "%s%s)%s;\n", tmpLine
, src_str
, dst_mask
);
993 /** Process signed comparison opcodes in GLSL. */
994 void shader_glsl_compare(SHADER_OPCODE_ARG
* arg
) {
997 char dst_str
[100], src0_str
[100], src1_str
[100];
998 char dst_reg
[50], src0_reg
[50], src1_reg
[50];
999 char dst_mask
[6], src0_mask
[6], src1_mask
[6];
1001 shader_glsl_add_param(arg
, arg
->dst
, 0, FALSE
, dst_reg
, dst_mask
, dst_str
);
1002 shader_glsl_add_param(arg
, arg
->src
[0], arg
->src_addr
[0], TRUE
, src0_reg
, src0_mask
, src0_str
);
1003 shader_glsl_add_dst(arg
->dst
, dst_reg
, dst_mask
, tmpLine
);
1005 /* If we are comparing vectors and not scalars, we should process this through map2gl using the GLSL functions. */
1006 if (strlen(src0_mask
) != 2) {
1007 shader_glsl_map2gl(arg
);
1011 shader_glsl_add_param(arg
, arg
->src
[1], arg
->src_addr
[1], TRUE
, src1_reg
, src1_mask
, src1_str
);
1013 switch (arg
->opcode
->opcode
) {
1014 case D3DSIO_SLT
: strcpy(compareStr
, "<"); break;
1015 case D3DSIO_SGE
: strcpy(compareStr
, ">="); break;
1017 FIXME("Can't handle opcode %s\n", arg
->opcode
->name
);
1019 shader_addline(arg
->buffer
, "%s(float(%s) %s float(%s)) ? 1.0 : 0.0)%s;\n",
1020 tmpLine
, src0_str
, compareStr
, src1_str
, dst_mask
);
1024 /** Process CMP instruction in GLSL (dst = src0.x > 0.0 ? src1.x : src2.x), per channel */
1025 void shader_glsl_cmp(SHADER_OPCODE_ARG
* arg
) {
1028 char dst_str
[100], src0_str
[100], src1_str
[100], src2_str
[100];
1029 char dst_reg
[50], src0_reg
[50], src1_reg
[50], src2_reg
[50];
1030 char dst_mask
[6], src0_mask
[6], src1_mask
[6], src2_mask
[6];
1032 shader_glsl_add_param(arg
, arg
->dst
, 0, FALSE
, dst_reg
, dst_mask
, dst_str
);
1033 shader_glsl_add_param(arg
, arg
->src
[0], arg
->src_addr
[0], TRUE
, src0_reg
, src0_mask
, src0_str
);
1034 shader_glsl_add_param(arg
, arg
->src
[1], arg
->src_addr
[1], TRUE
, src1_reg
, src1_mask
, src1_str
);
1035 shader_glsl_add_param(arg
, arg
->src
[2], arg
->src_addr
[2], TRUE
, src2_reg
, src2_mask
, src2_str
);
1037 shader_glsl_add_dst(arg
->dst
, dst_reg
, dst_mask
, tmpLine
);
1038 shader_addline(arg
->buffer
, "%smix(vec4(%s), vec4(%s), vec4(lessThan(vec4(%s), vec4(0.0)))))%s;\n",
1039 tmpLine
, src1_str
, src2_str
, src0_str
, dst_mask
);
1042 /** Process the CND opcode in GLSL (dst = (src0 < 0.5) ? src1 : src2) */
1043 void shader_glsl_cnd(SHADER_OPCODE_ARG
* arg
) {
1046 char dst_str
[100], src0_str
[100], src1_str
[100], src2_str
[100];
1047 char dst_reg
[50], src0_reg
[50], src1_reg
[50], src2_reg
[50];
1048 char dst_mask
[6], src0_mask
[6], src1_mask
[6], src2_mask
[6];
1050 shader_glsl_add_param(arg
, arg
->dst
, 0, FALSE
, dst_reg
, dst_mask
, dst_str
);
1051 shader_glsl_add_param(arg
, arg
->src
[0], arg
->src_addr
[0], TRUE
, src0_reg
, src0_mask
, src0_str
);
1052 shader_glsl_add_param(arg
, arg
->src
[1], arg
->src_addr
[1], TRUE
, src1_reg
, src1_mask
, src1_str
);
1053 shader_glsl_add_param(arg
, arg
->src
[2], arg
->src_addr
[2], TRUE
, src2_reg
, src2_mask
, src2_str
);
1054 shader_glsl_add_dst(arg
->dst
, dst_reg
, dst_mask
, tmpLine
);
1055 shader_addline(arg
->buffer
, "%s(%s < 0.5) ? %s : %s)%s;\n",
1056 tmpLine
, src0_str
, src1_str
, src2_str
, dst_mask
);
1059 /** GLSL code generation for D3DSIO_MAD: Multiply the first 2 opcodes, then add the last */
1060 void shader_glsl_mad(SHADER_OPCODE_ARG
* arg
) {
1063 char dst_str
[100], src0_str
[100], src1_str
[100], src2_str
[100];
1064 char dst_reg
[50], src0_reg
[50], src1_reg
[50], src2_reg
[50];
1065 char dst_mask
[6], src0_mask
[6], src1_mask
[6], src2_mask
[6];
1067 shader_glsl_add_param(arg
, arg
->dst
, 0, FALSE
, dst_reg
, dst_mask
, dst_str
);
1068 shader_glsl_add_param(arg
, arg
->src
[0], arg
->src_addr
[0], TRUE
, src0_reg
, src0_mask
, src0_str
);
1069 shader_glsl_add_param(arg
, arg
->src
[1], arg
->src_addr
[1], TRUE
, src1_reg
, src1_mask
, src1_str
);
1070 shader_glsl_add_param(arg
, arg
->src
[2], arg
->src_addr
[2], TRUE
, src2_reg
, src2_mask
, src2_str
);
1071 shader_glsl_add_dst(arg
->dst
, dst_reg
, dst_mask
, tmpLine
);
1073 shader_addline(arg
->buffer
, "%s(vec4(%s) * vec4(%s)) + vec4(%s))%s;\n",
1074 tmpLine
, src0_str
, src1_str
, src2_str
, dst_mask
);
1077 /** Handles transforming all D3DSIO_M?x? opcodes for
1078 Vertex shaders to GLSL codes */
1079 void shader_glsl_mnxn(SHADER_OPCODE_ARG
* arg
) {
1081 int nComponents
= 0;
1082 SHADER_OPCODE_ARG tmpArg
;
1084 memset(&tmpArg
, 0, sizeof(SHADER_OPCODE_ARG
));
1086 /* Set constants for the temporary argument */
1087 tmpArg
.shader
= arg
->shader
;
1088 tmpArg
.buffer
= arg
->buffer
;
1089 tmpArg
.src
[0] = arg
->src
[0];
1090 tmpArg
.src_addr
[0] = arg
->src_addr
[0];
1091 tmpArg
.src_addr
[1] = arg
->src_addr
[1];
1092 tmpArg
.reg_maps
= arg
->reg_maps
;
1094 switch(arg
->opcode
->opcode
) {
1097 tmpArg
.opcode
= &IWineD3DVertexShaderImpl_shader_ins
[D3DSIO_DP4
];
1101 tmpArg
.opcode
= &IWineD3DVertexShaderImpl_shader_ins
[D3DSIO_DP4
];
1105 tmpArg
.opcode
= &IWineD3DVertexShaderImpl_shader_ins
[D3DSIO_DP3
];
1109 tmpArg
.opcode
= &IWineD3DVertexShaderImpl_shader_ins
[D3DSIO_DP3
];
1113 tmpArg
.opcode
= &IWineD3DVertexShaderImpl_shader_ins
[D3DSIO_DP3
];
1119 for (i
= 0; i
< nComponents
; i
++) {
1120 tmpArg
.dst
= ((arg
->dst
) & ~D3DSP_WRITEMASK_ALL
)|(D3DSP_WRITEMASK_0
<<i
);
1121 tmpArg
.src
[1] = arg
->src
[1]+i
;
1122 shader_glsl_dot(&tmpArg
);
1127 The LRP instruction performs a component-wise linear interpolation
1128 between the second and third operands using the first operand as the
1129 blend factor. Equation: (dst = src2 * (src1 - src0) + src0)
1131 void shader_glsl_lrp(SHADER_OPCODE_ARG
* arg
) {
1134 char dst_str
[100], src0_str
[100], src1_str
[100], src2_str
[100];
1135 char dst_reg
[50], src0_reg
[50], src1_reg
[50], src2_reg
[50];
1136 char dst_mask
[6], src0_mask
[6], src1_mask
[6], src2_mask
[6];
1138 shader_glsl_add_param(arg
, arg
->dst
, 0, FALSE
, dst_reg
, dst_mask
, dst_str
);
1139 shader_glsl_add_param(arg
, arg
->src
[0], arg
->src_addr
[0], TRUE
, src0_reg
, src0_mask
, src0_str
);
1140 shader_glsl_add_param(arg
, arg
->src
[1], arg
->src_addr
[1], TRUE
, src1_reg
, src1_mask
, src1_str
);
1141 shader_glsl_add_param(arg
, arg
->src
[2], arg
->src_addr
[2], TRUE
, src2_reg
, src2_mask
, src2_str
);
1143 shader_glsl_add_dst(arg
->dst
, dst_reg
, dst_mask
, tmpLine
);
1145 shader_addline(arg
->buffer
, "%s%s + %s * (%s - %s))%s;\n",
1146 tmpLine
, src2_str
, src0_str
, src1_str
, src2_str
, dst_mask
);
1149 /** Process the D3DSIO_LIT instruction in GLSL:
1150 * dst.x = dst.w = 1.0
1151 * dst.y = (src0.x > 0) ? src0.x
1152 * dst.z = (src0.x > 0) ? ((src0.y > 0) ? pow(src0.y, src.w) : 0) : 0
1153 * where src.w is clamped at +- 128
1155 void shader_glsl_lit(SHADER_OPCODE_ARG
* arg
) {
1157 char dst_str
[100], src0_str
[100];
1158 char dst_reg
[50], src0_reg
[50];
1159 char dst_mask
[6], src0_mask
[6];
1161 shader_glsl_add_param(arg
, arg
->dst
, 0, FALSE
, dst_reg
, dst_mask
, dst_str
);
1162 shader_glsl_add_param(arg
, arg
->src
[0], arg
->src_addr
[0], TRUE
, src0_reg
, src0_mask
, src0_str
);
1164 shader_addline(arg
->buffer
,
1165 "%s = vec4(1.0, (%s.x > 0.0 ? %s.x : 0.0), (%s.x > 0.0 ? ((%s.y > 0.0) ? pow(%s.y, clamp(%s.w, -128.0, 128.0)) : 0.0) : 0.0), 1.0)%s;\n",
1166 dst_str
, src0_reg
, src0_reg
, src0_reg
, src0_reg
, src0_reg
, src0_reg
, dst_mask
);
1169 /** Process the D3DSIO_DST instruction in GLSL:
1171 * dst.y = src0.x * src0.y
1175 void shader_glsl_dst(SHADER_OPCODE_ARG
* arg
) {
1177 char dst_str
[100], src0_str
[100], src1_str
[100];
1178 char dst_reg
[50], src0_reg
[50], src1_reg
[50];
1179 char dst_mask
[6], src0_mask
[6], src1_mask
[6];
1181 shader_glsl_add_param(arg
, arg
->dst
, 0, FALSE
, dst_reg
, dst_mask
, dst_str
);
1182 shader_glsl_add_param(arg
, arg
->src
[0], arg
->src_addr
[0], TRUE
, src0_reg
, src0_mask
, src0_str
);
1183 shader_glsl_add_param(arg
, arg
->src
[1], arg
->src_addr
[1], TRUE
, src1_reg
, src1_mask
, src1_str
);
1185 shader_addline(arg
->buffer
, "%s = vec4(1.0, %s.x * %s.y, %s.z, %s.w)%s;\n",
1186 dst_str
, src0_reg
, src1_reg
, src0_reg
, src1_reg
, dst_mask
);
1189 /** Process the D3DSIO_SINCOS instruction in GLSL:
1190 * VS 2.0 requires that specific cosine and sine constants be passed to this instruction so the hardware
1191 * can handle it. But, these functions are built-in for GLSL, so we can just ignore the last 2 params.
1193 * dst.x = cos(src0.?)
1194 * dst.y = sin(src0.?)
1198 void shader_glsl_sincos(SHADER_OPCODE_ARG
* arg
) {
1200 char dst_str
[100], src0_str
[100];
1201 char dst_reg
[50], src0_reg
[50];
1202 char dst_mask
[6], src0_mask
[6];
1204 shader_glsl_add_param(arg
, arg
->dst
, 0, FALSE
, dst_reg
, dst_mask
, dst_str
);
1205 shader_glsl_add_param(arg
, arg
->src
[0], arg
->src_addr
[0], TRUE
, src0_reg
, src0_mask
, src0_str
);
1207 shader_addline(arg
->buffer
, "%s = vec4(cos(%s), sin(%s), %s.z, %s.w)%s;\n",
1208 dst_str
, src0_str
, src0_str
, dst_reg
, dst_reg
, dst_mask
);
1211 /** Process the D3DSIO_LOOP instruction in GLSL:
1212 * Start a for() loop where src0.y is the initial value of aL,
1213 * increment aL by src0.z for a total of src0.x iterations.
1214 * Need to use a temporary variable for this operation.
1216 void shader_glsl_loop(SHADER_OPCODE_ARG
* arg
) {
1222 shader_glsl_add_param(arg
, arg
->src
[1], arg
->src_addr
[1], TRUE
, src1_reg
, src1_mask
, src1_str
);
1224 shader_addline(arg
->buffer
, "for (tmpInt = 0, aL = %s.y; tmpInt < %s.x; tmpInt++, aL += %s.z) {\n",
1225 src1_reg
, src1_reg
, src1_reg
);
1228 void shader_glsl_end(SHADER_OPCODE_ARG
* arg
) {
1229 shader_addline(arg
->buffer
, "}\n");
1232 void shader_glsl_rep(SHADER_OPCODE_ARG
* arg
) {
1238 shader_glsl_add_param(arg
, arg
->src
[0], arg
->src_addr
[0], TRUE
, src0_reg
, src0_mask
, src0_str
);
1239 shader_addline(arg
->buffer
, "for (tmpInt = 0; tmpInt < %s.x; tmpInt++) {\n", src0_reg
);
1242 void shader_glsl_if(SHADER_OPCODE_ARG
* arg
) {
1248 shader_glsl_add_param(arg
, arg
->src
[0], arg
->src_addr
[0], TRUE
, src0_reg
, src0_mask
, src0_str
);
1249 shader_addline(arg
->buffer
, "if (%s) {\n", src0_str
);
1252 void shader_glsl_ifc(SHADER_OPCODE_ARG
* arg
) {
1254 char src0_str
[100], src1_str
[100];
1255 char src0_reg
[50], src1_reg
[50];
1256 char src0_mask
[6], src1_mask
[6];
1258 shader_glsl_add_param(arg
, arg
->src
[0], arg
->src_addr
[0], TRUE
, src0_reg
, src0_mask
, src0_str
);
1259 shader_glsl_add_param(arg
, arg
->src
[1], arg
->src_addr
[1], TRUE
, src1_reg
, src1_mask
, src1_str
);
1261 shader_addline(arg
->buffer
, "if (%s %s %s) {\n",
1262 src0_str
, shader_get_comp_op(arg
->opcode_token
), src1_str
);
1265 void shader_glsl_else(SHADER_OPCODE_ARG
* arg
) {
1266 shader_addline(arg
->buffer
, "} else {\n");
1269 void shader_glsl_break(SHADER_OPCODE_ARG
* arg
) {
1270 shader_addline(arg
->buffer
, "break;\n");
1273 void shader_glsl_breakc(SHADER_OPCODE_ARG
* arg
) {
1275 char src0_str
[100], src1_str
[100];
1276 char src0_reg
[50], src1_reg
[50];
1277 char src0_mask
[6], src1_mask
[6];
1279 shader_glsl_add_param(arg
, arg
->src
[0], arg
->src_addr
[0], TRUE
, src0_reg
, src0_mask
, src0_str
);
1280 shader_glsl_add_param(arg
, arg
->src
[1], arg
->src_addr
[1], TRUE
, src1_reg
, src1_mask
, src1_str
);
1282 shader_addline(arg
->buffer
, "if (%s %s %s) break;\n",
1283 src0_str
, shader_get_comp_op(arg
->opcode_token
), src1_str
);
1286 void shader_glsl_label(SHADER_OPCODE_ARG
* arg
) {
1288 DWORD snum
= (arg
->src
[0]) & D3DSP_REGNUM_MASK
;
1289 shader_addline(arg
->buffer
, "}\n");
1290 shader_addline(arg
->buffer
, "void subroutine%lu () {\n", snum
);
1293 void shader_glsl_call(SHADER_OPCODE_ARG
* arg
) {
1294 DWORD snum
= (arg
->src
[0]) & D3DSP_REGNUM_MASK
;
1295 shader_addline(arg
->buffer
, "subroutine%lu();\n", snum
);
1298 void shader_glsl_callnz(SHADER_OPCODE_ARG
* arg
) {
1304 DWORD snum
= (arg
->src
[0]) & D3DSP_REGNUM_MASK
;
1305 shader_glsl_add_param(arg
, arg
->src
[1], arg
->src_addr
[1], TRUE
, src1_reg
, src1_mask
, src1_str
);
1306 shader_addline(arg
->buffer
, "if (%s) subroutine%lu();\n", src1_str
, snum
);
1309 /*********************************************
1310 * Pixel Shader Specific Code begins here
1311 ********************************************/
1312 void pshader_glsl_tex(SHADER_OPCODE_ARG
* arg
) {
1314 /* FIXME: Make this work for more than just 2D textures */
1316 IWineD3DPixelShaderImpl
* This
= (IWineD3DPixelShaderImpl
*) arg
->shader
;
1317 SHADER_BUFFER
* buffer
= arg
->buffer
;
1318 DWORD hex_version
= This
->baseShader
.hex_version
;
1320 char dst_str
[100], dst_reg
[50], dst_mask
[6];
1321 char coord_str
[100], coord_reg
[50], coord_mask
[6];
1322 char sampler_str
[100], sampler_reg
[50], sampler_mask
[6];
1323 DWORD reg_dest_code
= arg
->dst
& D3DSP_REGNUM_MASK
;
1324 DWORD sampler_code
, sampler_type
;
1326 /* All versions have a destination register */
1327 shader_glsl_add_param(arg
, arg
->dst
, 0, FALSE
, dst_reg
, dst_mask
, dst_str
);
1329 /* 1.0-1.3: Use destination register as coordinate source.
1330 1.4+: Use provided coordinate source register. */
1331 if (hex_version
< D3DPS_VERSION(1,4))
1332 strcpy(coord_reg
, dst_reg
);
1334 shader_glsl_add_param(arg
, arg
->src
[0], arg
->src_addr
[0], TRUE
, coord_reg
, coord_mask
, coord_str
);
1336 /* 1.0-1.4: Use destination register as coordinate source.
1337 * 2.0+: Use provided coordinate source register. */
1338 if (hex_version
< D3DPS_VERSION(2,0)) {
1339 sprintf(sampler_str
, "Psampler%lu", reg_dest_code
);
1340 sampler_code
= reg_dest_code
;
1343 shader_glsl_add_param(arg
, arg
->src
[1], arg
->src_addr
[1], TRUE
, sampler_reg
, sampler_mask
, sampler_str
);
1344 sampler_code
= arg
->src
[1] & D3DSP_REGNUM_MASK
;
1347 sampler_type
= arg
->reg_maps
->samplers
[sampler_code
] & WINED3DSP_TEXTURETYPE_MASK
;
1348 switch(sampler_type
) {
1351 shader_addline(buffer
, "%s = texture2D(%s, %s.st);\n", dst_str
, sampler_str
, coord_reg
);
1353 case WINED3DSTT_CUBE
:
1354 shader_addline(buffer
, "%s = textureCube(%s, %s.stp);\n", dst_str
, sampler_str
, coord_reg
);
1356 case WINED3DSTT_VOLUME
:
1357 shader_addline(buffer
, "%s = texture3D(%s, %s.stp);\n", dst_str
, sampler_str
, coord_reg
);
1360 shader_addline(buffer
, "%s = unrecognized_stype(%s, %s.stp);\n", dst_str
, sampler_str
, coord_reg
);
1361 FIXME("Unrecognized sampler type: %#lx;\n", sampler_type
);
1366 void pshader_glsl_texcoord(SHADER_OPCODE_ARG
* arg
) {
1368 /* FIXME: Make this work for more than just 2D textures */
1370 IWineD3DPixelShaderImpl
* This
= (IWineD3DPixelShaderImpl
*) arg
->shader
;
1371 SHADER_BUFFER
* buffer
= arg
->buffer
;
1372 DWORD hex_version
= This
->baseShader
.hex_version
;
1379 shader_glsl_add_param(arg
, arg
->dst
, 0, FALSE
, tmpReg
, tmpMask
, tmpStr
);
1381 if (hex_version
!= D3DPS_VERSION(1,4)) {
1382 DWORD reg
= arg
->dst
& D3DSP_REGNUM_MASK
;
1383 shader_addline(buffer
, "%s = clamp(gl_TexCoord[%lu], 0.0, 1.0);\n", tmpReg
, reg
);
1385 DWORD reg2
= arg
->src
[0] & D3DSP_REGNUM_MASK
;
1386 shader_addline(buffer
, "%s = gl_TexCoord[%lu]%s;\n", tmpStr
, reg2
, tmpMask
);
1390 /** Process the D3DSIO_TEXDP3TEX instruction in GLSL:
1391 * Take a 3-component dot product of the TexCoord[dstreg] and src,
1392 * then perform a 1D texture lookup from stage dstregnum, place into dst. */
1393 void pshader_glsl_texdp3tex(SHADER_OPCODE_ARG
* arg
) {
1395 DWORD dstreg
= arg
->dst
& D3DSP_REGNUM_MASK
;
1396 char src0_str
[100], dst_str
[100];
1397 char src0_name
[50], dst_name
[50];
1398 char src0_mask
[6], dst_mask
[6];
1400 shader_glsl_add_param(arg
, arg
->dst
, 0, FALSE
, dst_name
, dst_mask
, dst_str
);
1401 shader_glsl_add_param(arg
, arg
->src
[0], arg
->src_addr
[0], TRUE
, src0_name
, src0_mask
, src0_str
);
1403 shader_addline(arg
->buffer
, "tmp0.x = dot(vec3(gl_TexCoord[%lu]), vec3(%s));\n", dstreg
, src0_str
);
1404 shader_addline(arg
->buffer
, "%s = vec4(texture1D(Psampler%lu, tmp0.x))%s;\n", dst_str
, dstreg
, dst_mask
);
1407 /** Process the D3DSIO_TEXDP3 instruction in GLSL:
1408 * Take a 3-component dot product of the TexCoord[dstreg] and src. */
1409 void pshader_glsl_texdp3(SHADER_OPCODE_ARG
* arg
) {
1411 DWORD dstreg
= arg
->dst
& D3DSP_REGNUM_MASK
;
1412 char src0_str
[100], dst_str
[100];
1413 char src0_name
[50], dst_name
[50];
1414 char src0_mask
[6], dst_mask
[6];
1416 shader_glsl_add_param(arg
, arg
->dst
, 0, FALSE
, dst_name
, dst_mask
, dst_str
);
1417 shader_glsl_add_param(arg
, arg
->src
[0], arg
->src_addr
[0], TRUE
, src0_name
, src0_mask
, src0_str
);
1419 shader_addline(arg
->buffer
, "%s = vec4(dot(vec3(T%lu), vec3(%s)))%s;\n",
1420 dst_str
, dstreg
, src0_str
, dst_mask
);
1423 /** Process the D3DSIO_TEXDEPTH instruction in GLSL:
1424 * Calculate the depth as dst.x / dst.y */
1425 void pshader_glsl_texdepth(SHADER_OPCODE_ARG
* arg
) {
1431 shader_glsl_add_param(arg
, arg
->dst
, 0, FALSE
, dst_reg
, dst_mask
, dst_str
);
1433 shader_addline(arg
->buffer
, "gl_FragDepth = %s.x / %s.y;\n", dst_reg
, dst_reg
);
1436 /** Process the D3DSIO_TEXM3X2DEPTH instruction in GLSL:
1437 * Last row of a 3x2 matrix multiply, use the result to calculate the depth:
1438 * Calculate tmp0.y = TexCoord[dstreg] . src.xyz; (tmp0.x has already been calculated)
1439 * depth = (tmp0.y == 0.0) ? 1.0 : tmp0.x / tmp0.y
1441 void pshader_glsl_texm3x2depth(SHADER_OPCODE_ARG
* arg
) {
1443 DWORD dstreg
= arg
->dst
& D3DSP_REGNUM_MASK
;
1444 char src0_str
[100], dst_str
[100];
1445 char src0_name
[50], dst_name
[50];
1446 char src0_mask
[6], dst_mask
[6];
1448 shader_glsl_add_param(arg
, arg
->dst
, 0, FALSE
, dst_name
, dst_mask
, dst_str
);
1449 shader_glsl_add_param(arg
, arg
->src
[0], arg
->src_addr
[0], TRUE
, src0_name
, src0_mask
, src0_str
);
1451 shader_addline(arg
->buffer
, "tmp0.y = dot(vec3(T%lu), vec3(%s));\n", dstreg
, src0_str
);
1452 shader_addline(arg
->buffer
, "gl_FragDepth = vec4((tmp0.y == 0.0) ? 1.0 : tmp0.x / tmp0.y)%s;\n", dst_str
, dst_name
);
1455 /** Process the D3DSIO_TEXM3X2PAD instruction in GLSL
1456 * Calculate the 1st of a 2-row matrix multiplication. */
1457 void pshader_glsl_texm3x2pad(SHADER_OPCODE_ARG
* arg
) {
1459 DWORD reg
= arg
->dst
& D3DSP_REGNUM_MASK
;
1460 SHADER_BUFFER
* buffer
= arg
->buffer
;
1465 shader_glsl_add_param(arg
, arg
->src
[0], arg
->src_addr
[0], TRUE
, src0_name
, src0_mask
, src0_str
);
1466 shader_addline(buffer
, "tmp0.x = dot(vec3(T%lu), vec3(%s));\n", reg
, src0_str
);
1469 /** Process the D3DSIO_TEXM3X3PAD instruction in GLSL
1470 * Calculate the 1st or 2nd row of a 3-row matrix multiplication. */
1471 void pshader_glsl_texm3x3pad(SHADER_OPCODE_ARG
* arg
) {
1473 IWineD3DPixelShaderImpl
* shader
= (IWineD3DPixelShaderImpl
*) arg
->shader
;
1474 DWORD reg
= arg
->dst
& D3DSP_REGNUM_MASK
;
1475 SHADER_BUFFER
* buffer
= arg
->buffer
;
1476 SHADER_PARSE_STATE
* current_state
= &shader
->baseShader
.parse_state
;
1481 shader_glsl_add_param(arg
, arg
->src
[0], arg
->src_addr
[0], TRUE
, src0_name
, src0_mask
, src0_str
);
1482 shader_addline(buffer
, "tmp0.%c = dot(vec3(T%lu), vec3(%s));\n", 'x' + current_state
->current_row
, reg
, src0_str
);
1483 current_state
->texcoord_w
[current_state
->current_row
++] = reg
;
1486 void pshader_glsl_texm3x2tex(SHADER_OPCODE_ARG
* arg
) {
1488 /* FIXME: Make this work for more than just 2D textures */
1490 DWORD reg
= arg
->dst
& D3DSP_REGNUM_MASK
;
1491 SHADER_BUFFER
* buffer
= arg
->buffer
;
1496 shader_glsl_add_param(arg
, arg
->src
[0], arg
->src_addr
[0], TRUE
, src0_name
, src0_mask
, src0_str
);
1497 shader_addline(buffer
, "tmp0.y = dot(vec3(T%lu), vec3(%s));\n", reg
, src0_str
);
1498 shader_addline(buffer
, "T%lu = texture2D(Psampler%lu, tmp0.st);\n", reg
, reg
);
1501 /** Process the D3DSIO_TEXM3X3TEX instruction in GLSL
1502 * Perform the 3rd row of a 3x3 matrix multiply, then sample the texture using the calculate coordinates */
1503 void pshader_glsl_texm3x3tex(SHADER_OPCODE_ARG
* arg
) {
1509 DWORD reg
= arg
->dst
& D3DSP_REGNUM_MASK
;
1510 DWORD src0_regnum
= arg
->src
[0] & D3DSP_REGNUM_MASK
;
1511 DWORD stype
= arg
->reg_maps
->samplers
[src0_regnum
] & WINED3DSP_TEXTURETYPE_MASK
;
1512 IWineD3DPixelShaderImpl
* This
= (IWineD3DPixelShaderImpl
*) arg
->shader
;
1513 SHADER_PARSE_STATE
* current_state
= &This
->baseShader
.parse_state
;
1516 case WINED3DSTT_2D
: strcpy(dimensions
, "2D"); break;
1517 case WINED3DSTT_CUBE
: strcpy(dimensions
, "Cube"); break;
1518 case WINED3DSTT_VOLUME
: strcpy(dimensions
, "3D"); break;
1520 strcpy(dimensions
, "");
1521 FIXME("Unrecognized sampler type: %#lx\n", stype
);
1525 shader_glsl_add_param(arg
, arg
->src
[0], arg
->src_addr
[0], TRUE
, src0_name
, src0_mask
, src0_str
);
1526 shader_addline(arg
->buffer
, "tmp0.z = dot(vec3(T%lu), vec3(%s));\n", reg
, src0_str
);
1527 shader_addline(arg
->buffer
, "T%lu = texture%s(Psampler%lu, tmp0.%s);\n",
1528 reg
, dimensions
, reg
, (stype
== WINED3DSTT_2D
) ? "xy" : "xyz");
1529 current_state
->current_row
= 0;
1532 /** Process the D3DSIO_TEXM3X3 instruction in GLSL
1533 * Perform the 3rd row of a 3x3 matrix multiply */
1534 void pshader_glsl_texm3x3(SHADER_OPCODE_ARG
* arg
) {
1539 DWORD reg
= arg
->dst
& D3DSP_REGNUM_MASK
;
1540 IWineD3DPixelShaderImpl
* This
= (IWineD3DPixelShaderImpl
*) arg
->shader
;
1541 SHADER_PARSE_STATE
* current_state
= &This
->baseShader
.parse_state
;
1543 shader_glsl_add_param(arg
, arg
->src
[0], arg
->src_addr
[0], TRUE
, src0_name
, src0_mask
, src0_str
);
1545 shader_addline(arg
->buffer
, "tmp0.z = dot(vec3(T%lu), vec3(%s));\n", reg
, src0_str
);
1546 shader_addline(arg
->buffer
, "T%lu = vec4(tmp0.x, tmp0.y, tmp0.z, 1.0);\n", reg
);
1547 current_state
->current_row
= 0;
1550 /** Process the D3DSIO_TEXM3X3SPEC instruction in GLSL
1551 * Peform the final texture lookup based on the previous 2 3x3 matrix multiplies */
1552 void pshader_glsl_texm3x3spec(SHADER_OPCODE_ARG
* arg
) {
1554 IWineD3DPixelShaderImpl
* shader
= (IWineD3DPixelShaderImpl
*) arg
->shader
;
1555 DWORD reg
= arg
->dst
& D3DSP_REGNUM_MASK
;
1557 char src0_str
[100], src0_name
[50], src0_mask
[6];
1558 char src1_str
[100], src1_name
[50], src1_mask
[6];
1559 SHADER_BUFFER
* buffer
= arg
->buffer
;
1560 SHADER_PARSE_STATE
* current_state
= &shader
->baseShader
.parse_state
;
1561 DWORD stype
= arg
->reg_maps
->samplers
[reg
] & WINED3DSP_TEXTURETYPE_MASK
;
1564 case WINED3DSTT_2D
: strcpy(dimensions
, "2D"); break;
1565 case WINED3DSTT_CUBE
: strcpy(dimensions
, "Cube"); break;
1566 case WINED3DSTT_VOLUME
: strcpy(dimensions
, "3D"); break;
1568 strcpy(dimensions
, "");
1569 FIXME("Unrecognized sampler type: %#lx\n", stype
);
1573 shader_glsl_add_param(arg
, arg
->src
[0], arg
->src_addr
[0], TRUE
, src0_name
, src0_mask
, src0_str
);
1574 shader_glsl_add_param(arg
, arg
->src
[1], arg
->src_addr
[1], TRUE
, src1_name
, src1_mask
, src1_str
);
1576 /* Perform the last matrix multiply operation */
1577 shader_addline(buffer
, "tmp0.z = dot(vec3(T%lu), vec3(%s));\n", reg
, src0_str
);
1579 /* Calculate reflection vector */
1580 shader_addline(buffer
, "tmp0.xyz = reflect(-vec3(%s), vec3(tmp0));\n", src1_str
);
1582 /* Sample the texture */
1583 shader_addline(buffer
, "T%lu = texture%s(Psampler%lu, tmp0.%s);\n",
1584 reg
, dimensions
, reg
, (stype
== WINED3DSTT_2D
) ? "xy" : "xyz");
1585 current_state
->current_row
= 0;
1588 /** Process the D3DSIO_TEXM3X3VSPEC instruction in GLSL
1589 * Peform the final texture lookup based on the previous 2 3x3 matrix multiplies */
1590 void pshader_glsl_texm3x3vspec(SHADER_OPCODE_ARG
* arg
) {
1592 IWineD3DPixelShaderImpl
* shader
= (IWineD3DPixelShaderImpl
*) arg
->shader
;
1593 DWORD reg
= arg
->dst
& D3DSP_REGNUM_MASK
;
1594 SHADER_BUFFER
* buffer
= arg
->buffer
;
1595 SHADER_PARSE_STATE
* current_state
= &shader
->baseShader
.parse_state
;
1596 char src0_str
[100], src0_name
[50], src0_mask
[6];
1598 shader_glsl_add_param(arg
, arg
->src
[0], arg
->src_addr
[0], TRUE
, src0_name
, src0_mask
, src0_str
);
1600 /* Perform the last matrix multiply operation */
1601 shader_addline(buffer
, "tmp0.z = dot(vec3(T%lu), vec3(%s));\n", reg
, src0_str
);
1603 /* Construct the eye-ray vector from w coordinates */
1604 shader_addline(buffer
, "tmp1.x = gl_TexCoord[%lu].w;\n", current_state
->texcoord_w
[0]);
1605 shader_addline(buffer
, "tmp1.y = gl_TexCoord[%lu].w;\n", current_state
->texcoord_w
[1]);
1606 shader_addline(buffer
, "tmp1.z = gl_TexCoord[%lu].w;\n", reg
);
1608 /* Calculate reflection vector (Assume normal is normalized): RF = 2*(N.E)*N -E */
1609 shader_addline(buffer
, "tmp0.x = dot(vec3(tmp0), vec3(tmp1));\n");
1610 shader_addline(buffer
, "tmp0 = tmp0.w * tmp0;\n");
1611 shader_addline(buffer
, "tmp0 = (2.0 * tmp0) - tmp1;\n");
1614 * We don't really know if a Cube or a Volume texture is being sampled, but since Cube textures
1615 * are used more commonly, we'll default to that.
1616 * We probably need to push back the pixel shader generation code until drawPrimitive() for
1617 * shader versions < 2.0, since that's the only time we can guarantee that we're sampling
1618 * the correct type of texture because we can lookup what textures are bound at that point.
1620 shader_addline(buffer
, "T%lu = textureCube(Psampler%lu, tmp0.xyz);\n", reg
, reg
);
1621 current_state
->current_row
= 0;
1624 /** Process the D3DSIO_TEXBEM instruction in GLSL.
1625 * Apply a fake bump map transform.
1626 * FIXME: Should apply the BUMPMAPENV matrix. For now, just sample the texture */
1627 void pshader_glsl_texbem(SHADER_OPCODE_ARG
* arg
) {
1629 DWORD reg1
= arg
->dst
& D3DSP_REGNUM_MASK
;
1630 DWORD reg2
= arg
->src
[0] & D3DSP_REGNUM_MASK
;
1632 FIXME("Not applying the BUMPMAPENV matrix for pixel shader instruction texbem.\n");
1633 shader_addline(arg
->buffer
, "T%lu = texture2D(Psampler%lu, gl_TexCoord[%lu].xy + T%lu.xy);\n",
1634 reg1
, reg1
, reg1
, reg2
);
1637 /** Process the D3DSIO_TEXREG2AR instruction in GLSL
1638 * Sample 2D texture at dst using the alpha & red (wx) components of src as texture coordinates */
1639 void pshader_glsl_texreg2ar(SHADER_OPCODE_ARG
* arg
) {
1642 char dst_str
[100], src0_str
[100];
1643 char dst_reg
[50], src0_reg
[50];
1644 char dst_mask
[6], src0_mask
[6];
1645 DWORD src0_regnum
= arg
->src
[0] & D3DSP_REGNUM_MASK
;
1647 shader_glsl_add_param(arg
, arg
->dst
, 0, FALSE
, dst_reg
, dst_mask
, dst_str
);
1648 shader_glsl_add_param(arg
, arg
->src
[0], arg
->src_addr
[0], TRUE
, src0_reg
, src0_mask
, src0_str
);
1650 shader_glsl_add_dst(arg
->dst
, dst_reg
, dst_mask
, tmpLine
);
1651 shader_addline(arg
->buffer
, "%stexture2D(Psampler%lu, %s.yz))%s;\n",
1652 tmpLine
, src0_regnum
, dst_reg
, dst_mask
);
1655 /** Process the D3DSIO_TEXREG2GB instruction in GLSL
1656 * Sample 2D texture at dst using the green & blue (yz) components of src as texture coordinates */
1657 void pshader_glsl_texreg2gb(SHADER_OPCODE_ARG
* arg
) {
1660 char dst_str
[100], src0_str
[100];
1661 char dst_reg
[50], src0_reg
[50];
1662 char dst_mask
[6], src0_mask
[6];
1663 DWORD src0_regnum
= arg
->src
[0] & D3DSP_REGNUM_MASK
;
1665 shader_glsl_add_param(arg
, arg
->dst
, 0, FALSE
, dst_reg
, dst_mask
, dst_str
);
1666 shader_glsl_add_param(arg
, arg
->src
[0], arg
->src_addr
[0], TRUE
, src0_reg
, src0_mask
, src0_str
);
1668 shader_glsl_add_dst(arg
->dst
, dst_reg
, dst_mask
, tmpLine
);
1669 shader_addline(arg
->buffer
, "%stexture2D(Psampler%lu, %s.yz))%s;\n",
1670 tmpLine
, src0_regnum
, dst_reg
, dst_mask
);
1673 /** Process the D3DSIO_TEXREG2RGB instruction in GLSL
1674 * Sample texture at dst using the rgb (xyz) components of src as texture coordinates */
1675 void pshader_glsl_texreg2rgb(SHADER_OPCODE_ARG
* arg
) {
1678 char dst_str
[100], src0_str
[100];
1679 char dst_reg
[50], src0_reg
[50];
1680 char dst_mask
[6], src0_mask
[6];
1682 DWORD src0_regnum
= arg
->src
[0] & D3DSP_REGNUM_MASK
;
1683 DWORD stype
= arg
->reg_maps
->samplers
[src0_regnum
] & WINED3DSP_TEXTURETYPE_MASK
;
1685 case WINED3DSTT_2D
: strcpy(dimensions
, "2D"); break;
1686 case WINED3DSTT_CUBE
: strcpy(dimensions
, "Cube"); break;
1687 case WINED3DSTT_VOLUME
: strcpy(dimensions
, "3D"); break;
1689 strcpy(dimensions
, "");
1690 FIXME("Unrecognized sampler type: %#lx\n", stype
);
1694 shader_glsl_add_param(arg
, arg
->dst
, 0, FALSE
, dst_reg
, dst_mask
, dst_str
);
1695 shader_glsl_add_param(arg
, arg
->src
[0], arg
->src_addr
[0], TRUE
, src0_reg
, src0_mask
, src0_str
);
1697 shader_glsl_add_dst(arg
->dst
, dst_reg
, dst_mask
, tmpLine
);
1698 shader_addline(arg
->buffer
, "%stexture%s(Psampler%lu, %s.%s))%s;\n",
1699 tmpLine
, dimensions
, src0_regnum
, dst_reg
, (stype
== WINED3DSTT_2D
) ? "xy" : "xyz", dst_mask
);
1702 /** Process the D3DSIO_TEXKILL instruction in GLSL.
1703 * If any of the first 3 components are < 0, discard this pixel */
1704 void pshader_glsl_texkill(SHADER_OPCODE_ARG
* arg
) {
1706 char dst_str
[100], dst_name
[50], dst_mask
[6];
1708 shader_glsl_add_param(arg
, arg
->dst
, 0, FALSE
, dst_name
, dst_mask
, dst_str
);
1709 shader_addline(arg
->buffer
, "if (any(lessThan(%s.xyz, vec3(0.0)))) discard;\n", dst_name
);
1712 /** Process the D3DSIO_DP2ADD instruction in GLSL.
1713 * dst = dot2(src0, src1) + src2 */
1714 void pshader_glsl_dp2add(SHADER_OPCODE_ARG
* arg
) {
1717 char dst_str
[100], src0_str
[100], src1_str
[100], src2_str
[100];
1718 char dst_reg
[50], src0_reg
[50], src1_reg
[50], src2_reg
[50];
1719 char dst_mask
[6], src0_mask
[6], src1_mask
[6], src2_mask
[6];
1721 shader_glsl_add_param(arg
, arg
->dst
, 0, FALSE
, dst_reg
, dst_mask
, dst_str
);
1722 shader_glsl_add_param(arg
, arg
->src
[0], arg
->src_addr
[0], TRUE
, src0_reg
, src0_mask
, src0_str
);
1723 shader_glsl_add_param(arg
, arg
->src
[1], arg
->src_addr
[1], TRUE
, src1_reg
, src1_mask
, src1_str
);
1724 shader_glsl_add_param(arg
, arg
->src
[2], arg
->src_addr
[2], TRUE
, src2_reg
, src2_mask
, src2_str
);
1725 shader_glsl_add_dst(arg
->dst
, dst_reg
, dst_mask
, tmpLine
);
1726 shader_addline(arg
->buffer
, "%sdot(vec2(%s), vec2(%s)) + %s)%s;\n",
1727 tmpLine
, src0_str
, src1_str
, src2_str
, dst_mask
);
1730 void pshader_glsl_input_pack(
1731 SHADER_BUFFER
* buffer
,
1732 semantic
* semantics_in
) {
1736 for (i
= 0; i
< MAX_REG_INPUT
; i
++) {
1738 DWORD usage_token
= semantics_in
[i
].usage
;
1739 DWORD register_token
= semantics_in
[i
].reg
;
1740 DWORD usage
, usage_idx
;
1744 if (!usage_token
) continue;
1745 usage
= (usage_token
& D3DSP_DCL_USAGE_MASK
) >> D3DSP_DCL_USAGE_SHIFT
;
1746 usage_idx
= (usage_token
& D3DSP_DCL_USAGEINDEX_MASK
) >> D3DSP_DCL_USAGEINDEX_SHIFT
;
1747 shader_glsl_get_output_register_swizzle(register_token
, reg_mask
);
1751 case D3DDECLUSAGE_COLOR
:
1753 shader_addline(buffer
, "IN%lu%s = vec4(gl_Color)%s;\n",
1754 i
, reg_mask
, reg_mask
);
1755 else if (usage_idx
== 1)
1756 shader_addline(buffer
, "IN%lu%s = vec4(gl_SecondaryColor)%s;\n",
1757 i
, reg_mask
, reg_mask
);
1759 shader_addline(buffer
, "IN%lu%s = vec4(unsupported_color_input)%s;\n",
1760 i
, reg_mask
, reg_mask
);
1763 case D3DDECLUSAGE_TEXCOORD
:
1764 shader_addline(buffer
, "IN%lu%s = vec4(gl_TexCoord[%lu])%s;\n",
1765 i
, reg_mask
, usage_idx
, reg_mask
);
1768 case D3DDECLUSAGE_FOG
:
1769 shader_addline(buffer
, "IN%lu%s = vec4(gl_FogFragCoord)%s;\n",
1770 i
, reg_mask
, reg_mask
);
1774 shader_addline(buffer
, "IN%lu%s = vec4(unsupported_input)%s;\n",
1775 i
, reg_mask
, reg_mask
);
1780 /*********************************************
1781 * Vertex Shader Specific Code begins here
1782 ********************************************/
1784 void vshader_glsl_output_unpack(
1785 SHADER_BUFFER
* buffer
,
1786 semantic
* semantics_out
) {
1790 for (i
= 0; i
< MAX_REG_OUTPUT
; i
++) {
1792 DWORD usage_token
= semantics_out
[i
].usage
;
1793 DWORD register_token
= semantics_out
[i
].reg
;
1794 DWORD usage
, usage_idx
;
1798 if (!usage_token
) continue;
1800 usage
= (usage_token
& D3DSP_DCL_USAGE_MASK
) >> D3DSP_DCL_USAGE_SHIFT
;
1801 usage_idx
= (usage_token
& D3DSP_DCL_USAGEINDEX_MASK
) >> D3DSP_DCL_USAGEINDEX_SHIFT
;
1802 shader_glsl_get_output_register_swizzle(register_token
, reg_mask
);
1806 case D3DDECLUSAGE_COLOR
:
1808 shader_addline(buffer
, "gl_FrontColor%s = OUT%lu%s;\n", reg_mask
, i
, reg_mask
);
1809 else if (usage_idx
== 1)
1810 shader_addline(buffer
, "gl_FrontSecondaryColor%s = OUT%lu%s;\n", reg_mask
, i
, reg_mask
);
1812 shader_addline(buffer
, "unsupported_color_output%s = OUT%lu%s;\n", reg_mask
, i
, reg_mask
);
1815 case D3DDECLUSAGE_POSITION
:
1816 shader_addline(buffer
, "gl_Position%s = OUT%lu%s;\n", reg_mask
, i
, reg_mask
);
1819 case D3DDECLUSAGE_TEXCOORD
:
1820 shader_addline(buffer
, "gl_TexCoord[%lu]%s = OUT%lu%s;\n",
1821 usage_idx
, reg_mask
, i
, reg_mask
);
1824 case WINED3DSHADERDECLUSAGE_PSIZE
:
1825 shader_addline(buffer
, "gl_PointSize = OUT%lu.x;\n", i
);
1828 case WINED3DSHADERDECLUSAGE_FOG
:
1829 shader_addline(buffer
, "gl_FogFragCoord%s = OUT%lu%s;\n", reg_mask
, i
, reg_mask
);
1833 shader_addline(buffer
, "unsupported_output%s = OUT%lu%s;\n", reg_mask
, i
, reg_mask
);