2 * shaders implementation
4 * Copyright 2002-2003 Jason Edmeades
5 * Copyright 2002-2003 Raphael Junqueira
6 * Copyright 2004 Christian Costa
7 * Copyright 2005 Oliver Stieber
8 * Copyright 2006 Ivan Gyurdiev
10 * This library is free software; you can redistribute it and/or
11 * modify it under the terms of the GNU Lesser General Public
12 * License as published by the Free Software Foundation; either
13 * version 2.1 of the License, or (at your option) any later version.
15 * This library is distributed in the hope that it will be useful,
16 * but WITHOUT ANY WARRANTY; without even the implied warranty of
17 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
18 * Lesser General Public License for more details.
20 * You should have received a copy of the GNU Lesser General Public
21 * License along with this library; if not, write to the Free Software
22 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
30 #include "wined3d_private.h"
32 WINE_DEFAULT_DEBUG_CHANNEL(d3d_shader
);
34 #define GLINFO_LOCATION ((IWineD3DImpl *)(((IWineD3DDeviceImpl *)This->baseShader.device)->wineD3D))->gl_info
36 /* Shader debugging - Change the following line to enable debugging of software
38 #if 0 /* Musxt not be 1 in cvs version */
39 # define VSTRACE(A) TRACE A
40 # define TRACE_VSVECTOR(name) TRACE( #name "=(%f, %f, %f, %f)\n", name.x, name.y, name.z, name.w)
43 # define TRACE_VSVECTOR(name)
47 * DirectX9 SDK download
48 * http://msdn.microsoft.com/library/default.asp?url=/downloads/list/directx.asp
51 * http://msdn.microsoft.com/library/default.asp?url=/library/en-us/dndrive/html/directx07162002.asp
53 * Using Vertex Shaders
54 * http://msdn.microsoft.com/library/default.asp?url=/library/en-us/dndrive/html/directx02192001.asp
57 * http://msdn.microsoft.com/library/default.asp?url=/library/en-us/directx9_c/directx/graphics/whatsnew.asp
60 * http://msdn.microsoft.com/library/default.asp?url=/library/en-us/directx9_c/directx/graphics/reference/Shaders/VertexShader2_0/VertexShader2_0.asp
61 * http://msdn.microsoft.com/library/default.asp?url=/library/en-us/directx9_c/directx/graphics/reference/Shaders/VertexShader2_0/Instructions/Instructions.asp
62 * http://msdn.microsoft.com/library/default.asp?url=/library/en-us/directx9_c/directx/graphics/programmingguide/GettingStarted/VertexDeclaration/VertexDeclaration.asp
63 * http://msdn.microsoft.com/library/default.asp?url=/library/en-us/directx9_c/directx/graphics/reference/Shaders/VertexShader3_0/VertexShader3_0.asp
66 * http://msdn.microsoft.com/library/default.asp?url=/library/en-us/directx9_c/directx/graphics/programmingguide/advancedtopics/VertexPipe/matrixstack/matrixstack.asp
69 * http://msdn.microsoft.com/library/en-us/directx9_c/directx/graphics/programmingguide/GettingStarted/VertexFormats/vformats.asp
71 * NVIDIA: DX8 Vertex Shader to NV Vertex Program
72 * http://developer.nvidia.com/view.asp?IO=vstovp
74 * NVIDIA: Memory Management with VAR
75 * http://developer.nvidia.com/view.asp?IO=var_memory_management
78 /* TODO: Vertex and Pixel shaders are almost identicle, the only exception being the way that some of the data is looked up or the availablity of some of the data i.e. some instructions are only valid for pshaders and some for vshaders
79 because of this the bulk of the software pipeline can be shared between pixel and vertex shaders... and it wouldn't supprise me if the programes can be cross compiled using a large body body shared code */
81 #define GLNAME_REQUIRE_GLSL ((const char *)1)
83 CONST SHADER_OPCODE IWineD3DVertexShaderImpl_shader_ins
[] = {
84 /* This table is not order or position dependent. */
87 {WINED3DSIO_NOP
, "nop", "NOP", 0, 0, vshader_hw_map2gl
, NULL
, 0, 0},
88 {WINED3DSIO_MOV
, "mov", "MOV", 1, 2, vshader_hw_map2gl
, shader_glsl_mov
, 0, 0},
89 {WINED3DSIO_MOVA
, "mova", NULL
, 1, 2, vshader_hw_map2gl
, shader_glsl_mov
, WINED3DVS_VERSION(2,0), -1},
90 {WINED3DSIO_ADD
, "add", "ADD", 1, 3, vshader_hw_map2gl
, shader_glsl_arith
, 0, 0},
91 {WINED3DSIO_SUB
, "sub", "SUB", 1, 3, vshader_hw_map2gl
, shader_glsl_arith
, 0, 0},
92 {WINED3DSIO_MAD
, "mad", "MAD", 1, 4, vshader_hw_map2gl
, shader_glsl_mad
, 0, 0},
93 {WINED3DSIO_MUL
, "mul", "MUL", 1, 3, vshader_hw_map2gl
, shader_glsl_arith
, 0, 0},
94 {WINED3DSIO_RCP
, "rcp", "RCP", 1, 2, vshader_hw_rsq_rcp
, shader_glsl_rcp
, 0, 0},
95 {WINED3DSIO_RSQ
, "rsq", "RSQ", 1, 2, vshader_hw_rsq_rcp
, shader_glsl_map2gl
, 0, 0},
96 {WINED3DSIO_DP3
, "dp3", "DP3", 1, 3, vshader_hw_map2gl
, shader_glsl_dot
, 0, 0},
97 {WINED3DSIO_DP4
, "dp4", "DP4", 1, 3, vshader_hw_map2gl
, shader_glsl_dot
, 0, 0},
98 {WINED3DSIO_MIN
, "min", "MIN", 1, 3, vshader_hw_map2gl
, shader_glsl_map2gl
, 0, 0},
99 {WINED3DSIO_MAX
, "max", "MAX", 1, 3, vshader_hw_map2gl
, shader_glsl_map2gl
, 0, 0},
100 {WINED3DSIO_SLT
, "slt", "SLT", 1, 3, vshader_hw_map2gl
, shader_glsl_compare
, 0, 0},
101 {WINED3DSIO_SGE
, "sge", "SGE", 1, 3, vshader_hw_map2gl
, shader_glsl_compare
, 0, 0},
102 {WINED3DSIO_ABS
, "abs", "ABS", 1, 2, vshader_hw_map2gl
, shader_glsl_map2gl
, 0, 0},
103 {WINED3DSIO_EXP
, "exp", "EX2", 1, 2, vshader_hw_map2gl
, shader_glsl_map2gl
, 0, 0},
104 {WINED3DSIO_LOG
, "log", "LG2", 1, 2, vshader_hw_map2gl
, shader_glsl_map2gl
, 0, 0},
105 {WINED3DSIO_EXPP
, "expp", "EXP", 1, 2, vshader_hw_map2gl
, shader_glsl_expp
, 0, 0},
106 {WINED3DSIO_LOGP
, "logp", "LOG", 1, 2, vshader_hw_map2gl
, shader_glsl_map2gl
, 0, 0},
107 {WINED3DSIO_LIT
, "lit", "LIT", 1, 2, vshader_hw_map2gl
, shader_glsl_lit
, 0, 0},
108 {WINED3DSIO_DST
, "dst", "DST", 1, 3, vshader_hw_map2gl
, shader_glsl_dst
, 0, 0},
109 {WINED3DSIO_LRP
, "lrp", "LRP", 1, 4, NULL
, shader_glsl_lrp
, 0, 0},
110 {WINED3DSIO_FRC
, "frc", "FRC", 1, 2, vshader_hw_map2gl
, shader_glsl_map2gl
, 0, 0},
111 {WINED3DSIO_POW
, "pow", "POW", 1, 3, NULL
, shader_glsl_map2gl
, 0, 0},
112 {WINED3DSIO_CRS
, "crs", "XPS", 1, 3, NULL
, shader_glsl_cross
, 0, 0},
113 /* TODO: sng can possibly be performed a s
116 {WINED3DSIO_SGN
, "sgn", NULL
, 1, 2, NULL
, shader_glsl_map2gl
, 0, 0},
117 /* TODO: xyz normalise can be performed as VS_ARB using one temporary register,
120 MUL vec.xyz, vec, tmp;
121 but I think this is better because it accounts for w properly.
126 {WINED3DSIO_NRM
, "nrm", NULL
, 1, 2, NULL
, shader_glsl_map2gl
, 0, 0},
127 {WINED3DSIO_SINCOS
, "sincos", NULL
, 1, 4, NULL
, shader_glsl_sincos
, WINED3DVS_VERSION(2,0), WINED3DVS_VERSION(2,1)},
128 {WINED3DSIO_SINCOS
, "sincos", NULL
, 1, 2, NULL
, shader_glsl_sincos
, WINED3DVS_VERSION(3,0), -1},
130 {WINED3DSIO_M4x4
, "m4x4", "undefined", 1, 3, vshader_hw_mnxn
, shader_glsl_mnxn
, 0, 0},
131 {WINED3DSIO_M4x3
, "m4x3", "undefined", 1, 3, vshader_hw_mnxn
, shader_glsl_mnxn
, 0, 0},
132 {WINED3DSIO_M3x4
, "m3x4", "undefined", 1, 3, vshader_hw_mnxn
, shader_glsl_mnxn
, 0, 0},
133 {WINED3DSIO_M3x3
, "m3x3", "undefined", 1, 3, vshader_hw_mnxn
, shader_glsl_mnxn
, 0, 0},
134 {WINED3DSIO_M3x2
, "m3x2", "undefined", 1, 3, vshader_hw_mnxn
, shader_glsl_mnxn
, 0, 0},
135 /* Declare registers */
136 {WINED3DSIO_DCL
, "dcl", NULL
, 0, 2, NULL
, NULL
, 0, 0},
137 /* Constant definitions */
138 {WINED3DSIO_DEF
, "def", NULL
, 1, 5, NULL
, NULL
, 0, 0},
139 {WINED3DSIO_DEFB
, "defb", GLNAME_REQUIRE_GLSL
, 1, 2, NULL
, NULL
, 0, 0},
140 {WINED3DSIO_DEFI
, "defi", GLNAME_REQUIRE_GLSL
, 1, 5, NULL
, NULL
, 0, 0},
141 /* Flow control - requires GLSL or software shaders */
142 {WINED3DSIO_REP
, "rep", NULL
, 0, 1, NULL
, shader_glsl_rep
, WINED3DVS_VERSION(2,0), -1},
143 {WINED3DSIO_ENDREP
, "endrep", NULL
, 0, 0, NULL
, shader_glsl_end
, WINED3DVS_VERSION(2,0), -1},
144 {WINED3DSIO_IF
, "if", NULL
, 0, 1, NULL
, shader_glsl_if
, WINED3DVS_VERSION(2,0), -1},
145 {WINED3DSIO_IFC
, "ifc", NULL
, 0, 2, NULL
, shader_glsl_ifc
, WINED3DVS_VERSION(2,1), -1},
146 {WINED3DSIO_ELSE
, "else", NULL
, 0, 0, NULL
, shader_glsl_else
, WINED3DVS_VERSION(2,0), -1},
147 {WINED3DSIO_ENDIF
, "endif", NULL
, 0, 0, NULL
, shader_glsl_end
, WINED3DVS_VERSION(2,0), -1},
148 {WINED3DSIO_BREAK
, "break", NULL
, 0, 0, NULL
, shader_glsl_break
, WINED3DVS_VERSION(2,1), -1},
149 {WINED3DSIO_BREAKC
, "breakc", NULL
, 0, 2, NULL
, shader_glsl_breakc
, WINED3DVS_VERSION(2,1), -1},
150 {WINED3DSIO_BREAKP
, "breakp", GLNAME_REQUIRE_GLSL
, 0, 1, NULL
, NULL
, 0, 0},
151 {WINED3DSIO_CALL
, "call", NULL
, 0, 1, NULL
, shader_glsl_call
, WINED3DVS_VERSION(2,0), -1},
152 {WINED3DSIO_CALLNZ
, "callnz", NULL
, 0, 2, NULL
, shader_glsl_callnz
, WINED3DVS_VERSION(2,0), -1},
153 {WINED3DSIO_LOOP
, "loop", NULL
, 0, 2, NULL
, shader_glsl_loop
, WINED3DVS_VERSION(2,0), -1},
154 {WINED3DSIO_RET
, "ret", NULL
, 0, 0, NULL
, NULL
, WINED3DVS_VERSION(2,0), -1},
155 {WINED3DSIO_ENDLOOP
,"endloop", NULL
, 0, 0, NULL
, shader_glsl_end
, WINED3DVS_VERSION(2,0), -1},
156 {WINED3DSIO_LABEL
, "label", NULL
, 0, 1, NULL
, shader_glsl_label
, WINED3DVS_VERSION(2,0), -1},
158 {WINED3DSIO_SETP
, "setp", GLNAME_REQUIRE_GLSL
, 1, 3, NULL
, NULL
, 0, 0},
159 {WINED3DSIO_TEXLDL
, "texdl", GLNAME_REQUIRE_GLSL
, 1, 3, NULL
, NULL
, 0, 0},
160 {0, NULL
, NULL
, 0, 0, NULL
, NULL
, 0, 0}
163 static void vshader_set_limits(
164 IWineD3DVertexShaderImpl
*This
) {
166 This
->baseShader
.limits
.texcoord
= 0;
167 This
->baseShader
.limits
.attributes
= 16;
168 This
->baseShader
.limits
.packed_input
= 0;
170 /* Must match D3DCAPS9.MaxVertexShaderConst: at least 256 for vs_2_0 */
171 This
->baseShader
.limits
.constant_float
= GL_LIMITS(vshader_constantsF
);
173 switch (This
->baseShader
.hex_version
) {
174 case WINED3DVS_VERSION(1,0):
175 case WINED3DVS_VERSION(1,1):
176 This
->baseShader
.limits
.temporary
= 12;
177 This
->baseShader
.limits
.constant_bool
= 0;
178 This
->baseShader
.limits
.constant_int
= 0;
179 This
->baseShader
.limits
.address
= 1;
180 This
->baseShader
.limits
.packed_output
= 0;
181 This
->baseShader
.limits
.sampler
= 0;
182 This
->baseShader
.limits
.label
= 0;
185 case WINED3DVS_VERSION(2,0):
186 case WINED3DVS_VERSION(2,1):
187 This
->baseShader
.limits
.temporary
= 12;
188 This
->baseShader
.limits
.constant_bool
= 16;
189 This
->baseShader
.limits
.constant_int
= 16;
190 This
->baseShader
.limits
.address
= 1;
191 This
->baseShader
.limits
.packed_output
= 0;
192 This
->baseShader
.limits
.sampler
= 0;
193 This
->baseShader
.limits
.label
= 16;
196 case WINED3DVS_VERSION(3,0):
197 This
->baseShader
.limits
.temporary
= 32;
198 This
->baseShader
.limits
.constant_bool
= 32;
199 This
->baseShader
.limits
.constant_int
= 32;
200 This
->baseShader
.limits
.address
= 1;
201 This
->baseShader
.limits
.packed_output
= 12;
202 This
->baseShader
.limits
.sampler
= 4;
203 This
->baseShader
.limits
.label
= 16; /* FIXME: 2048 */
206 default: This
->baseShader
.limits
.temporary
= 12;
207 This
->baseShader
.limits
.constant_bool
= 16;
208 This
->baseShader
.limits
.constant_int
= 16;
209 This
->baseShader
.limits
.address
= 1;
210 This
->baseShader
.limits
.packed_output
= 0;
211 This
->baseShader
.limits
.sampler
= 0;
212 This
->baseShader
.limits
.label
= 16;
213 FIXME("Unrecognized vertex shader version %#x\n",
214 This
->baseShader
.hex_version
);
218 /* This is an internal function,
219 * used to create fake semantics for shaders
220 * that don't have them - d3d8 shaders where the declaration
221 * stores the register for each input
223 static void vshader_set_input(
224 IWineD3DVertexShaderImpl
* This
,
226 BYTE usage
, BYTE usage_idx
) {
228 /* Fake usage: set reserved bit, usage, usage_idx */
229 DWORD usage_token
= (0x1 << 31) |
230 (usage
<< WINED3DSP_DCL_USAGE_SHIFT
) | (usage_idx
<< WINED3DSP_DCL_USAGEINDEX_SHIFT
);
232 /* Fake register; set reserved bit, regnum, type: input, wmask: all */
233 DWORD reg_token
= (0x1 << 31) |
234 WINED3DSP_WRITEMASK_ALL
| (WINED3DSPR_INPUT
<< WINED3DSP_REGTYPE_SHIFT
) | regnum
;
236 This
->semantics_in
[regnum
].usage
= usage_token
;
237 This
->semantics_in
[regnum
].reg
= reg_token
;
240 static BOOL
match_usage(BYTE usage1
, BYTE usage_idx1
, BYTE usage2
, BYTE usage_idx2
) {
241 if (usage_idx1
!= usage_idx2
) return FALSE
;
242 if (usage1
== usage2
) return TRUE
;
243 if (usage1
== WINED3DDECLUSAGE_POSITION
&& usage2
== WINED3DDECLUSAGE_POSITIONT
) return TRUE
;
244 if (usage2
== WINED3DDECLUSAGE_POSITION
&& usage1
== WINED3DDECLUSAGE_POSITIONT
) return TRUE
;
249 BOOL
vshader_get_input(
250 IWineD3DVertexShader
* iface
,
251 BYTE usage_req
, BYTE usage_idx_req
,
252 unsigned int* regnum
) {
254 IWineD3DVertexShaderImpl
* This
= (IWineD3DVertexShaderImpl
*) iface
;
257 for (i
= 0; i
< MAX_ATTRIBS
; i
++) {
258 DWORD usage_token
= This
->semantics_in
[i
].usage
;
259 DWORD usage
= (usage_token
& WINED3DSP_DCL_USAGE_MASK
) >> WINED3DSP_DCL_USAGE_SHIFT
;
260 DWORD usage_idx
= (usage_token
& WINED3DSP_DCL_USAGEINDEX_MASK
) >> WINED3DSP_DCL_USAGEINDEX_SHIFT
;
262 if (usage_token
&& match_usage(usage
, usage_idx
, usage_req
, usage_idx_req
)) {
270 BOOL
vshader_input_is_color(
271 IWineD3DVertexShader
* iface
,
272 unsigned int regnum
) {
274 IWineD3DVertexShaderImpl
* This
= (IWineD3DVertexShaderImpl
*) iface
;
275 IWineD3DDeviceImpl
* deviceImpl
= (IWineD3DDeviceImpl
*) This
->baseShader
.device
;
276 IWineD3DVertexDeclarationImpl
*vertexDeclaration
= (IWineD3DVertexDeclarationImpl
*)deviceImpl
->stateBlock
->vertexDecl
;
278 DWORD usage_token
= This
->semantics_in
[regnum
].usage
;
279 DWORD usage
= (usage_token
& WINED3DSP_DCL_USAGE_MASK
) >> WINED3DSP_DCL_USAGE_SHIFT
;
280 DWORD usage_idx
= (usage_token
& WINED3DSP_DCL_USAGEINDEX_MASK
) >> WINED3DSP_DCL_USAGEINDEX_SHIFT
;
282 if (vertexDeclaration
) {
284 /* Find the declaration element that matches our register, then check
285 * if it has D3DCOLOR as it's type. This works for both d3d8 and d3d9. */
286 for (i
= 0; i
< vertexDeclaration
->declarationWNumElements
-1; ++i
) {
287 WINED3DVERTEXELEMENT
*element
= vertexDeclaration
->pDeclarationWine
+ i
;
288 if (match_usage(element
->Usage
, element
->UsageIndex
, usage
, usage_idx
)) {
289 return element
->Type
== WINED3DDECLTYPE_D3DCOLOR
;
294 ERR("Either no vertexdeclaration present, or register not matched. This should never happen.\n");
298 /** Generate a vertex shader string using either GL_VERTEX_PROGRAM_ARB
299 or GLSL and send it to the card */
300 static VOID
IWineD3DVertexShaderImpl_GenerateShader(
301 IWineD3DVertexShader
*iface
,
302 shader_reg_maps
* reg_maps
,
303 CONST DWORD
*pFunction
) {
305 IWineD3DVertexShaderImpl
*This
= (IWineD3DVertexShaderImpl
*)iface
;
306 SHADER_BUFFER buffer
;
308 #if 0 /* FIXME: Use the buffer that is held by the device, this is ok since fixups will be skipped for software shaders
309 it also requires entering a critical section but cuts down the runtime footprint of wined3d and any memory fragmentation that may occur... */
310 if (This
->device
->fixupVertexBufferSize
< SHADER_PGMSIZE
) {
311 HeapFree(GetProcessHeap(), 0, This
->fixupVertexBuffer
);
312 This
->fixupVertexBuffer
= HeapAlloc(GetProcessHeap() , 0, SHADER_PGMSIZE
);
313 This
->fixupVertexBufferSize
= PGMSIZE
;
314 This
->fixupVertexBuffer
[0] = 0;
316 buffer
.buffer
= This
->device
->fixupVertexBuffer
;
318 buffer
.buffer
= HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY
, SHADER_PGMSIZE
);
322 buffer
.newline
= TRUE
;
324 if (This
->baseShader
.shader_mode
== SHADER_GLSL
) {
326 /* Create the hw GLSL shader program and assign it as the baseShader.prgId */
327 GLhandleARB shader_obj
= GL_EXTCALL(glCreateShaderObjectARB(GL_VERTEX_SHADER_ARB
));
329 /* Base Declarations */
330 shader_generate_glsl_declarations( (IWineD3DBaseShader
*) This
, reg_maps
, &buffer
, &GLINFO_LOCATION
);
332 /* Base Shader Body */
333 shader_generate_main( (IWineD3DBaseShader
*) This
, &buffer
, reg_maps
, pFunction
);
335 /* Unpack 3.0 outputs */
336 if (This
->baseShader
.hex_version
>= WINED3DVS_VERSION(3,0))
337 vshader_glsl_output_unpack(&buffer
, This
->semantics_out
);
339 /* If this shader doesn't use fog copy the z coord to the fog coord so that we can use table fog */
343 shader_addline(&buffer
, "gl_FogFragCoord = gl_Position.z;\n");
345 /* Write the final position.
347 * OpenGL coordinates specify the center of the pixel while d3d coords specify
348 * the corner. The offsets are stored in z and w in the 2nd row of the projection
349 * matrix to avoid wasting a free shader constant. Add them to the w and z coord
352 shader_addline(&buffer
, "gl_Position.x = gl_Position.x + posFixup[2];\n");
353 shader_addline(&buffer
, "gl_Position.y = gl_Position.y + posFixup[3];\n");
354 /* Account for any inverted textures (render to texture case) by reversing the y coordinate
355 * (this is handled in drawPrim() when it sets the MODELVIEW and PROJECTION matrices)
357 shader_addline(&buffer
, "gl_Position.y = gl_Position.y * posFixup[1];\n");
359 shader_addline(&buffer
, "}\n");
361 TRACE("Compiling shader object %u\n", shader_obj
);
362 GL_EXTCALL(glShaderSourceARB(shader_obj
, 1, (const char**)&buffer
.buffer
, NULL
));
363 GL_EXTCALL(glCompileShaderARB(shader_obj
));
364 print_glsl_info_log(&GLINFO_LOCATION
, shader_obj
);
366 /* Store the shader object */
367 This
->baseShader
.prgId
= shader_obj
;
369 } else if (This
->baseShader
.shader_mode
== SHADER_ARB
) {
371 /* Create the hw ARB shader */
372 shader_addline(&buffer
, "!!ARBvp1.0\n");
374 /* Mesa supports only 95 constants */
375 if (GL_VEND(MESA
) || GL_VEND(WINE
))
376 This
->baseShader
.limits
.constant_float
=
377 min(95, This
->baseShader
.limits
.constant_float
);
379 /* Base Declarations */
380 shader_generate_arb_declarations( (IWineD3DBaseShader
*) This
, reg_maps
, &buffer
, &GLINFO_LOCATION
);
382 /* We need a constant to fixup the final position */
383 shader_addline(&buffer
, "PARAM posFixup = program.env[%d];\n", ARB_SHADER_PRIVCONST_POS
);
385 /* Base Shader Body */
386 shader_generate_main( (IWineD3DBaseShader
*) This
, &buffer
, reg_maps
, pFunction
);
388 /* If this shader doesn't use fog copy the z coord to the fog coord so that we can use table fog */
392 shader_addline(&buffer
, "MOV result.fogcoord, TMP_OUT.z;\n");
394 /* Write the final position.
396 * OpenGL coordinates specify the center of the pixel while d3d coords specify
397 * the corner. The offsets are stored in the 2nd row of the projection matrix,
398 * the x offset in z and the y offset in w. Add them to the resulting position
400 shader_addline(&buffer
, "ADD TMP_OUT.x, TMP_OUT.x, posFixup.z;\n");
401 shader_addline(&buffer
, "ADD TMP_OUT.y, TMP_OUT.y, posFixup.w;\n");
402 /* Account for any inverted textures (render to texture case) by reversing the y coordinate
403 * (this is handled in drawPrim() when it sets the MODELVIEW and PROJECTION matrices)
405 shader_addline(&buffer
, "MUL TMP_OUT.y, TMP_OUT.y, posFixup.y;\n");
407 shader_addline(&buffer
, "MOV result.position, TMP_OUT;\n");
409 shader_addline(&buffer
, "END\n");
411 /* TODO: change to resource.glObjectHandle or something like that */
412 GL_EXTCALL(glGenProgramsARB(1, &This
->baseShader
.prgId
));
414 TRACE("Creating a hw vertex shader, prg=%d\n", This
->baseShader
.prgId
);
415 GL_EXTCALL(glBindProgramARB(GL_VERTEX_PROGRAM_ARB
, This
->baseShader
.prgId
));
417 TRACE("Created hw vertex shader, prg=%d\n", This
->baseShader
.prgId
);
418 /* Create the program and check for errors */
419 GL_EXTCALL(glProgramStringARB(GL_VERTEX_PROGRAM_ARB
, GL_PROGRAM_FORMAT_ASCII_ARB
,
420 buffer
.bsize
, buffer
.buffer
));
422 if (glGetError() == GL_INVALID_OPERATION
) {
424 glGetIntegerv(GL_PROGRAM_ERROR_POSITION_ARB
, &errPos
);
425 FIXME("HW VertexShader Error at position %d: %s\n",
426 errPos
, debugstr_a((const char *)glGetString(GL_PROGRAM_ERROR_STRING_ARB
)));
427 This
->baseShader
.prgId
= -1;
431 #if 1 /* if were using the data buffer of device then we don't need to free it */
432 HeapFree(GetProcessHeap(), 0, buffer
.buffer
);
436 /* *******************************************
437 IWineD3DVertexShader IUnknown parts follow
438 ******************************************* */
439 static HRESULT WINAPI
IWineD3DVertexShaderImpl_QueryInterface(IWineD3DVertexShader
*iface
, REFIID riid
, LPVOID
*ppobj
)
441 IWineD3DVertexShaderImpl
*This
= (IWineD3DVertexShaderImpl
*)iface
;
442 TRACE("(%p)->(%s,%p)\n",This
,debugstr_guid(riid
),ppobj
);
443 if (IsEqualGUID(riid
, &IID_IUnknown
)
444 || IsEqualGUID(riid
, &IID_IWineD3DBase
)
445 || IsEqualGUID(riid
, &IID_IWineD3DBaseShader
)
446 || IsEqualGUID(riid
, &IID_IWineD3DVertexShader
)) {
447 IUnknown_AddRef(iface
);
452 return E_NOINTERFACE
;
455 static ULONG WINAPI
IWineD3DVertexShaderImpl_AddRef(IWineD3DVertexShader
*iface
) {
456 IWineD3DVertexShaderImpl
*This
= (IWineD3DVertexShaderImpl
*)iface
;
457 TRACE("(%p) : AddRef increasing from %d\n", This
, This
->ref
);
458 return InterlockedIncrement(&This
->ref
);
461 static ULONG WINAPI
IWineD3DVertexShaderImpl_Release(IWineD3DVertexShader
*iface
) {
462 IWineD3DVertexShaderImpl
*This
= (IWineD3DVertexShaderImpl
*)iface
;
464 TRACE("(%p) : Releasing from %d\n", This
, This
->ref
);
465 ref
= InterlockedDecrement(&This
->ref
);
467 if(iface
== ((IWineD3DDeviceImpl
*) This
->baseShader
.device
)->stateBlock
->vertexShader
) {
468 /* See comment in PixelShader::Release */
469 IWineD3DDeviceImpl_MarkStateDirty((IWineD3DDeviceImpl
*) This
->baseShader
.device
, STATE_VSHADER
);
472 if (This
->baseShader
.shader_mode
== SHADER_GLSL
&& This
->baseShader
.prgId
!= 0) {
473 struct list
*linked_programs
= &This
->baseShader
.linked_programs
;
475 TRACE("Deleting linked programs\n");
476 if (linked_programs
->next
) {
477 struct glsl_shader_prog_link
*entry
, *entry2
;
478 LIST_FOR_EACH_ENTRY_SAFE(entry
, entry2
, linked_programs
, struct glsl_shader_prog_link
, vshader_entry
) {
479 delete_glsl_program_entry(This
->baseShader
.device
, entry
);
483 TRACE("Deleting shader object %u\n", This
->baseShader
.prgId
);
484 GL_EXTCALL(glDeleteObjectARB(This
->baseShader
.prgId
));
485 checkGLcall("glDeleteObjectARB");
487 shader_delete_constant_list(&This
->baseShader
.constantsF
);
488 shader_delete_constant_list(&This
->baseShader
.constantsB
);
489 shader_delete_constant_list(&This
->baseShader
.constantsI
);
490 HeapFree(GetProcessHeap(), 0, This
);
496 /* *******************************************
497 IWineD3DVertexShader IWineD3DVertexShader parts follow
498 ******************************************* */
500 static HRESULT WINAPI
IWineD3DVertexShaderImpl_GetParent(IWineD3DVertexShader
*iface
, IUnknown
** parent
){
501 IWineD3DVertexShaderImpl
*This
= (IWineD3DVertexShaderImpl
*)iface
;
503 *parent
= This
->parent
;
504 IUnknown_AddRef(*parent
);
505 TRACE("(%p) : returning %p\n", This
, *parent
);
509 static HRESULT WINAPI
IWineD3DVertexShaderImpl_GetDevice(IWineD3DVertexShader
* iface
, IWineD3DDevice
**pDevice
){
510 IWineD3DVertexShaderImpl
*This
= (IWineD3DVertexShaderImpl
*)iface
;
511 IWineD3DDevice_AddRef(This
->baseShader
.device
);
512 *pDevice
= This
->baseShader
.device
;
513 TRACE("(%p) returning %p\n", This
, *pDevice
);
517 static HRESULT WINAPI
IWineD3DVertexShaderImpl_GetFunction(IWineD3DVertexShader
* impl
, VOID
* pData
, UINT
* pSizeOfData
) {
518 IWineD3DVertexShaderImpl
*This
= (IWineD3DVertexShaderImpl
*)impl
;
519 TRACE("(%p) : pData(%p), pSizeOfData(%p)\n", This
, pData
, pSizeOfData
);
522 *pSizeOfData
= This
->baseShader
.functionLength
;
525 if (*pSizeOfData
< This
->baseShader
.functionLength
) {
526 /* MSDN claims (for d3d8 at least) that if *pSizeOfData is smaller
527 * than the required size we should write the required size and
528 * return D3DERR_MOREDATA. That's not actually true. */
529 return WINED3DERR_INVALIDCALL
;
531 if (NULL
== This
->baseShader
.function
) { /* no function defined */
532 TRACE("(%p) : GetFunction no User Function defined using NULL to %p\n", This
, pData
);
533 (*(DWORD
**) pData
) = NULL
;
535 if(This
->baseShader
.functionLength
== 0){
538 TRACE("(%p) : GetFunction copying to %p\n", This
, pData
);
539 memcpy(pData
, This
->baseShader
.function
, This
->baseShader
.functionLength
);
544 /* Note that for vertex shaders CompileShader isn't called until the
545 * shader is first used. The reason for this is that we need the vertex
546 * declaration the shader will be used with in order to determine if
547 * the data in a register is of type D3DCOLOR, and needs swizzling. */
548 static HRESULT WINAPI
IWineD3DVertexShaderImpl_SetFunction(IWineD3DVertexShader
*iface
, CONST DWORD
*pFunction
) {
550 IWineD3DVertexShaderImpl
*This
=(IWineD3DVertexShaderImpl
*)iface
;
551 IWineD3DDeviceImpl
*deviceImpl
= (IWineD3DDeviceImpl
*) This
->baseShader
.device
;
553 shader_reg_maps
*reg_maps
= &This
->baseShader
.reg_maps
;
555 TRACE("(%p) : pFunction %p\n", iface
, pFunction
);
557 /* First pass: trace shader */
558 shader_trace_init((IWineD3DBaseShader
*) This
, pFunction
);
559 vshader_set_limits(This
);
561 /* Initialize immediate constant lists */
562 list_init(&This
->baseShader
.constantsF
);
563 list_init(&This
->baseShader
.constantsB
);
564 list_init(&This
->baseShader
.constantsI
);
566 /* Second pass: figure out registers used, semantics, etc.. */
567 memset(reg_maps
, 0, sizeof(shader_reg_maps
));
568 hr
= shader_get_registers_used((IWineD3DBaseShader
*) This
, reg_maps
,
569 This
->semantics_in
, This
->semantics_out
, pFunction
, deviceImpl
->stateBlock
);
570 if (hr
!= WINED3D_OK
) return hr
;
572 This
->baseShader
.shader_mode
= deviceImpl
->vs_selected_mode
;
574 /* copy the function ... because it will certainly be released by application */
575 if (NULL
!= pFunction
) {
578 function
= HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY
, This
->baseShader
.functionLength
);
579 if (!function
) return E_OUTOFMEMORY
;
580 memcpy(function
, pFunction
, This
->baseShader
.functionLength
);
581 This
->baseShader
.function
= function
;
583 This
->baseShader
.function
= NULL
;
589 /* Preload semantics for d3d8 shaders */
590 static void WINAPI
IWineD3DVertexShaderImpl_FakeSemantics(IWineD3DVertexShader
*iface
, IWineD3DVertexDeclaration
*vertex_declaration
) {
591 IWineD3DVertexShaderImpl
*This
=(IWineD3DVertexShaderImpl
*)iface
;
592 IWineD3DVertexDeclarationImpl
* vdecl
= (IWineD3DVertexDeclarationImpl
*)vertex_declaration
;
595 for (i
= 0; i
< vdecl
->declarationWNumElements
- 1; ++i
) {
596 WINED3DVERTEXELEMENT
* element
= vdecl
->pDeclarationWine
+ i
;
597 vshader_set_input(This
, element
->Reg
, element
->Usage
, element
->UsageIndex
);
601 /* Set local constants for d3d8 shaders */
602 static HRESULT WINAPI
IWIneD3DVertexShaderImpl_SetLocalConstantsF(IWineD3DVertexShader
*iface
,
603 UINT start_idx
, const float *src_data
, UINT count
) {
604 IWineD3DVertexShaderImpl
*This
=(IWineD3DVertexShaderImpl
*)iface
;
607 TRACE("(%p) : start_idx %u, src_data %p, count %u\n", This
, start_idx
, src_data
, count
);
609 end_idx
= start_idx
+ count
;
610 if (end_idx
> GL_LIMITS(vshader_constantsF
)) {
611 WARN("end_idx %u > float constants limit %u\n", end_idx
, GL_LIMITS(vshader_constantsF
));
612 end_idx
= GL_LIMITS(vshader_constantsF
);
615 for (i
= start_idx
; i
< end_idx
; ++i
) {
616 local_constant
* lconst
= HeapAlloc(GetProcessHeap(), 0, sizeof(local_constant
));
617 if (!lconst
) return E_OUTOFMEMORY
;
620 CopyMemory(lconst
->value
, src_data
+ i
* 4, 4 * sizeof(float));
621 list_add_head(&This
->baseShader
.constantsF
, &lconst
->entry
);
627 static HRESULT WINAPI
IWineD3DVertexShaderImpl_CompileShader(IWineD3DVertexShader
*iface
) {
628 IWineD3DVertexShaderImpl
*This
= (IWineD3DVertexShaderImpl
*)iface
;
629 CONST DWORD
*function
= This
->baseShader
.function
;
631 TRACE("(%p) : function %p\n", iface
, function
);
633 /* We're already compiled. */
634 if (This
->baseShader
.is_compiled
) return WINED3D_OK
;
636 /* We don't need to compile */
638 This
->baseShader
.is_compiled
= TRUE
;
642 /* Generate the HW shader */
643 TRACE("(%p) : Generating hardware program\n", This
);
644 IWineD3DVertexShaderImpl_GenerateShader(iface
, &This
->baseShader
.reg_maps
, function
);
646 This
->baseShader
.is_compiled
= TRUE
;
651 const IWineD3DVertexShaderVtbl IWineD3DVertexShader_Vtbl
=
653 /*** IUnknown methods ***/
654 IWineD3DVertexShaderImpl_QueryInterface
,
655 IWineD3DVertexShaderImpl_AddRef
,
656 IWineD3DVertexShaderImpl_Release
,
657 /*** IWineD3DBase methods ***/
658 IWineD3DVertexShaderImpl_GetParent
,
659 /*** IWineD3DBaseShader methods ***/
660 IWineD3DVertexShaderImpl_SetFunction
,
661 IWineD3DVertexShaderImpl_CompileShader
,
662 /*** IWineD3DVertexShader methods ***/
663 IWineD3DVertexShaderImpl_GetDevice
,
664 IWineD3DVertexShaderImpl_GetFunction
,
665 IWineD3DVertexShaderImpl_FakeSemantics
,
666 IWIneD3DVertexShaderImpl_SetLocalConstantsF