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
] & D3DSP_TEXTURETYPE_MASK
;
362 shader_addline(buffer
, "uniform sampler2D %csampler%lu;\n", prefix
, i
);
365 shader_addline(buffer
, "uniform samplerCube %csampler%lu;\n", prefix
, i
);
368 shader_addline(buffer
, "uniform sampler3D %csampler%lu;\n", prefix
, i
);
371 shader_addline(buffer
, "uniform unsupported_sampler %csampler%lu;\n", prefix
, i
);
372 FIXME("Unrecognized sampler type: %#lx\n", stype
);
378 /* Declare address variables */
379 for (i
= 0; i
< This
->baseShader
.limits
.address
; i
++) {
380 if (reg_maps
->address
[i
])
381 shader_addline(buffer
, "ivec4 A%ld;\n", i
);
384 /* Declare texture coordinate temporaries and initialize them */
385 for (i
= 0; i
< This
->baseShader
.limits
.texcoord
; i
++) {
386 if (reg_maps
->texcoord
[i
])
387 shader_addline(buffer
, "vec4 T%lu = gl_TexCoord[%lu];\n", i
, i
);
390 /* Declare input register temporaries */
391 for (i
=0; i
< This
->baseShader
.limits
.packed_input
; i
++) {
392 if (reg_maps
->packed_input
[i
])
393 shader_addline(buffer
, "vec4 IN%lu;\n", i
);
396 /* Declare output register temporaries */
397 for (i
= 0; i
< This
->baseShader
.limits
.packed_output
; i
++) {
398 if (reg_maps
->packed_output
[i
])
399 shader_addline(buffer
, "vec4 OUT%lu;\n", i
);
402 /* Declare temporary variables */
403 for(i
= 0; i
< This
->baseShader
.limits
.temporary
; i
++) {
404 if (reg_maps
->temporary
[i
])
405 shader_addline(buffer
, "vec4 R%lu;\n", i
);
408 /* Declare attributes */
409 for (i
= 0; i
< This
->baseShader
.limits
.attributes
; i
++) {
410 if (reg_maps
->attributes
[i
])
411 shader_addline(buffer
, "attribute vec4 attrib%i;\n", i
);
414 /* Declare loop register aL */
415 if (reg_maps
->loop
) {
416 shader_addline(buffer
, "int aL;\n");
417 shader_addline(buffer
, "int tmpInt;\n");
420 /* Temporary variables for matrix operations */
421 shader_addline(buffer
, "vec4 tmp0;\n");
422 shader_addline(buffer
, "vec4 tmp1;\n");
424 /* Start the main program */
425 shader_addline(buffer
, "void main() {\n");
428 /*****************************************************************************
429 * Functions to generate GLSL strings from DirectX Shader bytecode begin here.
431 * For more information, see http://wiki.winehq.org/DirectX-Shaders
432 ****************************************************************************/
435 static void shader_glsl_add_param(
436 SHADER_OPCODE_ARG
* arg
,
438 const DWORD addr_token
,
444 /** Used for opcode modifiers - They multiply the result by the specified amount */
445 static const char* shift_glsl_tab
[] = {
447 "2.0 * ", /* 1 (x2) */
448 "4.0 * ", /* 2 (x4) */
449 "8.0 * ", /* 3 (x8) */
450 "16.0 * ", /* 4 (x16) */
451 "32.0 * ", /* 5 (x32) */
458 "0.0625 * ", /* 12 (d16) */
459 "0.125 * ", /* 13 (d8) */
460 "0.25 * ", /* 14 (d4) */
461 "0.5 * " /* 15 (d2) */
464 /** Print the beginning of the generated GLSL string. example: "reg_name.xyzw = vec4("
465 * Will also change the reg_mask if necessary (not all register types are equal in DX vs GL) */
466 static void shader_glsl_add_dst(DWORD param
, const char* reg_name
, char* reg_mask
, char* outStr
) {
468 int shift
= (param
& D3DSP_DSTSHIFT_MASK
) >> D3DSP_DSTSHIFT_SHIFT
;
471 if ((shader_get_regtype(param
) == D3DSPR_RASTOUT
)
472 && ((param
& D3DSP_REGNUM_MASK
) != 0)) {
473 /* gl_FogFragCoord or glPointSize - both floats */
474 strcpy(cast
, "float");
475 strcpy(reg_mask
, "");
477 } else if (reg_name
[0] == 'A') {
478 /* Address register for vertex shaders (ivec4) */
479 strcpy(cast
, "ivec4");
482 /* Everything else should be a 4 component float vector */
483 strcpy(cast
, "vec4");
486 sprintf(outStr
, "%s%s = %s%s(", reg_name
, reg_mask
, shift_glsl_tab
[shift
], cast
);
489 /* Generate a GLSL parameter that does the input modifier computation and return the input register/mask to use */
490 static void shader_glsl_gen_modifier (
493 const char *in_regswizzle
,
498 if (instr
== D3DSIO_TEXKILL
)
501 switch (instr
& D3DSP_SRCMOD_MASK
) {
503 sprintf(out_str
, "%s%s", in_reg
, in_regswizzle
);
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 - vec4(0.5)%s)", in_reg
, in_regswizzle
, in_regswizzle
);
514 case D3DSPSM_BIASNEG
:
515 sprintf(out_str
, "-(%s%s - vec4(0.5)%s)", in_reg
, in_regswizzle
, in_regswizzle
);
518 sprintf(out_str
, "(2.0 * (%s%s - 0.5))", in_reg
, in_regswizzle
);
520 case D3DSPSM_SIGNNEG
:
521 sprintf(out_str
, "-(2.0 * (%s%s - 0.5))", in_reg
, in_regswizzle
);
524 sprintf(out_str
, "(1.0 - %s%s)", in_reg
, in_regswizzle
);
527 sprintf(out_str
, "(2.0 * %s%s)", in_reg
, in_regswizzle
);
530 sprintf(out_str
, "-(2.0 * %s%s)", in_reg
, in_regswizzle
);
532 case D3DSPSM_DZ
: /* reg1_db = { reg1.r/b, reg1.g/b, ...} The g & a components are undefined, so we'll leave them alone */
533 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
);
536 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
);
539 sprintf(out_str
, "abs(%s%s)", in_reg
, in_regswizzle
);
542 sprintf(out_str
, "-abs(%s%s)", in_reg
, in_regswizzle
);
545 FIXME("Unhandled modifier %lu\n", (instr
& D3DSP_SRCMOD_MASK
));
546 sprintf(out_str
, "%s%s", in_reg
, in_regswizzle
);
550 /** Writes the GLSL variable name that corresponds to the register that the
551 * DX opcode parameter is trying to access */
552 static void shader_glsl_get_register_name(
554 const DWORD addr_token
,
557 SHADER_OPCODE_ARG
* arg
) {
559 /* oPos, oFog and oPts in D3D */
560 const char* hwrastout_reg_names
[] = { "gl_Position", "gl_FogFragCoord", "gl_PointSize" };
562 DWORD reg
= param
& D3DSP_REGNUM_MASK
;
563 DWORD regtype
= shader_get_regtype(param
);
564 IWineD3DBaseShaderImpl
* This
= (IWineD3DBaseShaderImpl
*) arg
->shader
;
565 char pshader
= shader_is_pshader_version(This
->baseShader
.hex_version
);
572 sprintf(tmpStr
, "R%lu", reg
);
576 /* Pixel shaders >= 3.0 */
577 if (D3DSHADER_VERSION_MAJOR(This
->baseShader
.hex_version
) >= 3)
578 sprintf(tmpStr
, "IN%lu", reg
);
581 strcpy(tmpStr
, "gl_Color");
583 strcpy(tmpStr
, "gl_SecondaryColor");
586 if (vshader_input_is_color((IWineD3DVertexShader
*) This
, reg
))
588 sprintf(tmpStr
, "attrib%lu", reg
);
593 const char* prefix
= pshader
? "PC":"VC";
595 /* Relative addressing */
596 if (param
& D3DVS_ADDRMODE_RELATIVE
) {
598 /* Relative addressing on shaders 2.0+ have a relative address token,
599 * prior to that, it was hard-coded as "A0.x" because there's only 1 register */
600 if (D3DSHADER_VERSION_MAJOR(This
->baseShader
.hex_version
) >= 2) {
601 char relStr
[100], relReg
[50], relMask
[6];
602 shader_glsl_add_param(arg
, addr_token
, 0, TRUE
, relReg
, relMask
, relStr
);
603 sprintf(tmpStr
, "%s[%s + %lu]", prefix
, relStr
, reg
);
605 sprintf(tmpStr
, "%s[A0.x + %lu]", prefix
, reg
);
608 sprintf(tmpStr
, "%s[%lu]", prefix
, reg
);
612 case D3DSPR_CONSTINT
:
614 sprintf(tmpStr
, "PI[%lu]", reg
);
616 sprintf(tmpStr
, "VI[%lu]", reg
);
618 case D3DSPR_CONSTBOOL
:
620 sprintf(tmpStr
, "PB[%lu]", reg
);
622 sprintf(tmpStr
, "VB[%lu]", reg
);
624 case D3DSPR_TEXTURE
: /* case D3DSPR_ADDR: */
626 sprintf(tmpStr
, "T%lu", reg
);
628 sprintf(tmpStr
, "A%lu", reg
);
632 sprintf(tmpStr
, "aL");
636 sprintf(tmpStr
, "Psampler%lu", reg
);
638 sprintf(tmpStr
, "Vsampler%lu", reg
);
640 case D3DSPR_COLOROUT
:
642 sprintf(tmpStr
, "gl_FragColor");
644 /* TODO: See GL_ARB_draw_buffers */
645 FIXME("Unsupported write to render target %lu\n", reg
);
646 sprintf(tmpStr
, "unsupported_register");
650 sprintf(tmpStr
, "%s", hwrastout_reg_names
[reg
]);
652 case D3DSPR_DEPTHOUT
:
653 sprintf(tmpStr
, "gl_FragDepth");
657 sprintf(tmpStr
, "gl_FrontColor");
659 sprintf(tmpStr
, "gl_FrontSecondaryColor");
662 case D3DSPR_TEXCRDOUT
:
663 /* Vertex shaders >= 3.0: D3DSPR_OUTPUT */
664 if (D3DSHADER_VERSION_MAJOR(This
->baseShader
.hex_version
) >= 3)
665 sprintf(tmpStr
, "OUT%lu", reg
);
667 sprintf(tmpStr
, "gl_TexCoord[%lu]", reg
);
670 FIXME("Unhandled register name Type(%ld)\n", regtype
);
671 sprintf(tmpStr
, "unrecognized_register");
675 strcat(regstr
, tmpStr
);
678 /* Writes the GLSL writemask for the destination register */
679 static void shader_glsl_get_output_register_swizzle(
684 if ((param
& D3DSP_WRITEMASK_ALL
) != D3DSP_WRITEMASK_ALL
) {
685 strcat(write_mask
, ".");
686 if (param
& D3DSP_WRITEMASK_0
) strcat(write_mask
, "x");
687 if (param
& D3DSP_WRITEMASK_1
) strcat(write_mask
, "y");
688 if (param
& D3DSP_WRITEMASK_2
) strcat(write_mask
, "z");
689 if (param
& D3DSP_WRITEMASK_3
) strcat(write_mask
, "w");
693 static void shader_glsl_get_input_register_swizzle(
698 const char swizzle_reg_chars_color_fix
[] = "zyxw";
699 const char swizzle_reg_chars
[] = "xyzw";
700 const char* swizzle_regs
= NULL
;
703 DWORD swizzle
= (param
& D3DVS_SWIZZLE_MASK
) >> D3DVS_SWIZZLE_SHIFT
;
704 DWORD swizzle_x
= swizzle
& 0x03;
705 DWORD swizzle_y
= (swizzle
>> 2) & 0x03;
706 DWORD swizzle_z
= (swizzle
>> 4) & 0x03;
707 DWORD swizzle_w
= (swizzle
>> 6) & 0x03;
710 swizzle_regs
= swizzle_reg_chars_color_fix
;
712 swizzle_regs
= swizzle_reg_chars
;
716 * swizzle bits fields:
719 if ((D3DVS_NOSWIZZLE
>> D3DVS_SWIZZLE_SHIFT
) == swizzle
) { /* D3DVS_NOSWIZZLE == 0xE4 << D3DVS_SWIZZLE_SHIFT */
721 sprintf(reg_mask
, ".%c%c%c%c",
722 swizzle_regs
[swizzle_x
],
723 swizzle_regs
[swizzle_y
],
724 swizzle_regs
[swizzle_z
],
725 swizzle_regs
[swizzle_w
]);
729 if (swizzle_x
== swizzle_y
&&
730 swizzle_x
== swizzle_z
&&
731 swizzle_x
== swizzle_w
)
733 sprintf(reg_mask
, ".%c", swizzle_regs
[swizzle_x
]);
735 sprintf(reg_mask
, ".%c%c%c%c",
736 swizzle_regs
[swizzle_x
],
737 swizzle_regs
[swizzle_y
],
738 swizzle_regs
[swizzle_z
],
739 swizzle_regs
[swizzle_w
]);
743 /** From a given parameter token, generate the corresponding GLSL string.
744 * Also, return the actual register name and swizzle in case the
745 * caller needs this information as well. */
746 static void shader_glsl_add_param(
747 SHADER_OPCODE_ARG
* arg
,
749 const DWORD addr_token
,
755 BOOL is_color
= FALSE
;
756 reg_mask
[0] = reg_name
[0] = out_str
[0] = 0;
758 shader_glsl_get_register_name(param
, addr_token
, reg_name
, &is_color
, arg
);
761 shader_glsl_get_input_register_swizzle(param
, is_color
, reg_mask
);
762 shader_glsl_gen_modifier(param
, reg_name
, reg_mask
, out_str
);
764 shader_glsl_get_output_register_swizzle(param
, reg_mask
);
765 sprintf(out_str
, "%s%s", reg_name
, reg_mask
);
769 /** Process GLSL instruction modifiers */
770 void shader_glsl_add_instruction_modifiers(SHADER_OPCODE_ARG
* arg
) {
772 DWORD mask
= arg
->dst
& D3DSP_DSTMOD_MASK
;
774 if (arg
->opcode
->dst_token
&& mask
!= 0) {
779 shader_glsl_add_param(arg
, arg
->dst
, 0, FALSE
, dst_reg
, dst_mask
, dst_str
);
781 if (mask
& D3DSPDM_SATURATE
) {
782 /* _SAT means to clamp the value of the register to between 0 and 1 */
783 shader_addline(arg
->buffer
, "%s%s = clamp(%s%s, 0.0, 1.0);\n", dst_reg
, dst_mask
, dst_reg
, dst_mask
);
785 if (mask
& D3DSPDM_MSAMPCENTROID
) {
786 FIXME("_centroid modifier not handled\n");
788 if (mask
& D3DSPDM_PARTIALPRECISION
) {
789 /* MSDN says this modifier can be safely ignored, so that's what we'll do. */
794 static inline const char* shader_get_comp_op(
795 const DWORD opcode
) {
797 DWORD op
= (opcode
& INST_CONTROLS_MASK
) >> INST_CONTROLS_SHIFT
;
799 case COMPARISON_GT
: return ">";
800 case COMPARISON_EQ
: return "==";
801 case COMPARISON_GE
: return ">=";
802 case COMPARISON_LT
: return "<";
803 case COMPARISON_NE
: return "!=";
804 case COMPARISON_LE
: return "<=";
806 FIXME("Unrecognized comparison value: %lu\n", op
);
811 /*****************************************************************************
813 * Begin processing individual instruction opcodes
815 ****************************************************************************/
817 /* Generate GLSL arithmetic functions (dst = src1 + src2) */
818 void shader_glsl_arith(SHADER_OPCODE_ARG
* arg
) {
820 CONST SHADER_OPCODE
* curOpcode
= arg
->opcode
;
821 SHADER_BUFFER
* buffer
= arg
->buffer
;
823 char dst_reg
[50], src0_reg
[50], src1_reg
[50];
824 char dst_mask
[6], src0_mask
[6], src1_mask
[6];
825 char dst_str
[100], src0_str
[100], src1_str
[100];
827 shader_glsl_add_param(arg
, arg
->dst
, 0, FALSE
, dst_reg
, dst_mask
, dst_str
);
828 shader_glsl_add_param(arg
, arg
->src
[0], arg
->src_addr
[0], TRUE
, src0_reg
, src0_mask
, src0_str
);
829 shader_glsl_add_param(arg
, arg
->src
[1], arg
->src_addr
[1], TRUE
, src1_reg
, src1_mask
, src1_str
);
830 shader_glsl_add_dst(arg
->dst
, dst_reg
, dst_mask
, tmpLine
);
831 strcat(tmpLine
, "vec4(");
832 strcat(tmpLine
, src0_str
);
833 strcat(tmpLine
, ")");
835 /* Determine the GLSL operator to use based on the opcode */
836 switch (curOpcode
->opcode
) {
837 case D3DSIO_MUL
: strcat(tmpLine
, " * "); break;
838 case D3DSIO_ADD
: strcat(tmpLine
, " + "); break;
839 case D3DSIO_SUB
: strcat(tmpLine
, " - "); break;
841 FIXME("Opcode %s not yet handled in GLSL\n", curOpcode
->name
);
844 shader_addline(buffer
, "%svec4(%s))%s;\n", tmpLine
, src1_str
, dst_mask
);
847 /* Process the D3DSIO_MOV opcode using GLSL (dst = src) */
848 void shader_glsl_mov(SHADER_OPCODE_ARG
* arg
) {
850 SHADER_BUFFER
* buffer
= arg
->buffer
;
852 char dst_str
[100], src0_str
[100];
853 char dst_reg
[50], src0_reg
[50];
854 char dst_mask
[6], src0_mask
[6];
856 shader_glsl_add_param(arg
, arg
->dst
, 0, FALSE
, dst_reg
, dst_mask
, dst_str
);
857 shader_glsl_add_param(arg
, arg
->src
[0], arg
->src_addr
[0], TRUE
, src0_reg
, src0_mask
, src0_str
);
858 shader_glsl_add_dst(arg
->dst
, dst_reg
, dst_mask
, tmpLine
);
859 shader_addline(buffer
, "%s%s)%s;\n", tmpLine
, src0_str
, dst_mask
);
862 /* Process the dot product operators DP3 and DP4 in GLSL (dst = dot(src0, src1)) */
863 void shader_glsl_dot(SHADER_OPCODE_ARG
* arg
) {
865 CONST SHADER_OPCODE
* curOpcode
= arg
->opcode
;
866 SHADER_BUFFER
* buffer
= arg
->buffer
;
868 char dst_str
[100], src0_str
[100], src1_str
[100];
869 char dst_reg
[50], src0_reg
[50], src1_reg
[50];
870 char dst_mask
[6], src0_mask
[6], src1_mask
[6];
873 shader_glsl_add_param(arg
, arg
->dst
, 0, FALSE
, dst_reg
, dst_mask
, dst_str
);
874 shader_glsl_add_param(arg
, arg
->src
[0], arg
->src_addr
[0], TRUE
, src0_reg
, src0_mask
, src0_str
);
875 shader_glsl_add_param(arg
, arg
->src
[1], arg
->src_addr
[1], TRUE
, src1_reg
, src1_mask
, src1_str
);
877 shader_glsl_add_dst(arg
->dst
, dst_reg
, dst_mask
, tmpDest
);
879 /* Need to cast the src vectors to vec3 for dp3, and vec4 for dp4 */
880 if (curOpcode
->opcode
== D3DSIO_DP4
)
881 strcpy(cast
, "vec4(");
883 strcpy(cast
, "vec3(");
885 shader_addline(buffer
, "%sdot(%s%s), %s%s)))%s;\n",
886 tmpDest
, cast
, src0_str
, cast
, src1_str
, dst_mask
);
889 /* Map the opcode 1-to-1 to the GL code (arg->dst = instruction(src0, src1, ...) */
890 void shader_glsl_map2gl(SHADER_OPCODE_ARG
* arg
) {
892 CONST SHADER_OPCODE
* curOpcode
= arg
->opcode
;
893 SHADER_BUFFER
* buffer
= arg
->buffer
;
895 char dst_str
[100], src_str
[100];
896 char dst_reg
[50], src_reg
[50];
897 char dst_mask
[6], src_mask
[6];
900 shader_glsl_add_param(arg
, arg
->dst
, 0, FALSE
, dst_reg
, dst_mask
, dst_str
);
902 shader_glsl_add_dst(arg
->dst
, dst_reg
, dst_mask
, tmpLine
);
904 /* Determine the GLSL function to use based on the opcode */
905 /* TODO: Possibly make this a table for faster lookups */
906 switch (curOpcode
->opcode
) {
907 case D3DSIO_MIN
: strcat(tmpLine
, "min"); break;
908 case D3DSIO_MAX
: strcat(tmpLine
, "max"); break;
909 case D3DSIO_RSQ
: strcat(tmpLine
, "inversesqrt"); break;
910 case D3DSIO_ABS
: strcat(tmpLine
, "abs"); break;
911 case D3DSIO_FRC
: strcat(tmpLine
, "fract"); break;
912 case D3DSIO_POW
: strcat(tmpLine
, "pow"); break;
913 case D3DSIO_CRS
: strcat(tmpLine
, "cross"); break;
914 case D3DSIO_NRM
: strcat(tmpLine
, "normalize"); break;
916 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 RCP (reciprocal or inverse) opcode in GLSL (dst = 1 / src) */
946 void shader_glsl_rcp(SHADER_OPCODE_ARG
* arg
) {
949 char dst_str
[100], src_str
[100];
950 char dst_reg
[50], src_reg
[50];
951 char dst_mask
[6], src_mask
[6];
953 shader_glsl_add_param(arg
, arg
->dst
, 0, FALSE
, dst_reg
, dst_mask
, dst_str
);
954 shader_glsl_add_param(arg
, arg
->src
[0], arg
->src_addr
[0], TRUE
, src_reg
, src_mask
, src_str
);
955 shader_glsl_add_dst(arg
->dst
, dst_reg
, dst_mask
, tmpLine
);
956 strcat(tmpLine
, "1.0 / ");
957 shader_addline(arg
->buffer
, "%s%s)%s;\n", tmpLine
, src_str
, dst_mask
);
960 /** Process signed comparison opcodes in GLSL. */
961 void shader_glsl_compare(SHADER_OPCODE_ARG
* arg
) {
964 char dst_str
[100], src0_str
[100], src1_str
[100];
965 char dst_reg
[50], src0_reg
[50], src1_reg
[50];
966 char dst_mask
[6], src0_mask
[6], src1_mask
[6];
968 shader_glsl_add_param(arg
, arg
->dst
, 0, FALSE
, dst_reg
, dst_mask
, dst_str
);
969 shader_glsl_add_param(arg
, arg
->src
[0], arg
->src_addr
[0], TRUE
, src0_reg
, src0_mask
, src0_str
);
970 shader_glsl_add_dst(arg
->dst
, dst_reg
, dst_mask
, tmpLine
);
972 /* If we are comparing vectors and not scalars, we should process this through map2gl using the GLSL functions. */
973 if (strlen(src0_mask
) != 2) {
974 shader_glsl_map2gl(arg
);
978 shader_glsl_add_param(arg
, arg
->src
[1], arg
->src_addr
[1], TRUE
, src1_reg
, src1_mask
, src1_str
);
980 switch (arg
->opcode
->opcode
) {
981 case D3DSIO_SLT
: strcpy(compareStr
, "<"); break;
982 case D3DSIO_SGE
: strcpy(compareStr
, ">="); break;
984 FIXME("Can't handle opcode %s\n", arg
->opcode
->name
);
986 shader_addline(arg
->buffer
, "%s(float(%s) %s float(%s)) ? 1.0 : 0.0)%s;\n",
987 tmpLine
, src0_str
, compareStr
, src1_str
, dst_mask
);
991 /** Process CMP instruction in GLSL (dst = src0.x > 0.0 ? src1.x : src2.x), per channel */
992 void shader_glsl_cmp(SHADER_OPCODE_ARG
* arg
) {
995 char dst_str
[100], src0_str
[100], src1_str
[100], src2_str
[100];
996 char dst_reg
[50], src0_reg
[50], src1_reg
[50], src2_reg
[50];
997 char dst_mask
[6], src0_mask
[6], src1_mask
[6], src2_mask
[6];
999 shader_glsl_add_param(arg
, arg
->dst
, 0, FALSE
, dst_reg
, dst_mask
, dst_str
);
1000 shader_glsl_add_param(arg
, arg
->src
[0], arg
->src_addr
[0], TRUE
, src0_reg
, src0_mask
, src0_str
);
1001 shader_glsl_add_param(arg
, arg
->src
[1], arg
->src_addr
[1], TRUE
, src1_reg
, src1_mask
, src1_str
);
1002 shader_glsl_add_param(arg
, arg
->src
[2], arg
->src_addr
[2], TRUE
, src2_reg
, src2_mask
, src2_str
);
1004 shader_glsl_add_dst(arg
->dst
, dst_reg
, dst_mask
, tmpLine
);
1005 shader_addline(arg
->buffer
, "%smix(vec4(%s), vec4(%s), vec4(lessThan(vec4(%s), vec4(0.0)))))%s;\n",
1006 tmpLine
, src1_str
, src2_str
, src0_str
, dst_mask
);
1009 /** Process the CND opcode in GLSL (dst = (src0 < 0.5) ? src1 : src2) */
1010 void shader_glsl_cnd(SHADER_OPCODE_ARG
* arg
) {
1013 char dst_str
[100], src0_str
[100], src1_str
[100], src2_str
[100];
1014 char dst_reg
[50], src0_reg
[50], src1_reg
[50], src2_reg
[50];
1015 char dst_mask
[6], src0_mask
[6], src1_mask
[6], src2_mask
[6];
1017 shader_glsl_add_param(arg
, arg
->dst
, 0, FALSE
, dst_reg
, dst_mask
, dst_str
);
1018 shader_glsl_add_param(arg
, arg
->src
[0], arg
->src_addr
[0], TRUE
, src0_reg
, src0_mask
, src0_str
);
1019 shader_glsl_add_param(arg
, arg
->src
[1], arg
->src_addr
[1], TRUE
, src1_reg
, src1_mask
, src1_str
);
1020 shader_glsl_add_param(arg
, arg
->src
[2], arg
->src_addr
[2], TRUE
, src2_reg
, src2_mask
, src2_str
);
1021 shader_glsl_add_dst(arg
->dst
, dst_reg
, dst_mask
, tmpLine
);
1022 shader_addline(arg
->buffer
, "%s(%s < 0.5) ? %s : %s)%s;\n",
1023 tmpLine
, src0_str
, src1_str
, src2_str
, dst_mask
);
1026 /** GLSL code generation for D3DSIO_MAD: Multiply the first 2 opcodes, then add the last */
1027 void shader_glsl_mad(SHADER_OPCODE_ARG
* arg
) {
1030 char dst_str
[100], src0_str
[100], src1_str
[100], src2_str
[100];
1031 char dst_reg
[50], src0_reg
[50], src1_reg
[50], src2_reg
[50];
1032 char dst_mask
[6], src0_mask
[6], src1_mask
[6], src2_mask
[6];
1034 shader_glsl_add_param(arg
, arg
->dst
, 0, FALSE
, dst_reg
, dst_mask
, dst_str
);
1035 shader_glsl_add_param(arg
, arg
->src
[0], arg
->src_addr
[0], TRUE
, src0_reg
, src0_mask
, src0_str
);
1036 shader_glsl_add_param(arg
, arg
->src
[1], arg
->src_addr
[1], TRUE
, src1_reg
, src1_mask
, src1_str
);
1037 shader_glsl_add_param(arg
, arg
->src
[2], arg
->src_addr
[2], TRUE
, src2_reg
, src2_mask
, src2_str
);
1038 shader_glsl_add_dst(arg
->dst
, dst_reg
, dst_mask
, tmpLine
);
1040 shader_addline(arg
->buffer
, "%s(vec4(%s) * vec4(%s)) + vec4(%s))%s;\n",
1041 tmpLine
, src0_str
, src1_str
, src2_str
, dst_mask
);
1044 /** Handles transforming all D3DSIO_M?x? opcodes for
1045 Vertex shaders to GLSL codes */
1046 void shader_glsl_mnxn(SHADER_OPCODE_ARG
* arg
) {
1048 int nComponents
= 0;
1049 SHADER_OPCODE_ARG tmpArg
;
1051 memset(&tmpArg
, 0, sizeof(SHADER_OPCODE_ARG
));
1053 /* Set constants for the temporary argument */
1054 tmpArg
.shader
= arg
->shader
;
1055 tmpArg
.buffer
= arg
->buffer
;
1056 tmpArg
.src
[0] = arg
->src
[0];
1057 tmpArg
.src_addr
[0] = arg
->src_addr
[0];
1058 tmpArg
.src_addr
[1] = arg
->src_addr
[1];
1059 tmpArg
.reg_maps
= arg
->reg_maps
;
1061 switch(arg
->opcode
->opcode
) {
1064 tmpArg
.opcode
= &IWineD3DVertexShaderImpl_shader_ins
[D3DSIO_DP4
];
1068 tmpArg
.opcode
= &IWineD3DVertexShaderImpl_shader_ins
[D3DSIO_DP4
];
1072 tmpArg
.opcode
= &IWineD3DVertexShaderImpl_shader_ins
[D3DSIO_DP3
];
1076 tmpArg
.opcode
= &IWineD3DVertexShaderImpl_shader_ins
[D3DSIO_DP3
];
1080 tmpArg
.opcode
= &IWineD3DVertexShaderImpl_shader_ins
[D3DSIO_DP3
];
1086 for (i
= 0; i
< nComponents
; i
++) {
1087 tmpArg
.dst
= ((arg
->dst
) & ~D3DSP_WRITEMASK_ALL
)|(D3DSP_WRITEMASK_0
<<i
);
1088 tmpArg
.src
[1] = arg
->src
[1]+i
;
1089 shader_glsl_dot(&tmpArg
);
1094 The LRP instruction performs a component-wise linear interpolation
1095 between the second and third operands using the first operand as the
1096 blend factor. Equation: (dst = src2 * (src1 - src0) + src0)
1098 void shader_glsl_lrp(SHADER_OPCODE_ARG
* arg
) {
1101 char dst_str
[100], src0_str
[100], src1_str
[100], src2_str
[100];
1102 char dst_reg
[50], src0_reg
[50], src1_reg
[50], src2_reg
[50];
1103 char dst_mask
[6], src0_mask
[6], src1_mask
[6], src2_mask
[6];
1105 shader_glsl_add_param(arg
, arg
->dst
, 0, FALSE
, dst_reg
, dst_mask
, dst_str
);
1106 shader_glsl_add_param(arg
, arg
->src
[0], arg
->src_addr
[0], TRUE
, src0_reg
, src0_mask
, src0_str
);
1107 shader_glsl_add_param(arg
, arg
->src
[1], arg
->src_addr
[1], TRUE
, src1_reg
, src1_mask
, src1_str
);
1108 shader_glsl_add_param(arg
, arg
->src
[2], arg
->src_addr
[2], TRUE
, src2_reg
, src2_mask
, src2_str
);
1110 shader_glsl_add_dst(arg
->dst
, dst_reg
, dst_mask
, tmpLine
);
1112 shader_addline(arg
->buffer
, "%s%s + %s * (%s - %s))%s;\n",
1113 tmpLine
, src2_str
, src0_str
, src1_str
, src2_str
, dst_mask
);
1116 /** Process the D3DSIO_LIT instruction in GLSL:
1117 * dst.x = dst.w = 1.0
1118 * dst.y = (src0.x > 0) ? src0.x
1119 * dst.z = (src0.x > 0) ? ((src0.y > 0) ? pow(src0.y, src.w) : 0) : 0
1120 * where src.w is clamped at +- 128
1122 void shader_glsl_lit(SHADER_OPCODE_ARG
* arg
) {
1124 char dst_str
[100], src0_str
[100];
1125 char dst_reg
[50], src0_reg
[50];
1126 char dst_mask
[6], src0_mask
[6];
1128 shader_glsl_add_param(arg
, arg
->dst
, 0, FALSE
, dst_reg
, dst_mask
, dst_str
);
1129 shader_glsl_add_param(arg
, arg
->src
[0], arg
->src_addr
[0], TRUE
, src0_reg
, src0_mask
, src0_str
);
1131 shader_addline(arg
->buffer
,
1132 "%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",
1133 dst_str
, src0_reg
, src0_reg
, src0_reg
, src0_reg
, src0_reg
, src0_reg
, dst_mask
);
1136 /** Process the D3DSIO_DST instruction in GLSL:
1138 * dst.y = src0.x * src0.y
1142 void shader_glsl_dst(SHADER_OPCODE_ARG
* arg
) {
1144 char dst_str
[100], src0_str
[100], src1_str
[100];
1145 char dst_reg
[50], src0_reg
[50], src1_reg
[50];
1146 char dst_mask
[6], src0_mask
[6], src1_mask
[6];
1148 shader_glsl_add_param(arg
, arg
->dst
, 0, FALSE
, dst_reg
, dst_mask
, dst_str
);
1149 shader_glsl_add_param(arg
, arg
->src
[0], arg
->src_addr
[0], TRUE
, src0_reg
, src0_mask
, src0_str
);
1150 shader_glsl_add_param(arg
, arg
->src
[1], arg
->src_addr
[1], TRUE
, src1_reg
, src1_mask
, src1_str
);
1152 shader_addline(arg
->buffer
, "%s = vec4(1.0, %s.x * %s.y, %s.z, %s.w)%s;\n",
1153 dst_str
, src0_reg
, src1_reg
, src0_reg
, src1_reg
, dst_mask
);
1156 /** Process the D3DSIO_SINCOS instruction in GLSL:
1157 * VS 2.0 requires that specific cosine and sine constants be passed to this instruction so the hardware
1158 * can handle it. But, these functions are built-in for GLSL, so we can just ignore the last 2 params.
1160 * dst.x = cos(src0.?)
1161 * dst.y = sin(src0.?)
1165 void shader_glsl_sincos(SHADER_OPCODE_ARG
* arg
) {
1167 char dst_str
[100], src0_str
[100];
1168 char dst_reg
[50], src0_reg
[50];
1169 char dst_mask
[6], src0_mask
[6];
1171 shader_glsl_add_param(arg
, arg
->dst
, 0, FALSE
, dst_reg
, dst_mask
, dst_str
);
1172 shader_glsl_add_param(arg
, arg
->src
[0], arg
->src_addr
[0], TRUE
, src0_reg
, src0_mask
, src0_str
);
1174 shader_addline(arg
->buffer
, "%s = vec4(cos(%s), sin(%s), %s.z, %s.w)%s;\n",
1175 dst_str
, src0_str
, src0_str
, dst_reg
, dst_reg
, dst_mask
);
1178 /** Process the D3DSIO_LOOP instruction in GLSL:
1179 * Start a for() loop where src0.y is the initial value of aL,
1180 * increment aL by src0.z for a total of src0.x iterations.
1181 * Need to use a temporary variable for this operation.
1183 void shader_glsl_loop(SHADER_OPCODE_ARG
* arg
) {
1189 shader_glsl_add_param(arg
, arg
->src
[1], arg
->src_addr
[1], TRUE
, src1_reg
, src1_mask
, src1_str
);
1191 shader_addline(arg
->buffer
, "for (tmpInt = 0, aL = %s.y; tmpInt < %s.x; tmpInt++, aL += %s.z) {\n",
1192 src1_reg
, src1_reg
, src1_reg
);
1195 void shader_glsl_end(SHADER_OPCODE_ARG
* arg
) {
1196 shader_addline(arg
->buffer
, "}\n");
1199 void shader_glsl_rep(SHADER_OPCODE_ARG
* arg
) {
1205 shader_glsl_add_param(arg
, arg
->src
[0], arg
->src_addr
[0], TRUE
, src0_reg
, src0_mask
, src0_str
);
1206 shader_addline(arg
->buffer
, "for (tmpInt = 0; tmpInt < %s.x; tmpInt++) {\n", src0_reg
);
1209 void shader_glsl_if(SHADER_OPCODE_ARG
* arg
) {
1215 shader_glsl_add_param(arg
, arg
->src
[0], arg
->src_addr
[0], TRUE
, src0_reg
, src0_mask
, src0_str
);
1216 shader_addline(arg
->buffer
, "if (%s) {\n", src0_str
);
1219 void shader_glsl_ifc(SHADER_OPCODE_ARG
* arg
) {
1221 char src0_str
[100], src1_str
[100];
1222 char src0_reg
[50], src1_reg
[50];
1223 char src0_mask
[6], src1_mask
[6];
1225 shader_glsl_add_param(arg
, arg
->src
[0], arg
->src_addr
[0], TRUE
, src0_reg
, src0_mask
, src0_str
);
1226 shader_glsl_add_param(arg
, arg
->src
[1], arg
->src_addr
[1], TRUE
, src1_reg
, src1_mask
, src1_str
);
1228 shader_addline(arg
->buffer
, "if (%s %s %s) {\n",
1229 src0_str
, shader_get_comp_op(arg
->opcode_token
), src1_str
);
1232 void shader_glsl_else(SHADER_OPCODE_ARG
* arg
) {
1233 shader_addline(arg
->buffer
, "} else {\n");
1236 void shader_glsl_break(SHADER_OPCODE_ARG
* arg
) {
1237 shader_addline(arg
->buffer
, "break;\n");
1240 void shader_glsl_breakc(SHADER_OPCODE_ARG
* arg
) {
1242 char src0_str
[100], src1_str
[100];
1243 char src0_reg
[50], src1_reg
[50];
1244 char src0_mask
[6], src1_mask
[6];
1246 shader_glsl_add_param(arg
, arg
->src
[0], arg
->src_addr
[0], TRUE
, src0_reg
, src0_mask
, src0_str
);
1247 shader_glsl_add_param(arg
, arg
->src
[1], arg
->src_addr
[1], TRUE
, src1_reg
, src1_mask
, src1_str
);
1249 shader_addline(arg
->buffer
, "if (%s %s %s) break;\n",
1250 src0_str
, shader_get_comp_op(arg
->opcode_token
), src1_str
);
1253 void shader_glsl_label(SHADER_OPCODE_ARG
* arg
) {
1255 DWORD snum
= (arg
->src
[0]) & D3DSP_REGNUM_MASK
;
1256 shader_addline(arg
->buffer
, "}\n");
1257 shader_addline(arg
->buffer
, "void subroutine%lu () {\n", snum
);
1260 void shader_glsl_call(SHADER_OPCODE_ARG
* arg
) {
1261 DWORD snum
= (arg
->src
[0]) & D3DSP_REGNUM_MASK
;
1262 shader_addline(arg
->buffer
, "subroutine%lu();\n", snum
);
1265 void shader_glsl_callnz(SHADER_OPCODE_ARG
* arg
) {
1271 DWORD snum
= (arg
->src
[0]) & D3DSP_REGNUM_MASK
;
1272 shader_glsl_add_param(arg
, arg
->src
[1], arg
->src_addr
[1], TRUE
, src1_reg
, src1_mask
, src1_str
);
1273 shader_addline(arg
->buffer
, "if (%s) subroutine%lu();\n", src1_str
, snum
);
1276 /*********************************************
1277 * Pixel Shader Specific Code begins here
1278 ********************************************/
1279 void pshader_glsl_tex(SHADER_OPCODE_ARG
* arg
) {
1281 /* FIXME: Make this work for more than just 2D textures */
1283 IWineD3DPixelShaderImpl
* This
= (IWineD3DPixelShaderImpl
*) arg
->shader
;
1284 SHADER_BUFFER
* buffer
= arg
->buffer
;
1285 DWORD hex_version
= This
->baseShader
.hex_version
;
1287 char dst_str
[100], dst_reg
[50], dst_mask
[6];
1288 char coord_str
[100], coord_reg
[50], coord_mask
[6];
1289 char sampler_str
[100], sampler_reg
[50], sampler_mask
[6];
1290 DWORD reg_dest_code
= arg
->dst
& D3DSP_REGNUM_MASK
;
1291 DWORD sampler_code
, sampler_type
;
1293 /* All versions have a destination register */
1294 shader_glsl_add_param(arg
, arg
->dst
, 0, FALSE
, dst_reg
, dst_mask
, dst_str
);
1296 /* 1.0-1.3: Use destination register as coordinate source.
1297 1.4+: Use provided coordinate source register. */
1298 if (hex_version
< D3DPS_VERSION(1,4))
1299 strcpy(coord_reg
, dst_reg
);
1301 shader_glsl_add_param(arg
, arg
->src
[0], arg
->src_addr
[0], TRUE
, coord_reg
, coord_mask
, coord_str
);
1303 /* 1.0-1.4: Use destination register as coordinate source.
1304 * 2.0+: Use provided coordinate source register. */
1305 if (hex_version
< D3DPS_VERSION(2,0)) {
1306 sprintf(sampler_str
, "Psampler%lu", reg_dest_code
);
1307 sampler_code
= reg_dest_code
;
1310 shader_glsl_add_param(arg
, arg
->src
[1], arg
->src_addr
[1], TRUE
, sampler_reg
, sampler_mask
, sampler_str
);
1311 sampler_code
= arg
->src
[1] & D3DSP_REGNUM_MASK
;
1314 sampler_type
= arg
->reg_maps
->samplers
[sampler_code
] & D3DSP_TEXTURETYPE_MASK
;
1315 switch(sampler_type
) {
1318 shader_addline(buffer
, "%s = texture2D(%s, %s.st);\n", dst_str
, sampler_str
, coord_reg
);
1321 shader_addline(buffer
, "%s = textureCube(%s, %s.stp);\n", dst_str
, sampler_str
, coord_reg
);
1324 shader_addline(buffer
, "%s = texture3D(%s, %s.stp);\n", dst_str
, sampler_str
, coord_reg
);
1327 shader_addline(buffer
, "%s = unrecognized_stype(%s, %s.stp);\n", dst_str
, sampler_str
, coord_reg
);
1328 FIXME("Unrecognized sampler type: %#lx;\n", sampler_type
);
1333 void pshader_glsl_texcoord(SHADER_OPCODE_ARG
* arg
) {
1335 /* FIXME: Make this work for more than just 2D textures */
1337 IWineD3DPixelShaderImpl
* This
= (IWineD3DPixelShaderImpl
*) arg
->shader
;
1338 SHADER_BUFFER
* buffer
= arg
->buffer
;
1339 DWORD hex_version
= This
->baseShader
.hex_version
;
1346 shader_glsl_add_param(arg
, arg
->dst
, 0, FALSE
, tmpReg
, tmpMask
, tmpStr
);
1348 if (hex_version
!= D3DPS_VERSION(1,4)) {
1349 DWORD reg
= arg
->dst
& D3DSP_REGNUM_MASK
;
1350 shader_addline(buffer
, "%s = clamp(gl_TexCoord[%lu], 0.0, 1.0);\n", tmpReg
, reg
);
1352 DWORD reg2
= arg
->src
[0] & D3DSP_REGNUM_MASK
;
1353 shader_addline(buffer
, "%s = gl_TexCoord[%lu]%s;\n", tmpStr
, reg2
, tmpMask
);
1357 void pshader_glsl_texm3x2pad(SHADER_OPCODE_ARG
* arg
) {
1359 DWORD reg
= arg
->dst
& D3DSP_REGNUM_MASK
;
1360 SHADER_BUFFER
* buffer
= arg
->buffer
;
1365 shader_glsl_add_param(arg
, arg
->src
[0], arg
->src_addr
[0], TRUE
, src0_name
, src0_mask
, src0_str
);
1366 shader_addline(buffer
, "tmp0.x = dot(vec3(T%lu), vec3(%s));\n", reg
, src0_name
, src0_str
);
1369 /** Process the D3DSIO_TEXM3X3PAD instruction in GLSL
1370 * Calculate the 1st or 2nd row of a 3-row matrix multiplication. */
1371 void pshader_glsl_texm3x3pad(SHADER_OPCODE_ARG
* arg
) {
1373 IWineD3DPixelShaderImpl
* shader
= (IWineD3DPixelShaderImpl
*) arg
->shader
;
1374 DWORD reg
= arg
->dst
& D3DSP_REGNUM_MASK
;
1375 SHADER_BUFFER
* buffer
= arg
->buffer
;
1376 SHADER_PARSE_STATE
* current_state
= &shader
->baseShader
.parse_state
;
1381 shader_glsl_add_param(arg
, arg
->src
[0], arg
->src_addr
[0], TRUE
, src0_name
, src0_mask
, src0_str
);
1382 shader_addline(buffer
, "tmp0.%c = dot(vec3(T%lu), vec3(%s));\n", 'x' + current_state
->current_row
, reg
, src0_str
);
1383 current_state
->texcoord_w
[current_state
->current_row
++] = reg
;
1386 void pshader_glsl_texm3x2tex(SHADER_OPCODE_ARG
* arg
) {
1388 /* FIXME: Make this work for more than just 2D textures */
1390 DWORD reg
= arg
->dst
& D3DSP_REGNUM_MASK
;
1391 SHADER_BUFFER
* buffer
= arg
->buffer
;
1396 shader_glsl_add_param(arg
, arg
->src
[0], arg
->src_addr
[0], TRUE
, src0_name
, src0_mask
, src0_str
);
1397 shader_addline(buffer
, "tmp0.y = dot(vec3(T%lu), vec3(%s));\n", reg
, src0_str
);
1398 shader_addline(buffer
, "T%lu = texture2D(Psampler%lu, tmp0.st);\n", reg
, reg
);
1401 /** Process the D3DSIO_TEXM3X3VSPEC instruction in GLSL
1402 * Peform the final texture lookup based on the previous 2 3x3 matrix multiplies */
1403 void pshader_glsl_texm3x3vspec(SHADER_OPCODE_ARG
* arg
) {
1405 IWineD3DPixelShaderImpl
* shader
= (IWineD3DPixelShaderImpl
*) arg
->shader
;
1406 DWORD reg
= arg
->dst
& D3DSP_REGNUM_MASK
;
1407 SHADER_BUFFER
* buffer
= arg
->buffer
;
1408 SHADER_PARSE_STATE
* current_state
= &shader
->baseShader
.parse_state
;
1409 char src0_str
[100], src0_name
[50], src0_mask
[6];
1411 shader_glsl_add_param(arg
, arg
->src
[0], arg
->src_addr
[0], TRUE
, src0_name
, src0_mask
, src0_str
);
1413 /* Perform the last matrix multiply operation */
1414 shader_addline(buffer
, "tmp0.z = dot(vec3(T%lu), vec3(%s));\n", reg
, src0_str
);
1416 /* Construct the eye-ray vector from w coordinates */
1417 shader_addline(buffer
, "tmp1.x = gl_TexCoord[%lu].w;\n", current_state
->texcoord_w
[0]);
1418 shader_addline(buffer
, "tmp1.y = gl_TexCoord[%lu].w;\n", current_state
->texcoord_w
[1]);
1419 shader_addline(buffer
, "tmp1.z = gl_TexCoord[%lu].w;\n", reg
);
1421 /* Calculate reflection vector (Assume normal is normalized): RF = 2*(N.E)*N -E */
1422 shader_addline(buffer
, "tmp0.x = dot(vec3(tmp0), vec3(tmp1));\n");
1423 shader_addline(buffer
, "tmp0 = tmp0.w * tmp0;\n");
1424 shader_addline(buffer
, "tmp0 = (2.0 * tmp0) - tmp1;\n");
1427 * We don't really know if a Cube or a Volume texture is being sampled, but since Cube textures
1428 * are used more commonly, we'll default to that.
1429 * We probably need to push back the pixel shader generation code until drawPrimitive() for
1430 * shader versions < 2.0, since that's the only time we can guarantee that we're sampling
1431 * the correct type of texture because we can lookup what textures are bound at that point.
1433 shader_addline(buffer
, "T%lu = textureCube(Psampler%lu, tmp0.xyz);\n", reg
, reg
);
1434 current_state
->current_row
= 0;
1437 /** Process the D3DSIO_TEXBEM instruction in GLSL.
1438 * Apply a fake bump map transform.
1439 * FIXME: Should apply the BUMPMAPENV matrix. For now, just sample the texture */
1440 void pshader_glsl_texbem(SHADER_OPCODE_ARG
* arg
) {
1442 DWORD reg1
= arg
->dst
& D3DSP_REGNUM_MASK
;
1443 DWORD reg2
= arg
->src
[0] & D3DSP_REGNUM_MASK
;
1445 FIXME("Not applying the BUMPMAPENV matrix for pixel shader instruction texbem.\n");
1446 shader_addline(arg
->buffer
, "T%lu = texture2D(Psampler%lu, gl_TexCoord[%lu].xy + T%lu.xy);\n",
1447 reg1
, reg1
, reg1
, reg2
);
1450 /** Process the D3DSIO_TEXKILL instruction in GLSL.
1451 * If any of the first 3 components are < 0, discard this pixel */
1452 void pshader_glsl_texkill(SHADER_OPCODE_ARG
* arg
) {
1454 char dst_str
[100], dst_name
[50], dst_mask
[6];
1456 shader_glsl_add_param(arg
, arg
->dst
, 0, FALSE
, dst_name
, dst_mask
, dst_str
);
1457 shader_addline(arg
->buffer
, "if (any(lessThan(%s.xyz, vec3(0.0)))) discard;\n", dst_name
);
1460 /** Process the D3DSIO_DP2ADD instruction in GLSL.
1461 * dst = dot2(src0, src1) + src2 */
1462 void pshader_glsl_dp2add(SHADER_OPCODE_ARG
* arg
) {
1465 char dst_str
[100], src0_str
[100], src1_str
[100], src2_str
[100];
1466 char dst_reg
[50], src0_reg
[50], src1_reg
[50], src2_reg
[50];
1467 char dst_mask
[6], src0_mask
[6], src1_mask
[6], src2_mask
[6];
1469 shader_glsl_add_param(arg
, arg
->dst
, 0, FALSE
, dst_reg
, dst_mask
, dst_str
);
1470 shader_glsl_add_param(arg
, arg
->src
[0], arg
->src_addr
[0], TRUE
, src0_reg
, src0_mask
, src0_str
);
1471 shader_glsl_add_param(arg
, arg
->src
[1], arg
->src_addr
[1], TRUE
, src1_reg
, src1_mask
, src1_str
);
1472 shader_glsl_add_param(arg
, arg
->src
[2], arg
->src_addr
[2], TRUE
, src2_reg
, src2_mask
, src2_str
);
1473 shader_glsl_add_dst(arg
->dst
, dst_reg
, dst_mask
, tmpLine
);
1474 shader_addline(arg
->buffer
, "%sdot(vec2(%s), vec2(%s)) + %s)%s;\n",
1475 tmpLine
, src0_str
, src1_str
, src2_str
, dst_mask
);
1478 void pshader_glsl_input_pack(
1479 SHADER_BUFFER
* buffer
,
1480 semantic
* semantics_in
) {
1484 for (i
= 0; i
< MAX_REG_INPUT
; i
++) {
1486 DWORD usage_token
= semantics_in
[i
].usage
;
1487 DWORD register_token
= semantics_in
[i
].reg
;
1488 DWORD usage
, usage_idx
;
1492 if (!usage_token
) continue;
1493 usage
= (usage_token
& D3DSP_DCL_USAGE_MASK
) >> D3DSP_DCL_USAGE_SHIFT
;
1494 usage_idx
= (usage_token
& D3DSP_DCL_USAGEINDEX_MASK
) >> D3DSP_DCL_USAGEINDEX_SHIFT
;
1495 shader_glsl_get_output_register_swizzle(register_token
, reg_mask
);
1499 case D3DDECLUSAGE_COLOR
:
1501 shader_addline(buffer
, "IN%lu%s = vec4(gl_Color)%s;\n",
1502 i
, reg_mask
, reg_mask
);
1503 else if (usage_idx
== 1)
1504 shader_addline(buffer
, "IN%lu%s = vec4(gl_SecondaryColor)%s;\n",
1505 i
, reg_mask
, reg_mask
);
1507 shader_addline(buffer
, "IN%lu%s = vec4(unsupported_color_input)%s;\n",
1508 i
, reg_mask
, reg_mask
);
1511 case D3DDECLUSAGE_TEXCOORD
:
1512 shader_addline(buffer
, "IN%lu%s = vec4(gl_TexCoord[%lu])%s;\n",
1513 i
, reg_mask
, usage_idx
, reg_mask
);
1516 case D3DDECLUSAGE_FOG
:
1517 shader_addline(buffer
, "IN%lu%s = vec4(gl_FogFragCoord)%s;\n",
1518 i
, reg_mask
, reg_mask
);
1522 shader_addline(buffer
, "IN%lu%s = vec4(unsupported_input)%s;\n",
1523 i
, reg_mask
, reg_mask
);
1528 /*********************************************
1529 * Vertex Shader Specific Code begins here
1530 ********************************************/
1532 void vshader_glsl_output_unpack(
1533 SHADER_BUFFER
* buffer
,
1534 semantic
* semantics_out
) {
1538 for (i
= 0; i
< MAX_REG_OUTPUT
; i
++) {
1540 DWORD usage_token
= semantics_out
[i
].usage
;
1541 DWORD register_token
= semantics_out
[i
].reg
;
1542 DWORD usage
, usage_idx
;
1546 if (!usage_token
) continue;
1548 usage
= (usage_token
& D3DSP_DCL_USAGE_MASK
) >> D3DSP_DCL_USAGE_SHIFT
;
1549 usage_idx
= (usage_token
& D3DSP_DCL_USAGEINDEX_MASK
) >> D3DSP_DCL_USAGEINDEX_SHIFT
;
1550 shader_glsl_get_output_register_swizzle(register_token
, reg_mask
);
1554 case D3DDECLUSAGE_COLOR
:
1556 shader_addline(buffer
, "gl_FrontColor%s = OUT%lu%s;\n", reg_mask
, i
, reg_mask
);
1557 else if (usage_idx
== 1)
1558 shader_addline(buffer
, "gl_FrontSecondaryColor%s = OUT%lu%s;\n", reg_mask
, i
, reg_mask
);
1560 shader_addline(buffer
, "unsupported_color_output%s = OUT%lu%s;\n", reg_mask
, i
, reg_mask
);
1563 case D3DDECLUSAGE_POSITION
:
1564 shader_addline(buffer
, "gl_Position%s = OUT%lu%s;\n", reg_mask
, i
, reg_mask
);
1567 case D3DDECLUSAGE_TEXCOORD
:
1568 shader_addline(buffer
, "gl_TexCoord[%lu]%s = OUT%lu%s;\n",
1569 usage_idx
, reg_mask
, i
, reg_mask
);
1572 case WINED3DSHADERDECLUSAGE_PSIZE
:
1573 shader_addline(buffer
, "gl_PointSize = OUT%lu.x;\n", i
);
1576 case WINED3DSHADERDECLUSAGE_FOG
:
1577 shader_addline(buffer
, "gl_FogFragCoord%s = OUT%lu%s;\n", reg_mask
, i
, reg_mask
);
1581 shader_addline(buffer
, "unsupported_output%s = OUT%lu%s;\n", reg_mask
, i
, reg_mask
);