2 * shaders implementation
4 * Copyright 2002-2003 Jason Edmeades
5 * Copyright 2002-2003 Raphael Junqueira
6 * Copyright 2005 Oliver Stieber
8 * This library is free software; you can redistribute it and/or
9 * modify it under the terms of the GNU Lesser General Public
10 * License as published by the Free Software Foundation; either
11 * version 2.1 of the License, or (at your option) any later version.
13 * This library is distributed in the hope that it will be useful,
14 * but WITHOUT ANY WARRANTY; without even the implied warranty of
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
16 * Lesser General Public License for more details.
18 * You should have received a copy of the GNU Lesser General Public
19 * License along with this library; if not, write to the Free Software
20 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
28 #include "wined3d_private.h"
30 WINE_DEFAULT_DEBUG_CHANNEL(d3d_shader);
32 #define GLINFO_LOCATION ((IWineD3DImpl *)(((IWineD3DDeviceImpl *)This->wineD3DDevice)->wineD3D))->gl_info
34 /* Shader debugging - Change the following line to enable debugging of software
36 #if 0 /* Musxt not be 1 in cvs version */
37 # define VSTRACE(A) TRACE A
38 # define TRACE_VSVECTOR(name) TRACE( #name "=(%f, %f, %f, %f)\n", name.x, name.y, name.z, name.w)
41 # define TRACE_VSVECTOR(name)
44 #if 1 /* FIXME : Needs sorting when vshader code moved in properly */
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 /*******************************
84 * vshader functions software VM
87 void vshader_add(WINED3DSHADERVECTOR* d, WINED3DSHADERVECTOR* s0, WINED3DSHADERVECTOR* s1) {
92 VSTRACE(("executing add: s0=(%f, %f, %f, %f) s1=(%f, %f, %f, %f) => d=(%f, %f, %f, %f)\n",
93 s0->x, s0->y, s0->z, s0->w, s1->x, s1->y, s1->z, s1->w, d->x, d->y, d->z, d->w));
96 void vshader_dp3(WINED3DSHADERVECTOR* d, WINED3DSHADERVECTOR* s0, WINED3DSHADERVECTOR* s1) {
97 d->x = d->y = d->z = d->w = s0->x * s1->x + s0->y * s1->y + s0->z * s1->z;
98 VSTRACE(("executing dp3: s0=(%f, %f, %f, %f) s1=(%f, %f, %f, %f) => d=(%f, %f, %f, %f)\n",
99 s0->x, s0->y, s0->z, s0->w, s1->x, s1->y, s1->z, s1->w, d->x, d->y, d->z, d->w));
102 void vshader_dp4(WINED3DSHADERVECTOR* d, WINED3DSHADERVECTOR* s0, WINED3DSHADERVECTOR* s1) {
103 d->x = d->y = d->z = d->w = s0->x * s1->x + s0->y * s1->y + s0->z * s1->z + s0->w * s1->w;
104 VSTRACE(("executing dp4: s0=(%f, %f, %f, %f) s1=(%f, %f, %f, %f) => d=(%f, %f, %f, %f)\n",
105 s0->x, s0->y, s0->z, s0->w, s1->x, s1->y, s1->z, s1->w, d->x, d->y, d->z, d->w));
108 void vshader_dst(WINED3DSHADERVECTOR* d, WINED3DSHADERVECTOR* s0, WINED3DSHADERVECTOR* s1) {
110 d->y = s0->y * s1->y;
113 VSTRACE(("executing dst: s0=(%f, %f, %f, %f) s1=(%f, %f, %f, %f) => d=(%f, %f, %f, %f)\n",
114 s0->x, s0->y, s0->z, s0->w, s1->x, s1->y, s1->z, s1->w, d->x, d->y, d->z, d->w));
117 void vshader_expp(WINED3DSHADERVECTOR* d, WINED3DSHADERVECTOR* s0) {
123 tmp.f = floorf(s0->w);
124 d->x = powf(2.0f, tmp.f);
125 d->y = s0->w - tmp.f;
126 tmp.f = powf(2.0f, s0->w);
127 tmp.d &= 0xFFFFFF00U;
130 VSTRACE(("executing exp: s0=(%f, %f, %f, %f) => d=(%f, %f, %f, %f)\n",
131 s0->x, s0->y, s0->z, s0->w, d->x, d->y, d->z, d->w));
134 void vshader_lit(WINED3DSHADERVECTOR* d, WINED3DSHADERVECTOR* s0) {
136 d->y = (0.0f < s0->x) ? s0->x : 0.0f;
137 d->z = (0.0f < s0->x && 0.0f < s0->y) ? powf(s0->y, s0->w) : 0.0f;
139 VSTRACE(("executing lit: s0=(%f, %f, %f, %f) => d=(%f, %f, %f, %f)\n",
140 s0->x, s0->y, s0->z, s0->w, d->x, d->y, d->z, d->w));
143 void vshader_logp(WINED3DSHADERVECTOR* d, WINED3DSHADERVECTOR* s0) {
144 float tmp_f = fabsf(s0->w);
145 d->x = d->y = d->z = d->w = (0.0f != tmp_f) ? logf(tmp_f) / logf(2.0f) : -HUGE_VAL;
146 VSTRACE(("executing logp: s0=(%f, %f, %f, %f) => d=(%f, %f, %f, %f)\n",
147 s0->x, s0->y, s0->z, s0->w, d->x, d->y, d->z, d->w));
150 void vshader_mad(WINED3DSHADERVECTOR* d, WINED3DSHADERVECTOR* s0, WINED3DSHADERVECTOR* s1, WINED3DSHADERVECTOR* s2) {
151 d->x = s0->x * s1->x + s2->x;
152 d->y = s0->y * s1->y + s2->y;
153 d->z = s0->z * s1->z + s2->z;
154 d->w = s0->w * s1->w + s2->w;
155 VSTRACE(("executing mad: s0=(%f, %f, %f, %f) s1=(%f, %f, %f, %f) s2=(%f, %f, %f, %f) => d=(%f, %f, %f, %f)\n",
156 s0->x, s0->y, s0->z, s0->w, s1->x, s1->y, s1->z, s1->w, s2->x, s2->y, s2->z, s2->w, d->x, d->y, d->z, d->w));
159 void vshader_max(WINED3DSHADERVECTOR* d, WINED3DSHADERVECTOR* s0, WINED3DSHADERVECTOR* s1) {
160 d->x = (s0->x >= s1->x) ? s0->x : s1->x;
161 d->y = (s0->y >= s1->y) ? s0->y : s1->y;
162 d->z = (s0->z >= s1->z) ? s0->z : s1->z;
163 d->w = (s0->w >= s1->w) ? s0->w : s1->w;
164 VSTRACE(("executing max: s0=(%f, %f, %f, %f) s1=(%f, %f, %f, %f) => d=(%f, %f, %f, %f)\n",
165 s0->x, s0->y, s0->z, s0->w, s1->x, s1->y, s1->z, s1->w, d->x, d->y, d->z, d->w));
168 void vshader_min(WINED3DSHADERVECTOR* d, WINED3DSHADERVECTOR* s0, WINED3DSHADERVECTOR* s1) {
169 d->x = (s0->x < s1->x) ? s0->x : s1->x;
170 d->y = (s0->y < s1->y) ? s0->y : s1->y;
171 d->z = (s0->z < s1->z) ? s0->z : s1->z;
172 d->w = (s0->w < s1->w) ? s0->w : s1->w;
173 VSTRACE(("executing min: s0=(%f, %f, %f, %f) s1=(%f, %f, %f, %f) => d=(%f, %f, %f, %f)\n",
174 s0->x, s0->y, s0->z, s0->w, s1->x, s1->y, s1->z, s1->w, d->x, d->y, d->z, d->w));
177 void vshader_mov(WINED3DSHADERVECTOR* d, WINED3DSHADERVECTOR* s0) {
182 VSTRACE(("executing mov: s0=(%f, %f, %f, %f) => d=(%f, %f, %f, %f)\n",
183 s0->x, s0->y, s0->z, s0->w, d->x, d->y, d->z, d->w));
186 void vshader_mul(WINED3DSHADERVECTOR* d, WINED3DSHADERVECTOR* s0, WINED3DSHADERVECTOR* s1) {
187 d->x = s0->x * s1->x;
188 d->y = s0->y * s1->y;
189 d->z = s0->z * s1->z;
190 d->w = s0->w * s1->w;
191 VSTRACE(("executing mul: s0=(%f, %f, %f, %f) s1=(%f, %f, %f, %f) => d=(%f, %f, %f, %f)\n",
192 s0->x, s0->y, s0->z, s0->w, s1->x, s1->y, s1->z, s1->w, d->x, d->y, d->z, d->w));
195 void vshader_nop(void) {
196 /* NOPPPP ahhh too easy ;) */
197 VSTRACE(("executing nop\n"));
200 void vshader_rcp(WINED3DSHADERVECTOR* d, WINED3DSHADERVECTOR* s0) {
201 d->x = d->y = d->z = d->w = (0.0f == s0->w) ? HUGE_VAL : 1.0f / s0->w;
202 VSTRACE(("executing rcp: s0=(%f, %f, %f, %f) => d=(%f, %f, %f, %f)\n",
203 s0->x, s0->y, s0->z, s0->w, d->x, d->y, d->z, d->w));
206 void vshader_rsq(WINED3DSHADERVECTOR* d, WINED3DSHADERVECTOR* s0) {
207 float tmp_f = fabsf(s0->w);
208 d->x = d->y = d->z = d->w = (0.0f == tmp_f) ? HUGE_VAL : ((1.0f != tmp_f) ? 1.0f / sqrtf(tmp_f) : 1.0f);
209 VSTRACE(("executing rsq: s0=(%f, %f, %f, %f) => d=(%f, %f, %f, %f)\n",
210 s0->x, s0->y, s0->z, s0->w, d->x, d->y, d->z, d->w));
213 void vshader_sge(WINED3DSHADERVECTOR* d, WINED3DSHADERVECTOR* s0, WINED3DSHADERVECTOR* s1) {
214 d->x = (s0->x >= s1->x) ? 1.0f : 0.0f;
215 d->y = (s0->y >= s1->y) ? 1.0f : 0.0f;
216 d->z = (s0->z >= s1->z) ? 1.0f : 0.0f;
217 d->w = (s0->w >= s1->w) ? 1.0f : 0.0f;
218 VSTRACE(("executing sge: s0=(%f, %f, %f, %f) s1=(%f, %f, %f, %f) => d=(%f, %f, %f, %f)\n",
219 s0->x, s0->y, s0->z, s0->w, s1->x, s1->y, s1->z, s1->w, d->x, d->y, d->z, d->w));
222 void vshader_slt(WINED3DSHADERVECTOR* d, WINED3DSHADERVECTOR* s0, WINED3DSHADERVECTOR* s1) {
223 d->x = (s0->x < s1->x) ? 1.0f : 0.0f;
224 d->y = (s0->y < s1->y) ? 1.0f : 0.0f;
225 d->z = (s0->z < s1->z) ? 1.0f : 0.0f;
226 d->w = (s0->w < s1->w) ? 1.0f : 0.0f;
227 VSTRACE(("executing slt: s0=(%f, %f, %f, %f) s1=(%f, %f, %f, %f) => d=(%f, %f, %f, %f)\n",
228 s0->x, s0->y, s0->z, s0->w, s1->x, s1->y, s1->z, s1->w, d->x, d->y, d->z, d->w));
231 void vshader_sub(WINED3DSHADERVECTOR* d, WINED3DSHADERVECTOR* s0, WINED3DSHADERVECTOR* s1) {
232 d->x = s0->x - s1->x;
233 d->y = s0->y - s1->y;
234 d->z = s0->z - s1->z;
235 d->w = s0->w - s1->w;
236 VSTRACE(("executing sub: s0=(%f, %f, %f, %f) s1=(%f, %f, %f, %f) => d=(%f, %f, %f, %f)\n",
237 s0->x, s0->y, s0->z, s0->w, s1->x, s1->y, s1->z, s1->w, d->x, d->y, d->z, d->w));
241 * Version 1.1 specific
244 void vshader_exp(WINED3DSHADERVECTOR* d, WINED3DSHADERVECTOR* s0) {
245 d->x = d->y = d->z = d->w = powf(2.0f, s0->w);
246 VSTRACE(("executing exp: s0=(%f, %f, %f, %f) => d=(%f, %f, %f, %f)\n",
247 s0->x, s0->y, s0->z, s0->w, d->x, d->y, d->z, d->w));
250 void vshader_log(WINED3DSHADERVECTOR* d, WINED3DSHADERVECTOR* s0) {
251 float tmp_f = fabsf(s0->w);
252 d->x = d->y = d->z = d->w = (0.0f != tmp_f) ? logf(tmp_f) / logf(2.0f) : -HUGE_VAL;
253 VSTRACE(("executing log: s0=(%f, %f, %f, %f) => d=(%f, %f, %f, %f)\n",
254 s0->x, s0->y, s0->z, s0->w, d->x, d->y, d->z, d->w));
257 void vshader_frc(WINED3DSHADERVECTOR* d, WINED3DSHADERVECTOR* s0) {
258 d->x = s0->x - floorf(s0->x);
259 d->y = s0->y - floorf(s0->y);
262 VSTRACE(("executing frc: s0=(%f, %f, %f, %f) => d=(%f, %f, %f, %f)\n",
263 s0->x, s0->y, s0->z, s0->w, d->x, d->y, d->z, d->w));
266 typedef FLOAT D3DMATRIX44[4][4];
267 typedef FLOAT D3DMATRIX43[4][3];
268 typedef FLOAT D3DMATRIX34[3][4];
269 typedef FLOAT D3DMATRIX33[3][3];
270 typedef FLOAT D3DMATRIX23[2][3];
272 void vshader_m4x4(WINED3DSHADERVECTOR* d, WINED3DSHADERVECTOR* s0, /*WINED3DSHADERVECTOR* mat1*/ D3DMATRIX44 mat) {
274 * Buggy CODE: here only if cast not work for copy/paste
275 WINED3DSHADERVECTOR* mat2 = mat1 + 1;
276 WINED3DSHADERVECTOR* mat3 = mat1 + 2;
277 WINED3DSHADERVECTOR* mat4 = mat1 + 3;
278 d->x = mat1->x * s0->x + mat2->x * s0->y + mat3->x * s0->z + mat4->x * s0->w;
279 d->y = mat1->y * s0->x + mat2->y * s0->y + mat3->y * s0->z + mat4->y * s0->w;
280 d->z = mat1->z * s0->x + mat2->z * s0->y + mat3->z * s0->z + mat4->z * s0->w;
281 d->w = mat1->w * s0->x + mat2->w * s0->y + mat3->w * s0->z + mat4->w * s0->w;
283 d->x = mat[0][0] * s0->x + mat[0][1] * s0->y + mat[0][2] * s0->z + mat[0][3] * s0->w;
284 d->y = mat[1][0] * s0->x + mat[1][1] * s0->y + mat[1][2] * s0->z + mat[1][3] * s0->w;
285 d->z = mat[2][0] * s0->x + mat[2][1] * s0->y + mat[2][2] * s0->z + mat[2][3] * s0->w;
286 d->w = mat[3][0] * s0->x + mat[3][1] * s0->y + mat[3][2] * s0->z + mat[3][3] * s0->w;
287 VSTRACE(("executing m4x4(1): mat=(%f, %f, %f, %f) s0=(%f) d=(%f) \n", mat[0][0], mat[0][1], mat[0][2], mat[0][3], s0->x, d->x));
288 VSTRACE(("executing m4x4(2): mat=(%f, %f, %f, %f) (%f) (%f) \n", mat[1][0], mat[1][1], mat[1][2], mat[1][3], s0->y, d->y));
289 VSTRACE(("executing m4x4(3): mat=(%f, %f, %f, %f) X (%f) = (%f) \n", mat[2][0], mat[2][1], mat[2][2], mat[2][3], s0->z, d->z));
290 VSTRACE(("executing m4x4(4): mat=(%f, %f, %f, %f) (%f) (%f) \n", mat[3][0], mat[3][1], mat[3][2], mat[3][3], s0->w, d->w));
293 void vshader_m4x3(WINED3DSHADERVECTOR* d, WINED3DSHADERVECTOR* s0, D3DMATRIX34 mat) {
294 d->x = mat[0][0] * s0->x + mat[0][1] * s0->y + mat[0][2] * s0->z + mat[0][3] * s0->w;
295 d->y = mat[1][0] * s0->x + mat[1][1] * s0->y + mat[1][2] * s0->z + mat[1][3] * s0->w;
296 d->z = mat[2][0] * s0->x + mat[2][1] * s0->y + mat[2][2] * s0->z + mat[2][3] * s0->w;
298 VSTRACE(("executing m4x3(1): mat=(%f, %f, %f, %f) s0=(%f) d=(%f) \n", mat[0][0], mat[0][1], mat[0][2], mat[0][3], s0->x, d->x));
299 VSTRACE(("executing m4x3(2): mat=(%f, %f, %f, %f) (%f) (%f) \n", mat[1][0], mat[1][1], mat[1][2], mat[1][3], s0->y, d->y));
300 VSTRACE(("executing m4x3(3): mat=(%f, %f, %f, %f) X (%f) = (%f) \n", mat[2][0], mat[2][1], mat[2][2], mat[2][3], s0->z, d->z));
301 VSTRACE(("executing m4x3(4): (%f) (%f) \n", s0->w, d->w));
304 void vshader_m3x4(WINED3DSHADERVECTOR* d, WINED3DSHADERVECTOR* s0, D3DMATRIX43 mat) {
305 d->x = mat[0][0] * s0->x + mat[0][1] * s0->y + mat[0][2] * s0->z;
306 d->y = mat[1][0] * s0->x + mat[1][1] * s0->y + mat[1][2] * s0->z;
307 d->z = mat[2][0] * s0->x + mat[2][1] * s0->y + mat[2][2] * s0->z;
308 d->w = mat[3][0] * s0->x + mat[3][1] * s0->y + mat[3][2] * s0->z;
309 VSTRACE(("executing m3x4(1): mat=(%f, %f, %f) s0=(%f) d=(%f) \n", mat[0][0], mat[0][1], mat[0][2], s0->x, d->x));
310 VSTRACE(("executing m3x4(2): mat=(%f, %f, %f) (%f) (%f) \n", mat[1][0], mat[1][1], mat[1][2], s0->y, d->y));
311 VSTRACE(("executing m3x4(3): mat=(%f, %f, %f) X (%f) = (%f) \n", mat[2][0], mat[2][1], mat[2][2], s0->z, d->z));
312 VSTRACE(("executing m3x4(4): mat=(%f, %f, %f) (%f) (%f) \n", mat[3][0], mat[3][1], mat[3][2], s0->w, d->w));
315 void vshader_m3x3(WINED3DSHADERVECTOR* d, WINED3DSHADERVECTOR* s0, D3DMATRIX33 mat) {
316 d->x = mat[0][0] * s0->x + mat[0][1] * s0->y + mat[0][2] * s0->z;
317 d->y = mat[1][0] * s0->x + mat[1][1] * s0->y + mat[1][2] * s0->z;
318 d->z = mat[2][0] * s0->x + mat[2][1] * s0->y + mat[2][2] * s0->z;
320 VSTRACE(("executing m3x3(1): mat=(%f, %f, %f) s0=(%f) d=(%f) \n", mat[0][0], mat[0][1], mat[0][2], s0->x, d->x));
321 VSTRACE(("executing m3x3(2): mat=(%f, %f, %f) (%f) (%f) \n", mat[1][0], mat[1][1], mat[1][2], s0->y, d->y));
322 VSTRACE(("executing m3x3(3): mat=(%f, %f, %f) X (%f) = (%f) \n", mat[2][0], mat[2][1], mat[2][2], s0->z, d->z));
323 VSTRACE(("executing m3x3(4): (%f) \n", d->w));
326 void vshader_m3x2(WINED3DSHADERVECTOR* d, WINED3DSHADERVECTOR* s0, D3DMATRIX23 mat) {
328 d->x = mat[0][0] * s0->x + mat[0][1] * s0->y + mat[0][2] * s0->z;
329 d->y = mat[1][0] * s0->x + mat[1][1] * s0->y + mat[1][2] * s0->z;
335 * Version 2.0 specific
337 void vshader_lrp(WINED3DSHADERVECTOR* d, WINED3DSHADERVECTOR* s0, WINED3DSHADERVECTOR* s1, WINED3DSHADERVECTOR* s2) {
338 d->x = s0->x * (s1->x - s2->x) + s2->x;
339 d->y = s0->y * (s1->y - s2->y) + s2->y;
340 d->z = s0->z * (s1->z - s2->z) + s2->z;
341 d->w = s0->w * (s1->w - s2->w) + s2->w;
344 void vshader_crs(WINED3DSHADERVECTOR* d, WINED3DSHADERVECTOR* s0, WINED3DSHADERVECTOR* s1) {
345 d->x = s0->y * s1->z - s0->z * s1->y;
346 d->y = s0->z * s1->x - s0->x * s1->z;
347 d->z = s0->x * s1->y - s0->y * s1->x;
348 d->w = 0.9f; /* w is undefined, so set it to something safeish */
350 VSTRACE(("executing crs: s0=(%f, %f, %f, %f) s1=(%f, %f, %f, %f) => d=(%f, %f, %f, %f)\n",
351 s0->x, s0->y, s0->z, s0->w, s1->x, s1->y, s1->z, s1->w, d->x, d->y, d->z, d->w));
354 void vshader_abs(WINED3DSHADERVECTOR* d, WINED3DSHADERVECTOR* s0) {
360 VSTRACE(("executing abs: s0=(%f, %f, %f, %f) => d=(%f, %f, %f, %f)\n",
361 s0->x, s0->y, s0->z, s0->w, d->x, d->y, d->z, d->w));
366 /* Def is C[n] = {n.nf, n.nf, n.nf, n.nf} */
367 void vshader_def(WINED3DSHADERVECTOR* d, WINED3DSHADERVECTOR* s0, WINED3DSHADERVECTOR* s1, WINED3DSHADERVECTOR* s2, WINED3DSHADERVECTOR* s3) {
371 void vshader_call(WINED3DSHADERVECTOR* d) {
375 void vshader_callnz(WINED3DSHADERVECTOR* d, WINED3DSHADERVECTOR* s0) {
379 void vshader_loop(WINED3DSHADERVECTOR* d, WINED3DSHADERVECTOR* s0) {
383 void vshader_ret(void) {
387 void vshader_endloop(void) {
391 void vshader_dcl(WINED3DSHADERVECTOR* d, WINED3DSHADERVECTOR* s0) {
395 void vshader_pow(WINED3DSHADERVECTOR* d, WINED3DSHADERVECTOR* s0, WINED3DSHADERVECTOR* s1) {
399 void vshader_sng(WINED3DSHADERVECTOR* d, WINED3DSHADERVECTOR* s0) {
403 void vshader_nrm(WINED3DSHADERVECTOR* d, WINED3DSHADERVECTOR* s0) {
407 void vshader_sincos(WINED3DSHADERVECTOR* d, WINED3DSHADERVECTOR* s0) {
411 void vshader_rep(WINED3DSHADERVECTOR* d) {
415 void vshader_endrep(void) {
419 void vshader_if(WINED3DSHADERVECTOR* d) {
423 void vshader_ifc(WINED3DSHADERVECTOR* d, WINED3DSHADERVECTOR* s0) {
427 void vshader_else(void) {
431 void vshader_label(WINED3DSHADERVECTOR* d) {
435 void vshader_endif(void) {
439 void vshader_break(void) {
443 void vshader_breakc(WINED3DSHADERVECTOR* d, WINED3DSHADERVECTOR* s0) {
447 void vshader_breakp(WINED3DSHADERVECTOR* d) {
451 void vshader_mova(WINED3DSHADERVECTOR* d) {
455 void vshader_defb(WINED3DSHADERVECTOR* d) {
459 void vshader_defi(WINED3DSHADERVECTOR* d) {
463 void vshader_texldd(WINED3DSHADERVECTOR* d) {
467 void vshader_setp(WINED3DSHADERVECTOR* d) {
471 void vshader_texldl(WINED3DSHADERVECTOR* d) {
476 * log, exp, frc, m*x* seems to be macros ins ... to see
478 CONST SHADER_OPCODE IWineD3DVertexShaderImpl_shader_ins[] = {
479 {D3DSIO_NOP, "nop", "NOP", 0, vshader_nop, 0, 0},
480 {D3DSIO_MOV, "mov", "MOV", 2, vshader_mov, 0, 0},
481 {D3DSIO_ADD, "add", "ADD", 3, vshader_add, 0, 0},
482 {D3DSIO_SUB, "sub", "SUB", 3, vshader_sub, 0, 0},
483 {D3DSIO_MAD, "mad", "MAD", 4, vshader_mad, 0, 0},
484 {D3DSIO_MUL, "mul", "MUL", 3, vshader_mul, 0, 0},
485 {D3DSIO_RCP, "rcp", "RCP", 2, vshader_rcp, 0, 0},
486 {D3DSIO_RSQ, "rsq", "RSQ", 2, vshader_rsq, 0, 0},
487 {D3DSIO_DP3, "dp3", "DP3", 3, vshader_dp3, 0, 0},
488 {D3DSIO_DP4, "dp4", "DP4", 3, vshader_dp4, 0, 0},
489 {D3DSIO_MIN, "min", "MIN", 3, vshader_min, 0, 0},
490 {D3DSIO_MAX, "max", "MAX", 3, vshader_max, 0, 0},
491 {D3DSIO_SLT, "slt", "SLT", 3, vshader_slt, 0, 0},
492 {D3DSIO_SGE, "sge", "SGE", 3, vshader_sge, 0, 0},
493 {D3DSIO_ABS, "abs", "ABS", 2, vshader_abs, 0, 0},
494 {D3DSIO_EXP, "exp", "EX2", 2, vshader_exp, 0, 0},
495 {D3DSIO_LOG, "log", "LG2", 2, vshader_log, 0, 0},
496 {D3DSIO_LIT, "lit", "LIT", 2, vshader_lit, 0, 0},
497 {D3DSIO_DST, "dst", "DST", 3, vshader_dst, 0, 0},
498 {D3DSIO_LRP, "lrp", "LRP", 4, vshader_lrp, 0, 0},
499 {D3DSIO_FRC, "frc", "FRC", 2, vshader_frc, 0, 0},
500 {D3DSIO_M4x4, "m4x4", "undefined", 3, vshader_m4x4, 0, 0},
501 {D3DSIO_M4x3, "m4x3", "undefined", 3, vshader_m4x3, 0, 0},
502 {D3DSIO_M3x4, "m3x4", "undefined", 3, vshader_m3x4, 0, 0},
503 {D3DSIO_M3x3, "m3x3", "undefined", 3, vshader_m3x3, 0, 0},
504 {D3DSIO_M3x2, "m3x2", "undefined", 3, vshader_m3x2, 0, 0},
506 /** FIXME: use direct access so add the others opcodes as stubs */
507 /* DCL is a specil operation */
508 {D3DSIO_DCL, "dcl", NULL, 2, vshader_dcl, 0, 0},
509 {D3DSIO_POW, "pow", "POW", 3, vshader_pow, 0, 0},
510 {D3DSIO_CRS, "crs", "XPS", 3, vshader_crs, 0, 0},
511 /* TODO: sng can possibly be performed as
514 {D3DSIO_SGN, "sng", NULL, 2, vshader_sng, 0, 0},
515 /* TODO: xyz normalise can be performed as VS_ARB using one temporary register,
518 MUL vec.xyz, vec, tmp;
519 but I think this is better because it accounts for w properly.
525 {D3DSIO_NRM, "nrm", NULL, 2, vshader_nrm, 0, 0},
526 {D3DSIO_SINCOS, "sincos", NULL, 2, vshader_sincos, 0, 0},
528 /* Flow control - requires GLSL or software shaders */
529 {D3DSIO_REP , "rep", GLNAME_REQUIRE_GLSL, 1, vshader_rep, 0, 0},
530 {D3DSIO_ENDREP, "endrep", GLNAME_REQUIRE_GLSL, 0, vshader_endrep, 0, 0},
531 {D3DSIO_IF, "if", GLNAME_REQUIRE_GLSL, 1, vshader_if, 0, 0},
532 {D3DSIO_IFC, "ifc", GLNAME_REQUIRE_GLSL, 2, vshader_ifc, 0, 0},
533 {D3DSIO_ELSE, "else", GLNAME_REQUIRE_GLSL, 0, vshader_else, 0, 0},
534 {D3DSIO_ENDIF, "endif", GLNAME_REQUIRE_GLSL, 0, vshader_endif, 0, 0},
535 {D3DSIO_BREAK, "break", GLNAME_REQUIRE_GLSL, 0, vshader_break, 0, 0},
536 {D3DSIO_BREAKC, "breakc", GLNAME_REQUIRE_GLSL, 2, vshader_breakc, 0, 0},
537 {D3DSIO_BREAKP, "breakp", GLNAME_REQUIRE_GLSL, 1, vshader_breakp, 0, 0},
538 {D3DSIO_CALL, "call", GLNAME_REQUIRE_GLSL, 1, vshader_call, 0, 0},
539 {D3DSIO_CALLNZ, "callnz", GLNAME_REQUIRE_GLSL, 2, vshader_callnz, 0, 0},
540 {D3DSIO_LOOP, "loop", GLNAME_REQUIRE_GLSL, 2, vshader_loop, 0, 0},
541 {D3DSIO_RET, "ret", GLNAME_REQUIRE_GLSL, 0, vshader_ret, 0, 0},
542 {D3DSIO_ENDLOOP, "endloop", GLNAME_REQUIRE_GLSL, 0, vshader_endloop, 0, 0},
543 {D3DSIO_LABEL, "label", GLNAME_REQUIRE_GLSL, 1, vshader_label, 0, 0},
545 {D3DSIO_MOVA, "mova", GLNAME_REQUIRE_GLSL, 2, vshader_mova, 0, 0},
546 {D3DSIO_DEFB, "defb", GLNAME_REQUIRE_GLSL, 2, vshader_defb, 0, 0},
547 {D3DSIO_DEFI, "defi", GLNAME_REQUIRE_GLSL, 2, vshader_defi, 0, 0},
548 {D3DSIO_EXPP, "expp", "EXP", 2, vshader_expp, 0, 0},
549 {D3DSIO_LOGP, "logp", "LOG", 2, vshader_logp, 0, 0},
550 /* def is a special operation */
551 {D3DSIO_DEF, "def", NULL, 5, vshader_def, 0, 0},
552 {D3DSIO_SETP, "setp", GLNAME_REQUIRE_GLSL, 2, vshader_setp, 0, 0},
553 {D3DSIO_TEXLDL, "texdl", GLNAME_REQUIRE_GLSL, 2, vshader_texldl, 0, 0},
554 {0, NULL, NULL, 0, NULL, 0, 0}
557 inline static const SHADER_OPCODE* vshader_program_get_opcode(IWineD3DVertexShaderImpl *This, const DWORD code) {
559 const SHADER_OPCODE *shader_ins = This->baseShader.shader_ins;
561 /** TODO: use dichotomic search or hash table */
562 while (NULL != shader_ins[i].name) {
563 if ((code & D3DSI_OPCODE_MASK) == shader_ins[i].opcode) {
564 return &shader_ins[i];
568 FIXME("Unsupported opcode %lx\n",code);
572 inline static int vshader_program_get_regtype(const DWORD param) {
573 return (((param & D3DSP_REGTYPE_MASK) >> D3DSP_REGTYPE_SHIFT) |
574 ((param & D3DSP_REGTYPE_MASK2) >> D3DSP_REGTYPE_SHIFT2));
577 inline static void vshader_program_dump_param(const DWORD param, int input) {
578 static const char* rastout_reg_names[] = { "oPos", "oFog", "oPts" };
579 static const char swizzle_reg_chars[] = "xyzw";
581 DWORD reg = param & D3DSP_REGNUM_MASK;
582 DWORD regtype = vshader_program_get_regtype(param);
584 if ((param & D3DSP_SRCMOD_MASK) == D3DSPSM_NEG) TRACE("-");
588 TRACE("R[%lu]", reg);
594 TRACE("C[%s%lu]", (param & D3DVS_ADDRMODE_RELATIVE) ? "a0.x + " : "", reg);
596 case D3DSPR_ADDR: /*case D3DSPR_TEXTURE:*/
597 TRACE("a[%lu]", reg);
600 TRACE("%s", rastout_reg_names[reg]);
603 TRACE("oD[%lu]", reg);
605 case D3DSPR_TEXCRDOUT:
606 TRACE("oT[%lu]", reg);
609 FIXME("Unknown %lu %u reg %lu\n",regtype, D3DSPR_ATTROUT, reg);
614 /** operand output */
615 if ((param & D3DSP_WRITEMASK_ALL) != D3DSP_WRITEMASK_ALL) {
616 if (param & D3DSP_WRITEMASK_0) TRACE(".x");
617 if (param & D3DSP_WRITEMASK_1) TRACE(".y");
618 if (param & D3DSP_WRITEMASK_2) TRACE(".z");
619 if (param & D3DSP_WRITEMASK_3) TRACE(".w");
623 DWORD swizzle = (param & D3DVS_SWIZZLE_MASK) >> D3DVS_SWIZZLE_SHIFT;
624 DWORD swizzle_x = swizzle & 0x03;
625 DWORD swizzle_y = (swizzle >> 2) & 0x03;
626 DWORD swizzle_z = (swizzle >> 4) & 0x03;
627 DWORD swizzle_w = (swizzle >> 6) & 0x03;
629 * swizzle bits fields:
632 if ((D3DVS_NOSWIZZLE >> D3DVS_SWIZZLE_SHIFT) != swizzle) { /* ! D3DVS_NOSWIZZLE == 0xE4 << D3DVS_SWIZZLE_SHIFT */
633 if (swizzle_x == swizzle_y &&
634 swizzle_x == swizzle_z &&
635 swizzle_x == swizzle_w) {
636 TRACE(".%c", swizzle_reg_chars[swizzle_x]);
639 swizzle_reg_chars[swizzle_x],
640 swizzle_reg_chars[swizzle_y],
641 swizzle_reg_chars[swizzle_z],
642 swizzle_reg_chars[swizzle_w]);
648 inline static void vshader_program_dump_vs_param(const DWORD param, int input) {
649 static const char* rastout_reg_names[] = { "oPos", "oFog", "oPts" };
650 static const char swizzle_reg_chars[] = "xyzw";
652 DWORD reg = param & D3DSP_REGNUM_MASK;
653 DWORD regtype = vshader_program_get_regtype(param);
655 if ((param & D3DSP_SRCMOD_MASK) == D3DSPSM_NEG) TRACE("-");
657 switch (regtype /*<< D3DSP_REGTYPE_SHIFT*/) {
665 TRACE("c%s%lu", (param & D3DVS_ADDRMODE_RELATIVE) ? "a0.x + " : "", reg);
667 case D3DSPR_ADDR: /*case D3DSPR_TEXTURE:*/
671 TRACE("%s", rastout_reg_names[reg]);
676 case D3DSPR_TEXCRDOUT:
679 case D3DSPR_CONSTINT:
680 TRACE("i%s%lu", (param & D3DVS_ADDRMODE_RELATIVE) ? "a0.x + " : "", reg);
682 case D3DSPR_CONSTBOOL:
683 TRACE("b%s%lu", (param & D3DVS_ADDRMODE_RELATIVE) ? "a0.x + " : "", reg);
689 TRACE("aL%s%lu", (param & D3DVS_ADDRMODE_RELATIVE) ? "a0.x + " : "", reg);
695 FIXME("Unknown %lu reg %lu\n",regtype, reg);
700 /** operand output */
701 if ((param & D3DSP_WRITEMASK_ALL) != D3DSP_WRITEMASK_ALL) {
702 if (param & D3DSP_WRITEMASK_0) TRACE(".x");
703 if (param & D3DSP_WRITEMASK_1) TRACE(".y");
704 if (param & D3DSP_WRITEMASK_2) TRACE(".z");
705 if (param & D3DSP_WRITEMASK_3) TRACE(".w");
709 DWORD swizzle = (param & D3DVS_SWIZZLE_MASK) >> D3DVS_SWIZZLE_SHIFT;
710 DWORD swizzle_x = swizzle & 0x03;
711 DWORD swizzle_y = (swizzle >> 2) & 0x03;
712 DWORD swizzle_z = (swizzle >> 4) & 0x03;
713 DWORD swizzle_w = (swizzle >> 6) & 0x03;
715 * swizzle bits fields:
718 if ((D3DVS_NOSWIZZLE >> D3DVS_SWIZZLE_SHIFT) != swizzle) { /* ! D3DVS_NOSWIZZLE == 0xE4 << D3DVS_SWIZZLE_SHIFT */
719 if (swizzle_x == swizzle_y &&
720 swizzle_x == swizzle_z &&
721 swizzle_x == swizzle_w) {
722 TRACE(".%c", swizzle_reg_chars[swizzle_x]);
725 swizzle_reg_chars[swizzle_x],
726 swizzle_reg_chars[swizzle_y],
727 swizzle_reg_chars[swizzle_z],
728 swizzle_reg_chars[swizzle_w]);
734 inline static void vshader_program_dump_decl_usage(
735 IWineD3DVertexShaderImpl *This, DWORD decl, DWORD param) {
736 DWORD regtype = vshader_program_get_regtype(param);
740 if (regtype == D3DSPR_SAMPLER) {
741 DWORD ttype = decl & D3DSP_TEXTURETYPE_MASK;
744 case D3DSTT_2D: TRACE("2d "); break;
745 case D3DSTT_CUBE: TRACE("cube "); break;
746 case D3DSTT_VOLUME: TRACE("volume "); break;
747 default: TRACE("unknown_ttype(%08lx) ", ttype);
752 DWORD usage = decl & D3DSP_DCL_USAGE_MASK;
753 DWORD idx = (decl & D3DSP_DCL_USAGEINDEX_MASK) >> D3DSP_DCL_USAGEINDEX_SHIFT;
756 case D3DDECLUSAGE_POSITION:
757 TRACE("%s%ld ", "position", idx);
759 case D3DDECLUSAGE_BLENDINDICES:
760 TRACE("%s ", "blend");
762 case D3DDECLUSAGE_BLENDWEIGHT:
763 TRACE("%s ", "weight");
765 case D3DDECLUSAGE_NORMAL:
766 TRACE("%s%ld ", "normal", idx);
768 case D3DDECLUSAGE_PSIZE:
769 TRACE("%s ", "psize");
771 case D3DDECLUSAGE_COLOR:
773 TRACE("%s ", "color");
775 TRACE("%s ", "specular");
778 case D3DDECLUSAGE_TEXCOORD:
779 TRACE("%s%ld ", "texture", idx);
781 case D3DDECLUSAGE_TANGENT:
782 TRACE("%s ", "tangent");
784 case D3DDECLUSAGE_BINORMAL:
785 TRACE("%s ", "binormal");
787 case D3DDECLUSAGE_TESSFACTOR:
788 TRACE("%s ", "tessfactor");
790 case D3DDECLUSAGE_POSITIONT:
791 TRACE("%s%ld ", "positionT", idx);
793 case D3DDECLUSAGE_FOG:
796 case D3DDECLUSAGE_DEPTH:
797 TRACE("%s ", "depth");
799 case D3DDECLUSAGE_SAMPLE:
800 TRACE("%s ", "sample");
803 FIXME("Unrecognised dcl %08lx", usage);
808 inline static BOOL vshader_is_version_token(DWORD token) {
809 return 0xFFFE0000 == (token & 0xFFFE0000);
812 inline static BOOL vshader_is_comment_token(DWORD token) {
813 return D3DSIO_COMMENT == (token & D3DSI_OPCODE_MASK);
816 inline static void vshader_program_add_output_param_swizzle(const DWORD param, int is_color, char *hwLine) {
817 /** operand output */
818 if ((param & D3DSP_WRITEMASK_ALL) != D3DSP_WRITEMASK_ALL) {
820 if (param & D3DSP_WRITEMASK_0) { strcat(hwLine, "x"); }
821 if (param & D3DSP_WRITEMASK_1) { strcat(hwLine, "y"); }
822 if (param & D3DSP_WRITEMASK_2) { strcat(hwLine, "z"); }
823 if (param & D3DSP_WRITEMASK_3) { strcat(hwLine, "w"); }
827 inline static void vshader_program_add_input_param_swizzle(const DWORD param, int is_color, char *hwLine) {
828 static const char swizzle_reg_chars_color_fix[] = "zyxw";
829 static const char swizzle_reg_chars[] = "xyzw";
830 const char* swizzle_regs = NULL;
834 DWORD swizzle = (param & D3DVS_SWIZZLE_MASK) >> D3DVS_SWIZZLE_SHIFT;
835 DWORD swizzle_x = swizzle & 0x03;
836 DWORD swizzle_y = (swizzle >> 2) & 0x03;
837 DWORD swizzle_z = (swizzle >> 4) & 0x03;
838 DWORD swizzle_w = (swizzle >> 6) & 0x03;
841 swizzle_regs = swizzle_reg_chars_color_fix;
843 swizzle_regs = swizzle_reg_chars;
847 * swizzle bits fields:
850 if ((D3DVS_NOSWIZZLE >> D3DVS_SWIZZLE_SHIFT) == swizzle) { /* D3DVS_NOSWIZZLE == 0xE4 << D3DVS_SWIZZLE_SHIFT */
852 sprintf(tmpReg, ".%c%c%c%c",
853 swizzle_regs[swizzle_x],
854 swizzle_regs[swizzle_y],
855 swizzle_regs[swizzle_z],
856 swizzle_regs[swizzle_w]);
857 strcat(hwLine, tmpReg);
861 if (swizzle_x == swizzle_y &&
862 swizzle_x == swizzle_z &&
863 swizzle_x == swizzle_w)
865 sprintf(tmpReg, ".%c", swizzle_regs[swizzle_x]);
866 strcat(hwLine, tmpReg);
868 sprintf(tmpReg, ".%c%c%c%c",
869 swizzle_regs[swizzle_x],
870 swizzle_regs[swizzle_y],
871 swizzle_regs[swizzle_z],
872 swizzle_regs[swizzle_w]);
873 strcat(hwLine, tmpReg);
877 inline static void vshader_program_add_param(IWineD3DVertexShaderImpl *This, const DWORD param, BOOL is_input, char *hwLine) {
878 /* oPos, oFog and oPts in D3D */
879 static const char* hwrastout_reg_names[] = { "result.position", "result.fogcoord", "result.pointsize" };
881 DWORD reg = param & D3DSP_REGNUM_MASK;
882 DWORD regtype = vshader_program_get_regtype(param);
884 BOOL is_color = FALSE;
886 if ((param & D3DSP_SRCMOD_MASK) == D3DSPSM_NEG) {
887 strcat(hwLine, " -");
894 sprintf(tmpReg, "T%lu", reg);
895 strcat(hwLine, tmpReg);
898 if (reg == This->arrayUsageMap[WINED3DSHADERDECLUSAGE_DIFFUSE]
899 || reg == This->arrayUsageMap[WINED3DSHADERDECLUSAGE_SPECULAR]) {
902 /* if the attributes come in as named dcl's then use a named vertex (called namedVertexN) */
903 if (This->namedArrays) {
904 sprintf(tmpReg, "namedVertex%lu", reg);
906 /* otherwise the input is on a numbered attribute so use opengl numbered attributes */
907 sprintf(tmpReg, "vertex.attrib[%lu]", reg);
909 strcat(hwLine, tmpReg);
912 /* FIXME: some constants are named so we need a constants map*/
913 if (This->constantsUsedBitmap[reg] == VS_CONSTANT_CONSTANT) {
914 if (param & D3DVS_ADDRMODE_RELATIVE) {
915 FIXME("Relative addressing not expected for a named constant %lu\n", reg);
917 sprintf(tmpReg, "const%lu", reg);
919 sprintf(tmpReg, "C[%s%lu]", (param & D3DVS_ADDRMODE_RELATIVE) ? "A0.x + " : "", reg);
921 strcat(hwLine, tmpReg);
923 case D3DSPR_ADDR: /*case D3DSPR_TEXTURE:*/
924 sprintf(tmpReg, "A%lu", reg);
925 strcat(hwLine, tmpReg);
928 sprintf(tmpReg, "%s", hwrastout_reg_names[reg]);
929 strcat(hwLine, tmpReg);
933 strcat(hwLine, "result.color.primary");
935 strcat(hwLine, "result.color.secondary");
938 case D3DSPR_TEXCRDOUT:
939 sprintf(tmpReg, "result.texcoord[%lu]", reg);
940 strcat(hwLine, tmpReg);
943 FIXME("Unknown reg type %ld %ld\n", regtype, reg);
948 vshader_program_add_output_param_swizzle(param, is_color, hwLine);
950 vshader_program_add_input_param_swizzle(param, is_color, hwLine);
954 DWORD MacroExpansion[4*4];
956 int ExpandMxMacro(DWORD macro_opcode, const DWORD* args) {
961 switch(macro_opcode) {
985 for (i = 0; i < nComponents; i++) {
986 MacroExpansion[i*4+0] = opcode;
987 MacroExpansion[i*4+1] = ((*args) & ~D3DSP_WRITEMASK_ALL)|(D3DSP_WRITEMASK_0<<i);
988 MacroExpansion[i*4+2] = *(args+1);
989 MacroExpansion[i*4+3] = (*(args+2))+i;
994 static void parse_decl_usage(IWineD3DVertexShaderImpl *This, INT usage, INT arrayNo)
996 switch(usage & 0xFFFF) {
997 case D3DDECLUSAGE_POSITION:
998 if((usage & 0xF0000) >> 16 == 0) { /* tween data */
999 TRACE("Setting position to %d\n", arrayNo);
1000 This->arrayUsageMap[WINED3DSHADERDECLUSAGE_POSITION] = arrayNo;
1001 This->namedArrays = TRUE;
1003 /* TODO: position indexes go from 0-8!!*/
1004 TRACE("Setting position 2 to %d because usage = %d\n", arrayNo, (usage & 0xF0000) >> 16);
1005 /* robots uses positions up to 8, the position arrays are just packed.*/
1006 if ((usage & 0xF0000) >> 16 > 1) {
1007 TRACE("Loaded for position %d (greater than 2)\n", (usage & 0xF0000) >> 16);
1009 This->arrayUsageMap[WINED3DSHADERDECLUSAGE_POSITION2 + ((usage & 0xF0000) >> 16) -1] = arrayNo;
1010 This->declaredArrays = TRUE;
1013 case D3DDECLUSAGE_BLENDINDICES:
1014 /* not supported by openGL */
1015 TRACE("Setting BLENDINDICES to %d\n", arrayNo);
1016 This->arrayUsageMap[WINED3DSHADERDECLUSAGE_BLENDINDICES] = arrayNo;
1017 This->declaredArrays = TRUE;
1018 if ((usage & 0xF0000) >> 16 != 0) FIXME("Extended BLENDINDICES\n");
1020 case D3DDECLUSAGE_BLENDWEIGHT:
1021 TRACE("Setting BLENDWEIGHT to %d\n", arrayNo);
1022 This->arrayUsageMap[WINED3DSHADERDECLUSAGE_BLENDWEIGHT] = arrayNo;
1023 This->namedArrays = TRUE;
1024 if ((usage & 0xF0000) >> 16 != 0) FIXME("Extended blend weights\n");
1026 case D3DDECLUSAGE_NORMAL:
1027 if((usage & 0xF0000) >> 16 == 0) { /* tween data */
1028 TRACE("Setting normal to %d\n", arrayNo);
1029 This->arrayUsageMap[WINED3DSHADERDECLUSAGE_NORMAL] = arrayNo;
1030 This->namedArrays = TRUE;
1032 TRACE("Setting normal 2 to %d because usage = %d\n", arrayNo, (usage & 0xF0000) >> 16);
1033 This->arrayUsageMap[WINED3DSHADERDECLUSAGE_NORMAL2] = arrayNo;
1034 This->declaredArrays = TRUE;
1037 case D3DDECLUSAGE_PSIZE:
1038 TRACE("Setting PSIZE to %d\n", arrayNo);
1039 This->arrayUsageMap[WINED3DSHADERDECLUSAGE_PSIZE] = arrayNo;
1040 This->namedArrays = TRUE;
1041 if ((usage & 0xF0000) >> 16 != 0) FIXME("Extended PSIZE\n");
1043 case D3DDECLUSAGE_COLOR:
1044 if((usage & 0xF0000) >> 16 == 0) {
1045 TRACE("Setting DIFFUSE to %d\n", arrayNo);
1046 This->arrayUsageMap[WINED3DSHADERDECLUSAGE_DIFFUSE] = arrayNo;
1047 This->namedArrays = TRUE;
1049 TRACE("Setting SPECULAR to %d\n", arrayNo);
1050 This->arrayUsageMap[WINED3DSHADERDECLUSAGE_SPECULAR] = arrayNo;
1051 This->namedArrays = TRUE;
1054 case D3DDECLUSAGE_TEXCOORD:
1055 This->namedArrays = TRUE;
1056 /* only 7 texture coords have been designed for, so run a quick sanity check */
1057 if ((usage & 0xF0000) >> 16 > 7) {
1058 FIXME("(%p) : Program uses texture coordinate %d but only 0-7 have been implemented\n", This, (usage & 0xF0000) >> 16);
1060 TRACE("Setting TEXCOORD %d to %d\n", ((usage & 0xF0000) >> 16), arrayNo);
1061 This->arrayUsageMap[WINED3DSHADERDECLUSAGE_TEXCOORD0 + ((usage & 0xF0000) >> 16)] = arrayNo;
1064 /* The following aren't supported by openGL,
1065 if we get them then everything needs to be mapped to numbered attributes instead of named ones.
1066 this should be caught in the first pass */
1067 case D3DDECLUSAGE_TANGENT:
1068 TRACE("Setting TANGENT to %d\n", arrayNo);
1069 This->arrayUsageMap[WINED3DSHADERDECLUSAGE_TANGENT] = arrayNo;
1070 This->declaredArrays = TRUE;
1072 case D3DDECLUSAGE_BINORMAL:
1073 TRACE("Setting BINORMAL to %d\n", arrayNo);
1074 This->arrayUsageMap[WINED3DSHADERDECLUSAGE_BINORMAL] = arrayNo;
1075 This->declaredArrays = TRUE;
1077 case D3DDECLUSAGE_TESSFACTOR:
1078 TRACE("Setting TESSFACTOR to %d\n", arrayNo);
1079 This->arrayUsageMap[WINED3DSHADERDECLUSAGE_TESSFACTOR] = arrayNo;
1080 This->declaredArrays = TRUE;
1082 case D3DDECLUSAGE_POSITIONT:
1083 if((usage & 0xF0000) >> 16 == 0) { /* tween data */
1084 FIXME("Setting positiont to %d\n", arrayNo);
1085 This->arrayUsageMap[WINED3DSHADERDECLUSAGE_POSITIONT] = arrayNo;
1086 This->namedArrays = TRUE;
1088 FIXME("Setting positiont 2 to %d because usage = %d\n", arrayNo, (usage & 0xF0000) >> 16);
1089 This->arrayUsageMap[WINED3DSHADERDECLUSAGE_POSITIONT2] = arrayNo;
1090 This->declaredArrays = TRUE;
1091 if ((usage & 0xF0000) >> 16 != 0) FIXME("Extended positiont\n");
1094 case D3DDECLUSAGE_FOG:
1095 /* supported by OpenGL */
1096 TRACE("Setting FOG to %d\n", arrayNo);
1097 This->arrayUsageMap[WINED3DSHADERDECLUSAGE_FOG] = arrayNo;
1098 This->namedArrays = TRUE;
1100 case D3DDECLUSAGE_DEPTH:
1101 TRACE("Setting DEPTH to %d\n", arrayNo);
1102 This->arrayUsageMap[WINED3DSHADERDECLUSAGE_DEPTH] = arrayNo;
1103 This->declaredArrays = TRUE;
1105 case D3DDECLUSAGE_SAMPLE:
1106 TRACE("Setting SAMPLE to %d\n", arrayNo);
1107 This->arrayUsageMap[WINED3DSHADERDECLUSAGE_SAMPLE] = arrayNo;
1108 This->declaredArrays = TRUE;
1111 FIXME("Unrecognised dcl %08x", usage & 0xFFFF);
1116 * Function parser ...
1119 inline static VOID IWineD3DVertexShaderImpl_GenerateProgramArbHW(IWineD3DVertexShader *iface, CONST DWORD* pFunction) {
1120 IWineD3DVertexShaderImpl *This = (IWineD3DVertexShaderImpl *)iface;
1121 const DWORD* pToken = pFunction;
1122 const DWORD* pSavedToken = NULL;
1123 const SHADER_OPCODE* curOpcode = NULL;
1126 unsigned lineNum = 0;
1127 char *pgmStr = NULL;
1129 DWORD nUseAddressRegister = 0;
1130 DWORD nUseTempRegister = 0;
1134 #if 0 /* TODO: loope register (just another address register ) */
1135 BOOL hasLoops = FALSE;
1138 #define PGMSIZE 65535
1139 /* Keep a running length for pgmStr so that we don't have to caculate strlen every time we concatanate */
1142 #if 0 /* FIXME: Use the buffer that is held by the device, this is ok since fixups will be skipped for software shaders
1143 it also requires entering a critical section but cuts down the runtime footprint of wined3d and any memory fragmentation that may occur... */
1144 if (This->device->fixupVertexBufferSize < PGMSIZE) {
1145 HeapFree(GetProcessHeap(), 0, This->fixupVertexBuffer);
1146 This->fixupVertexBuffer = HeapAlloc(GetProcessHeap() , 0, PGMSIZE);
1147 This->fixupVertexBufferSize = PGMSIZE;
1148 This->fixupVertexBuffer[0] = 0;
1150 pgmStr = This->device->fixupVertexBuffer;
1152 #define PNSTRCAT(_pgmStr, _tmpLine) { \
1153 int _tmpLineLen = strlen(_tmpLine); \
1154 if(_tmpLineLen + pgmLength > PGMSIZE) { \
1155 ERR("The buffer allocated for the vertex program string pgmStr is too small at %d bytes, at least %d bytes in total are required.\n", PGMSIZE, _tmpLineLen + pgmLength); \
1157 memcpy(_pgmStr + pgmLength, _tmpLine, _tmpLineLen); \
1159 pgmLength += _tmpLineLen; \
1162 pgmStr = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, 65535); /* 64kb should be enough */
1163 /* Initialise the shader */
1164 This->namedArrays = FALSE;
1165 This->declaredArrays = FALSE;
1166 for (i = 0; i < WINED3DSHADERDECLUSAGE_MAX_USAGE; i++) {
1167 This->arrayUsageMap[i] = -1;
1169 /* set all the tmpsUsed to not used */
1170 memset(tmpsUsed, FALSE , sizeof(tmpsUsed));
1172 /* TODO: renumbering of attributes if the values are higher than the highest supported attribute but the total number of attributes is less than the highest supported attribute */
1173 This->highestConstant = -1;
1176 * First pass to determine what we need to declare:
1177 * - Temporary variables
1178 * - Address variables
1180 if (NULL != pToken) {
1181 while (D3DVS_END() != *pToken) {
1182 if (vshader_is_version_token(*pToken)) {
1187 if (vshader_is_comment_token(*pToken)) { /** comment */
1188 DWORD comment_len = (*pToken & D3DSI_COMMENTSIZE_MASK) >> D3DSI_COMMENTSIZE_SHIFT;
1190 pToken += comment_len;
1193 curOpcode = vshader_program_get_opcode(This, *pToken);
1198 if (NULL == curOpcode) {
1199 while (*pToken & 0x80000000) {
1200 FIXME("unrecognized opcode: %08lx\n", *pToken);
1201 /* skip unrecognized opcode */
1205 if (curOpcode->opcode == D3DSIO_DCL){
1206 INT usage = *pToken++;
1207 INT arrayNo = (*pToken++ & D3DSP_REGNUM_MASK);
1208 parse_decl_usage(This, usage, arrayNo);
1209 } else if(curOpcode->opcode == D3DSIO_DEF) {
1210 This->constantsUsedBitmap[*pToken & 0xFF] = VS_CONSTANT_CONSTANT;
1211 FIXME("Constant %ld\n", *pToken & 0xFF);
1219 /* Check to see if and tmp or addressing redisters are used */
1220 if (curOpcode->num_params > 0) {
1221 regtype = vshader_program_get_regtype(*pToken);
1222 reg = ((*pToken) & D3DSP_REGNUM_MASK);
1223 if (D3DSPR_ADDR == regtype && nUseAddressRegister <= reg) nUseAddressRegister = reg + 1;
1224 if (D3DSPR_TEMP == regtype){
1225 tmpsUsed[reg] = TRUE;
1226 if(nUseTempRegister <= reg) nUseTempRegister = reg + 1;
1229 for (i = 1; i < curOpcode->num_params; ++i) {
1230 regtype = vshader_program_get_regtype(*pToken);
1231 reg = ((*pToken) & D3DSP_REGNUM_MASK);
1232 if (D3DSPR_ADDR == regtype && nUseAddressRegister <= reg) nUseAddressRegister = reg + 1;
1233 if (D3DSPR_TEMP == regtype){
1234 tmpsUsed[reg] = TRUE;
1235 if(nUseTempRegister <= reg) nUseTempRegister = reg + 1;
1241 #if 1 /* TODO: if the shaders uses calls or loops then we need to convert the shader into glsl */
1242 if (curOpcode->glname == GLNAME_REQUIRE_GLSL) {
1243 FIXME("This shader requires gl shader language support\n");
1245 This->shaderLanguage = GLSHADER_GLSL;
1253 #define VSHADER_ALWAYS_NUMBERED
1256 #ifdef VSHADER_ALWAYS_NUMBERED /* handy for debugging using numbered arrays instead of named arrays */
1257 /* TODO: using numbered arrays for software shaders makes things easier */
1258 This->declaredArrays = TRUE;
1261 /* named arrays and declared arrays are mutually exclusive */
1262 if (This->declaredArrays) {
1263 This->namedArrays = FALSE;
1266 nUseAddressRegister < = GL_MAX_PROGRAM_ADDRESS_REGISTERS_AR
1267 nUseTempRegister <= GL_MAX_PROGRAM_LOCAL_PARAMETERS_ARB
1270 /** second pass, now generate */
1273 if (NULL != pToken) {
1276 if ((nRemInstr >= 0) && (--nRemInstr == -1))
1277 /* Macro is finished, continue normal path */
1278 pToken = pSavedToken;
1279 if (D3DVS_END() == *pToken)
1282 if (vshader_is_version_token(*pToken)) { /** version */
1283 /* Extract version *10 into integer value (ie. 1.0 == 10, 1.1==11 etc */
1284 int version = (((*pToken >> 8) & 0x0F) * 10) + (*pToken & 0x0F);
1288 TRACE("found version token vs.%lu.%lu;\n", (*pToken >> 8) & 0x0F, (*pToken & 0x0F));
1290 /* Each release of vertex shaders has had different numbers of temp registers */
1293 case 11: numTemps=12;
1294 numConstants=96;/* min(GL_LIMITS(constants),96) */
1296 /* FIXME: if there are no calls or loops then use ARBvp1 otherwise use GLSL instead
1297 TODO: see if there are any operations in vs2/3 that aren't supported by ARBvp
1298 TODO: only map the maximum possible number of constants supported by openGL and not the maximum required by d3d (even better only map the used constants)*/
1299 case 20: numTemps=12; /* min(GL_LIMITS(temps),12) */
1300 numConstants=96; /* min(GL_LIMITS(constants),256) */
1301 FIXME("No work done yet to support vs2.0 in hw\n");
1303 case 21: numTemps=12; /* min(GL_LIMITS(temps),12) */
1304 numConstants=96; /* min(GL_LIMITS(constants),256) */
1305 FIXME("No work done yet to support vs2.1 in hw\n");
1307 case 30: numTemps=32; /* min(GL_LIMITS(temps),32) */
1308 numConstants=96;/* min(GL_LIMITS(constants),256) */
1309 FIXME("No work done yet to support vs3.0 in hw\n");
1312 numTemps=12;/* min(GL_LIMITS(temps),12) */
1313 numConstants=96;/* min(GL_LIMITS(constants),96) */
1314 FIXME("Unrecognized vertex shader version %d!\n", version);
1318 /* FIXME: if jumps are used, use GLSL, else use ARB_vertex_program */
1319 strcpy(tmpLine, "!!ARBvp1.0\n");
1320 TRACE("GL HW (%u) : %s", pgmLength, tmpLine); /* Don't add \n to this line as already in tmpLine */
1321 PNSTRCAT(pgmStr, tmpLine);
1324 /* This should be a bitmap so that only temp registers that are used are declared. */
1325 for (i = 0; i < nUseTempRegister /* we should check numTemps here */ ; i++) {
1326 if (tmpsUsed[i]) { /* only write out the temps if they are actually in use */
1327 sprintf(tmpLine, "TEMP T%ld;\n", i);
1329 TRACE("GL HW (%u, %u) : %s", lineNum, pgmLength, tmpLine); /* Don't add \n to this line as already in tmpLine */
1330 PNSTRCAT(pgmStr, tmpLine);
1334 /* TODO: loop register counts as an address register */
1335 for (i = 0; i < nUseAddressRegister; i++) {
1336 sprintf(tmpLine, "ADDRESS A%ld;\n", i);
1338 TRACE("GL HW (%u, %u) : %s", lineNum, pgmLength, tmpLine); /* Don't add \n to this line as already in tmpLine */
1339 PNSTRCAT(pgmStr, tmpLine);
1342 /* Due to the dynamic constants binding mechanism, we need to declare
1343 * all the constants for relative addressing. */
1344 /* Mesa supports only 95 constants for VS1.X although we should have at least 96. */
1345 if (GL_VEND(MESA) || GL_VEND(WINE)) {
1348 /* FIXME: We should be counting the number of constants in the first pass and then validating that many are supported
1349 Looking at some of the shaders in use by applications we'd need to create a list of all used env variables
1351 sprintf(tmpLine, "PARAM C[%d] = { program.env[0..%d] };\n", numConstants, numConstants - 1);
1352 TRACE("GL HW (%u,%u) : %s", lineNum, pgmLength, tmpLine); /* Don't add \n to this line as already in tmpLine */
1353 PNSTRCAT(pgmStr, tmpLine);
1360 if (vshader_is_comment_token(*pToken)) { /** comment */
1361 DWORD comment_len = (*pToken & D3DSI_COMMENTSIZE_MASK) >> D3DSI_COMMENTSIZE_SHIFT;
1363 TRACE("#%s\n", (char*)pToken);
1364 pToken += comment_len;
1368 curOpcode = vshader_program_get_opcode(This, *pToken);
1370 if (NULL == curOpcode) {
1371 /* unknown current opcode ... (shouldn't be any!) */
1372 while (*pToken & 0x80000000) {
1373 FIXME("unrecognized opcode: %08lx\n", *pToken);
1376 } else if (GLNAME_REQUIRE_GLSL == curOpcode->glname) {
1377 /* if the token isn't supported by this cross compiler then skip it and its parameters */
1379 FIXME("Token %s requires greater functionality than Vertex_Progarm_ARB supports\n", curOpcode->name);
1380 pToken += curOpcode->num_params;
1382 } else if (D3DSIO_DEF == curOpcode->opcode) {
1384 /* Handle definitions here, they don't fit well with the
1385 * other instructions below [for now ] */
1388 sprintf(tmpLine, "PARAM const%lu = {", *pToken & 0xFF);
1389 sprintf(tmpChar,"%f ,", *(float *) (pToken + 1));
1390 strcat(tmpLine, tmpChar);
1391 sprintf(tmpChar,"%f ,", *(float *) (pToken + 2));
1392 strcat(tmpLine, tmpChar);
1393 sprintf(tmpChar,"%f ,", *(float *) (pToken + 3));
1394 strcat(tmpLine, tmpChar);
1395 sprintf(tmpChar,"%f}", *(float *) (pToken + 4));
1396 strcat(tmpLine, tmpChar);
1398 strcat(tmpLine,";\n");
1400 TRACE("GL HW (%u, %u) : %s", lineNum, pgmLength, tmpLine); /* Don't add \n to this line as already in tmpLine */
1401 PNSTRCAT(pgmStr, tmpLine);
1406 } else if (D3DSIO_DCL == curOpcode->opcode) {
1408 /* Handle declarations here, they don't fit well with the
1409 * other instructions below [for now ] */
1411 if (This->namedArrays) {
1412 const char* attribName = "undefined";
1413 switch(*pToken & 0xFFFF) {
1414 case D3DDECLUSAGE_POSITION:
1415 attribName = "vertex.position";
1417 case D3DDECLUSAGE_BLENDINDICES:
1418 /* not supported by openGL */
1419 attribName = "vertex.blend";
1421 case D3DDECLUSAGE_BLENDWEIGHT:
1422 attribName = "vertex.weight";
1424 case D3DDECLUSAGE_NORMAL:
1425 attribName = "vertex.normal";
1427 case D3DDECLUSAGE_PSIZE:
1428 attribName = "vertex.psize";
1430 case D3DDECLUSAGE_COLOR:
1431 if((*pToken & 0xF0000) >> 16 == 0) {
1432 attribName = "vertex.color";
1434 attribName = "vertex.color.secondary";
1437 case D3DDECLUSAGE_TEXCOORD:
1441 sprintf(tmpChar,"vertex.texcoord[%lu]",(*pToken & 0xF0000) >> 16);
1442 attribName = tmpChar;
1445 /* The following aren't directly supported by openGL, so shouldn't come up using namedarrays. */
1446 case D3DDECLUSAGE_TANGENT:
1447 attribName = "vertex.tangent";
1449 case D3DDECLUSAGE_BINORMAL:
1450 attribName = "vertex.binormal";
1452 case D3DDECLUSAGE_TESSFACTOR:
1453 attribName = "vertex.tessfactor";
1455 case D3DDECLUSAGE_POSITIONT:
1456 attribName = "vertex.possitionT";
1458 case D3DDECLUSAGE_FOG:
1459 attribName = "vertex.fogcoord";
1461 case D3DDECLUSAGE_DEPTH:
1462 attribName = "vertex.depth";
1464 case D3DDECLUSAGE_SAMPLE:
1465 attribName = "vertex.sample";
1468 FIXME("Unrecognised dcl %08lx", *pToken & 0xFFFF);
1473 sprintf(tmpLine, "ATTRIB ");
1474 vshader_program_add_param(This, *pToken, FALSE, tmpLine);
1476 sprintf(tmpChar," = %s", attribName);
1477 strcat(tmpLine, tmpChar);
1478 strcat(tmpLine,";\n");
1480 if (This->namedArrays) {
1481 TRACE("GL HW (%u, %u) : %s", lineNum, pgmLength, tmpLine);
1482 PNSTRCAT(pgmStr, tmpLine);
1485 TRACE("GL HW (%u, %u) : %s", lineNum, pgmLength, tmpLine);
1489 /* eat the token so it doesn't generate a warning */
1497 /* Common Processing: ([instr] [dst] [src]*) */
1499 switch (curOpcode->opcode) {
1503 /* Address registers must be loaded with the ARL instruction */
1504 if (vshader_program_get_regtype(*pToken) == D3DSPR_ADDR) {
1505 if (((*pToken) & D3DSP_REGNUM_MASK) < nUseAddressRegister) {
1506 strcpy(tmpLine, "ARL");
1509 FIXME("(%p) Try to load A%ld an undeclared address register!\n",
1510 This, ((*pToken) & D3DSP_REGNUM_MASK));
1532 strcpy(tmpLine, curOpcode->glname);
1539 /* Expand the macro and get nusprintf(tmpLine,mber of generated instruction */
1540 nRemInstr = ExpandMxMacro(curOpcode->opcode, pToken);
1541 /* Save point to next instruction */
1542 pSavedToken = pToken + 3;
1543 /* Execute expanded macro */
1544 pToken = MacroExpansion;
1548 if (curOpcode->glname == GLNAME_REQUIRE_GLSL) {
1549 FIXME("Opcode %s requires Gl Shader languange 1.0\n", curOpcode->name);
1551 FIXME("Can't handle opcode %s in hwShader\n", curOpcode->name);
1554 pToken += curOpcode->num_params;
1558 if (curOpcode->num_params > 0) {
1559 vshader_program_add_param(This, *pToken, FALSE, tmpLine);
1562 for (i = 1; i < curOpcode->num_params; ++i) {
1563 strcat(tmpLine, ",");
1564 vshader_program_add_param(This, *pToken, TRUE, tmpLine);
1568 strcat(tmpLine,";\n");
1570 TRACE("GL HW (%u, %u) : %s", lineNum, pgmLength, tmpLine); /* Don't add \n to this line as already in tmpLine */
1571 PNSTRCAT(pgmStr, tmpLine);
1575 strcpy(tmpLine, "END\n");
1577 TRACE("GL HW (%u, %u) : %s", lineNum, pgmLength, tmpLine); /* Don't add \n to this line as already in tmpLine */
1578 PNSTRCAT(pgmStr, tmpLine);
1581 /* finally null terminate the pgmStr*/
1582 pgmStr[pgmLength] = 0;
1584 /* Check that Vertex Shaders are supported */
1585 if (GL_SUPPORT(ARB_VERTEX_PROGRAM)) {
1586 /* Create the hw shader */
1587 /* TODO: change to resource.glObjectHandel or something like that */
1588 GL_EXTCALL(glGenProgramsARB(1, &This->baseShader.prgId));
1589 TRACE("Creating a hw vertex shader, prg=%d\n", This->baseShader.prgId);
1590 GL_EXTCALL(glBindProgramARB(GL_VERTEX_PROGRAM_ARB, This->baseShader.prgId));
1592 /* Create the program and check for errors */
1593 GL_EXTCALL(glProgramStringARB(GL_VERTEX_PROGRAM_ARB, GL_PROGRAM_FORMAT_ASCII_ARB, strlen(pgmStr)/*pgmLength*/, pgmStr));
1594 if (glGetError() == GL_INVALID_OPERATION) {
1596 glGetIntegerv(GL_PROGRAM_ERROR_POSITION_ARB, &errPos);
1597 FIXME("HW VertexShader Error at position %d: %s\n",
1598 errPos, debugstr_a((const char *)glGetString(GL_PROGRAM_ERROR_STRING_ARB)));
1599 This->baseShader.prgId = -1;
1602 #if 1 /* if were using the data buffer of device then we don't need to free it */
1603 HeapFree(GetProcessHeap(), 0, pgmStr);
1608 BOOL IWineD3DVertexShaderImpl_ExecuteHAL(IWineD3DVertexShader* iface, WINEVSHADERINPUTDATA* input, WINEVSHADEROUTPUTDATA* output) {
1610 * TODO: use the NV_vertex_program (or 1_1) extension
1611 * and specifics vendors (ARB_vertex_program??) variants for it
1616 HRESULT WINAPI IWineD3DVertexShaderImpl_ExecuteSW(IWineD3DVertexShader* iface, WINEVSHADERINPUTDATA* input, WINEVSHADEROUTPUTDATA* output) {
1617 IWineD3DVertexShaderImpl *This = (IWineD3DVertexShaderImpl *)iface;
1619 /** Vertex Shader Temporary Registers */
1620 WINED3DSHADERVECTOR R[12];
1621 /*D3DSHADERSCALAR A0;*/
1622 WINED3DSHADERVECTOR A[1];
1623 /** temporary Vector for modifier management */
1624 WINED3DSHADERVECTOR d;
1625 WINED3DSHADERVECTOR s[3];
1627 const DWORD* pToken = This->baseShader.function;
1628 const SHADER_OPCODE* curOpcode = NULL;
1629 /** functions parameters */
1630 WINED3DSHADERVECTOR* p[4];
1631 WINED3DSHADERVECTOR* p_send[4];
1634 /** init temporary register */
1635 memset(R, 0, 12 * sizeof(WINED3DSHADERVECTOR));
1637 /* vshader_program_parse(vshader); */
1638 #if 0 /* Must not be 1 in cvs */
1640 TRACE_VSVECTOR(This->data->C[0]);
1641 TRACE_VSVECTOR(This->data->C[1]);
1642 TRACE_VSVECTOR(This->data->C[2]);
1643 TRACE_VSVECTOR(This->data->C[3]);
1644 TRACE_VSVECTOR(This->data->C[4]);
1645 TRACE_VSVECTOR(This->data->C[5]);
1646 TRACE_VSVECTOR(This->data->C[6]);
1647 TRACE_VSVECTOR(This->data->C[7]);
1648 TRACE_VSVECTOR(This->data->C[8]);
1649 TRACE_VSVECTOR(This->data->C[64]);
1650 TRACE_VSVECTOR(input->V[D3DVSDE_POSITION]);
1651 TRACE_VSVECTOR(input->V[D3DVSDE_BLENDWEIGHT]);
1652 TRACE_VSVECTOR(input->V[D3DVSDE_BLENDINDICES]);
1653 TRACE_VSVECTOR(input->V[D3DVSDE_NORMAL]);
1654 TRACE_VSVECTOR(input->V[D3DVSDE_PSIZE]);
1655 TRACE_VSVECTOR(input->V[D3DVSDE_DIFFUSE]);
1656 TRACE_VSVECTOR(input->V[D3DVSDE_SPECULAR]);
1657 TRACE_VSVECTOR(input->V[D3DVSDE_TEXCOORD0]);
1658 TRACE_VSVECTOR(input->V[D3DVSDE_TEXCOORD1]);
1661 TRACE_VSVECTOR(vshader->data->C[64]);
1662 /* TODO: Run through all the tokens and find and labels, if, endifs, loops etc...., and make a labels list */
1664 /* the first dword is the version tag */
1665 /* TODO: parse it */
1667 if (vshader_is_version_token(*pToken)) { /** version */
1670 while (D3DVS_END() != *pToken) {
1671 if (vshader_is_comment_token(*pToken)) { /** comment */
1672 DWORD comment_len = (*pToken & D3DSI_COMMENTSIZE_MASK) >> D3DSI_COMMENTSIZE_SHIFT;
1674 pToken += comment_len;
1677 curOpcode = vshader_program_get_opcode(This, *pToken);
1679 if (NULL == curOpcode) {
1681 /* unknown current opcode ... */
1682 /* TODO: Think of a name for 0x80000000 and replace its use with a constant */
1683 while (*pToken & 0x80000000) {
1685 FIXME("unrecognized opcode: pos=%d token=%08lX\n", (pToken - 1) - This->baseShader.function, *(pToken - 1));
1687 FIXME("unrecognized opcode param: pos=%d token=%08lX what=", pToken - This->baseShader.function, *pToken);
1688 vshader_program_dump_param(*pToken, i);
1695 if (curOpcode->num_params > 0) {
1696 /* TRACE(">> execting opcode: pos=%d opcode_name=%s token=%08lX\n", pToken - vshader->function, curOpcode->name, *pToken); */
1697 for (i = 0; i < curOpcode->num_params; ++i) {
1698 DWORD reg = pToken[i] & D3DSP_REGNUM_MASK;
1699 DWORD regtype = vshader_program_get_regtype(pToken[i]);
1701 switch (regtype /*<< D3DSP_REGTYPE_SHIFT*/) {
1703 /* TRACE("p[%d]=R[%d]\n", i, reg); */
1707 /* TRACE("p[%d]=V[%s]\n", i, VertexShaderDeclRegister[reg]); */
1708 p[i] = &input->V[reg];
1711 if (pToken[i] & D3DVS_ADDRMODE_RELATIVE) {
1712 p[i] = &This->data->C[(DWORD) A[0].x + reg];
1714 p[i] = &This->data->C[reg];
1717 case D3DSPR_ADDR: /* case D3DSPR_TEXTURE: */
1719 ERR("cannot handle address registers != a0, forcing use of a0\n");
1722 /* TRACE("p[%d]=A[%d]\n", i, reg); */
1725 case D3DSPR_RASTOUT:
1727 case D3DSRO_POSITION:
1728 p[i] = &output->oPos;
1731 p[i] = &output->oFog;
1733 case D3DSRO_POINT_SIZE:
1734 p[i] = &output->oPts;
1738 case D3DSPR_ATTROUT:
1739 /* TRACE("p[%d]=oD[%d]\n", i, reg); */
1740 p[i] = &output->oD[reg];
1742 case D3DSPR_TEXCRDOUT:
1743 /* TRACE("p[%d]=oT[%d]\n", i, reg); */
1744 p[i] = &output->oT[reg];
1746 /* TODO Decls and defs */
1755 if (i > 0) { /* input reg */
1756 DWORD swizzle = (pToken[i] & D3DVS_SWIZZLE_MASK) >> D3DVS_SWIZZLE_SHIFT;
1757 UINT isNegative = ((pToken[i] & D3DSP_SRCMOD_MASK) == D3DSPSM_NEG);
1759 if (!isNegative && (D3DVS_NOSWIZZLE >> D3DVS_SWIZZLE_SHIFT) == swizzle) {
1760 /* TRACE("p[%d] not swizzled\n", i); */
1763 DWORD swizzle_x = swizzle & 0x03;
1764 DWORD swizzle_y = (swizzle >> 2) & 0x03;
1765 DWORD swizzle_z = (swizzle >> 4) & 0x03;
1766 DWORD swizzle_w = (swizzle >> 6) & 0x03;
1767 /* TRACE("p[%d] swizzled\n", i); */
1768 float* tt = (float*) p[i];
1769 s[i].x = (isNegative) ? -tt[swizzle_x] : tt[swizzle_x];
1770 s[i].y = (isNegative) ? -tt[swizzle_y] : tt[swizzle_y];
1771 s[i].z = (isNegative) ? -tt[swizzle_z] : tt[swizzle_z];
1772 s[i].w = (isNegative) ? -tt[swizzle_w] : tt[swizzle_w];
1775 } else { /* output reg */
1776 if ((pToken[i] & D3DSP_WRITEMASK_ALL) == D3DSP_WRITEMASK_ALL) {
1779 p_send[i] = &d; /* to be post-processed for modifiers management */
1785 switch (curOpcode->num_params) {
1787 curOpcode->soft_fct();
1790 curOpcode->soft_fct(p_send[0]);
1793 curOpcode->soft_fct(p_send[0], p_send[1]);
1796 curOpcode->soft_fct(p_send[0], p_send[1], p_send[2]);
1799 curOpcode->soft_fct(p_send[0], p_send[1], p_send[2], p_send[3]);
1802 curOpcode->soft_fct(p_send[0], p_send[1], p_send[2], p_send[3], p_send[4]);
1805 curOpcode->soft_fct(p_send[0], p_send[1], p_send[2], p_send[3], p_send[4], p_send[5]);
1808 ERR("%s too many params: %u\n", curOpcode->name, curOpcode->num_params);
1811 /* check if output reg modifier post-process */
1812 if (curOpcode->num_params > 0 && (pToken[0] & D3DSP_WRITEMASK_ALL) != D3DSP_WRITEMASK_ALL) {
1813 if (pToken[0] & D3DSP_WRITEMASK_0) p[0]->x = d.x;
1814 if (pToken[0] & D3DSP_WRITEMASK_1) p[0]->y = d.y;
1815 if (pToken[0] & D3DSP_WRITEMASK_2) p[0]->z = d.z;
1816 if (pToken[0] & D3DSP_WRITEMASK_3) p[0]->w = d.w;
1819 TRACE_VSVECTOR(output->oPos);
1820 TRACE_VSVECTOR(output->oD[0]);
1821 TRACE_VSVECTOR(output->oD[1]);
1822 TRACE_VSVECTOR(output->oT[0]);
1823 TRACE_VSVECTOR(output->oT[1]);
1824 TRACE_VSVECTOR(R[0]);
1825 TRACE_VSVECTOR(R[1]);
1826 TRACE_VSVECTOR(R[2]);
1827 TRACE_VSVECTOR(R[3]);
1828 TRACE_VSVECTOR(R[4]);
1829 TRACE_VSVECTOR(R[5]);
1832 /* to next opcode token */
1833 pToken += curOpcode->num_params;
1836 TRACE("End of current instruction:\n");
1837 TRACE_VSVECTOR(output->oPos);
1838 TRACE_VSVECTOR(output->oD[0]);
1839 TRACE_VSVECTOR(output->oD[1]);
1840 TRACE_VSVECTOR(output->oT[0]);
1841 TRACE_VSVECTOR(output->oT[1]);
1842 TRACE_VSVECTOR(R[0]);
1843 TRACE_VSVECTOR(R[1]);
1844 TRACE_VSVECTOR(R[2]);
1845 TRACE_VSVECTOR(R[3]);
1846 TRACE_VSVECTOR(R[4]);
1847 TRACE_VSVECTOR(R[5]);
1850 #if 0 /* Must not be 1 in cvs */
1852 TRACE_VSVECTOR(output->oPos);
1853 TRACE_VSVECTOR(output->oD[0]);
1854 TRACE_VSVECTOR(output->oD[1]);
1855 TRACE_VSVECTOR(output->oT[0]);
1856 TRACE_VSVECTOR(output->oT[1]);
1861 HRESULT WINAPI IWineD3DVertexShaderImpl_SetConstantF(IWineD3DVertexShader *iface, UINT StartRegister, CONST FLOAT *pConstantData, UINT Vector4fCount) {
1862 IWineD3DVertexShaderImpl *This = (IWineD3DVertexShaderImpl *)iface;
1863 FIXME("(%p) : stub\n", This);
1867 HRESULT WINAPI IWineD3DVertexShaderImpl_GetConstantF(IWineD3DVertexShader *iface, UINT StartRegister, FLOAT *pConstantData, UINT Vector4fCount) {
1868 IWineD3DVertexShaderImpl *This = (IWineD3DVertexShaderImpl *)iface;
1869 FIXME("(%p) : stub\n", This);
1873 HRESULT WINAPI IWineD3DVertexShaderImpl_SetConstantI(IWineD3DVertexShader *iface, UINT StartRegister, CONST int *pConstantData, UINT Vector4iCount) {
1874 IWineD3DVertexShaderImpl *This = (IWineD3DVertexShaderImpl *)iface;
1875 if (StartRegister + Vector4iCount > WINED3D_VSHADER_MAX_CONSTANTS) {
1876 ERR("(%p) : SetVertexShaderConstantI C[%u] invalid\n", This, StartRegister);
1877 return WINED3DERR_INVALIDCALL;
1879 if (NULL == pConstantData) {
1880 return WINED3DERR_INVALIDCALL;
1882 FIXME("(%p) : stub\n", This);
1886 HRESULT WINAPI IWineD3DVertexShaderImpl_GetConstantI(IWineD3DVertexShader *iface, UINT StartRegister, int *pConstantData, UINT Vector4iCount) {
1887 IWineD3DVertexShaderImpl *This = (IWineD3DVertexShaderImpl *)iface;
1888 TRACE("(%p) : C[%u] count=%u\n", This, StartRegister, Vector4iCount);
1889 if (StartRegister + Vector4iCount > WINED3D_VSHADER_MAX_CONSTANTS) {
1890 return WINED3DERR_INVALIDCALL;
1892 if (NULL == pConstantData) {
1893 return WINED3DERR_INVALIDCALL;
1895 FIXME("(%p) : stub\n", This);
1899 HRESULT WINAPI IWineD3DVertexShaderImpl_SetConstantB(IWineD3DVertexShader *iface, UINT StartRegister, CONST BOOL *pConstantData, UINT BoolCount) {
1900 IWineD3DVertexShaderImpl *This = (IWineD3DVertexShaderImpl *)iface;
1901 if (StartRegister + BoolCount > WINED3D_VSHADER_MAX_CONSTANTS) {
1902 ERR("(%p) : SetVertexShaderConstantB C[%u] invalid\n", This, StartRegister);
1903 return WINED3DERR_INVALIDCALL;
1905 if (NULL == pConstantData) {
1906 return WINED3DERR_INVALIDCALL;
1908 FIXME("(%p) : stub\n", This);
1912 HRESULT WINAPI IWineD3DVertexShaderImpl_GetConstantB(IWineD3DVertexShader *iface, UINT StartRegister, BOOL *pConstantData, UINT BoolCount) {
1913 IWineD3DVertexShaderImpl* This = (IWineD3DVertexShaderImpl *)iface;
1914 FIXME("(%p) : stub\n", This);
1920 /* *******************************************
1921 IWineD3DVertexShader IUnknown parts follow
1922 ******************************************* */
1923 HRESULT WINAPI IWineD3DVertexShaderImpl_QueryInterface(IWineD3DVertexShader *iface, REFIID riid, LPVOID *ppobj)
1925 IWineD3DVertexShaderImpl *This = (IWineD3DVertexShaderImpl *)iface;
1926 TRACE("(%p)->(%s,%p)\n",This,debugstr_guid(riid),ppobj);
1927 if (IsEqualGUID(riid, &IID_IUnknown)
1928 || IsEqualGUID(riid, &IID_IWineD3DBase)
1929 || IsEqualGUID(riid, &IID_IWineD3DBaseShader)
1930 || IsEqualGUID(riid, &IID_IWineD3DVertexShader)) {
1931 IUnknown_AddRef(iface);
1936 return E_NOINTERFACE;
1939 ULONG WINAPI IWineD3DVertexShaderImpl_AddRef(IWineD3DVertexShader *iface) {
1940 IWineD3DVertexShaderImpl *This = (IWineD3DVertexShaderImpl *)iface;
1941 TRACE("(%p) : AddRef increasing from %ld\n", This, This->ref);
1942 return InterlockedIncrement(&This->ref);
1945 ULONG WINAPI IWineD3DVertexShaderImpl_Release(IWineD3DVertexShader *iface) {
1946 IWineD3DVertexShaderImpl *This = (IWineD3DVertexShaderImpl *)iface;
1948 TRACE("(%p) : Releasing from %ld\n", This, This->ref);
1949 ref = InterlockedDecrement(&This->ref);
1951 if (This->vertexDeclaration) IWineD3DVertexDeclaration_Release(This->vertexDeclaration);
1952 HeapFree(GetProcessHeap(), 0, This);
1957 /* *******************************************
1958 IWineD3DVertexShader IWineD3DVertexShader parts follow
1959 ******************************************* */
1961 HRESULT WINAPI IWineD3DVertexShaderImpl_GetParent(IWineD3DVertexShader *iface, IUnknown** parent){
1962 IWineD3DVertexShaderImpl *This = (IWineD3DVertexShaderImpl *)iface;
1964 *parent = This->parent;
1965 IUnknown_AddRef(*parent);
1966 TRACE("(%p) : returning %p\n", This, *parent);
1970 HRESULT WINAPI IWineD3DVertexShaderImpl_GetDevice(IWineD3DVertexShader* iface, IWineD3DDevice **pDevice){
1971 IWineD3DVertexShaderImpl *This = (IWineD3DVertexShaderImpl *)iface;
1972 IWineD3DDevice_AddRef((IWineD3DDevice *)This->wineD3DDevice);
1973 *pDevice = (IWineD3DDevice *)This->wineD3DDevice;
1974 TRACE("(%p) returning %p\n", This, *pDevice);
1978 HRESULT WINAPI IWineD3DVertexShaderImpl_GetFunction(IWineD3DVertexShader* impl, VOID* pData, UINT* pSizeOfData) {
1979 IWineD3DVertexShaderImpl *This = (IWineD3DVertexShaderImpl *)impl;
1980 FIXME("(%p) : pData(%p), pSizeOfData(%p)\n", This, pData, pSizeOfData);
1982 if (NULL == pData) {
1983 *pSizeOfData = This->baseShader.functionLength;
1986 if (*pSizeOfData < This->baseShader.functionLength) {
1987 *pSizeOfData = This->baseShader.functionLength;
1988 return WINED3DERR_MOREDATA;
1990 if (NULL == This->baseShader.function) { /* no function defined */
1991 TRACE("(%p) : GetFunction no User Function defined using NULL to %p\n", This, pData);
1992 (*(DWORD **) pData) = NULL;
1994 if(This->baseShader.functionLength == 0){
1997 TRACE("(%p) : GetFunction copying to %p\n", This, pData);
1998 memcpy(pData, This->baseShader.function, This->baseShader.functionLength);
2003 HRESULT WINAPI IWineD3DVertexShaderImpl_SetFunction(IWineD3DVertexShader *iface, CONST DWORD *pFunction) {
2004 IWineD3DVertexShaderImpl *This =(IWineD3DVertexShaderImpl *)iface;
2005 const DWORD* pToken = pFunction;
2006 const SHADER_OPCODE* curOpcode = NULL;
2009 TRACE("(%p) : Parsing programme\n", This);
2011 if (NULL != pToken) {
2012 while (D3DVS_END() != *pToken) {
2013 if (vshader_is_version_token(*pToken)) { /** version */
2014 TRACE("vs_%lu_%lu\n", (*pToken >> 8) & 0x0F, (*pToken & 0x0F));
2019 if (vshader_is_comment_token(*pToken)) { /** comment */
2020 DWORD comment_len = (*pToken & D3DSI_COMMENTSIZE_MASK) >> D3DSI_COMMENTSIZE_SHIFT;
2022 TRACE("//%s\n", (char*)pToken);
2023 pToken += comment_len;
2024 len += comment_len + 1;
2027 curOpcode = vshader_program_get_opcode(This, *pToken);
2030 if (NULL == curOpcode) {
2031 /* TODO: Think of a good name for 0x80000000 and replace it with a constant */
2032 while (*pToken & 0x80000000) {
2033 /* unknown current opcode ... */
2034 FIXME("unrecognized opcode: %08lx", *pToken);
2041 if (curOpcode->opcode == D3DSIO_DCL) {
2042 vshader_program_dump_decl_usage(This, *pToken, *(pToken + 1));
2045 vshader_program_dump_vs_param(*pToken, 0);
2049 if (curOpcode->opcode == D3DSIO_DEF) {
2050 TRACE("def c%lu = ", *pToken & 0xFF);
2053 TRACE("%f ,", *(float *)pToken);
2056 TRACE("%f ,", *(float *)pToken);
2059 TRACE("%f ,", *(float *)pToken);
2062 TRACE("%f", *(float *)pToken);
2066 TRACE("%s ", curOpcode->name);
2067 if (curOpcode->num_params > 0) {
2068 vshader_program_dump_vs_param(*pToken, 0);
2071 for (i = 1; i < curOpcode->num_params; ++i) {
2073 vshader_program_dump_vs_param(*pToken, 1);
2082 This->baseShader.functionLength = (len + 1) * sizeof(DWORD);
2084 This->baseShader.functionLength = 1; /* no Function defined use fixed function vertex processing */
2087 /* Generate HW shader in needed */
2088 if (NULL != pFunction && wined3d_settings.vs_mode == VS_HW) {
2090 IWineD3DVertexShaderImpl_GenerateProgramArbHW(iface, pFunction);
2094 /* copy the function ... because it will certainly be released by application */
2095 if (NULL != pFunction) {
2096 This->baseShader.function = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, This->baseShader.functionLength);
2097 memcpy((void *)This->baseShader.function, pFunction, This->baseShader.functionLength);
2099 This->baseShader.function = NULL;
2104 const IWineD3DVertexShaderVtbl IWineD3DVertexShader_Vtbl =
2106 /*** IUnknown methods ***/
2107 IWineD3DVertexShaderImpl_QueryInterface,
2108 IWineD3DVertexShaderImpl_AddRef,
2109 IWineD3DVertexShaderImpl_Release,
2110 /*** IWineD3DBase methods ***/
2111 IWineD3DVertexShaderImpl_GetParent,
2112 /*** IWineD3DBaseShader methods ***/
2113 IWineD3DVertexShaderImpl_SetFunction,
2114 /*** IWineD3DVertexShader methods ***/
2115 IWineD3DVertexShaderImpl_GetDevice,
2116 IWineD3DVertexShaderImpl_GetFunction