wined3d: Rework dcl processing.
[wine/multimedia.git] / dlls / wined3d / vertexshader.c
blob17f364b219f2a3f0c6a52ee3180864465c6d1942
1 /*
2 * shaders implementation
4 * Copyright 2002-2003 Jason Edmeades
5 * Copyright 2002-2003 Raphael Junqueira
6 * Copyright 2005 Oliver Stieber
7 * Copyright 2006 Ivan Gyurdiev
9 * This library is free software; you can redistribute it and/or
10 * modify it under the terms of the GNU Lesser General Public
11 * License as published by the Free Software Foundation; either
12 * version 2.1 of the License, or (at your option) any later version.
14 * This library is distributed in the hope that it will be useful,
15 * but WITHOUT ANY WARRANTY; without even the implied warranty of
16 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
17 * Lesser General Public License for more details.
19 * You should have received a copy of the GNU Lesser General Public
20 * License along with this library; if not, write to the Free Software
21 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
24 #include "config.h"
26 #include <math.h>
27 #include <stdio.h>
29 #include "wined3d_private.h"
31 WINE_DEFAULT_DEBUG_CHANNEL(d3d_shader);
33 #define GLINFO_LOCATION ((IWineD3DImpl *)(((IWineD3DDeviceImpl *)This->wineD3DDevice)->wineD3D))->gl_info
35 /* Shader debugging - Change the following line to enable debugging of software
36 vertex shaders */
37 #if 0 /* Musxt not be 1 in cvs version */
38 # define VSTRACE(A) TRACE A
39 # define TRACE_VSVECTOR(name) TRACE( #name "=(%f, %f, %f, %f)\n", name.x, name.y, name.z, name.w)
40 #else
41 # define VSTRACE(A)
42 # define TRACE_VSVECTOR(name)
43 #endif
45 #if 1 /* FIXME : Needs sorting when vshader code moved in properly */
47 /**
48 * DirectX9 SDK download
49 * http://msdn.microsoft.com/library/default.asp?url=/downloads/list/directx.asp
51 * Exploring D3DX
52 * http://msdn.microsoft.com/library/default.asp?url=/library/en-us/dndrive/html/directx07162002.asp
54 * Using Vertex Shaders
55 * http://msdn.microsoft.com/library/default.asp?url=/library/en-us/dndrive/html/directx02192001.asp
57 * Dx9 New
58 * http://msdn.microsoft.com/library/default.asp?url=/library/en-us/directx9_c/directx/graphics/whatsnew.asp
60 * Dx9 Shaders
61 * http://msdn.microsoft.com/library/default.asp?url=/library/en-us/directx9_c/directx/graphics/reference/Shaders/VertexShader2_0/VertexShader2_0.asp
62 * http://msdn.microsoft.com/library/default.asp?url=/library/en-us/directx9_c/directx/graphics/reference/Shaders/VertexShader2_0/Instructions/Instructions.asp
63 * http://msdn.microsoft.com/library/default.asp?url=/library/en-us/directx9_c/directx/graphics/programmingguide/GettingStarted/VertexDeclaration/VertexDeclaration.asp
64 * http://msdn.microsoft.com/library/default.asp?url=/library/en-us/directx9_c/directx/graphics/reference/Shaders/VertexShader3_0/VertexShader3_0.asp
66 * Dx9 D3DX
67 * http://msdn.microsoft.com/library/default.asp?url=/library/en-us/directx9_c/directx/graphics/programmingguide/advancedtopics/VertexPipe/matrixstack/matrixstack.asp
69 * FVF
70 * http://msdn.microsoft.com/library/en-us/directx9_c/directx/graphics/programmingguide/GettingStarted/VertexFormats/vformats.asp
72 * NVIDIA: DX8 Vertex Shader to NV Vertex Program
73 * http://developer.nvidia.com/view.asp?IO=vstovp
75 * NVIDIA: Memory Management with VAR
76 * http://developer.nvidia.com/view.asp?IO=var_memory_management
79 /* 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
80 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 */
82 #define GLNAME_REQUIRE_GLSL ((const char *)1)
84 /*******************************
85 * vshader functions software VM
88 static void vshader_add(WINED3DSHADERVECTOR* d, WINED3DSHADERVECTOR* s0, WINED3DSHADERVECTOR* s1) {
89 d->x = s0->x + s1->x;
90 d->y = s0->y + s1->y;
91 d->z = s0->z + s1->z;
92 d->w = s0->w + s1->w;
93 VSTRACE(("executing add: s0=(%f, %f, %f, %f) s1=(%f, %f, %f, %f) => d=(%f, %f, %f, %f)\n",
94 s0->x, s0->y, s0->z, s0->w, s1->x, s1->y, s1->z, s1->w, d->x, d->y, d->z, d->w));
97 static void vshader_dp3(WINED3DSHADERVECTOR* d, WINED3DSHADERVECTOR* s0, WINED3DSHADERVECTOR* s1) {
98 d->x = d->y = d->z = d->w = s0->x * s1->x + s0->y * s1->y + s0->z * s1->z;
99 VSTRACE(("executing dp3: s0=(%f, %f, %f, %f) s1=(%f, %f, %f, %f) => d=(%f, %f, %f, %f)\n",
100 s0->x, s0->y, s0->z, s0->w, s1->x, s1->y, s1->z, s1->w, d->x, d->y, d->z, d->w));
103 static void vshader_dp4(WINED3DSHADERVECTOR* d, WINED3DSHADERVECTOR* s0, WINED3DSHADERVECTOR* s1) {
104 d->x = d->y = d->z = d->w = s0->x * s1->x + s0->y * s1->y + s0->z * s1->z + s0->w * s1->w;
105 VSTRACE(("executing dp4: s0=(%f, %f, %f, %f) s1=(%f, %f, %f, %f) => d=(%f, %f, %f, %f)\n",
106 s0->x, s0->y, s0->z, s0->w, s1->x, s1->y, s1->z, s1->w, d->x, d->y, d->z, d->w));
109 static void vshader_dst(WINED3DSHADERVECTOR* d, WINED3DSHADERVECTOR* s0, WINED3DSHADERVECTOR* s1) {
110 d->x = 1.0f;
111 d->y = s0->y * s1->y;
112 d->z = s0->z;
113 d->w = s1->w;
114 VSTRACE(("executing dst: s0=(%f, %f, %f, %f) s1=(%f, %f, %f, %f) => d=(%f, %f, %f, %f)\n",
115 s0->x, s0->y, s0->z, s0->w, s1->x, s1->y, s1->z, s1->w, d->x, d->y, d->z, d->w));
118 static void vshader_expp(WINED3DSHADERVECTOR* d, WINED3DSHADERVECTOR* s0) {
119 union {
120 float f;
121 DWORD d;
122 } tmp;
124 tmp.f = floorf(s0->w);
125 d->x = powf(2.0f, tmp.f);
126 d->y = s0->w - tmp.f;
127 tmp.f = powf(2.0f, s0->w);
128 tmp.d &= 0xFFFFFF00U;
129 d->z = tmp.f;
130 d->w = 1.0f;
131 VSTRACE(("executing exp: s0=(%f, %f, %f, %f) => d=(%f, %f, %f, %f)\n",
132 s0->x, s0->y, s0->z, s0->w, d->x, d->y, d->z, d->w));
135 static void vshader_lit(WINED3DSHADERVECTOR* d, WINED3DSHADERVECTOR* s0) {
136 d->x = 1.0f;
137 d->y = (0.0f < s0->x) ? s0->x : 0.0f;
138 d->z = (0.0f < s0->x && 0.0f < s0->y) ? powf(s0->y, s0->w) : 0.0f;
139 d->w = 1.0f;
140 VSTRACE(("executing lit: s0=(%f, %f, %f, %f) => d=(%f, %f, %f, %f)\n",
141 s0->x, s0->y, s0->z, s0->w, d->x, d->y, d->z, d->w));
144 static void vshader_logp(WINED3DSHADERVECTOR* d, WINED3DSHADERVECTOR* s0) {
145 float tmp_f = fabsf(s0->w);
146 d->x = d->y = d->z = d->w = (0.0f != tmp_f) ? logf(tmp_f) / logf(2.0f) : -HUGE_VAL;
147 VSTRACE(("executing logp: s0=(%f, %f, %f, %f) => d=(%f, %f, %f, %f)\n",
148 s0->x, s0->y, s0->z, s0->w, d->x, d->y, d->z, d->w));
151 static void vshader_mad(WINED3DSHADERVECTOR* d, WINED3DSHADERVECTOR* s0, WINED3DSHADERVECTOR* s1, WINED3DSHADERVECTOR* s2) {
152 d->x = s0->x * s1->x + s2->x;
153 d->y = s0->y * s1->y + s2->y;
154 d->z = s0->z * s1->z + s2->z;
155 d->w = s0->w * s1->w + s2->w;
156 VSTRACE(("executing mad: s0=(%f, %f, %f, %f) s1=(%f, %f, %f, %f) s2=(%f, %f, %f, %f) => d=(%f, %f, %f, %f)\n",
157 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));
160 static void vshader_max(WINED3DSHADERVECTOR* d, WINED3DSHADERVECTOR* s0, WINED3DSHADERVECTOR* s1) {
161 d->x = (s0->x >= s1->x) ? s0->x : s1->x;
162 d->y = (s0->y >= s1->y) ? s0->y : s1->y;
163 d->z = (s0->z >= s1->z) ? s0->z : s1->z;
164 d->w = (s0->w >= s1->w) ? s0->w : s1->w;
165 VSTRACE(("executing max: s0=(%f, %f, %f, %f) s1=(%f, %f, %f, %f) => d=(%f, %f, %f, %f)\n",
166 s0->x, s0->y, s0->z, s0->w, s1->x, s1->y, s1->z, s1->w, d->x, d->y, d->z, d->w));
169 static void vshader_min(WINED3DSHADERVECTOR* d, WINED3DSHADERVECTOR* s0, WINED3DSHADERVECTOR* s1) {
170 d->x = (s0->x < s1->x) ? s0->x : s1->x;
171 d->y = (s0->y < s1->y) ? s0->y : s1->y;
172 d->z = (s0->z < s1->z) ? s0->z : s1->z;
173 d->w = (s0->w < s1->w) ? s0->w : s1->w;
174 VSTRACE(("executing min: s0=(%f, %f, %f, %f) s1=(%f, %f, %f, %f) => d=(%f, %f, %f, %f)\n",
175 s0->x, s0->y, s0->z, s0->w, s1->x, s1->y, s1->z, s1->w, d->x, d->y, d->z, d->w));
178 static void vshader_mov(WINED3DSHADERVECTOR* d, WINED3DSHADERVECTOR* s0) {
179 d->x = s0->x;
180 d->y = s0->y;
181 d->z = s0->z;
182 d->w = s0->w;
183 VSTRACE(("executing mov: s0=(%f, %f, %f, %f) => d=(%f, %f, %f, %f)\n",
184 s0->x, s0->y, s0->z, s0->w, d->x, d->y, d->z, d->w));
187 static void vshader_mul(WINED3DSHADERVECTOR* d, WINED3DSHADERVECTOR* s0, WINED3DSHADERVECTOR* s1) {
188 d->x = s0->x * s1->x;
189 d->y = s0->y * s1->y;
190 d->z = s0->z * s1->z;
191 d->w = s0->w * s1->w;
192 VSTRACE(("executing mul: s0=(%f, %f, %f, %f) s1=(%f, %f, %f, %f) => d=(%f, %f, %f, %f)\n",
193 s0->x, s0->y, s0->z, s0->w, s1->x, s1->y, s1->z, s1->w, d->x, d->y, d->z, d->w));
196 static void vshader_nop(void) {
197 /* NOPPPP ahhh too easy ;) */
198 VSTRACE(("executing nop\n"));
201 static void vshader_rcp(WINED3DSHADERVECTOR* d, WINED3DSHADERVECTOR* s0) {
202 d->x = d->y = d->z = d->w = (0.0f == s0->w) ? HUGE_VAL : 1.0f / s0->w;
203 VSTRACE(("executing rcp: s0=(%f, %f, %f, %f) => d=(%f, %f, %f, %f)\n",
204 s0->x, s0->y, s0->z, s0->w, d->x, d->y, d->z, d->w));
207 static void vshader_rsq(WINED3DSHADERVECTOR* d, WINED3DSHADERVECTOR* s0) {
208 float tmp_f = fabsf(s0->w);
209 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);
210 VSTRACE(("executing rsq: s0=(%f, %f, %f, %f) => d=(%f, %f, %f, %f)\n",
211 s0->x, s0->y, s0->z, s0->w, d->x, d->y, d->z, d->w));
214 static void vshader_sge(WINED3DSHADERVECTOR* d, WINED3DSHADERVECTOR* s0, WINED3DSHADERVECTOR* s1) {
215 d->x = (s0->x >= s1->x) ? 1.0f : 0.0f;
216 d->y = (s0->y >= s1->y) ? 1.0f : 0.0f;
217 d->z = (s0->z >= s1->z) ? 1.0f : 0.0f;
218 d->w = (s0->w >= s1->w) ? 1.0f : 0.0f;
219 VSTRACE(("executing sge: s0=(%f, %f, %f, %f) s1=(%f, %f, %f, %f) => d=(%f, %f, %f, %f)\n",
220 s0->x, s0->y, s0->z, s0->w, s1->x, s1->y, s1->z, s1->w, d->x, d->y, d->z, d->w));
223 static void vshader_slt(WINED3DSHADERVECTOR* d, WINED3DSHADERVECTOR* s0, WINED3DSHADERVECTOR* s1) {
224 d->x = (s0->x < s1->x) ? 1.0f : 0.0f;
225 d->y = (s0->y < s1->y) ? 1.0f : 0.0f;
226 d->z = (s0->z < s1->z) ? 1.0f : 0.0f;
227 d->w = (s0->w < s1->w) ? 1.0f : 0.0f;
228 VSTRACE(("executing slt: s0=(%f, %f, %f, %f) s1=(%f, %f, %f, %f) => d=(%f, %f, %f, %f)\n",
229 s0->x, s0->y, s0->z, s0->w, s1->x, s1->y, s1->z, s1->w, d->x, d->y, d->z, d->w));
232 static void vshader_sub(WINED3DSHADERVECTOR* d, WINED3DSHADERVECTOR* s0, WINED3DSHADERVECTOR* s1) {
233 d->x = s0->x - s1->x;
234 d->y = s0->y - s1->y;
235 d->z = s0->z - s1->z;
236 d->w = s0->w - s1->w;
237 VSTRACE(("executing sub: s0=(%f, %f, %f, %f) s1=(%f, %f, %f, %f) => d=(%f, %f, %f, %f)\n",
238 s0->x, s0->y, s0->z, s0->w, s1->x, s1->y, s1->z, s1->w, d->x, d->y, d->z, d->w));
242 * Version 1.1 specific
245 static void vshader_exp(WINED3DSHADERVECTOR* d, WINED3DSHADERVECTOR* s0) {
246 d->x = d->y = d->z = d->w = powf(2.0f, s0->w);
247 VSTRACE(("executing exp: s0=(%f, %f, %f, %f) => d=(%f, %f, %f, %f)\n",
248 s0->x, s0->y, s0->z, s0->w, d->x, d->y, d->z, d->w));
251 static void vshader_log(WINED3DSHADERVECTOR* d, WINED3DSHADERVECTOR* s0) {
252 float tmp_f = fabsf(s0->w);
253 d->x = d->y = d->z = d->w = (0.0f != tmp_f) ? logf(tmp_f) / logf(2.0f) : -HUGE_VAL;
254 VSTRACE(("executing log: s0=(%f, %f, %f, %f) => d=(%f, %f, %f, %f)\n",
255 s0->x, s0->y, s0->z, s0->w, d->x, d->y, d->z, d->w));
258 static void vshader_frc(WINED3DSHADERVECTOR* d, WINED3DSHADERVECTOR* s0) {
259 d->x = s0->x - floorf(s0->x);
260 d->y = s0->y - floorf(s0->y);
261 d->z = 0.0f;
262 d->w = 1.0f;
263 VSTRACE(("executing frc: s0=(%f, %f, %f, %f) => d=(%f, %f, %f, %f)\n",
264 s0->x, s0->y, s0->z, s0->w, d->x, d->y, d->z, d->w));
267 typedef FLOAT D3DMATRIX44[4][4];
268 typedef FLOAT D3DMATRIX43[4][3];
269 typedef FLOAT D3DMATRIX34[3][4];
270 typedef FLOAT D3DMATRIX33[3][3];
271 typedef FLOAT D3DMATRIX23[2][3];
273 static void vshader_m4x4(WINED3DSHADERVECTOR* d, WINED3DSHADERVECTOR* s0, /*WINED3DSHADERVECTOR* mat1*/ D3DMATRIX44 mat) {
275 * Buggy CODE: here only if cast not work for copy/paste
276 WINED3DSHADERVECTOR* mat2 = mat1 + 1;
277 WINED3DSHADERVECTOR* mat3 = mat1 + 2;
278 WINED3DSHADERVECTOR* mat4 = mat1 + 3;
279 d->x = mat1->x * s0->x + mat2->x * s0->y + mat3->x * s0->z + mat4->x * s0->w;
280 d->y = mat1->y * s0->x + mat2->y * s0->y + mat3->y * s0->z + mat4->y * s0->w;
281 d->z = mat1->z * s0->x + mat2->z * s0->y + mat3->z * s0->z + mat4->z * s0->w;
282 d->w = mat1->w * s0->x + mat2->w * s0->y + mat3->w * s0->z + mat4->w * s0->w;
284 d->x = mat[0][0] * s0->x + mat[0][1] * s0->y + mat[0][2] * s0->z + mat[0][3] * s0->w;
285 d->y = mat[1][0] * s0->x + mat[1][1] * s0->y + mat[1][2] * s0->z + mat[1][3] * s0->w;
286 d->z = mat[2][0] * s0->x + mat[2][1] * s0->y + mat[2][2] * s0->z + mat[2][3] * s0->w;
287 d->w = mat[3][0] * s0->x + mat[3][1] * s0->y + mat[3][2] * s0->z + mat[3][3] * s0->w;
288 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));
289 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));
290 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));
291 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));
294 static void vshader_m4x3(WINED3DSHADERVECTOR* d, WINED3DSHADERVECTOR* s0, D3DMATRIX34 mat) {
295 d->x = mat[0][0] * s0->x + mat[0][1] * s0->y + mat[0][2] * s0->z + mat[0][3] * s0->w;
296 d->y = mat[1][0] * s0->x + mat[1][1] * s0->y + mat[1][2] * s0->z + mat[1][3] * s0->w;
297 d->z = mat[2][0] * s0->x + mat[2][1] * s0->y + mat[2][2] * s0->z + mat[2][3] * s0->w;
298 d->w = 1.0f;
299 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));
300 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));
301 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));
302 VSTRACE(("executing m4x3(4): (%f) (%f) \n", s0->w, d->w));
305 static void vshader_m3x4(WINED3DSHADERVECTOR* d, WINED3DSHADERVECTOR* s0, D3DMATRIX43 mat) {
306 d->x = mat[0][0] * s0->x + mat[0][1] * s0->y + mat[0][2] * s0->z;
307 d->y = mat[1][0] * s0->x + mat[1][1] * s0->y + mat[1][2] * s0->z;
308 d->z = mat[2][0] * s0->x + mat[2][1] * s0->y + mat[2][2] * s0->z;
309 d->w = mat[3][0] * s0->x + mat[3][1] * s0->y + mat[3][2] * s0->z;
310 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));
311 VSTRACE(("executing m3x4(2): mat=(%f, %f, %f) (%f) (%f) \n", mat[1][0], mat[1][1], mat[1][2], s0->y, d->y));
312 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));
313 VSTRACE(("executing m3x4(4): mat=(%f, %f, %f) (%f) (%f) \n", mat[3][0], mat[3][1], mat[3][2], s0->w, d->w));
316 static void vshader_m3x3(WINED3DSHADERVECTOR* d, WINED3DSHADERVECTOR* s0, D3DMATRIX33 mat) {
317 d->x = mat[0][0] * s0->x + mat[0][1] * s0->y + mat[0][2] * s0->z;
318 d->y = mat[1][0] * s0->x + mat[1][1] * s0->y + mat[1][2] * s0->z;
319 d->z = mat[2][0] * s0->x + mat[2][1] * s0->y + mat[2][2] * s0->z;
320 d->w = 1.0f;
321 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));
322 VSTRACE(("executing m3x3(2): mat=(%f, %f, %f) (%f) (%f) \n", mat[1][0], mat[1][1], mat[1][2], s0->y, d->y));
323 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));
324 VSTRACE(("executing m3x3(4): (%f) \n", d->w));
327 static void vshader_m3x2(WINED3DSHADERVECTOR* d, WINED3DSHADERVECTOR* s0, D3DMATRIX23 mat) {
328 FIXME("check\n");
329 d->x = mat[0][0] * s0->x + mat[0][1] * s0->y + mat[0][2] * s0->z;
330 d->y = mat[1][0] * s0->x + mat[1][1] * s0->y + mat[1][2] * s0->z;
331 d->z = 0.0f;
332 d->w = 1.0f;
336 * Version 2.0 specific
338 static void vshader_lrp(WINED3DSHADERVECTOR* d, WINED3DSHADERVECTOR* s0, WINED3DSHADERVECTOR* s1, WINED3DSHADERVECTOR* s2) {
339 d->x = s0->x * (s1->x - s2->x) + s2->x;
340 d->y = s0->y * (s1->y - s2->y) + s2->y;
341 d->z = s0->z * (s1->z - s2->z) + s2->z;
342 d->w = s0->w * (s1->w - s2->w) + s2->w;
345 static void vshader_crs(WINED3DSHADERVECTOR* d, WINED3DSHADERVECTOR* s0, WINED3DSHADERVECTOR* s1) {
346 d->x = s0->y * s1->z - s0->z * s1->y;
347 d->y = s0->z * s1->x - s0->x * s1->z;
348 d->z = s0->x * s1->y - s0->y * s1->x;
349 d->w = 0.9f; /* w is undefined, so set it to something safeish */
351 VSTRACE(("executing crs: s0=(%f, %f, %f, %f) s1=(%f, %f, %f, %f) => d=(%f, %f, %f, %f)\n",
352 s0->x, s0->y, s0->z, s0->w, s1->x, s1->y, s1->z, s1->w, d->x, d->y, d->z, d->w));
355 static void vshader_abs(WINED3DSHADERVECTOR* d, WINED3DSHADERVECTOR* s0) {
357 d->x = fabsf(s0->x);
358 d->y = fabsf(s0->y);
359 d->z = fabsf(s0->z);
360 d->w = fabsf(s0->w);
361 VSTRACE(("executing abs: s0=(%f, %f, %f, %f) => d=(%f, %f, %f, %f)\n",
362 s0->x, s0->y, s0->z, s0->w, d->x, d->y, d->z, d->w));
365 /* Stubs */
367 /* Def is C[n] = {n.nf, n.nf, n.nf, n.nf} */
368 static void vshader_def(WINED3DSHADERVECTOR* d, WINED3DSHADERVECTOR* s0, WINED3DSHADERVECTOR* s1, WINED3DSHADERVECTOR* s2, WINED3DSHADERVECTOR* s3) {
369 FIXME(" : Stub\n");
372 static void vshader_call(WINED3DSHADERVECTOR* d) {
373 FIXME(" : Stub\n");
376 static void vshader_callnz(WINED3DSHADERVECTOR* d, WINED3DSHADERVECTOR* s0) {
377 FIXME(" : Stub\n");
380 static void vshader_loop(WINED3DSHADERVECTOR* d, WINED3DSHADERVECTOR* s0) {
381 FIXME(" : Stub\n");
384 static void vshader_ret(void) {
385 FIXME(" : Stub\n");
388 static void vshader_endloop(void) {
389 FIXME(" : Stub\n");
392 static void vshader_dcl(WINED3DSHADERVECTOR* d, WINED3DSHADERVECTOR* s0) {
393 FIXME(" : Stub\n");
396 static void vshader_pow(WINED3DSHADERVECTOR* d, WINED3DSHADERVECTOR* s0, WINED3DSHADERVECTOR* s1) {
397 FIXME(" : Stub\n");
400 static void vshader_sng(WINED3DSHADERVECTOR* d, WINED3DSHADERVECTOR* s0) {
401 FIXME(" : Stub\n");
404 static void vshader_nrm(WINED3DSHADERVECTOR* d, WINED3DSHADERVECTOR* s0) {
405 FIXME(" : Stub\n");
408 static void vshader_sincos3(WINED3DSHADERVECTOR* d, WINED3DSHADERVECTOR* s0) {
409 FIXME(" : Stub\n");
412 static void vshader_sincos2(WINED3DSHADERVECTOR* d, WINED3DSHADERVECTOR* s0, WINED3DSHADERVECTOR* s1, WINED3DSHADERVECTOR* s2) {
413 FIXME(" : Stub\n");
416 static void vshader_rep(WINED3DSHADERVECTOR* d) {
417 FIXME(" : Stub\n");
420 static void vshader_endrep(void) {
421 FIXME(" : Stub\n");
424 static void vshader_if(WINED3DSHADERVECTOR* d) {
425 FIXME(" : Stub\n");
428 static void vshader_ifc(WINED3DSHADERVECTOR* d, WINED3DSHADERVECTOR* s0) {
429 FIXME(" : Stub\n");
432 static void vshader_else(void) {
433 FIXME(" : Stub\n");
436 static void vshader_label(WINED3DSHADERVECTOR* d) {
437 FIXME(" : Stub\n");
440 static void vshader_endif(void) {
441 FIXME(" : Stub\n");
444 static void vshader_break(void) {
445 FIXME(" : Stub\n");
448 static void vshader_breakc(WINED3DSHADERVECTOR* d, WINED3DSHADERVECTOR* s0) {
449 FIXME(" : Stub\n");
452 static void vshader_breakp(WINED3DSHADERVECTOR* d) {
453 FIXME(" : Stub\n");
456 static void vshader_mova(WINED3DSHADERVECTOR* d) {
457 FIXME(" : Stub\n");
460 static void vshader_defb(WINED3DSHADERVECTOR* d) {
461 FIXME(" : Stub\n");
464 static void vshader_defi(WINED3DSHADERVECTOR* d, WINED3DSHADERVECTOR* s0, WINED3DSHADERVECTOR* s1, WINED3DSHADERVECTOR* s2, WINED3DSHADERVECTOR* s3) {
465 FIXME(" : Stub\n");
468 static void vshader_setp(WINED3DSHADERVECTOR* d, WINED3DSHADERVECTOR* s0, WINED3DSHADERVECTOR* s1) {
469 FIXME(" : Stub\n");
472 static void vshader_texldl(WINED3DSHADERVECTOR* d) {
473 FIXME(" : Stub\n");
476 /* Prototype */
477 static void vshader_hw_map2gl(SHADER_OPCODE_ARG* arg);
478 static void vshader_hw_mnxn(SHADER_OPCODE_ARG* arg);
481 * log, exp, frc, m*x* seems to be macros ins ... to see
483 CONST SHADER_OPCODE IWineD3DVertexShaderImpl_shader_ins[] = {
485 /* Arithmetic */
486 {D3DSIO_NOP, "nop", "NOP", 0, vshader_nop, vshader_hw_map2gl, NULL, 0, 0},
487 {D3DSIO_MOV, "mov", "MOV", 2, vshader_mov, vshader_hw_map2gl, shader_glsl_mov, 0, 0},
488 {D3DSIO_ADD, "add", "ADD", 3, vshader_add, vshader_hw_map2gl, shader_glsl_arith, 0, 0},
489 {D3DSIO_SUB, "sub", "SUB", 3, vshader_sub, vshader_hw_map2gl, shader_glsl_arith, 0, 0},
490 {D3DSIO_MAD, "mad", "MAD", 4, vshader_mad, vshader_hw_map2gl, shader_glsl_mad, 0, 0},
491 {D3DSIO_MUL, "mul", "MUL", 3, vshader_mul, vshader_hw_map2gl, shader_glsl_arith, 0, 0},
492 {D3DSIO_RCP, "rcp", "RCP", 2, vshader_rcp, vshader_hw_map2gl, shader_glsl_rcp, 0, 0},
493 {D3DSIO_RSQ, "rsq", "RSQ", 2, vshader_rsq, vshader_hw_map2gl, shader_glsl_map2gl, 0, 0},
494 {D3DSIO_DP3, "dp3", "DP3", 3, vshader_dp3, vshader_hw_map2gl, shader_glsl_dot, 0, 0},
495 {D3DSIO_DP4, "dp4", "DP4", 3, vshader_dp4, vshader_hw_map2gl, shader_glsl_dot, 0, 0},
496 {D3DSIO_MIN, "min", "MIN", 3, vshader_min, vshader_hw_map2gl, shader_glsl_map2gl, 0, 0},
497 {D3DSIO_MAX, "max", "MAX", 3, vshader_max, vshader_hw_map2gl, shader_glsl_map2gl, 0, 0},
498 {D3DSIO_SLT, "slt", "SLT", 3, vshader_slt, vshader_hw_map2gl, shader_glsl_compare, 0, 0},
499 {D3DSIO_SGE, "sge", "SGE", 3, vshader_sge, vshader_hw_map2gl, shader_glsl_compare, 0, 0},
500 {D3DSIO_ABS, "abs", "ABS", 2, vshader_abs, vshader_hw_map2gl, shader_glsl_map2gl, 0, 0},
501 {D3DSIO_EXP, "exp", "EX2", 2, vshader_exp, vshader_hw_map2gl, shader_glsl_map2gl, 0, 0},
502 {D3DSIO_LOG, "log", "LG2", 2, vshader_log, vshader_hw_map2gl, shader_glsl_map2gl, 0, 0},
503 {D3DSIO_EXPP, "expp", "EXP", 2, vshader_expp, vshader_hw_map2gl, shader_glsl_map2gl, 0, 0},
504 {D3DSIO_LOGP, "logp", "LOG", 2, vshader_logp, vshader_hw_map2gl, NULL, 0, 0},
505 {D3DSIO_LIT, "lit", "LIT", 2, vshader_lit, vshader_hw_map2gl, NULL, 0, 0},
506 {D3DSIO_DST, "dst", "DST", 3, vshader_dst, vshader_hw_map2gl, NULL, 0, 0},
507 {D3DSIO_LRP, "lrp", "LRP", 4, vshader_lrp, NULL, shader_glsl_lrp, 0, 0},
508 {D3DSIO_FRC, "frc", "FRC", 2, vshader_frc, vshader_hw_map2gl, shader_glsl_map2gl, 0, 0},
509 {D3DSIO_POW, "pow", "POW", 3, vshader_pow, NULL, shader_glsl_map2gl, 0, 0},
510 {D3DSIO_CRS, "crs", "XPS", 3, vshader_crs, NULL, shader_glsl_map2gl, 0, 0},
511 /* TODO: sng can possibly be performed a s
512 RCP tmp, vec
513 MUL out, tmp, vec*/
514 {D3DSIO_SGN, "sng", NULL, 2, vshader_sng, NULL, NULL, 0, 0},
515 /* TODO: xyz normalise can be performed as VS_ARB using one temporary register,
516 DP3 tmp , vec, vec;
517 RSQ tmp, tmp.x;
518 MUL vec.xyz, vec, tmp;
519 but I think this is better because it accounts for w properly.
520 DP3 tmp , vec, vec;
521 RSQ tmp, tmp.x;
522 MUL vec, vec, tmp;
525 {D3DSIO_NRM, "nrm", NULL, 2, vshader_nrm, NULL, shader_glsl_map2gl, 0, 0},
526 {D3DSIO_SINCOS, "sincos", NULL, 4, vshader_sincos2, NULL, NULL, D3DVS_VERSION(2,0), D3DVS_VERSION(2,0)},
527 {D3DSIO_SINCOS, "sincos", NULL, 2, vshader_sincos3, NULL, NULL, D3DVS_VERSION(3,0), -1},
529 /* Matrix */
530 {D3DSIO_M4x4, "m4x4", "undefined", 3, vshader_m4x4, vshader_hw_mnxn, shader_glsl_mnxn, 0, 0},
531 {D3DSIO_M4x3, "m4x3", "undefined", 3, vshader_m4x3, vshader_hw_mnxn, shader_glsl_mnxn, 0, 0},
532 {D3DSIO_M3x4, "m3x4", "undefined", 3, vshader_m3x4, vshader_hw_mnxn, shader_glsl_mnxn, 0, 0},
533 {D3DSIO_M3x3, "m3x3", "undefined", 3, vshader_m3x3, vshader_hw_mnxn, shader_glsl_mnxn, 0, 0},
534 {D3DSIO_M3x2, "m3x2", "undefined", 3, vshader_m3x2, vshader_hw_mnxn, shader_glsl_mnxn, 0, 0},
536 /* Declare registers */
537 {D3DSIO_DCL, "dcl", NULL, 2, vshader_dcl, NULL, NULL, 0, 0},
539 /* Constant definitions */
540 {D3DSIO_DEF, "def", NULL, 5, vshader_def, shader_hw_def, shader_glsl_def, 0, 0},
541 {D3DSIO_DEFB, "defb", GLNAME_REQUIRE_GLSL, 2, vshader_defb, NULL, NULL, 0, 0},
542 {D3DSIO_DEFI, "defi", GLNAME_REQUIRE_GLSL, 5, vshader_defi, NULL, NULL, 0, 0},
544 /* Flow control - requires GLSL or software shaders */
545 {D3DSIO_REP , "rep", GLNAME_REQUIRE_GLSL, 1, vshader_rep, NULL, NULL, 0, 0},
546 {D3DSIO_ENDREP, "endrep", GLNAME_REQUIRE_GLSL, 0, vshader_endrep, NULL, NULL, 0, 0},
547 {D3DSIO_IF, "if", GLNAME_REQUIRE_GLSL, 1, vshader_if, NULL, NULL, 0, 0},
548 {D3DSIO_IFC, "ifc", GLNAME_REQUIRE_GLSL, 2, vshader_ifc, NULL, NULL, 0, 0},
549 {D3DSIO_ELSE, "else", GLNAME_REQUIRE_GLSL, 0, vshader_else, NULL, NULL, 0, 0},
550 {D3DSIO_ENDIF, "endif", GLNAME_REQUIRE_GLSL, 0, vshader_endif, NULL, NULL, 0, 0},
551 {D3DSIO_BREAK, "break", GLNAME_REQUIRE_GLSL, 0, vshader_break, NULL, NULL, 0, 0},
552 {D3DSIO_BREAKC, "breakc", GLNAME_REQUIRE_GLSL, 2, vshader_breakc, NULL, NULL, 0, 0},
553 {D3DSIO_BREAKP, "breakp", GLNAME_REQUIRE_GLSL, 1, vshader_breakp, NULL, NULL, 0, 0},
554 {D3DSIO_CALL, "call", GLNAME_REQUIRE_GLSL, 1, vshader_call, NULL, NULL, 0, 0},
555 {D3DSIO_CALLNZ, "callnz", GLNAME_REQUIRE_GLSL, 2, vshader_callnz, NULL, NULL, 0, 0},
556 {D3DSIO_LOOP, "loop", GLNAME_REQUIRE_GLSL, 2, vshader_loop, NULL, NULL, 0, 0},
557 {D3DSIO_RET, "ret", GLNAME_REQUIRE_GLSL, 0, vshader_ret, NULL, NULL, 0, 0},
558 {D3DSIO_ENDLOOP, "endloop", GLNAME_REQUIRE_GLSL, 0, vshader_endloop, NULL, NULL, 0, 0},
559 {D3DSIO_LABEL, "label", GLNAME_REQUIRE_GLSL, 1, vshader_label, NULL, NULL, 0, 0},
561 {D3DSIO_MOVA, "mova", GLNAME_REQUIRE_GLSL, 2, vshader_mova, NULL, shader_glsl_mov, 0, 0},
562 {D3DSIO_SETP, "setp", GLNAME_REQUIRE_GLSL, 3, vshader_setp, NULL, NULL, 0, 0},
563 {D3DSIO_TEXLDL, "texdl", GLNAME_REQUIRE_GLSL, 2, vshader_texldl, NULL, NULL, 0, 0},
564 {0, NULL, NULL, 0, NULL, NULL, 0, 0}
567 inline static void vshader_program_add_output_param_swizzle(const DWORD param, int is_color, char *hwLine) {
568 /** operand output */
569 if ((param & D3DSP_WRITEMASK_ALL) != D3DSP_WRITEMASK_ALL) {
570 strcat(hwLine, ".");
571 if (param & D3DSP_WRITEMASK_0) { strcat(hwLine, "x"); }
572 if (param & D3DSP_WRITEMASK_1) { strcat(hwLine, "y"); }
573 if (param & D3DSP_WRITEMASK_2) { strcat(hwLine, "z"); }
574 if (param & D3DSP_WRITEMASK_3) { strcat(hwLine, "w"); }
578 inline static void vshader_program_add_input_param_swizzle(const DWORD param, int is_color, char *hwLine) {
579 static const char swizzle_reg_chars_color_fix[] = "zyxw";
580 static const char swizzle_reg_chars[] = "xyzw";
581 const char* swizzle_regs = NULL;
582 char tmpReg[255];
584 /** operand input */
585 DWORD swizzle = (param & D3DVS_SWIZZLE_MASK) >> D3DVS_SWIZZLE_SHIFT;
586 DWORD swizzle_x = swizzle & 0x03;
587 DWORD swizzle_y = (swizzle >> 2) & 0x03;
588 DWORD swizzle_z = (swizzle >> 4) & 0x03;
589 DWORD swizzle_w = (swizzle >> 6) & 0x03;
591 if (is_color) {
592 swizzle_regs = swizzle_reg_chars_color_fix;
593 } else {
594 swizzle_regs = swizzle_reg_chars;
598 * swizzle bits fields:
599 * WWZZYYXX
601 if ((D3DVS_NOSWIZZLE >> D3DVS_SWIZZLE_SHIFT) == swizzle) { /* D3DVS_NOSWIZZLE == 0xE4 << D3DVS_SWIZZLE_SHIFT */
602 if (is_color) {
603 sprintf(tmpReg, ".%c%c%c%c",
604 swizzle_regs[swizzle_x],
605 swizzle_regs[swizzle_y],
606 swizzle_regs[swizzle_z],
607 swizzle_regs[swizzle_w]);
608 strcat(hwLine, tmpReg);
610 return ;
612 if (swizzle_x == swizzle_y &&
613 swizzle_x == swizzle_z &&
614 swizzle_x == swizzle_w)
616 sprintf(tmpReg, ".%c", swizzle_regs[swizzle_x]);
617 strcat(hwLine, tmpReg);
618 } else {
619 sprintf(tmpReg, ".%c%c%c%c",
620 swizzle_regs[swizzle_x],
621 swizzle_regs[swizzle_y],
622 swizzle_regs[swizzle_z],
623 swizzle_regs[swizzle_w]);
624 strcat(hwLine, tmpReg);
628 inline static void vshader_program_add_param(SHADER_OPCODE_ARG *arg, const DWORD param, BOOL is_input, char *hwLine) {
630 IWineD3DVertexShaderImpl *This = (IWineD3DVertexShaderImpl *)arg->shader;
632 /* oPos, oFog and oPts in D3D */
633 static const char* hwrastout_reg_names[] = { "result.position", "result.fogcoord", "result.pointsize" };
635 DWORD reg = param & D3DSP_REGNUM_MASK;
636 DWORD regtype = shader_get_regtype(param);
637 char tmpReg[255];
638 BOOL is_color = FALSE;
640 if ((param & D3DSP_SRCMOD_MASK) == D3DSPSM_NEG) {
641 strcat(hwLine, " -");
642 } else {
643 strcat(hwLine, " ");
646 switch (regtype) {
647 case D3DSPR_TEMP:
648 sprintf(tmpReg, "R%lu", reg);
649 strcat(hwLine, tmpReg);
650 break;
651 case D3DSPR_INPUT:
653 if (This->arrayUsageMap[WINED3DSHADERDECLUSAGE_DIFFUSE] &&
654 reg == (This->arrayUsageMap[WINED3DSHADERDECLUSAGE_DIFFUSE] & D3DSP_REGNUM_MASK))
655 is_color = TRUE;
657 if (This->arrayUsageMap[WINED3DSHADERDECLUSAGE_SPECULAR] &&
658 reg == (This->arrayUsageMap[WINED3DSHADERDECLUSAGE_SPECULAR] & D3DSP_REGNUM_MASK))
659 is_color = TRUE;
661 /* FIXME: Shaders in 8.1 appear to not require a dcl statement - use
662 * the reg value from the vertex declaration. However, arrayUsageMap is not initialized
663 * in that case - how can we know if an input contains color data or not? */
665 sprintf(tmpReg, "vertex.attrib[%lu]", reg);
666 strcat(hwLine, tmpReg);
667 break;
668 case D3DSPR_CONST:
669 /* FIXME: some constants are named so we need a constants map*/
670 if (arg->reg_maps->constantsF[reg]) {
671 if (param & D3DVS_ADDRMODE_RELATIVE) {
672 FIXME("Relative addressing not expected for a named constant %lu\n", reg);
674 sprintf(tmpReg, "C%lu", reg);
675 } else {
676 sprintf(tmpReg, "C[%s%lu]", (param & D3DVS_ADDRMODE_RELATIVE) ? "A0.x + " : "", reg);
678 strcat(hwLine, tmpReg);
679 break;
680 case D3DSPR_ADDR: /*case D3DSPR_TEXTURE:*/
681 sprintf(tmpReg, "A%lu", reg);
682 strcat(hwLine, tmpReg);
683 break;
684 case D3DSPR_RASTOUT:
685 sprintf(tmpReg, "%s", hwrastout_reg_names[reg]);
686 strcat(hwLine, tmpReg);
687 break;
688 case D3DSPR_ATTROUT:
689 if (reg==0) {
690 strcat(hwLine, "result.color.primary");
691 } else {
692 strcat(hwLine, "result.color.secondary");
694 break;
695 case D3DSPR_TEXCRDOUT:
696 sprintf(tmpReg, "result.texcoord[%lu]", reg);
697 strcat(hwLine, tmpReg);
698 break;
699 default:
700 FIXME("Unknown reg type %ld %ld\n", regtype, reg);
701 strcat(hwLine, "unrecognized_register");
702 break;
705 if (!is_input) {
706 vshader_program_add_output_param_swizzle(param, is_color, hwLine);
707 } else {
708 vshader_program_add_input_param_swizzle(param, is_color, hwLine);
712 static void vshader_set_version(
713 IWineD3DVertexShaderImpl *This,
714 DWORD version) {
716 DWORD major = (version >> 8) & 0x0F;
717 DWORD minor = version & 0x0F;
719 This->baseShader.hex_version = version;
720 This->baseShader.version = major * 10 + minor;
721 TRACE("vs_%lu_%lu\n", major, minor);
723 This->baseShader.limits.texture = 0;
724 This->baseShader.limits.attributes = 16;
726 /* Must match D3DCAPS9.MaxVertexShaderConst: at least 256 for vs_2_0 */
727 This->baseShader.limits.constant_float = WINED3D_VSHADER_MAX_CONSTANTS;
729 switch (This->baseShader.version) {
730 case 10:
731 case 11: This->baseShader.limits.temporary = 12;
732 This->baseShader.limits.constant_bool = 0;
733 This->baseShader.limits.constant_int = 0;
734 This->baseShader.limits.address = 1;
735 break;
737 case 20:
738 case 21: This->baseShader.limits.temporary = 12;
739 This->baseShader.limits.constant_bool = 16;
740 This->baseShader.limits.constant_int = 16;
741 This->baseShader.limits.address = 1;
742 break;
744 case 30: This->baseShader.limits.temporary = 32;
745 This->baseShader.limits.constant_bool = 32;
746 This->baseShader.limits.constant_int = 32;
747 This->baseShader.limits.address = 1;
748 break;
750 default: This->baseShader.limits.temporary = 12;
751 This->baseShader.limits.constant_bool = 0;
752 This->baseShader.limits.constant_int = 0;
753 This->baseShader.limits.address = 1;
754 FIXME("Unrecognized vertex shader version %lx!\n", version);
758 /* Map the opcode 1-to-1 to the GL code */
759 static void vshader_hw_map2gl(SHADER_OPCODE_ARG* arg) {
761 CONST SHADER_OPCODE* curOpcode = arg->opcode;
762 SHADER_BUFFER* buffer = arg->buffer;
763 DWORD dst = arg->dst;
764 DWORD* src = arg->src;
766 DWORD dst_regtype = shader_get_regtype(dst);
767 char tmpLine[256];
768 unsigned int i;
770 if (curOpcode->opcode == D3DSIO_MOV && dst_regtype == D3DSPR_ADDR)
771 strcpy(tmpLine, "ARL");
772 else
773 strcpy(tmpLine, curOpcode->glname);
775 if (curOpcode->num_params > 0) {
776 vshader_program_add_param(arg, dst, FALSE, tmpLine);
777 for (i = 1; i < curOpcode->num_params; ++i) {
778 strcat(tmpLine, ",");
779 vshader_program_add_param(arg, src[i-1], TRUE, tmpLine);
782 shader_addline(buffer, "%s;\n", tmpLine);
785 /** Handles transforming all D3DSIO_M?x? opcodes for
786 Vertex shaders to ARB_vertex_program codes */
787 static void vshader_hw_mnxn(SHADER_OPCODE_ARG* arg) {
789 int i;
790 int nComponents = 0;
791 SHADER_OPCODE_ARG tmpArg;
793 /* Set constants for the temporary argument */
794 tmpArg.shader = arg->shader;
795 tmpArg.buffer = arg->buffer;
796 tmpArg.src[0] = arg->src[0];
797 tmpArg.reg_maps = arg->reg_maps;
799 switch(arg->opcode->opcode) {
800 case D3DSIO_M4x4:
801 nComponents = 4;
802 tmpArg.opcode = &IWineD3DVertexShaderImpl_shader_ins[D3DSIO_DP4];
803 break;
804 case D3DSIO_M4x3:
805 nComponents = 3;
806 tmpArg.opcode = &IWineD3DVertexShaderImpl_shader_ins[D3DSIO_DP4];
807 break;
808 case D3DSIO_M3x4:
809 nComponents = 4;
810 tmpArg.opcode = &IWineD3DVertexShaderImpl_shader_ins[D3DSIO_DP3];
811 break;
812 case D3DSIO_M3x3:
813 nComponents = 3;
814 tmpArg.opcode = &IWineD3DVertexShaderImpl_shader_ins[D3DSIO_DP3];
815 break;
816 case D3DSIO_M3x2:
817 nComponents = 2;
818 tmpArg.opcode = &IWineD3DVertexShaderImpl_shader_ins[D3DSIO_DP3];
819 break;
820 default:
821 break;
824 for (i = 0; i < nComponents; i++) {
825 tmpArg.dst = ((arg->dst) & ~D3DSP_WRITEMASK_ALL)|(D3DSP_WRITEMASK_0<<i);
826 tmpArg.src[1] = arg->src[1]+i;
827 vshader_hw_map2gl(&tmpArg);
831 /** Generate a vertex shader string using either GL_VERTEX_PROGRAM_ARB
832 or GLSL and send it to the card */
833 inline static VOID IWineD3DVertexShaderImpl_GenerateShader(
834 IWineD3DVertexShader *iface,
835 CONST DWORD *pFunction) {
837 IWineD3DVertexShaderImpl *This = (IWineD3DVertexShaderImpl *)iface;
838 SHADER_BUFFER buffer;
840 /* First pass: figure out which registers are used, what the semantics are, etc.. */
841 shader_reg_maps reg_maps;
842 DWORD semantics_out[WINED3DSHADERDECLUSAGE_MAX_USAGE];
844 memset(&reg_maps, 0, sizeof(shader_reg_maps));
845 memset(semantics_out, 0, WINED3DSHADERDECLUSAGE_MAX_USAGE * sizeof(DWORD));
846 reg_maps.semantics_in = This->arrayUsageMap;
847 reg_maps.semantics_out = semantics_out;
848 shader_get_registers_used((IWineD3DBaseShader*) This, &reg_maps, pFunction);
849 /* FIXME: validate against OpenGL */
851 #if 0 /* FIXME: Use the buffer that is held by the device, this is ok since fixups will be skipped for software shaders
852 it also requires entering a critical section but cuts down the runtime footprint of wined3d and any memory fragmentation that may occur... */
853 if (This->device->fixupVertexBufferSize < SHADER_PGMSIZE) {
854 HeapFree(GetProcessHeap(), 0, This->fixupVertexBuffer);
855 This->fixupVertexBuffer = HeapAlloc(GetProcessHeap() , 0, SHADER_PGMSIZE);
856 This->fixupVertexBufferSize = PGMSIZE;
857 This->fixupVertexBuffer[0] = 0;
859 buffer.buffer = This->device->fixupVertexBuffer;
860 #else
861 buffer.buffer = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, SHADER_PGMSIZE);
862 #endif
863 buffer.bsize = 0;
864 buffer.lineNo = 0;
866 if (wined3d_settings.shader_mode == SHADER_GLSL) {
868 /* Create the hw GLSL shader program and assign it as the baseShader.prgId */
869 GLhandleARB shader_obj = GL_EXTCALL(glCreateShaderObjectARB(GL_VERTEX_SHADER_ARB));
871 /* Base Shader Body */
872 shader_generate_main( (IWineD3DBaseShader*) This, &buffer, &reg_maps, pFunction);
874 shader_addline(&buffer, "}\n\0");
876 TRACE("Compiling shader object %u\n", shader_obj);
877 GL_EXTCALL(glShaderSourceARB(shader_obj, 1, (const char**)&buffer.buffer, NULL));
878 GL_EXTCALL(glCompileShaderARB(shader_obj));
879 print_glsl_info_log(&GLINFO_LOCATION, shader_obj);
881 /* Store the shader object */
882 This->baseShader.prgId = shader_obj;
884 } else if (wined3d_settings.shader_mode == SHADER_ARB) {
886 /* Create the hw ARB shader */
887 shader_addline(&buffer, "!!ARBvp1.0\n");
889 /* Mesa supports only 95 constants */
890 if (GL_VEND(MESA) || GL_VEND(WINE))
891 This->baseShader.limits.constant_float =
892 min(95, This->baseShader.limits.constant_float);
894 /* Base Shader Body */
895 shader_generate_main( (IWineD3DBaseShader*) This, &buffer, &reg_maps, pFunction);
897 shader_addline(&buffer, "END\n\0");
899 /* TODO: change to resource.glObjectHandle or something like that */
900 GL_EXTCALL(glGenProgramsARB(1, &This->baseShader.prgId));
902 TRACE("Creating a hw vertex shader, prg=%d\n", This->baseShader.prgId);
903 GL_EXTCALL(glBindProgramARB(GL_VERTEX_PROGRAM_ARB, This->baseShader.prgId));
905 TRACE("Created hw vertex shader, prg=%d\n", This->baseShader.prgId);
906 /* Create the program and check for errors */
907 GL_EXTCALL(glProgramStringARB(GL_VERTEX_PROGRAM_ARB, GL_PROGRAM_FORMAT_ASCII_ARB,
908 buffer.bsize, buffer.buffer));
910 if (glGetError() == GL_INVALID_OPERATION) {
911 GLint errPos;
912 glGetIntegerv(GL_PROGRAM_ERROR_POSITION_ARB, &errPos);
913 FIXME("HW VertexShader Error at position %d: %s\n",
914 errPos, debugstr_a((const char *)glGetString(GL_PROGRAM_ERROR_STRING_ARB)));
915 This->baseShader.prgId = -1;
919 #if 1 /* if were using the data buffer of device then we don't need to free it */
920 HeapFree(GetProcessHeap(), 0, buffer.buffer);
921 #endif
924 BOOL IWineD3DVertexShaderImpl_ExecuteHAL(IWineD3DVertexShader* iface, WINEVSHADERINPUTDATA* input, WINEVSHADEROUTPUTDATA* output) {
926 * TODO: use the NV_vertex_program (or 1_1) extension
927 * and specifics vendors (ARB_vertex_program??) variants for it
929 return TRUE;
932 HRESULT WINAPI IWineD3DVertexShaderImpl_ExecuteSW(IWineD3DVertexShader* iface, WINEVSHADERINPUTDATA* input, WINEVSHADEROUTPUTDATA* output) {
933 IWineD3DVertexShaderImpl *This = (IWineD3DVertexShaderImpl *)iface;
934 DWORD opcode_token;
936 /** Vertex Shader Temporary Registers */
937 WINED3DSHADERVECTOR R[12];
938 /*D3DSHADERSCALAR A0;*/
939 WINED3DSHADERVECTOR A[1];
940 /** temporary Vector for modifier management */
941 WINED3DSHADERVECTOR d;
942 WINED3DSHADERVECTOR s[3];
943 /** parser datas */
944 const DWORD* pToken = This->baseShader.function;
945 const SHADER_OPCODE* curOpcode = NULL;
946 /** functions parameters */
947 WINED3DSHADERVECTOR* p[6];
948 WINED3DSHADERVECTOR* p_send[6];
949 DWORD i;
951 /** init temporary register */
952 memset(R, 0, 12 * sizeof(WINED3DSHADERVECTOR));
954 /* vshader_program_parse(vshader); */
955 #if 0 /* Must not be 1 in cvs */
956 TRACE("Input:\n");
957 TRACE_VSVECTOR(This->data->C[0]);
958 TRACE_VSVECTOR(This->data->C[1]);
959 TRACE_VSVECTOR(This->data->C[2]);
960 TRACE_VSVECTOR(This->data->C[3]);
961 TRACE_VSVECTOR(This->data->C[4]);
962 TRACE_VSVECTOR(This->data->C[5]);
963 TRACE_VSVECTOR(This->data->C[6]);
964 TRACE_VSVECTOR(This->data->C[7]);
965 TRACE_VSVECTOR(This->data->C[8]);
966 TRACE_VSVECTOR(This->data->C[64]);
967 TRACE_VSVECTOR(input->V[D3DVSDE_POSITION]);
968 TRACE_VSVECTOR(input->V[D3DVSDE_BLENDWEIGHT]);
969 TRACE_VSVECTOR(input->V[D3DVSDE_BLENDINDICES]);
970 TRACE_VSVECTOR(input->V[D3DVSDE_NORMAL]);
971 TRACE_VSVECTOR(input->V[D3DVSDE_PSIZE]);
972 TRACE_VSVECTOR(input->V[D3DVSDE_DIFFUSE]);
973 TRACE_VSVECTOR(input->V[D3DVSDE_SPECULAR]);
974 TRACE_VSVECTOR(input->V[D3DVSDE_TEXCOORD0]);
975 TRACE_VSVECTOR(input->V[D3DVSDE_TEXCOORD1]);
976 #endif
978 TRACE_VSVECTOR(vshader->data->C[64]);
979 /* TODO: Run through all the tokens and find and labels, if, endifs, loops etc...., and make a labels list */
981 /* the first dword is the version tag */
982 /* TODO: parse it */
984 if (shader_is_vshader_version(*pToken)) { /** version */
985 ++pToken;
987 while (D3DVS_END() != *pToken) {
988 if (shader_is_comment(*pToken)) { /** comment */
989 DWORD comment_len = (*pToken & D3DSI_COMMENTSIZE_MASK) >> D3DSI_COMMENTSIZE_SHIFT;
990 ++pToken;
991 pToken += comment_len;
992 continue ;
995 opcode_token = *pToken++;
996 curOpcode = shader_get_opcode((IWineD3DBaseShader*) This, opcode_token);
998 if (NULL == curOpcode) {
999 FIXME("Unrecognized opcode: token=%08lX\n", opcode_token);
1000 pToken += shader_skip_unrecognized((IWineD3DBaseShader*) This, pToken);
1001 /* return FALSE; */
1003 } else {
1004 if (curOpcode->num_params > 0) {
1005 /* TRACE(">> execting opcode: pos=%d opcode_name=%s token=%08lX\n", pToken - vshader->function, curOpcode->name, *pToken); */
1006 for (i = 0; i < curOpcode->num_params; ++i) {
1007 DWORD reg = pToken[i] & D3DSP_REGNUM_MASK;
1008 DWORD regtype = shader_get_regtype(pToken[i]);
1010 switch (regtype) {
1011 case D3DSPR_TEMP:
1012 /* TRACE("p[%d]=R[%d]\n", i, reg); */
1013 p[i] = &R[reg];
1014 break;
1015 case D3DSPR_INPUT:
1016 /* TRACE("p[%d]=V[%s]\n", i, VertexShaderDeclRegister[reg]); */
1017 p[i] = &input->V[reg];
1018 break;
1019 case D3DSPR_CONST:
1020 if (pToken[i] & D3DVS_ADDRMODE_RELATIVE) {
1021 p[i] = &This->data->C[(DWORD) A[0].x + reg];
1022 } else {
1023 p[i] = &This->data->C[reg];
1025 break;
1026 case D3DSPR_ADDR: /* case D3DSPR_TEXTURE: */
1027 if (0 != reg) {
1028 ERR("cannot handle address registers != a0, forcing use of a0\n");
1029 reg = 0;
1031 /* TRACE("p[%d]=A[%d]\n", i, reg); */
1032 p[i] = &A[reg];
1033 break;
1034 case D3DSPR_RASTOUT:
1035 switch (reg) {
1036 case D3DSRO_POSITION:
1037 p[i] = &output->oPos;
1038 break;
1039 case D3DSRO_FOG:
1040 p[i] = &output->oFog;
1041 break;
1042 case D3DSRO_POINT_SIZE:
1043 p[i] = &output->oPts;
1044 break;
1046 break;
1047 case D3DSPR_ATTROUT:
1048 /* TRACE("p[%d]=oD[%d]\n", i, reg); */
1049 p[i] = &output->oD[reg];
1050 break;
1051 case D3DSPR_TEXCRDOUT:
1052 /* TRACE("p[%d]=oT[%d]\n", i, reg); */
1053 p[i] = &output->oT[reg];
1054 break;
1055 /* TODO Decls and defs */
1056 #if 0
1057 case D3DSPR_DCL:
1058 case D3DSPR_DEF:
1059 #endif
1060 default:
1061 break;
1064 if (i > 0) { /* input reg */
1065 DWORD swizzle = (pToken[i] & D3DVS_SWIZZLE_MASK) >> D3DVS_SWIZZLE_SHIFT;
1066 UINT isNegative = ((pToken[i] & D3DSP_SRCMOD_MASK) == D3DSPSM_NEG);
1068 if (!isNegative && (D3DVS_NOSWIZZLE >> D3DVS_SWIZZLE_SHIFT) == swizzle) {
1069 /* TRACE("p[%d] not swizzled\n", i); */
1070 p_send[i] = p[i];
1071 } else {
1072 DWORD swizzle_x = swizzle & 0x03;
1073 DWORD swizzle_y = (swizzle >> 2) & 0x03;
1074 DWORD swizzle_z = (swizzle >> 4) & 0x03;
1075 DWORD swizzle_w = (swizzle >> 6) & 0x03;
1076 /* TRACE("p[%d] swizzled\n", i); */
1077 float* tt = (float*) p[i];
1078 s[i].x = (isNegative) ? -tt[swizzle_x] : tt[swizzle_x];
1079 s[i].y = (isNegative) ? -tt[swizzle_y] : tt[swizzle_y];
1080 s[i].z = (isNegative) ? -tt[swizzle_z] : tt[swizzle_z];
1081 s[i].w = (isNegative) ? -tt[swizzle_w] : tt[swizzle_w];
1082 p_send[i] = &s[i];
1084 } else { /* output reg */
1085 if ((pToken[i] & D3DSP_WRITEMASK_ALL) == D3DSP_WRITEMASK_ALL) {
1086 p_send[i] = p[i];
1087 } else {
1088 p_send[i] = &d; /* to be post-processed for modifiers management */
1094 switch (curOpcode->num_params) {
1095 case 0:
1096 curOpcode->soft_fct();
1097 break;
1098 case 1:
1099 curOpcode->soft_fct(p_send[0]);
1100 break;
1101 case 2:
1102 curOpcode->soft_fct(p_send[0], p_send[1]);
1103 break;
1104 case 3:
1105 curOpcode->soft_fct(p_send[0], p_send[1], p_send[2]);
1106 break;
1107 case 4:
1108 curOpcode->soft_fct(p_send[0], p_send[1], p_send[2], p_send[3]);
1109 break;
1110 case 5:
1111 curOpcode->soft_fct(p_send[0], p_send[1], p_send[2], p_send[3], p_send[4]);
1112 break;
1113 case 6:
1114 curOpcode->soft_fct(p_send[0], p_send[1], p_send[2], p_send[3], p_send[4], p_send[5]);
1115 break;
1116 default:
1117 ERR("%s too many params: %u\n", curOpcode->name, curOpcode->num_params);
1120 /* check if output reg modifier post-process */
1121 if (curOpcode->num_params > 0 && (pToken[0] & D3DSP_WRITEMASK_ALL) != D3DSP_WRITEMASK_ALL) {
1122 if (pToken[0] & D3DSP_WRITEMASK_0) p[0]->x = d.x;
1123 if (pToken[0] & D3DSP_WRITEMASK_1) p[0]->y = d.y;
1124 if (pToken[0] & D3DSP_WRITEMASK_2) p[0]->z = d.z;
1125 if (pToken[0] & D3DSP_WRITEMASK_3) p[0]->w = d.w;
1127 #if 0
1128 TRACE_VSVECTOR(output->oPos);
1129 TRACE_VSVECTOR(output->oD[0]);
1130 TRACE_VSVECTOR(output->oD[1]);
1131 TRACE_VSVECTOR(output->oT[0]);
1132 TRACE_VSVECTOR(output->oT[1]);
1133 TRACE_VSVECTOR(R[0]);
1134 TRACE_VSVECTOR(R[1]);
1135 TRACE_VSVECTOR(R[2]);
1136 TRACE_VSVECTOR(R[3]);
1137 TRACE_VSVECTOR(R[4]);
1138 TRACE_VSVECTOR(R[5]);
1139 #endif
1141 /* to next opcode token */
1142 pToken += curOpcode->num_params;
1144 #if 0
1145 TRACE("End of current instruction:\n");
1146 TRACE_VSVECTOR(output->oPos);
1147 TRACE_VSVECTOR(output->oD[0]);
1148 TRACE_VSVECTOR(output->oD[1]);
1149 TRACE_VSVECTOR(output->oT[0]);
1150 TRACE_VSVECTOR(output->oT[1]);
1151 TRACE_VSVECTOR(R[0]);
1152 TRACE_VSVECTOR(R[1]);
1153 TRACE_VSVECTOR(R[2]);
1154 TRACE_VSVECTOR(R[3]);
1155 TRACE_VSVECTOR(R[4]);
1156 TRACE_VSVECTOR(R[5]);
1157 #endif
1159 #if 0 /* Must not be 1 in cvs */
1160 TRACE("Output:\n");
1161 TRACE_VSVECTOR(output->oPos);
1162 TRACE_VSVECTOR(output->oD[0]);
1163 TRACE_VSVECTOR(output->oD[1]);
1164 TRACE_VSVECTOR(output->oT[0]);
1165 TRACE_VSVECTOR(output->oT[1]);
1166 #endif
1167 return WINED3D_OK;
1170 HRESULT WINAPI IWineD3DVertexShaderImpl_SetConstantF(IWineD3DVertexShader *iface, UINT StartRegister, CONST FLOAT *pConstantData, UINT Vector4fCount) {
1171 IWineD3DVertexShaderImpl *This = (IWineD3DVertexShaderImpl *)iface;
1172 FIXME("(%p) : stub\n", This);
1173 return WINED3D_OK;
1176 HRESULT WINAPI IWineD3DVertexShaderImpl_GetConstantF(IWineD3DVertexShader *iface, UINT StartRegister, FLOAT *pConstantData, UINT Vector4fCount) {
1177 IWineD3DVertexShaderImpl *This = (IWineD3DVertexShaderImpl *)iface;
1178 FIXME("(%p) : stub\n", This);
1179 return WINED3D_OK;
1182 HRESULT WINAPI IWineD3DVertexShaderImpl_SetConstantI(IWineD3DVertexShader *iface, UINT StartRegister, CONST int *pConstantData, UINT Vector4iCount) {
1183 IWineD3DVertexShaderImpl *This = (IWineD3DVertexShaderImpl *)iface;
1184 if (StartRegister + Vector4iCount > WINED3D_VSHADER_MAX_CONSTANTS) {
1185 ERR("(%p) : SetVertexShaderConstantI C[%u] invalid\n", This, StartRegister);
1186 return WINED3DERR_INVALIDCALL;
1188 if (NULL == pConstantData) {
1189 return WINED3DERR_INVALIDCALL;
1191 FIXME("(%p) : stub\n", This);
1192 return WINED3D_OK;
1195 HRESULT WINAPI IWineD3DVertexShaderImpl_GetConstantI(IWineD3DVertexShader *iface, UINT StartRegister, int *pConstantData, UINT Vector4iCount) {
1196 IWineD3DVertexShaderImpl *This = (IWineD3DVertexShaderImpl *)iface;
1197 TRACE("(%p) : C[%u] count=%u\n", This, StartRegister, Vector4iCount);
1198 if (StartRegister + Vector4iCount > WINED3D_VSHADER_MAX_CONSTANTS) {
1199 return WINED3DERR_INVALIDCALL;
1201 if (NULL == pConstantData) {
1202 return WINED3DERR_INVALIDCALL;
1204 FIXME("(%p) : stub\n", This);
1205 return WINED3D_OK;
1208 HRESULT WINAPI IWineD3DVertexShaderImpl_SetConstantB(IWineD3DVertexShader *iface, UINT StartRegister, CONST BOOL *pConstantData, UINT BoolCount) {
1209 IWineD3DVertexShaderImpl *This = (IWineD3DVertexShaderImpl *)iface;
1210 if (StartRegister + BoolCount > WINED3D_VSHADER_MAX_CONSTANTS) {
1211 ERR("(%p) : SetVertexShaderConstantB C[%u] invalid\n", This, StartRegister);
1212 return WINED3DERR_INVALIDCALL;
1214 if (NULL == pConstantData) {
1215 return WINED3DERR_INVALIDCALL;
1217 FIXME("(%p) : stub\n", This);
1218 return WINED3D_OK;
1221 HRESULT WINAPI IWineD3DVertexShaderImpl_GetConstantB(IWineD3DVertexShader *iface, UINT StartRegister, BOOL *pConstantData, UINT BoolCount) {
1222 IWineD3DVertexShaderImpl* This = (IWineD3DVertexShaderImpl *)iface;
1223 FIXME("(%p) : stub\n", This);
1224 return WINED3D_OK;
1227 #endif
1229 /* *******************************************
1230 IWineD3DVertexShader IUnknown parts follow
1231 ******************************************* */
1232 static HRESULT WINAPI IWineD3DVertexShaderImpl_QueryInterface(IWineD3DVertexShader *iface, REFIID riid, LPVOID *ppobj)
1234 IWineD3DVertexShaderImpl *This = (IWineD3DVertexShaderImpl *)iface;
1235 TRACE("(%p)->(%s,%p)\n",This,debugstr_guid(riid),ppobj);
1236 if (IsEqualGUID(riid, &IID_IUnknown)
1237 || IsEqualGUID(riid, &IID_IWineD3DBase)
1238 || IsEqualGUID(riid, &IID_IWineD3DBaseShader)
1239 || IsEqualGUID(riid, &IID_IWineD3DVertexShader)) {
1240 IUnknown_AddRef(iface);
1241 *ppobj = This;
1242 return S_OK;
1244 *ppobj = NULL;
1245 return E_NOINTERFACE;
1248 static ULONG WINAPI IWineD3DVertexShaderImpl_AddRef(IWineD3DVertexShader *iface) {
1249 IWineD3DVertexShaderImpl *This = (IWineD3DVertexShaderImpl *)iface;
1250 TRACE("(%p) : AddRef increasing from %ld\n", This, This->ref);
1251 return InterlockedIncrement(&This->ref);
1254 static ULONG WINAPI IWineD3DVertexShaderImpl_Release(IWineD3DVertexShader *iface) {
1255 IWineD3DVertexShaderImpl *This = (IWineD3DVertexShaderImpl *)iface;
1256 ULONG ref;
1257 TRACE("(%p) : Releasing from %ld\n", This, This->ref);
1258 ref = InterlockedDecrement(&This->ref);
1259 if (ref == 0) {
1260 if (This->vertexDeclaration) IWineD3DVertexDeclaration_Release(This->vertexDeclaration);
1261 if (wined3d_settings.shader_mode == SHADER_GLSL && This->baseShader.prgId != 0) {
1262 /* If this shader is still attached to a program, GL will perform a lazy delete */
1263 TRACE("Deleting shader object %u\n", This->baseShader.prgId);
1264 GL_EXTCALL(glDeleteObjectARB(This->baseShader.prgId));
1265 checkGLcall("glDeleteObjectARB");
1267 HeapFree(GetProcessHeap(), 0, This);
1269 return ref;
1272 /* *******************************************
1273 IWineD3DVertexShader IWineD3DVertexShader parts follow
1274 ******************************************* */
1276 static HRESULT WINAPI IWineD3DVertexShaderImpl_GetParent(IWineD3DVertexShader *iface, IUnknown** parent){
1277 IWineD3DVertexShaderImpl *This = (IWineD3DVertexShaderImpl *)iface;
1279 *parent = This->parent;
1280 IUnknown_AddRef(*parent);
1281 TRACE("(%p) : returning %p\n", This, *parent);
1282 return WINED3D_OK;
1285 static HRESULT WINAPI IWineD3DVertexShaderImpl_GetDevice(IWineD3DVertexShader* iface, IWineD3DDevice **pDevice){
1286 IWineD3DVertexShaderImpl *This = (IWineD3DVertexShaderImpl *)iface;
1287 IWineD3DDevice_AddRef((IWineD3DDevice *)This->wineD3DDevice);
1288 *pDevice = (IWineD3DDevice *)This->wineD3DDevice;
1289 TRACE("(%p) returning %p\n", This, *pDevice);
1290 return WINED3D_OK;
1293 static HRESULT WINAPI IWineD3DVertexShaderImpl_GetFunction(IWineD3DVertexShader* impl, VOID* pData, UINT* pSizeOfData) {
1294 IWineD3DVertexShaderImpl *This = (IWineD3DVertexShaderImpl *)impl;
1295 TRACE("(%p) : pData(%p), pSizeOfData(%p)\n", This, pData, pSizeOfData);
1297 if (NULL == pData) {
1298 *pSizeOfData = This->baseShader.functionLength;
1299 return WINED3D_OK;
1301 if (*pSizeOfData < This->baseShader.functionLength) {
1302 *pSizeOfData = This->baseShader.functionLength;
1303 return WINED3DERR_MOREDATA;
1305 if (NULL == This->baseShader.function) { /* no function defined */
1306 TRACE("(%p) : GetFunction no User Function defined using NULL to %p\n", This, pData);
1307 (*(DWORD **) pData) = NULL;
1308 } else {
1309 if(This->baseShader.functionLength == 0){
1312 TRACE("(%p) : GetFunction copying to %p\n", This, pData);
1313 memcpy(pData, This->baseShader.function, This->baseShader.functionLength);
1315 return WINED3D_OK;
1318 static HRESULT WINAPI IWineD3DVertexShaderImpl_SetFunction(IWineD3DVertexShader *iface, CONST DWORD *pFunction) {
1319 IWineD3DVertexShaderImpl *This =(IWineD3DVertexShaderImpl *)iface;
1320 const DWORD* pToken = pFunction;
1321 const SHADER_OPCODE* curOpcode = NULL;
1322 DWORD opcode_token;
1323 DWORD len = 0;
1324 DWORD i;
1325 TRACE("(%p) : Parsing programme\n", This);
1327 if (NULL != pToken) {
1328 while (D3DVS_END() != *pToken) {
1329 if (shader_is_vshader_version(*pToken)) { /** version */
1330 vshader_set_version(This, *pToken);
1331 ++pToken;
1332 ++len;
1333 continue;
1335 if (shader_is_comment(*pToken)) { /** comment */
1336 DWORD comment_len = (*pToken & D3DSI_COMMENTSIZE_MASK) >> D3DSI_COMMENTSIZE_SHIFT;
1337 ++pToken;
1338 TRACE("//%s\n", (char*)pToken);
1339 pToken += comment_len;
1340 len += comment_len + 1;
1341 continue;
1344 opcode_token = *pToken++;
1345 curOpcode = shader_get_opcode((IWineD3DBaseShader*) This, opcode_token);
1346 len++;
1348 if (NULL == curOpcode) {
1349 int tokens_read;
1351 FIXME("Unrecognized opcode: token=%08lX\n", opcode_token);
1352 tokens_read = shader_skip_unrecognized((IWineD3DBaseShader*) This, pToken);
1353 pToken += tokens_read;
1354 len += tokens_read;
1356 } else {
1357 if (curOpcode->opcode == D3DSIO_DCL) {
1359 DWORD usage = *pToken;
1360 DWORD param = *(pToken + 1);
1362 shader_program_dump_decl_usage(usage, param);
1363 shader_dump_ins_modifiers(param);
1364 TRACE(" ");
1365 shader_dump_param((IWineD3DBaseShader*) This, param, 0, 0);
1366 pToken += 2;
1367 len += 2;
1369 } else if (curOpcode->opcode == D3DSIO_DEF) {
1371 unsigned int offset = shader_get_float_offset(*pToken);
1373 TRACE("def c%u = %f, %f, %f, %f", offset,
1374 *(float *)(pToken + 1),
1375 *(float *)(pToken + 2),
1376 *(float *)(pToken + 3),
1377 *(float *)(pToken + 4));
1379 pToken += 5;
1380 len += 5;
1382 } else if (curOpcode->opcode == D3DSIO_DEFI) {
1384 TRACE("defi i%lu = %ld, %ld, %ld, %ld", *pToken & D3DSP_REGNUM_MASK,
1385 (long) *(pToken + 1),
1386 (long) *(pToken + 2),
1387 (long) *(pToken + 3),
1388 (long) *(pToken + 4));
1390 pToken += 5;
1391 len += 5;
1393 } else if (curOpcode->opcode == D3DSIO_DEFB) {
1395 TRACE("defb b%lu = %s", *pToken & D3DSP_REGNUM_MASK,
1396 *(pToken + 1)? "true": "false");
1398 pToken += 2;
1399 len += 2;
1401 } else {
1403 DWORD param, addr_token;
1404 int tokens_read;
1406 /* Print out predication source token first - it follows
1407 * the destination token. */
1408 if (opcode_token & D3DSHADER_INSTRUCTION_PREDICATED) {
1409 TRACE("(");
1410 shader_dump_param((IWineD3DBaseShader*) This, *(pToken + 2), 0, 1);
1411 TRACE(") ");
1414 TRACE("%s", curOpcode->name);
1415 if (curOpcode->num_params > 0) {
1417 /* Destination token */
1418 tokens_read = shader_get_param((IWineD3DBaseShader*) This,
1419 pToken, &param, &addr_token);
1420 pToken += tokens_read;
1421 len += tokens_read;
1423 shader_dump_ins_modifiers(param);
1424 TRACE(" ");
1425 shader_dump_param((IWineD3DBaseShader*) This, param, addr_token, 0);
1427 /* Predication token - already printed out, just skip it */
1428 if (opcode_token & D3DSHADER_INSTRUCTION_PREDICATED) {
1429 pToken++;
1430 len++;
1433 /* Other source tokens */
1434 for (i = 1; i < curOpcode->num_params; ++i) {
1436 tokens_read = shader_get_param((IWineD3DBaseShader*) This,
1437 pToken, &param, &addr_token);
1438 pToken += tokens_read;
1439 len += tokens_read;
1441 TRACE(", ");
1442 shader_dump_param((IWineD3DBaseShader*) This, param, addr_token, 1);
1446 TRACE("\n");
1449 This->baseShader.functionLength = (len + 1) * sizeof(DWORD);
1450 } else {
1451 This->baseShader.functionLength = 1; /* no Function defined use fixed function vertex processing */
1454 /* Generate HW shader in needed */
1455 if (NULL != pFunction && wined3d_settings.vs_mode == VS_HW)
1456 IWineD3DVertexShaderImpl_GenerateShader(iface, pFunction);
1458 /* copy the function ... because it will certainly be released by application */
1459 if (NULL != pFunction) {
1460 This->baseShader.function = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, This->baseShader.functionLength);
1461 memcpy((void *)This->baseShader.function, pFunction, This->baseShader.functionLength);
1462 } else {
1463 This->baseShader.function = NULL;
1465 return WINED3D_OK;
1468 const IWineD3DVertexShaderVtbl IWineD3DVertexShader_Vtbl =
1470 /*** IUnknown methods ***/
1471 IWineD3DVertexShaderImpl_QueryInterface,
1472 IWineD3DVertexShaderImpl_AddRef,
1473 IWineD3DVertexShaderImpl_Release,
1474 /*** IWineD3DBase methods ***/
1475 IWineD3DVertexShaderImpl_GetParent,
1476 /*** IWineD3DBaseShader methods ***/
1477 IWineD3DVertexShaderImpl_SetFunction,
1478 /*** IWineD3DVertexShader methods ***/
1479 IWineD3DVertexShaderImpl_GetDevice,
1480 IWineD3DVertexShaderImpl_GetFunction