2 * shaders implementation
4 * Copyright 2002-2003 Jason Edmeades
5 * Copyright 2002-2003 Raphael Junqueira
6 * Copyright 2004 Christian Costa
7 * Copyright 2005 Oliver Stieber
8 * Copyright 2006 Ivan Gyurdiev
9 * Copyright 2007-2008 Stefan Dösinger for CodeWeavers
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.
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.
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
31 #include "wined3d_private.h"
33 WINE_DEFAULT_DEBUG_CHANNEL(d3d_shader);
35 #define GLINFO_LOCATION ((IWineD3DDeviceImpl *)This->baseShader.device)->adapter->gl_info
37 /* 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
38 because 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 */
40 CONST SHADER_OPCODE IWineD3DVertexShaderImpl_shader_ins[] = {
41 /* This table is not order or position dependent. */
44 {WINED3DSIO_NOP, "nop", 0, 0, WINED3DSIH_NOP, 0, 0 },
45 {WINED3DSIO_MOV, "mov", 1, 2, WINED3DSIH_MOV, 0, 0 },
46 {WINED3DSIO_MOVA, "mova", 1, 2, WINED3DSIH_MOVA, WINED3DVS_VERSION(2,0), -1 },
47 {WINED3DSIO_ADD, "add", 1, 3, WINED3DSIH_ADD, 0, 0 },
48 {WINED3DSIO_SUB, "sub", 1, 3, WINED3DSIH_SUB, 0, 0 },
49 {WINED3DSIO_MAD, "mad", 1, 4, WINED3DSIH_MAD, 0, 0 },
50 {WINED3DSIO_MUL, "mul", 1, 3, WINED3DSIH_MUL, 0, 0 },
51 {WINED3DSIO_RCP, "rcp", 1, 2, WINED3DSIH_RCP, 0, 0 },
52 {WINED3DSIO_RSQ, "rsq", 1, 2, WINED3DSIH_RSQ, 0, 0 },
53 {WINED3DSIO_DP3, "dp3", 1, 3, WINED3DSIH_DP3, 0, 0 },
54 {WINED3DSIO_DP4, "dp4", 1, 3, WINED3DSIH_DP4, 0, 0 },
55 {WINED3DSIO_MIN, "min", 1, 3, WINED3DSIH_MIN, 0, 0 },
56 {WINED3DSIO_MAX, "max", 1, 3, WINED3DSIH_MAX, 0, 0 },
57 {WINED3DSIO_SLT, "slt", 1, 3, WINED3DSIH_SLT, 0, 0 },
58 {WINED3DSIO_SGE, "sge", 1, 3, WINED3DSIH_SGE, 0, 0 },
59 {WINED3DSIO_ABS, "abs", 1, 2, WINED3DSIH_ABS, 0, 0 },
60 {WINED3DSIO_EXP, "exp", 1, 2, WINED3DSIH_EXP, 0, 0 },
61 {WINED3DSIO_LOG, "log", 1, 2, WINED3DSIH_LOG, 0, 0 },
62 {WINED3DSIO_EXPP, "expp", 1, 2, WINED3DSIH_EXPP, 0, 0 },
63 {WINED3DSIO_LOGP, "logp", 1, 2, WINED3DSIH_LOGP, 0, 0 },
64 {WINED3DSIO_LIT, "lit", 1, 2, WINED3DSIH_LIT, 0, 0 },
65 {WINED3DSIO_DST, "dst", 1, 3, WINED3DSIH_DST, 0, 0 },
66 {WINED3DSIO_LRP, "lrp", 1, 4, WINED3DSIH_LRP, 0, 0 },
67 {WINED3DSIO_FRC, "frc", 1, 2, WINED3DSIH_FRC, 0, 0 },
68 {WINED3DSIO_POW, "pow", 1, 3, WINED3DSIH_POW, 0, 0 },
69 {WINED3DSIO_CRS, "crs", 1, 3, WINED3DSIH_CRS, 0, 0 },
70 /* TODO: sng can possibly be performed as
73 {WINED3DSIO_SGN, "sgn", 1, 2, WINED3DSIH_SGN, 0, 0 },
74 {WINED3DSIO_NRM, "nrm", 1, 2, WINED3DSIH_NRM, 0, 0 },
75 {WINED3DSIO_SINCOS, "sincos", 1, 4, WINED3DSIH_SINCOS, WINED3DVS_VERSION(2,0), WINED3DVS_VERSION(2,1)},
76 {WINED3DSIO_SINCOS, "sincos", 1, 2, WINED3DSIH_SINCOS, WINED3DVS_VERSION(3,0), -1 },
78 {WINED3DSIO_M4x4, "m4x4", 1, 3, WINED3DSIH_M4x4, 0, 0 },
79 {WINED3DSIO_M4x3, "m4x3", 1, 3, WINED3DSIH_M4x3, 0, 0 },
80 {WINED3DSIO_M3x4, "m3x4", 1, 3, WINED3DSIH_M3x4, 0, 0 },
81 {WINED3DSIO_M3x3, "m3x3", 1, 3, WINED3DSIH_M3x3, 0, 0 },
82 {WINED3DSIO_M3x2, "m3x2", 1, 3, WINED3DSIH_M3x2, 0, 0 },
83 /* Declare registers */
84 {WINED3DSIO_DCL, "dcl", 0, 2, WINED3DSIH_DCL, 0, 0 },
85 /* Constant definitions */
86 {WINED3DSIO_DEF, "def", 1, 5, WINED3DSIH_DEF, 0, 0 },
87 {WINED3DSIO_DEFB, "defb", 1, 2, WINED3DSIH_DEFB, 0, 0 },
88 {WINED3DSIO_DEFI, "defi", 1, 5, WINED3DSIH_DEFI, 0, 0 },
89 /* Flow control - requires GLSL or software shaders */
90 {WINED3DSIO_REP , "rep", 0, 1, WINED3DSIH_REP, WINED3DVS_VERSION(2,0), -1 },
91 {WINED3DSIO_ENDREP, "endrep", 0, 0, WINED3DSIH_ENDREP, WINED3DVS_VERSION(2,0), -1 },
92 {WINED3DSIO_IF, "if", 0, 1, WINED3DSIH_IF, WINED3DVS_VERSION(2,0), -1 },
93 {WINED3DSIO_IFC, "ifc", 0, 2, WINED3DSIH_IFC, WINED3DVS_VERSION(2,1), -1 },
94 {WINED3DSIO_ELSE, "else", 0, 0, WINED3DSIH_ELSE, WINED3DVS_VERSION(2,0), -1 },
95 {WINED3DSIO_ENDIF, "endif", 0, 0, WINED3DSIH_ENDIF, WINED3DVS_VERSION(2,0), -1 },
96 {WINED3DSIO_BREAK, "break", 0, 0, WINED3DSIH_BREAK, WINED3DVS_VERSION(2,1), -1 },
97 {WINED3DSIO_BREAKC, "breakc", 0, 2, WINED3DSIH_BREAKC, WINED3DVS_VERSION(2,1), -1 },
98 {WINED3DSIO_BREAKP, "breakp", 0, 1, WINED3DSIH_BREAKP, 0, 0 },
99 {WINED3DSIO_CALL, "call", 0, 1, WINED3DSIH_CALL, WINED3DVS_VERSION(2,0), -1 },
100 {WINED3DSIO_CALLNZ, "callnz", 0, 2, WINED3DSIH_CALLNZ, WINED3DVS_VERSION(2,0), -1 },
101 {WINED3DSIO_LOOP, "loop", 0, 2, WINED3DSIH_LOOP, WINED3DVS_VERSION(2,0), -1 },
102 {WINED3DSIO_RET, "ret", 0, 0, WINED3DSIH_RET, WINED3DVS_VERSION(2,0), -1 },
103 {WINED3DSIO_ENDLOOP, "endloop", 0, 0, WINED3DSIH_ENDLOOP, WINED3DVS_VERSION(2,0), -1 },
104 {WINED3DSIO_LABEL, "label", 0, 1, WINED3DSIH_LABEL, WINED3DVS_VERSION(2,0), -1 },
106 {WINED3DSIO_SETP, "setp", 1, 3, WINED3DSIH_SETP, 0, 0 },
107 {WINED3DSIO_TEXLDL, "texldl", 1, 3, WINED3DSIH_TEXLDL, WINED3DVS_VERSION(3,0), -1 },
108 {0, NULL, 0, 0, 0, 0, 0 }
111 static void vshader_set_limits(
112 IWineD3DVertexShaderImpl *This) {
114 This->baseShader.limits.texcoord = 0;
115 This->baseShader.limits.attributes = 16;
116 This->baseShader.limits.packed_input = 0;
118 /* Must match D3DCAPS9.MaxVertexShaderConst: at least 256 for vs_2_0 */
119 This->baseShader.limits.constant_float = GL_LIMITS(vshader_constantsF);
121 switch (This->baseShader.reg_maps.shader_version)
123 case WINED3DVS_VERSION(1,0):
124 case WINED3DVS_VERSION(1,1):
125 This->baseShader.limits.temporary = 12;
126 This->baseShader.limits.constant_bool = 0;
127 This->baseShader.limits.constant_int = 0;
128 This->baseShader.limits.address = 1;
129 This->baseShader.limits.packed_output = 0;
130 This->baseShader.limits.sampler = 0;
131 This->baseShader.limits.label = 0;
134 case WINED3DVS_VERSION(2,0):
135 case WINED3DVS_VERSION(2,1):
136 This->baseShader.limits.temporary = 12;
137 This->baseShader.limits.constant_bool = 16;
138 This->baseShader.limits.constant_int = 16;
139 This->baseShader.limits.address = 1;
140 This->baseShader.limits.packed_output = 0;
141 This->baseShader.limits.sampler = 0;
142 This->baseShader.limits.label = 16;
145 case WINED3DVS_VERSION(3,0):
146 This->baseShader.limits.temporary = 32;
147 This->baseShader.limits.constant_bool = 32;
148 This->baseShader.limits.constant_int = 32;
149 This->baseShader.limits.address = 1;
150 This->baseShader.limits.packed_output = 12;
151 This->baseShader.limits.sampler = 4;
152 This->baseShader.limits.label = 16; /* FIXME: 2048 */
155 default: This->baseShader.limits.temporary = 12;
156 This->baseShader.limits.constant_bool = 16;
157 This->baseShader.limits.constant_int = 16;
158 This->baseShader.limits.address = 1;
159 This->baseShader.limits.packed_output = 0;
160 This->baseShader.limits.sampler = 0;
161 This->baseShader.limits.label = 16;
162 FIXME("Unrecognized vertex shader version %#x\n",
163 This->baseShader.reg_maps.shader_version);
167 /* This is an internal function,
168 * used to create fake semantics for shaders
169 * that don't have them - d3d8 shaders where the declaration
170 * stores the register for each input
172 static void vshader_set_input(
173 IWineD3DVertexShaderImpl* This,
175 BYTE usage, BYTE usage_idx) {
177 /* Fake usage: set reserved bit, usage, usage_idx */
178 DWORD usage_token = (0x1 << 31) |
179 (usage << WINED3DSP_DCL_USAGE_SHIFT) | (usage_idx << WINED3DSP_DCL_USAGEINDEX_SHIFT);
181 /* Fake register; set reserved bit, regnum, type: input, wmask: all */
182 DWORD reg_token = (0x1 << 31) |
183 WINED3DSP_WRITEMASK_ALL | (WINED3DSPR_INPUT << WINED3DSP_REGTYPE_SHIFT) | regnum;
185 This->semantics_in[regnum].usage = usage_token;
186 This->semantics_in[regnum].reg = reg_token;
189 static BOOL match_usage(BYTE usage1, BYTE usage_idx1, BYTE usage2, BYTE usage_idx2) {
190 if (usage_idx1 != usage_idx2) return FALSE;
191 if (usage1 == usage2) return TRUE;
192 if (usage1 == WINED3DDECLUSAGE_POSITION && usage2 == WINED3DDECLUSAGE_POSITIONT) return TRUE;
193 if (usage2 == WINED3DDECLUSAGE_POSITION && usage1 == WINED3DDECLUSAGE_POSITIONT) return TRUE;
198 BOOL vshader_get_input(
199 IWineD3DVertexShader* iface,
200 BYTE usage_req, BYTE usage_idx_req,
201 unsigned int* regnum) {
203 IWineD3DVertexShaderImpl* This = (IWineD3DVertexShaderImpl*) iface;
206 for (i = 0; i < MAX_ATTRIBS; i++) {
207 DWORD usage_token = This->semantics_in[i].usage;
208 DWORD usage = (usage_token & WINED3DSP_DCL_USAGE_MASK) >> WINED3DSP_DCL_USAGE_SHIFT;
209 DWORD usage_idx = (usage_token & WINED3DSP_DCL_USAGEINDEX_MASK) >> WINED3DSP_DCL_USAGEINDEX_SHIFT;
211 if (usage_token && match_usage(usage, usage_idx, usage_req, usage_idx_req)) {
219 /** Generate a vertex shader string using either GL_VERTEX_PROGRAM_ARB
220 or GLSL and send it to the card */
221 static void IWineD3DVertexShaderImpl_GenerateShader(IWineD3DVertexShader *iface,
222 const struct shader_reg_maps* reg_maps, const DWORD *pFunction)
224 IWineD3DVertexShaderImpl *This = (IWineD3DVertexShaderImpl *)iface;
225 SHADER_BUFFER buffer;
227 This->swizzle_map = ((IWineD3DDeviceImpl *)This->baseShader.device)->strided_streams.swizzle_map;
229 shader_buffer_init(&buffer);
230 ((IWineD3DDeviceImpl *)This->baseShader.device)->shader_backend->shader_generate_vshader(iface, &buffer);
231 shader_buffer_free(&buffer);
234 /* *******************************************
235 IWineD3DVertexShader IUnknown parts follow
236 ******************************************* */
237 static HRESULT WINAPI IWineD3DVertexShaderImpl_QueryInterface(IWineD3DVertexShader *iface, REFIID riid, LPVOID *ppobj) {
238 TRACE("iface %p, riid %s, ppobj %p\n", iface, debugstr_guid(riid), ppobj);
240 if (IsEqualGUID(riid, &IID_IWineD3DVertexShader)
241 || IsEqualGUID(riid, &IID_IWineD3DBaseShader)
242 || IsEqualGUID(riid, &IID_IWineD3DBase)
243 || IsEqualGUID(riid, &IID_IUnknown))
245 IUnknown_AddRef(iface);
250 WARN("%s not implemented, returning E_NOINTERFACE\n", debugstr_guid(riid));
253 return E_NOINTERFACE;
256 static ULONG WINAPI IWineD3DVertexShaderImpl_AddRef(IWineD3DVertexShader *iface) {
257 IWineD3DVertexShaderImpl *This = (IWineD3DVertexShaderImpl *)iface;
258 ULONG refcount = InterlockedIncrement(&This->baseShader.ref);
260 TRACE("%p increasing refcount to %u\n", This, refcount);
265 static ULONG WINAPI IWineD3DVertexShaderImpl_Release(IWineD3DVertexShader *iface) {
266 IWineD3DVertexShaderImpl *This = (IWineD3DVertexShaderImpl *)iface;
267 ULONG refcount = InterlockedDecrement(&This->baseShader.ref);
269 TRACE("%p decreasing refcount to %u\n", This, refcount);
273 shader_cleanup((IWineD3DBaseShader *)iface);
274 HeapFree(GetProcessHeap(), 0, This);
280 /* *******************************************
281 IWineD3DVertexShader IWineD3DVertexShader parts follow
282 ******************************************* */
284 static HRESULT WINAPI IWineD3DVertexShaderImpl_GetParent(IWineD3DVertexShader *iface, IUnknown** parent){
285 IWineD3DVertexShaderImpl *This = (IWineD3DVertexShaderImpl *)iface;
287 *parent = This->parent;
288 IUnknown_AddRef(*parent);
289 TRACE("(%p) : returning %p\n", This, *parent);
293 static HRESULT WINAPI IWineD3DVertexShaderImpl_GetDevice(IWineD3DVertexShader* iface, IWineD3DDevice **pDevice){
294 IWineD3DVertexShaderImpl *This = (IWineD3DVertexShaderImpl *)iface;
295 IWineD3DDevice_AddRef(This->baseShader.device);
296 *pDevice = This->baseShader.device;
297 TRACE("(%p) returning %p\n", This, *pDevice);
301 static HRESULT WINAPI IWineD3DVertexShaderImpl_GetFunction(IWineD3DVertexShader* impl, VOID* pData, UINT* pSizeOfData) {
302 IWineD3DVertexShaderImpl *This = (IWineD3DVertexShaderImpl *)impl;
303 TRACE("(%p) : pData(%p), pSizeOfData(%p)\n", This, pData, pSizeOfData);
306 *pSizeOfData = This->baseShader.functionLength;
309 if (*pSizeOfData < This->baseShader.functionLength) {
310 /* MSDN claims (for d3d8 at least) that if *pSizeOfData is smaller
311 * than the required size we should write the required size and
312 * return D3DERR_MOREDATA. That's not actually true. */
313 return WINED3DERR_INVALIDCALL;
316 TRACE("(%p) : GetFunction copying to %p\n", This, pData);
317 memcpy(pData, This->baseShader.function, This->baseShader.functionLength);
322 /* Note that for vertex shaders CompileShader isn't called until the
323 * shader is first used. The reason for this is that we need the vertex
324 * declaration the shader will be used with in order to determine if
325 * the data in a register is of type D3DCOLOR, and needs swizzling. */
326 static HRESULT WINAPI IWineD3DVertexShaderImpl_SetFunction(IWineD3DVertexShader *iface, CONST DWORD *pFunction) {
328 IWineD3DVertexShaderImpl *This =(IWineD3DVertexShaderImpl *)iface;
329 IWineD3DDeviceImpl *deviceImpl = (IWineD3DDeviceImpl *) This->baseShader.device;
331 shader_reg_maps *reg_maps = &This->baseShader.reg_maps;
333 TRACE("(%p) : pFunction %p\n", iface, pFunction);
335 /* First pass: trace shader */
336 if (TRACE_ON(d3d_shader)) shader_trace_init(pFunction, This->baseShader.shader_ins);
338 /* Initialize immediate constant lists */
339 list_init(&This->baseShader.constantsF);
340 list_init(&This->baseShader.constantsB);
341 list_init(&This->baseShader.constantsI);
343 /* Second pass: figure out registers used, semantics, etc.. */
344 This->min_rel_offset = GL_LIMITS(vshader_constantsF);
345 This->max_rel_offset = 0;
346 memset(reg_maps, 0, sizeof(shader_reg_maps));
347 hr = shader_get_registers_used((IWineD3DBaseShader*) This, reg_maps,
348 This->semantics_in, This->semantics_out, pFunction);
349 if (hr != WINED3D_OK) return hr;
351 vshader_set_limits(This);
353 This->baseShader.shader_mode = deviceImpl->vs_selected_mode;
355 if(deviceImpl->vs_selected_mode == SHADER_ARB &&
356 (GLINFO_LOCATION).arb_vs_offset_limit &&
357 This->min_rel_offset <= This->max_rel_offset) {
359 if(This->max_rel_offset - This->min_rel_offset > 127) {
360 FIXME("The difference between the minimum and maximum relative offset is > 127\n");
361 FIXME("Which this OpenGL implementation does not support. Try using GLSL\n");
362 FIXME("Min: %d, Max: %d\n", This->min_rel_offset, This->max_rel_offset);
363 } else if(This->max_rel_offset - This->min_rel_offset > 63) {
364 This->rel_offset = This->min_rel_offset + 63;
365 } else if(This->max_rel_offset > 63) {
366 This->rel_offset = This->min_rel_offset;
368 This->rel_offset = 0;
371 This->baseShader.load_local_constsF = This->baseShader.reg_maps.usesrelconstF && !list_empty(&This->baseShader.constantsF);
373 /* copy the function ... because it will certainly be released by application */
374 This->baseShader.function = HeapAlloc(GetProcessHeap(), 0, This->baseShader.functionLength);
375 if (!This->baseShader.function) return E_OUTOFMEMORY;
376 memcpy(This->baseShader.function, pFunction, This->baseShader.functionLength);
381 /* Preload semantics for d3d8 shaders */
382 static void WINAPI IWineD3DVertexShaderImpl_FakeSemantics(IWineD3DVertexShader *iface, IWineD3DVertexDeclaration *vertex_declaration) {
383 IWineD3DVertexShaderImpl *This =(IWineD3DVertexShaderImpl *)iface;
384 IWineD3DVertexDeclarationImpl* vdecl = (IWineD3DVertexDeclarationImpl*)vertex_declaration;
387 for (i = 0; i < vdecl->declarationWNumElements - 1; ++i) {
388 const WINED3DVERTEXELEMENT *element = vdecl->pDeclarationWine + i;
389 vshader_set_input(This, element->Reg, element->Usage, element->UsageIndex);
393 /* Set local constants for d3d8 shaders */
394 static HRESULT WINAPI IWIneD3DVertexShaderImpl_SetLocalConstantsF(IWineD3DVertexShader *iface,
395 UINT start_idx, const float *src_data, UINT count) {
396 IWineD3DVertexShaderImpl *This =(IWineD3DVertexShaderImpl *)iface;
399 TRACE("(%p) : start_idx %u, src_data %p, count %u\n", This, start_idx, src_data, count);
401 end_idx = start_idx + count;
402 if (end_idx > GL_LIMITS(vshader_constantsF)) {
403 WARN("end_idx %u > float constants limit %u\n", end_idx, GL_LIMITS(vshader_constantsF));
404 end_idx = GL_LIMITS(vshader_constantsF);
407 for (i = start_idx; i < end_idx; ++i) {
408 local_constant* lconst = HeapAlloc(GetProcessHeap(), 0, sizeof(local_constant));
409 if (!lconst) return E_OUTOFMEMORY;
412 memcpy(lconst->value, src_data + (i - start_idx) * 4 /* 4 components */, 4 * sizeof(float));
413 list_add_head(&This->baseShader.constantsF, &lconst->entry);
419 HRESULT IWineD3DVertexShaderImpl_CompileShader(IWineD3DVertexShader *iface) {
420 IWineD3DVertexShaderImpl *This = (IWineD3DVertexShaderImpl *)iface;
421 CONST DWORD *function = This->baseShader.function;
422 IWineD3DDeviceImpl *deviceImpl = (IWineD3DDeviceImpl *) This->baseShader.device;
424 TRACE("(%p) : function %p\n", iface, function);
426 /* We're already compiled. */
427 if (This->baseShader.is_compiled) {
428 if ((This->swizzle_map & deviceImpl->strided_streams.use_map) != deviceImpl->strided_streams.swizzle_map)
430 WARN("Recompiling vertex shader %p due to D3DCOLOR input changes\n", This);
437 if(This->recompile_count < 50) {
438 This->recompile_count++;
440 FIXME("Vertexshader %p recompiled more than 50 times\n", This);
443 deviceImpl->shader_backend->shader_destroy((IWineD3DBaseShader *) iface);
446 /* Generate the HW shader */
447 TRACE("(%p) : Generating hardware program\n", This);
448 IWineD3DVertexShaderImpl_GenerateShader(iface, &This->baseShader.reg_maps, function);
450 This->baseShader.is_compiled = TRUE;
455 const IWineD3DVertexShaderVtbl IWineD3DVertexShader_Vtbl =
457 /*** IUnknown methods ***/
458 IWineD3DVertexShaderImpl_QueryInterface,
459 IWineD3DVertexShaderImpl_AddRef,
460 IWineD3DVertexShaderImpl_Release,
461 /*** IWineD3DBase methods ***/
462 IWineD3DVertexShaderImpl_GetParent,
463 /*** IWineD3DBaseShader methods ***/
464 IWineD3DVertexShaderImpl_SetFunction,
465 /*** IWineD3DVertexShader methods ***/
466 IWineD3DVertexShaderImpl_GetDevice,
467 IWineD3DVertexShaderImpl_GetFunction,
468 IWineD3DVertexShaderImpl_FakeSemantics,
469 IWIneD3DVertexShaderImpl_SetLocalConstantsF