VirtualBox

source: vbox/trunk/src/VBox/Additions/WINNT/Graphics/Wine/wined3d/vertexshader.c@ 16684

Last change on this file since 16684 was 16477, checked in by vboxsync, 16 years ago

LGPL disclaimer by filemuncher

  • Property svn:eol-style set to native
File size: 31.2 KB
Line 
1/*
2 * shaders implementation
3 *
4 * Copyright 2002-2003 Jason Edmeades
5 * Copyright 2002-2003 Raphael Junqueira
6 * Copyright 2004 Christian Costa
7 * Copyright 2005 Oliver Stieber
8 * Copyright 2006 Ivan Gyurdiev
9 * Copyright 2007-2008 Stefan Dösinger for CodeWeavers
10 *
11 * This library is free software; you can redistribute it and/or
12 * modify it under the terms of the GNU Lesser General Public
13 * License as published by the Free Software Foundation; either
14 * version 2.1 of the License, or (at your option) any later version.
15 *
16 * This library is distributed in the hope that it will be useful,
17 * but WITHOUT ANY WARRANTY; without even the implied warranty of
18 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
19 * Lesser General Public License for more details.
20 *
21 * You should have received a copy of the GNU Lesser General Public
22 * License along with this library; if not, write to the Free Software
23 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
24 */
25
26/*
27 * Sun LGPL Disclaimer: For the avoidance of doubt, except that if any license choice
28 * other than GPL or LGPL is available it will apply instead, Sun elects to use only
29 * the Lesser General Public License version 2.1 (LGPLv2) at this time for any software where
30 * a choice of LGPL license versions is made available with the language indicating
31 * that LGPLv2 or any later version may be used, or where a choice of which version
32 * of the LGPL is applied is otherwise unspecified.
33 */
34
35#include "config.h"
36
37#include <math.h>
38#include <stdio.h>
39
40#include "wined3d_private.h"
41
42WINE_DEFAULT_DEBUG_CHANNEL(d3d_shader);
43
44#define GLINFO_LOCATION ((IWineD3DDeviceImpl *)This->baseShader.device)->adapter->gl_info
45
46/* TODO: Vertex and Pixel shaders are almost identical, the only exception being the way that some of the data is looked up or the availability of some of the data i.e. some instructions are only valid for pshaders and some for vshaders
47because of this the bulk of the software pipeline can be shared between pixel and vertex shaders... and it wouldn't surprise me if the program can be cross compiled using a large body of shared code */
48
49#define GLNAME_REQUIRE_GLSL ((const char *)1)
50
51CONST SHADER_OPCODE IWineD3DVertexShaderImpl_shader_ins[] = {
52 /* This table is not order or position dependent. */
53
54 /* Arithmetic */
55 {WINED3DSIO_NOP, "nop", "NOP", 0, 0, WINED3DSIH_NOP, 0, 0 },
56 {WINED3DSIO_MOV, "mov", "MOV", 1, 2, WINED3DSIH_MOV, 0, 0 },
57 {WINED3DSIO_MOVA, "mova", NULL, 1, 2, WINED3DSIH_MOVA, WINED3DVS_VERSION(2,0), -1 },
58 {WINED3DSIO_ADD, "add", "ADD", 1, 3, WINED3DSIH_ADD, 0, 0 },
59 {WINED3DSIO_SUB, "sub", "SUB", 1, 3, WINED3DSIH_SUB, 0, 0 },
60 {WINED3DSIO_MAD, "mad", "MAD", 1, 4, WINED3DSIH_MAD, 0, 0 },
61 {WINED3DSIO_MUL, "mul", "MUL", 1, 3, WINED3DSIH_MUL, 0, 0 },
62 {WINED3DSIO_RCP, "rcp", "RCP", 1, 2, WINED3DSIH_RCP, 0, 0 },
63 {WINED3DSIO_RSQ, "rsq", "RSQ", 1, 2, WINED3DSIH_RSQ, 0, 0 },
64 {WINED3DSIO_DP3, "dp3", "DP3", 1, 3, WINED3DSIH_DP3, 0, 0 },
65 {WINED3DSIO_DP4, "dp4", "DP4", 1, 3, WINED3DSIH_DP4, 0, 0 },
66 {WINED3DSIO_MIN, "min", "MIN", 1, 3, WINED3DSIH_MIN, 0, 0 },
67 {WINED3DSIO_MAX, "max", "MAX", 1, 3, WINED3DSIH_MAX, 0, 0 },
68 {WINED3DSIO_SLT, "slt", "SLT", 1, 3, WINED3DSIH_SLT, 0, 0 },
69 {WINED3DSIO_SGE, "sge", "SGE", 1, 3, WINED3DSIH_SGE, 0, 0 },
70 {WINED3DSIO_ABS, "abs", "ABS", 1, 2, WINED3DSIH_ABS, 0, 0 },
71 {WINED3DSIO_EXP, "exp", "EX2", 1, 2, WINED3DSIH_EXP, 0, 0 },
72 {WINED3DSIO_LOG, "log", "LG2", 1, 2, WINED3DSIH_LOG, 0, 0 },
73 {WINED3DSIO_EXPP, "expp", "EXP", 1, 2, WINED3DSIH_EXPP, 0, 0 },
74 {WINED3DSIO_LOGP, "logp", "LOG", 1, 2, WINED3DSIH_LOGP, 0, 0 },
75 {WINED3DSIO_LIT, "lit", "LIT", 1, 2, WINED3DSIH_LIT, 0, 0 },
76 {WINED3DSIO_DST, "dst", "DST", 1, 3, WINED3DSIH_DST, 0, 0 },
77 {WINED3DSIO_LRP, "lrp", "LRP", 1, 4, WINED3DSIH_LRP, 0, 0 },
78 {WINED3DSIO_FRC, "frc", "FRC", 1, 2, WINED3DSIH_FRC, 0, 0 },
79 {WINED3DSIO_POW, "pow", "POW", 1, 3, WINED3DSIH_POW, 0, 0 },
80 {WINED3DSIO_CRS, "crs", "XPD", 1, 3, WINED3DSIH_CRS, 0, 0 },
81 /* TODO: sng can possibly be performed a s
82 RCP tmp, vec
83 MUL out, tmp, vec*/
84 {WINED3DSIO_SGN, "sgn", NULL, 1, 2, WINED3DSIH_SGN, 0, 0 },
85 {WINED3DSIO_NRM, "nrm", NULL, 1, 2, WINED3DSIH_NRM, 0, 0 },
86 {WINED3DSIO_SINCOS, "sincos", NULL, 1, 4, WINED3DSIH_SINCOS, WINED3DVS_VERSION(2,0), WINED3DVS_VERSION(2,1)},
87 {WINED3DSIO_SINCOS, "sincos", "SCS", 1, 2, WINED3DSIH_SINCOS, WINED3DVS_VERSION(3,0), -1 },
88 /* Matrix */
89 {WINED3DSIO_M4x4, "m4x4", "undefined", 1, 3, WINED3DSIH_M4x4, 0, 0 },
90 {WINED3DSIO_M4x3, "m4x3", "undefined", 1, 3, WINED3DSIH_M4x3, 0, 0 },
91 {WINED3DSIO_M3x4, "m3x4", "undefined", 1, 3, WINED3DSIH_M3x4, 0, 0 },
92 {WINED3DSIO_M3x3, "m3x3", "undefined", 1, 3, WINED3DSIH_M3x3, 0, 0 },
93 {WINED3DSIO_M3x2, "m3x2", "undefined", 1, 3, WINED3DSIH_M3x2, 0, 0 },
94 /* Declare registers */
95 {WINED3DSIO_DCL, "dcl", NULL, 0, 2, WINED3DSIH_DCL, 0, 0 },
96 /* Constant definitions */
97 {WINED3DSIO_DEF, "def", NULL, 1, 5, WINED3DSIH_DEF, 0, 0 },
98 {WINED3DSIO_DEFB, "defb", GLNAME_REQUIRE_GLSL, 1, 2, WINED3DSIH_DEFB, 0, 0 },
99 {WINED3DSIO_DEFI, "defi", GLNAME_REQUIRE_GLSL, 1, 5, WINED3DSIH_DEFI, 0, 0 },
100 /* Flow control - requires GLSL or software shaders */
101 {WINED3DSIO_REP , "rep", NULL, 0, 1, WINED3DSIH_REP, WINED3DVS_VERSION(2,0), -1 },
102 {WINED3DSIO_ENDREP, "endrep", NULL, 0, 0, WINED3DSIH_ENDREP, WINED3DVS_VERSION(2,0), -1 },
103 {WINED3DSIO_IF, "if", NULL, 0, 1, WINED3DSIH_IF, WINED3DVS_VERSION(2,0), -1 },
104 {WINED3DSIO_IFC, "ifc", NULL, 0, 2, WINED3DSIH_IFC, WINED3DVS_VERSION(2,1), -1 },
105 {WINED3DSIO_ELSE, "else", NULL, 0, 0, WINED3DSIH_ELSE, WINED3DVS_VERSION(2,0), -1 },
106 {WINED3DSIO_ENDIF, "endif", NULL, 0, 0, WINED3DSIH_ENDIF, WINED3DVS_VERSION(2,0), -1 },
107 {WINED3DSIO_BREAK, "break", NULL, 0, 0, WINED3DSIH_BREAK, WINED3DVS_VERSION(2,1), -1 },
108 {WINED3DSIO_BREAKC, "breakc", NULL, 0, 2, WINED3DSIH_BREAKC, WINED3DVS_VERSION(2,1), -1 },
109 {WINED3DSIO_BREAKP, "breakp", GLNAME_REQUIRE_GLSL, 0, 1, WINED3DSIH_BREAKP, 0, 0 },
110 {WINED3DSIO_CALL, "call", NULL, 0, 1, WINED3DSIH_CALL, WINED3DVS_VERSION(2,0), -1 },
111 {WINED3DSIO_CALLNZ, "callnz", NULL, 0, 2, WINED3DSIH_CALLNZ, WINED3DVS_VERSION(2,0), -1 },
112 {WINED3DSIO_LOOP, "loop", NULL, 0, 2, WINED3DSIH_LOOP, WINED3DVS_VERSION(2,0), -1 },
113 {WINED3DSIO_RET, "ret", NULL, 0, 0, WINED3DSIH_RET, WINED3DVS_VERSION(2,0), -1 },
114 {WINED3DSIO_ENDLOOP, "endloop", NULL, 0, 0, WINED3DSIH_ENDLOOP, WINED3DVS_VERSION(2,0), -1 },
115 {WINED3DSIO_LABEL, "label", NULL, 0, 1, WINED3DSIH_LABEL, WINED3DVS_VERSION(2,0), -1 },
116
117 {WINED3DSIO_SETP, "setp", GLNAME_REQUIRE_GLSL, 1, 3, WINED3DSIH_SETP, 0, 0 },
118 {WINED3DSIO_TEXLDL, "texldl", NULL, 1, 3, WINED3DSIH_TEXLDL, WINED3DVS_VERSION(3,0), -1 },
119 {0, NULL, NULL, 0, 0, 0, 0, 0 }
120};
121
122static void vshader_set_limits(
123 IWineD3DVertexShaderImpl *This) {
124
125 This->baseShader.limits.texcoord = 0;
126 This->baseShader.limits.attributes = 16;
127 This->baseShader.limits.packed_input = 0;
128
129 /* Must match D3DCAPS9.MaxVertexShaderConst: at least 256 for vs_2_0 */
130 This->baseShader.limits.constant_float = GL_LIMITS(vshader_constantsF);
131
132 switch (This->baseShader.hex_version) {
133 case WINED3DVS_VERSION(1,0):
134 case WINED3DVS_VERSION(1,1):
135 This->baseShader.limits.temporary = 12;
136 This->baseShader.limits.constant_bool = 0;
137 This->baseShader.limits.constant_int = 0;
138 This->baseShader.limits.address = 1;
139 This->baseShader.limits.packed_output = 0;
140 This->baseShader.limits.sampler = 0;
141 This->baseShader.limits.label = 0;
142 break;
143
144 case WINED3DVS_VERSION(2,0):
145 case WINED3DVS_VERSION(2,1):
146 This->baseShader.limits.temporary = 12;
147 This->baseShader.limits.constant_bool = 16;
148 This->baseShader.limits.constant_int = 16;
149 This->baseShader.limits.address = 1;
150 This->baseShader.limits.packed_output = 0;
151 This->baseShader.limits.sampler = 0;
152 This->baseShader.limits.label = 16;
153 break;
154
155 case WINED3DVS_VERSION(3,0):
156 This->baseShader.limits.temporary = 32;
157 This->baseShader.limits.constant_bool = 32;
158 This->baseShader.limits.constant_int = 32;
159 This->baseShader.limits.address = 1;
160 This->baseShader.limits.packed_output = 12;
161 This->baseShader.limits.sampler = 4;
162 This->baseShader.limits.label = 16; /* FIXME: 2048 */
163 break;
164
165 default: This->baseShader.limits.temporary = 12;
166 This->baseShader.limits.constant_bool = 16;
167 This->baseShader.limits.constant_int = 16;
168 This->baseShader.limits.address = 1;
169 This->baseShader.limits.packed_output = 0;
170 This->baseShader.limits.sampler = 0;
171 This->baseShader.limits.label = 16;
172 FIXME("Unrecognized vertex shader version %#x\n",
173 This->baseShader.hex_version);
174 }
175}
176
177/* This is an internal function,
178 * used to create fake semantics for shaders
179 * that don't have them - d3d8 shaders where the declaration
180 * stores the register for each input
181 */
182static void vshader_set_input(
183 IWineD3DVertexShaderImpl* This,
184 unsigned int regnum,
185 BYTE usage, BYTE usage_idx) {
186
187 /* Fake usage: set reserved bit, usage, usage_idx */
188 DWORD usage_token = (0x1 << 31) |
189 (usage << WINED3DSP_DCL_USAGE_SHIFT) | (usage_idx << WINED3DSP_DCL_USAGEINDEX_SHIFT);
190
191 /* Fake register; set reserved bit, regnum, type: input, wmask: all */
192 DWORD reg_token = (0x1 << 31) |
193 WINED3DSP_WRITEMASK_ALL | (WINED3DSPR_INPUT << WINED3DSP_REGTYPE_SHIFT) | regnum;
194
195 This->semantics_in[regnum].usage = usage_token;
196 This->semantics_in[regnum].reg = reg_token;
197}
198
199static BOOL match_usage(BYTE usage1, BYTE usage_idx1, BYTE usage2, BYTE usage_idx2) {
200 if (usage_idx1 != usage_idx2) return FALSE;
201 if (usage1 == usage2) return TRUE;
202 if (usage1 == WINED3DDECLUSAGE_POSITION && usage2 == WINED3DDECLUSAGE_POSITIONT) return TRUE;
203 if (usage2 == WINED3DDECLUSAGE_POSITION && usage1 == WINED3DDECLUSAGE_POSITIONT) return TRUE;
204
205 return FALSE;
206}
207
208BOOL vshader_get_input(
209 IWineD3DVertexShader* iface,
210 BYTE usage_req, BYTE usage_idx_req,
211 unsigned int* regnum) {
212
213 IWineD3DVertexShaderImpl* This = (IWineD3DVertexShaderImpl*) iface;
214 int i;
215
216 for (i = 0; i < MAX_ATTRIBS; i++) {
217 DWORD usage_token = This->semantics_in[i].usage;
218 DWORD usage = (usage_token & WINED3DSP_DCL_USAGE_MASK) >> WINED3DSP_DCL_USAGE_SHIFT;
219 DWORD usage_idx = (usage_token & WINED3DSP_DCL_USAGEINDEX_MASK) >> WINED3DSP_DCL_USAGEINDEX_SHIFT;
220
221 if (usage_token && match_usage(usage, usage_idx, usage_req, usage_idx_req)) {
222 *regnum = i;
223 return TRUE;
224 }
225 }
226 return FALSE;
227}
228
229BOOL vshader_input_is_color(
230 IWineD3DVertexShader* iface,
231 unsigned int regnum) {
232
233 IWineD3DVertexShaderImpl* This = (IWineD3DVertexShaderImpl*) iface;
234
235 DWORD usage_token = This->semantics_in[regnum].usage;
236 DWORD usage = (usage_token & WINED3DSP_DCL_USAGE_MASK) >> WINED3DSP_DCL_USAGE_SHIFT;
237 DWORD usage_idx = (usage_token & WINED3DSP_DCL_USAGEINDEX_MASK) >> WINED3DSP_DCL_USAGEINDEX_SHIFT;
238
239 int i;
240
241 for(i = 0; i < This->num_swizzled_attribs; i++) {
242 if(This->swizzled_attribs[i].usage == usage &&
243 This->swizzled_attribs[i].idx == usage_idx) {
244 return TRUE;
245 }
246 }
247 return FALSE;
248}
249
250static inline void find_swizzled_attribs(IWineD3DVertexDeclaration *declaration, IWineD3DVertexShaderImpl *This) {
251 UINT num = 0, i, j;
252 UINT numoldswizzles = This->num_swizzled_attribs;
253 IWineD3DVertexDeclarationImpl *decl = (IWineD3DVertexDeclarationImpl *) declaration;
254
255 DWORD usage_token, usage, usage_idx;
256 BOOL found;
257
258 attrib_declaration oldswizzles[sizeof(This->swizzled_attribs) / sizeof(This->swizzled_attribs[0])];
259
260 /* Back up the old swizzles to keep attributes that are undefined in the current declaration */
261 memcpy(oldswizzles, This->swizzled_attribs, sizeof(oldswizzles));
262
263 memset(This->swizzled_attribs, 0, sizeof(This->swizzled_attribs[0]) * MAX_ATTRIBS);
264
265 for(i = 0; i < decl->num_swizzled_attribs; i++) {
266 for(j = 0; j < MAX_ATTRIBS; j++) {
267
268 if(!This->baseShader.reg_maps.attributes[j]) continue;
269
270 usage_token = This->semantics_in[j].usage;
271 usage = (usage_token & WINED3DSP_DCL_USAGE_MASK) >> WINED3DSP_DCL_USAGE_SHIFT;
272 usage_idx = (usage_token & WINED3DSP_DCL_USAGEINDEX_MASK) >> WINED3DSP_DCL_USAGEINDEX_SHIFT;
273
274 if(decl->swizzled_attribs[i].usage == usage &&
275 decl->swizzled_attribs[i].idx == usage_idx) {
276 This->swizzled_attribs[num].usage = usage;
277 This->swizzled_attribs[num].idx = usage_idx;
278 num++;
279 }
280 }
281 }
282
283 /* Add previously converted attributes back in if they are not defined in the current declaration */
284 for(i = 0; i < numoldswizzles; i++) {
285
286 found = FALSE;
287 for(j = 0; j < decl->declarationWNumElements; j++) {
288 if(oldswizzles[i].usage == decl->pDeclarationWine[j].Usage &&
289 oldswizzles[i].idx == decl->pDeclarationWine[j].UsageIndex) {
290 found = TRUE;
291 }
292 }
293 if(found) {
294 /* This previously converted attribute is declared in the current declaration. Either it is
295 * already in the new array, or it should not be there. Skip it
296 */
297 continue;
298 }
299 /* We have a previously swizzled attribute that is not defined by the current vertex declaration.
300 * Insert it into the new conversion array to keep it in the old defined state. Otherwise we end up
301 * recompiling if the old decl is used again because undefined attributes are reset to no swizzling.
302 * In the reverse way(attribute was not swizzled and is not declared in new declaration) the attrib
303 * stays unswizzled as well because it isn't found in the oldswizzles array
304 */
305 for(j = 0; j < num; j++) {
306 if(oldswizzles[i].usage > This->swizzled_attribs[j].usage || (
307 oldswizzles[i].usage == This->swizzled_attribs[j].usage &&
308 oldswizzles[i].idx > This->swizzled_attribs[j].idx)) {
309 memmove(&This->swizzled_attribs[j + 1], &This->swizzled_attribs[j],
310 sizeof(This->swizzled_attribs) - (sizeof(This->swizzled_attribs[0]) * (j + 1)));
311 break;
312 }
313 }
314 This->swizzled_attribs[j].usage = oldswizzles[i].usage;
315 This->swizzled_attribs[j].idx = oldswizzles[i].idx;
316 num++;
317 }
318
319 TRACE("New swizzled attributes array\n");
320 for(i = 0; i < num; i++) {
321 TRACE("%d: %s(%d), %d\n", i, debug_d3ddeclusage(This->swizzled_attribs[i].usage),
322 This->swizzled_attribs[i].usage, This->swizzled_attribs[i].idx);
323 }
324 This->num_swizzled_attribs = num;
325}
326/** Generate a vertex shader string using either GL_VERTEX_PROGRAM_ARB
327 or GLSL and send it to the card */
328static void IWineD3DVertexShaderImpl_GenerateShader(IWineD3DVertexShader *iface,
329 const struct shader_reg_maps* reg_maps, const DWORD *pFunction)
330{
331 IWineD3DVertexShaderImpl *This = (IWineD3DVertexShaderImpl *)iface;
332 IWineD3DVertexDeclaration *decl = ((IWineD3DDeviceImpl *) This->baseShader.device)->stateBlock->vertexDecl;
333 SHADER_BUFFER buffer;
334
335 find_swizzled_attribs(decl, This);
336
337#if 0 /* FIXME: Use the buffer that is held by the device, this is ok since fixups will be skipped for software shaders
338 it also requires entering a critical section but cuts down the runtime footprint of wined3d and any memory fragmentation that may occur... */
339 if (This->device->fixupVertexBufferSize < SHADER_PGMSIZE) {
340 HeapFree(GetProcessHeap(), 0, This->fixupVertexBuffer);
341 This->fixupVertexBuffer = HeapAlloc(GetProcessHeap() , 0, SHADER_PGMSIZE);
342 This->fixupVertexBufferSize = PGMSIZE;
343 This->fixupVertexBuffer[0] = 0;
344 }
345 buffer.buffer = This->device->fixupVertexBuffer;
346#else
347 buffer.buffer = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, SHADER_PGMSIZE);
348#endif
349 buffer.bsize = 0;
350 buffer.lineNo = 0;
351 buffer.newline = TRUE;
352
353 ((IWineD3DDeviceImpl *)This->baseShader.device)->shader_backend->shader_generate_vshader(iface, &buffer);
354
355#if 1 /* if were using the data buffer of device then we don't need to free it */
356 HeapFree(GetProcessHeap(), 0, buffer.buffer);
357#endif
358}
359
360/* *******************************************
361 IWineD3DVertexShader IUnknown parts follow
362 ******************************************* */
363static HRESULT WINAPI IWineD3DVertexShaderImpl_QueryInterface(IWineD3DVertexShader *iface, REFIID riid, LPVOID *ppobj) {
364 return IWineD3DBaseShaderImpl_QueryInterface((IWineD3DBaseShader *) iface, riid, ppobj);
365}
366
367static ULONG WINAPI IWineD3DVertexShaderImpl_AddRef(IWineD3DVertexShader *iface) {
368 return IWineD3DBaseShaderImpl_AddRef((IWineD3DBaseShader *) iface);
369}
370
371static ULONG WINAPI IWineD3DVertexShaderImpl_Release(IWineD3DVertexShader *iface) {
372 return IWineD3DBaseShaderImpl_Release((IWineD3DBaseShader *) iface);
373}
374
375/* *******************************************
376 IWineD3DVertexShader IWineD3DVertexShader parts follow
377 ******************************************* */
378
379static HRESULT WINAPI IWineD3DVertexShaderImpl_GetParent(IWineD3DVertexShader *iface, IUnknown** parent){
380 IWineD3DVertexShaderImpl *This = (IWineD3DVertexShaderImpl *)iface;
381
382 *parent = This->parent;
383 IUnknown_AddRef(*parent);
384 TRACE("(%p) : returning %p\n", This, *parent);
385 return WINED3D_OK;
386}
387
388static HRESULT WINAPI IWineD3DVertexShaderImpl_GetDevice(IWineD3DVertexShader* iface, IWineD3DDevice **pDevice){
389 IWineD3DVertexShaderImpl *This = (IWineD3DVertexShaderImpl *)iface;
390 IWineD3DDevice_AddRef(This->baseShader.device);
391 *pDevice = This->baseShader.device;
392 TRACE("(%p) returning %p\n", This, *pDevice);
393 return WINED3D_OK;
394}
395
396static HRESULT WINAPI IWineD3DVertexShaderImpl_GetFunction(IWineD3DVertexShader* impl, VOID* pData, UINT* pSizeOfData) {
397 IWineD3DVertexShaderImpl *This = (IWineD3DVertexShaderImpl *)impl;
398 TRACE("(%p) : pData(%p), pSizeOfData(%p)\n", This, pData, pSizeOfData);
399
400 if (NULL == pData) {
401 *pSizeOfData = This->baseShader.functionLength;
402 return WINED3D_OK;
403 }
404 if (*pSizeOfData < This->baseShader.functionLength) {
405 /* MSDN claims (for d3d8 at least) that if *pSizeOfData is smaller
406 * than the required size we should write the required size and
407 * return D3DERR_MOREDATA. That's not actually true. */
408 return WINED3DERR_INVALIDCALL;
409 }
410 if (NULL == This->baseShader.function) { /* no function defined */
411 TRACE("(%p) : GetFunction no User Function defined using NULL to %p\n", This, pData);
412 (*(DWORD **) pData) = NULL;
413 } else {
414 if(This->baseShader.functionLength == 0){
415
416 }
417 TRACE("(%p) : GetFunction copying to %p\n", This, pData);
418 memcpy(pData, This->baseShader.function, This->baseShader.functionLength);
419 }
420 return WINED3D_OK;
421}
422
423/* Note that for vertex shaders CompileShader isn't called until the
424 * shader is first used. The reason for this is that we need the vertex
425 * declaration the shader will be used with in order to determine if
426 * the data in a register is of type D3DCOLOR, and needs swizzling. */
427static HRESULT WINAPI IWineD3DVertexShaderImpl_SetFunction(IWineD3DVertexShader *iface, CONST DWORD *pFunction) {
428
429 IWineD3DVertexShaderImpl *This =(IWineD3DVertexShaderImpl *)iface;
430 IWineD3DDeviceImpl *deviceImpl = (IWineD3DDeviceImpl *) This->baseShader.device;
431 HRESULT hr;
432 shader_reg_maps *reg_maps = &This->baseShader.reg_maps;
433
434 TRACE("(%p) : pFunction %p\n", iface, pFunction);
435
436 /* First pass: trace shader */
437 shader_trace_init((IWineD3DBaseShader*) This, pFunction);
438 vshader_set_limits(This);
439
440 /* Initialize immediate constant lists */
441 list_init(&This->baseShader.constantsF);
442 list_init(&This->baseShader.constantsB);
443 list_init(&This->baseShader.constantsI);
444
445 /* Second pass: figure out registers used, semantics, etc.. */
446 This->min_rel_offset = GL_LIMITS(vshader_constantsF);
447 This->max_rel_offset = 0;
448 memset(reg_maps, 0, sizeof(shader_reg_maps));
449 hr = shader_get_registers_used((IWineD3DBaseShader*) This, reg_maps,
450 This->semantics_in, This->semantics_out, pFunction, NULL);
451 if (hr != WINED3D_OK) return hr;
452
453 This->baseShader.shader_mode = deviceImpl->vs_selected_mode;
454
455 if(deviceImpl->vs_selected_mode == SHADER_ARB &&
456 (GLINFO_LOCATION).arb_vs_offset_limit &&
457 This->min_rel_offset <= This->max_rel_offset) {
458
459 if(This->max_rel_offset - This->min_rel_offset > 127) {
460 FIXME("The difference between the minimum and maximum relative offset is > 127\n");
461 FIXME("Which this OpenGL implementation does not support. Try using GLSL\n");
462 FIXME("Min: %d, Max: %d\n", This->min_rel_offset, This->max_rel_offset);
463 } else if(This->max_rel_offset - This->min_rel_offset > 63) {
464 This->rel_offset = This->min_rel_offset + 63;
465 } else if(This->max_rel_offset > 63) {
466 This->rel_offset = This->min_rel_offset;
467 } else {
468 This->rel_offset = 0;
469 }
470 }
471 This->baseShader.load_local_constsF = This->baseShader.reg_maps.usesrelconstF && !list_empty(&This->baseShader.constantsF);
472
473 /* copy the function ... because it will certainly be released by application */
474 if (NULL != pFunction) {
475 void *function;
476
477 function = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, This->baseShader.functionLength);
478 if (!function) return E_OUTOFMEMORY;
479 memcpy(function, pFunction, This->baseShader.functionLength);
480 This->baseShader.function = function;
481 } else {
482 This->baseShader.function = NULL;
483 }
484
485 return WINED3D_OK;
486}
487
488/* Preload semantics for d3d8 shaders */
489static void WINAPI IWineD3DVertexShaderImpl_FakeSemantics(IWineD3DVertexShader *iface, IWineD3DVertexDeclaration *vertex_declaration) {
490 IWineD3DVertexShaderImpl *This =(IWineD3DVertexShaderImpl *)iface;
491 IWineD3DVertexDeclarationImpl* vdecl = (IWineD3DVertexDeclarationImpl*)vertex_declaration;
492
493 int i;
494 for (i = 0; i < vdecl->declarationWNumElements - 1; ++i) {
495 const WINED3DVERTEXELEMENT *element = vdecl->pDeclarationWine + i;
496 vshader_set_input(This, element->Reg, element->Usage, element->UsageIndex);
497 }
498}
499
500/* Set local constants for d3d8 shaders */
501static HRESULT WINAPI IWIneD3DVertexShaderImpl_SetLocalConstantsF(IWineD3DVertexShader *iface,
502 UINT start_idx, const float *src_data, UINT count) {
503 IWineD3DVertexShaderImpl *This =(IWineD3DVertexShaderImpl *)iface;
504 UINT i, end_idx;
505
506 TRACE("(%p) : start_idx %u, src_data %p, count %u\n", This, start_idx, src_data, count);
507
508 end_idx = start_idx + count;
509 if (end_idx > GL_LIMITS(vshader_constantsF)) {
510 WARN("end_idx %u > float constants limit %u\n", end_idx, GL_LIMITS(vshader_constantsF));
511 end_idx = GL_LIMITS(vshader_constantsF);
512 }
513
514 for (i = start_idx; i < end_idx; ++i) {
515 local_constant* lconst = HeapAlloc(GetProcessHeap(), 0, sizeof(local_constant));
516 if (!lconst) return E_OUTOFMEMORY;
517
518 lconst->idx = i;
519 memcpy(lconst->value, src_data + (i - start_idx) * 4 /* 4 components */, 4 * sizeof(float));
520 list_add_head(&This->baseShader.constantsF, &lconst->entry);
521 }
522
523 return WINED3D_OK;
524}
525
526static inline BOOL swizzled_attribs_differ(IWineD3DVertexShaderImpl *This, IWineD3DVertexDeclarationImpl *vdecl) {
527 UINT i, j, k;
528 BOOL found;
529
530 DWORD usage_token;
531 DWORD usage;
532 DWORD usage_idx;
533
534 for(i = 0; i < vdecl->declarationWNumElements; i++) {
535 /* Ignore tesselated streams and the termination entry(position0, stream 255, unused) */
536 if(vdecl->pDeclarationWine[i].Stream >= MAX_STREAMS ||
537 vdecl->pDeclarationWine[i].Type == WINED3DDECLTYPE_UNUSED) continue;
538
539 for(j = 0; j < MAX_ATTRIBS; j++) {
540 if(!This->baseShader.reg_maps.attributes[j]) continue;
541
542 usage_token = This->semantics_in[j].usage;
543 usage = (usage_token & WINED3DSP_DCL_USAGE_MASK) >> WINED3DSP_DCL_USAGE_SHIFT;
544 usage_idx = (usage_token & WINED3DSP_DCL_USAGEINDEX_MASK) >> WINED3DSP_DCL_USAGEINDEX_SHIFT;
545
546 if(vdecl->pDeclarationWine[i].Usage != usage ||
547 vdecl->pDeclarationWine[i].UsageIndex != usage_idx) {
548 continue;
549 }
550
551 found = FALSE;
552 for(k = 0; k < This->num_swizzled_attribs; k++) {
553 if(This->swizzled_attribs[k].usage == usage &&
554 This->swizzled_attribs[k].idx == usage_idx) {
555 found = TRUE;
556 }
557 }
558 if(!found && vdecl->pDeclarationWine[i].Type == WINED3DDECLTYPE_D3DCOLOR) {
559 TRACE("Attribute %s%d is D3DCOLOR now but wasn't before\n",
560 debug_d3ddeclusage(usage), usage_idx);
561 return TRUE;
562 }
563 if( found && vdecl->pDeclarationWine[i].Type != WINED3DDECLTYPE_D3DCOLOR) {
564 TRACE("Attribute %s%d was D3DCOLOR before but is not any more\n",
565 debug_d3ddeclusage(usage), usage_idx);
566 return TRUE;
567 }
568 }
569 }
570 return FALSE;
571}
572
573HRESULT IWineD3DVertexShaderImpl_CompileShader(IWineD3DVertexShader *iface) {
574 IWineD3DVertexShaderImpl *This = (IWineD3DVertexShaderImpl *)iface;
575 IWineD3DVertexDeclarationImpl *vdecl;
576 CONST DWORD *function = This->baseShader.function;
577 IWineD3DDeviceImpl *deviceImpl = (IWineD3DDeviceImpl *) This->baseShader.device;
578
579 TRACE("(%p) : function %p\n", iface, function);
580
581 /* We're already compiled. */
582 if (This->baseShader.is_compiled) {
583 vdecl = (IWineD3DVertexDeclarationImpl *) deviceImpl->stateBlock->vertexDecl;
584
585 if(This->num_swizzled_attribs != vdecl->num_swizzled_attribs ||
586 memcmp(This->swizzled_attribs, vdecl->swizzled_attribs, sizeof(vdecl->swizzled_attribs[0]) * This->num_swizzled_attribs) != 0) {
587
588 /* The swizzled attributes differ between shader and declaration. This doesn't necessarily mean
589 * we have to recompile, but we have to take a deeper look at see if the attribs that differ
590 * are declared in the decl and used in the shader
591 */
592 if(swizzled_attribs_differ(This, vdecl)) {
593 WARN("Recompiling vertex shader %p due to D3DCOLOR input changes\n", This);
594 goto recompile;
595 }
596 WARN("Swizzled attribute validation required an expensive comparison\n");
597 }
598
599 return WINED3D_OK;
600
601 recompile:
602 if(This->recompile_count < 50) {
603 This->recompile_count++;
604 } else {
605 FIXME("Vertexshader %p recompiled more than 50 times\n", This);
606 }
607
608 deviceImpl->shader_backend->shader_destroy((IWineD3DBaseShader *) iface);
609 }
610
611 /* We don't need to compile */
612 if (!function) {
613 This->baseShader.is_compiled = TRUE;
614 return WINED3D_OK;
615 }
616
617 /* Generate the HW shader */
618 TRACE("(%p) : Generating hardware program\n", This);
619 IWineD3DVertexShaderImpl_GenerateShader(iface, &This->baseShader.reg_maps, function);
620
621 This->baseShader.is_compiled = TRUE;
622
623 return WINED3D_OK;
624}
625
626const IWineD3DVertexShaderVtbl IWineD3DVertexShader_Vtbl =
627{
628 /*** IUnknown methods ***/
629 IWineD3DVertexShaderImpl_QueryInterface,
630 IWineD3DVertexShaderImpl_AddRef,
631 IWineD3DVertexShaderImpl_Release,
632 /*** IWineD3DBase methods ***/
633 IWineD3DVertexShaderImpl_GetParent,
634 /*** IWineD3DBaseShader methods ***/
635 IWineD3DVertexShaderImpl_SetFunction,
636 /*** IWineD3DVertexShader methods ***/
637 IWineD3DVertexShaderImpl_GetDevice,
638 IWineD3DVertexShaderImpl_GetFunction,
639 IWineD3DVertexShaderImpl_FakeSemantics,
640 IWIneD3DVertexShaderImpl_SetLocalConstantsF
641};
Note: See TracBrowser for help on using the repository browser.

© 2024 Oracle Support Privacy / Do Not Sell My Info Terms of Use Trademark Policy Automated Access Etiquette