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 #define GLNAME_REQUIRE_GLSL ((const char *)1)
42 CONST SHADER_OPCODE IWineD3DVertexShaderImpl_shader_ins[] = {
43 /* This table is not order or position dependent. */
46 {WINED3DSIO_NOP, "nop", 0, 0, WINED3DSIH_NOP, 0, 0 },
47 {WINED3DSIO_MOV, "mov", 1, 2, WINED3DSIH_MOV, 0, 0 },
48 {WINED3DSIO_MOVA, "mova", 1, 2, WINED3DSIH_MOVA, WINED3DVS_VERSION(2,0), -1 },
49 {WINED3DSIO_ADD, "add", 1, 3, WINED3DSIH_ADD, 0, 0 },
50 {WINED3DSIO_SUB, "sub", 1, 3, WINED3DSIH_SUB, 0, 0 },
51 {WINED3DSIO_MAD, "mad", 1, 4, WINED3DSIH_MAD, 0, 0 },
52 {WINED3DSIO_MUL, "mul", 1, 3, WINED3DSIH_MUL, 0, 0 },
53 {WINED3DSIO_RCP, "rcp", 1, 2, WINED3DSIH_RCP, 0, 0 },
54 {WINED3DSIO_RSQ, "rsq", 1, 2, WINED3DSIH_RSQ, 0, 0 },
55 {WINED3DSIO_DP3, "dp3", 1, 3, WINED3DSIH_DP3, 0, 0 },
56 {WINED3DSIO_DP4, "dp4", 1, 3, WINED3DSIH_DP4, 0, 0 },
57 {WINED3DSIO_MIN, "min", 1, 3, WINED3DSIH_MIN, 0, 0 },
58 {WINED3DSIO_MAX, "max", 1, 3, WINED3DSIH_MAX, 0, 0 },
59 {WINED3DSIO_SLT, "slt", 1, 3, WINED3DSIH_SLT, 0, 0 },
60 {WINED3DSIO_SGE, "sge", 1, 3, WINED3DSIH_SGE, 0, 0 },
61 {WINED3DSIO_ABS, "abs", 1, 2, WINED3DSIH_ABS, 0, 0 },
62 {WINED3DSIO_EXP, "exp", 1, 2, WINED3DSIH_EXP, 0, 0 },
63 {WINED3DSIO_LOG, "log", 1, 2, WINED3DSIH_LOG, 0, 0 },
64 {WINED3DSIO_EXPP, "expp", 1, 2, WINED3DSIH_EXPP, 0, 0 },
65 {WINED3DSIO_LOGP, "logp", 1, 2, WINED3DSIH_LOGP, 0, 0 },
66 {WINED3DSIO_LIT, "lit", 1, 2, WINED3DSIH_LIT, 0, 0 },
67 {WINED3DSIO_DST, "dst", 1, 3, WINED3DSIH_DST, 0, 0 },
68 {WINED3DSIO_LRP, "lrp", 1, 4, WINED3DSIH_LRP, 0, 0 },
69 {WINED3DSIO_FRC, "frc", 1, 2, WINED3DSIH_FRC, 0, 0 },
70 {WINED3DSIO_POW, "pow", 1, 3, WINED3DSIH_POW, 0, 0 },
71 {WINED3DSIO_CRS, "crs", 1, 3, WINED3DSIH_CRS, 0, 0 },
72 /* TODO: sng can possibly be performed as
75 {WINED3DSIO_SGN, "sgn", 1, 2, WINED3DSIH_SGN, 0, 0 },
76 {WINED3DSIO_NRM, "nrm", 1, 2, WINED3DSIH_NRM, 0, 0 },
77 {WINED3DSIO_SINCOS, "sincos", 1, 4, WINED3DSIH_SINCOS, WINED3DVS_VERSION(2,0), WINED3DVS_VERSION(2,1)},
78 {WINED3DSIO_SINCOS, "sincos", 1, 2, WINED3DSIH_SINCOS, WINED3DVS_VERSION(3,0), -1 },
80 {WINED3DSIO_M4x4, "m4x4", 1, 3, WINED3DSIH_M4x4, 0, 0 },
81 {WINED3DSIO_M4x3, "m4x3", 1, 3, WINED3DSIH_M4x3, 0, 0 },
82 {WINED3DSIO_M3x4, "m3x4", 1, 3, WINED3DSIH_M3x4, 0, 0 },
83 {WINED3DSIO_M3x3, "m3x3", 1, 3, WINED3DSIH_M3x3, 0, 0 },
84 {WINED3DSIO_M3x2, "m3x2", 1, 3, WINED3DSIH_M3x2, 0, 0 },
85 /* Declare registers */
86 {WINED3DSIO_DCL, "dcl", 0, 2, WINED3DSIH_DCL, 0, 0 },
87 /* Constant definitions */
88 {WINED3DSIO_DEF, "def", 1, 5, WINED3DSIH_DEF, 0, 0 },
89 {WINED3DSIO_DEFB, "defb", 1, 2, WINED3DSIH_DEFB, 0, 0 },
90 {WINED3DSIO_DEFI, "defi", 1, 5, WINED3DSIH_DEFI, 0, 0 },
91 /* Flow control - requires GLSL or software shaders */
92 {WINED3DSIO_REP , "rep", 0, 1, WINED3DSIH_REP, WINED3DVS_VERSION(2,0), -1 },
93 {WINED3DSIO_ENDREP, "endrep", 0, 0, WINED3DSIH_ENDREP, WINED3DVS_VERSION(2,0), -1 },
94 {WINED3DSIO_IF, "if", 0, 1, WINED3DSIH_IF, WINED3DVS_VERSION(2,0), -1 },
95 {WINED3DSIO_IFC, "ifc", 0, 2, WINED3DSIH_IFC, WINED3DVS_VERSION(2,1), -1 },
96 {WINED3DSIO_ELSE, "else", 0, 0, WINED3DSIH_ELSE, WINED3DVS_VERSION(2,0), -1 },
97 {WINED3DSIO_ENDIF, "endif", 0, 0, WINED3DSIH_ENDIF, WINED3DVS_VERSION(2,0), -1 },
98 {WINED3DSIO_BREAK, "break", 0, 0, WINED3DSIH_BREAK, WINED3DVS_VERSION(2,1), -1 },
99 {WINED3DSIO_BREAKC, "breakc", 0, 2, WINED3DSIH_BREAKC, WINED3DVS_VERSION(2,1), -1 },
100 {WINED3DSIO_BREAKP, "breakp", 0, 1, WINED3DSIH_BREAKP, 0, 0 },
101 {WINED3DSIO_CALL, "call", 0, 1, WINED3DSIH_CALL, WINED3DVS_VERSION(2,0), -1 },
102 {WINED3DSIO_CALLNZ, "callnz", 0, 2, WINED3DSIH_CALLNZ, WINED3DVS_VERSION(2,0), -1 },
103 {WINED3DSIO_LOOP, "loop", 0, 2, WINED3DSIH_LOOP, WINED3DVS_VERSION(2,0), -1 },
104 {WINED3DSIO_RET, "ret", 0, 0, WINED3DSIH_RET, WINED3DVS_VERSION(2,0), -1 },
105 {WINED3DSIO_ENDLOOP, "endloop", 0, 0, WINED3DSIH_ENDLOOP, WINED3DVS_VERSION(2,0), -1 },
106 {WINED3DSIO_LABEL, "label", 0, 1, WINED3DSIH_LABEL, WINED3DVS_VERSION(2,0), -1 },
108 {WINED3DSIO_SETP, "setp", 1, 3, WINED3DSIH_SETP, 0, 0 },
109 {WINED3DSIO_TEXLDL, "texldl", 1, 3, WINED3DSIH_TEXLDL, WINED3DVS_VERSION(3,0), -1 },
110 {0, NULL, 0, 0, 0, 0, 0 }
113 static void vshader_set_limits(
114 IWineD3DVertexShaderImpl *This) {
116 This->baseShader.limits.texcoord = 0;
117 This->baseShader.limits.attributes = 16;
118 This->baseShader.limits.packed_input = 0;
120 /* Must match D3DCAPS9.MaxVertexShaderConst: at least 256 for vs_2_0 */
121 This->baseShader.limits.constant_float = GL_LIMITS(vshader_constantsF);
123 switch (This->baseShader.reg_maps.shader_version)
125 case WINED3DVS_VERSION(1,0):
126 case WINED3DVS_VERSION(1,1):
127 This->baseShader.limits.temporary = 12;
128 This->baseShader.limits.constant_bool = 0;
129 This->baseShader.limits.constant_int = 0;
130 This->baseShader.limits.address = 1;
131 This->baseShader.limits.packed_output = 0;
132 This->baseShader.limits.sampler = 0;
133 This->baseShader.limits.label = 0;
136 case WINED3DVS_VERSION(2,0):
137 case WINED3DVS_VERSION(2,1):
138 This->baseShader.limits.temporary = 12;
139 This->baseShader.limits.constant_bool = 16;
140 This->baseShader.limits.constant_int = 16;
141 This->baseShader.limits.address = 1;
142 This->baseShader.limits.packed_output = 0;
143 This->baseShader.limits.sampler = 0;
144 This->baseShader.limits.label = 16;
147 case WINED3DVS_VERSION(3,0):
148 This->baseShader.limits.temporary = 32;
149 This->baseShader.limits.constant_bool = 32;
150 This->baseShader.limits.constant_int = 32;
151 This->baseShader.limits.address = 1;
152 This->baseShader.limits.packed_output = 12;
153 This->baseShader.limits.sampler = 4;
154 This->baseShader.limits.label = 16; /* FIXME: 2048 */
157 default: This->baseShader.limits.temporary = 12;
158 This->baseShader.limits.constant_bool = 16;
159 This->baseShader.limits.constant_int = 16;
160 This->baseShader.limits.address = 1;
161 This->baseShader.limits.packed_output = 0;
162 This->baseShader.limits.sampler = 0;
163 This->baseShader.limits.label = 16;
164 FIXME("Unrecognized vertex shader version %#x\n",
165 This->baseShader.reg_maps.shader_version);
169 /* This is an internal function,
170 * used to create fake semantics for shaders
171 * that don't have them - d3d8 shaders where the declaration
172 * stores the register for each input
174 static void vshader_set_input(
175 IWineD3DVertexShaderImpl* This,
177 BYTE usage, BYTE usage_idx) {
179 /* Fake usage: set reserved bit, usage, usage_idx */
180 DWORD usage_token = (0x1 << 31) |
181 (usage << WINED3DSP_DCL_USAGE_SHIFT) | (usage_idx << WINED3DSP_DCL_USAGEINDEX_SHIFT);
183 /* Fake register; set reserved bit, regnum, type: input, wmask: all */
184 DWORD reg_token = (0x1 << 31) |
185 WINED3DSP_WRITEMASK_ALL | (WINED3DSPR_INPUT << WINED3DSP_REGTYPE_SHIFT) | regnum;
187 This->semantics_in[regnum].usage = usage_token;
188 This->semantics_in[regnum].reg = reg_token;
191 static BOOL match_usage(BYTE usage1, BYTE usage_idx1, BYTE usage2, BYTE usage_idx2) {
192 if (usage_idx1 != usage_idx2) return FALSE;
193 if (usage1 == usage2) return TRUE;
194 if (usage1 == WINED3DDECLUSAGE_POSITION && usage2 == WINED3DDECLUSAGE_POSITIONT) return TRUE;
195 if (usage2 == WINED3DDECLUSAGE_POSITION && usage1 == WINED3DDECLUSAGE_POSITIONT) return TRUE;
200 BOOL vshader_get_input(
201 IWineD3DVertexShader* iface,
202 BYTE usage_req, BYTE usage_idx_req,
203 unsigned int* regnum) {
205 IWineD3DVertexShaderImpl* This = (IWineD3DVertexShaderImpl*) iface;
208 for (i = 0; i < MAX_ATTRIBS; i++) {
209 DWORD usage_token = This->semantics_in[i].usage;
210 DWORD usage = (usage_token & WINED3DSP_DCL_USAGE_MASK) >> WINED3DSP_DCL_USAGE_SHIFT;
211 DWORD usage_idx = (usage_token & WINED3DSP_DCL_USAGEINDEX_MASK) >> WINED3DSP_DCL_USAGEINDEX_SHIFT;
213 if (usage_token && match_usage(usage, usage_idx, usage_req, usage_idx_req)) {
221 /** Generate a vertex shader string using either GL_VERTEX_PROGRAM_ARB
222 or GLSL and send it to the card */
223 static void IWineD3DVertexShaderImpl_GenerateShader(IWineD3DVertexShader *iface,
224 const struct shader_reg_maps* reg_maps, const DWORD *pFunction)
226 IWineD3DVertexShaderImpl *This = (IWineD3DVertexShaderImpl *)iface;
227 SHADER_BUFFER buffer;
229 This->swizzle_map = ((IWineD3DDeviceImpl *)This->baseShader.device)->strided_streams.swizzle_map;
231 shader_buffer_init(&buffer);
232 ((IWineD3DDeviceImpl *)This->baseShader.device)->shader_backend->shader_generate_vshader(iface, &buffer);
233 shader_buffer_free(&buffer);
236 /* *******************************************
237 IWineD3DVertexShader IUnknown parts follow
238 ******************************************* */
239 static HRESULT WINAPI IWineD3DVertexShaderImpl_QueryInterface(IWineD3DVertexShader *iface, REFIID riid, LPVOID *ppobj) {
240 TRACE("iface %p, riid %s, ppobj %p\n", iface, debugstr_guid(riid), ppobj);
242 if (IsEqualGUID(riid, &IID_IWineD3DVertexShader)
243 || IsEqualGUID(riid, &IID_IWineD3DBaseShader)
244 || IsEqualGUID(riid, &IID_IWineD3DBase)
245 || IsEqualGUID(riid, &IID_IUnknown))
247 IUnknown_AddRef(iface);
252 WARN("%s not implemented, returning E_NOINTERFACE\n", debugstr_guid(riid));
255 return E_NOINTERFACE;
258 static ULONG WINAPI IWineD3DVertexShaderImpl_AddRef(IWineD3DVertexShader *iface) {
259 IWineD3DVertexShaderImpl *This = (IWineD3DVertexShaderImpl *)iface;
260 ULONG refcount = InterlockedIncrement(&This->baseShader.ref);
262 TRACE("%p increasing refcount to %u\n", This, refcount);
267 static ULONG WINAPI IWineD3DVertexShaderImpl_Release(IWineD3DVertexShader *iface) {
268 IWineD3DVertexShaderImpl *This = (IWineD3DVertexShaderImpl *)iface;
269 ULONG refcount = InterlockedDecrement(&This->baseShader.ref);
271 TRACE("%p decreasing refcount to %u\n", This, refcount);
275 shader_cleanup((IWineD3DBaseShader *)iface);
276 HeapFree(GetProcessHeap(), 0, This);
282 /* *******************************************
283 IWineD3DVertexShader IWineD3DVertexShader parts follow
284 ******************************************* */
286 static HRESULT WINAPI IWineD3DVertexShaderImpl_GetParent(IWineD3DVertexShader *iface, IUnknown** parent){
287 IWineD3DVertexShaderImpl *This = (IWineD3DVertexShaderImpl *)iface;
289 *parent = This->parent;
290 IUnknown_AddRef(*parent);
291 TRACE("(%p) : returning %p\n", This, *parent);
295 static HRESULT WINAPI IWineD3DVertexShaderImpl_GetDevice(IWineD3DVertexShader* iface, IWineD3DDevice **pDevice){
296 IWineD3DVertexShaderImpl *This = (IWineD3DVertexShaderImpl *)iface;
297 IWineD3DDevice_AddRef(This->baseShader.device);
298 *pDevice = This->baseShader.device;
299 TRACE("(%p) returning %p\n", This, *pDevice);
303 static HRESULT WINAPI IWineD3DVertexShaderImpl_GetFunction(IWineD3DVertexShader* impl, VOID* pData, UINT* pSizeOfData) {
304 IWineD3DVertexShaderImpl *This = (IWineD3DVertexShaderImpl *)impl;
305 TRACE("(%p) : pData(%p), pSizeOfData(%p)\n", This, pData, pSizeOfData);
308 *pSizeOfData = This->baseShader.functionLength;
311 if (*pSizeOfData < This->baseShader.functionLength) {
312 /* MSDN claims (for d3d8 at least) that if *pSizeOfData is smaller
313 * than the required size we should write the required size and
314 * return D3DERR_MOREDATA. That's not actually true. */
315 return WINED3DERR_INVALIDCALL;
318 TRACE("(%p) : GetFunction copying to %p\n", This, pData);
319 memcpy(pData, This->baseShader.function, This->baseShader.functionLength);
324 /* Note that for vertex shaders CompileShader isn't called until the
325 * shader is first used. The reason for this is that we need the vertex
326 * declaration the shader will be used with in order to determine if
327 * the data in a register is of type D3DCOLOR, and needs swizzling. */
328 static HRESULT WINAPI IWineD3DVertexShaderImpl_SetFunction(IWineD3DVertexShader *iface, CONST DWORD *pFunction) {
330 IWineD3DVertexShaderImpl *This =(IWineD3DVertexShaderImpl *)iface;
331 IWineD3DDeviceImpl *deviceImpl = (IWineD3DDeviceImpl *) This->baseShader.device;
333 shader_reg_maps *reg_maps = &This->baseShader.reg_maps;
335 TRACE("(%p) : pFunction %p\n", iface, pFunction);
337 /* First pass: trace shader */
338 if (TRACE_ON(d3d_shader)) shader_trace_init(pFunction, This->baseShader.shader_ins);
340 /* Initialize immediate constant lists */
341 list_init(&This->baseShader.constantsF);
342 list_init(&This->baseShader.constantsB);
343 list_init(&This->baseShader.constantsI);
345 /* Second pass: figure out registers used, semantics, etc.. */
346 This->min_rel_offset = GL_LIMITS(vshader_constantsF);
347 This->max_rel_offset = 0;
348 memset(reg_maps, 0, sizeof(shader_reg_maps));
349 hr = shader_get_registers_used((IWineD3DBaseShader*) This, reg_maps,
350 This->semantics_in, This->semantics_out, pFunction);
351 if (hr != WINED3D_OK) return hr;
353 vshader_set_limits(This);
355 This->baseShader.shader_mode = deviceImpl->vs_selected_mode;
357 if(deviceImpl->vs_selected_mode == SHADER_ARB &&
358 (GLINFO_LOCATION).arb_vs_offset_limit &&
359 This->min_rel_offset <= This->max_rel_offset) {
361 if(This->max_rel_offset - This->min_rel_offset > 127) {
362 FIXME("The difference between the minimum and maximum relative offset is > 127\n");
363 FIXME("Which this OpenGL implementation does not support. Try using GLSL\n");
364 FIXME("Min: %d, Max: %d\n", This->min_rel_offset, This->max_rel_offset);
365 } else if(This->max_rel_offset - This->min_rel_offset > 63) {
366 This->rel_offset = This->min_rel_offset + 63;
367 } else if(This->max_rel_offset > 63) {
368 This->rel_offset = This->min_rel_offset;
370 This->rel_offset = 0;
373 This->baseShader.load_local_constsF = This->baseShader.reg_maps.usesrelconstF && !list_empty(&This->baseShader.constantsF);
375 /* copy the function ... because it will certainly be released by application */
376 This->baseShader.function = HeapAlloc(GetProcessHeap(), 0, This->baseShader.functionLength);
377 if (!This->baseShader.function) return E_OUTOFMEMORY;
378 memcpy(This->baseShader.function, pFunction, This->baseShader.functionLength);
383 /* Preload semantics for d3d8 shaders */
384 static void WINAPI IWineD3DVertexShaderImpl_FakeSemantics(IWineD3DVertexShader *iface, IWineD3DVertexDeclaration *vertex_declaration) {
385 IWineD3DVertexShaderImpl *This =(IWineD3DVertexShaderImpl *)iface;
386 IWineD3DVertexDeclarationImpl* vdecl = (IWineD3DVertexDeclarationImpl*)vertex_declaration;
389 for (i = 0; i < vdecl->declarationWNumElements - 1; ++i) {
390 const WINED3DVERTEXELEMENT *element = vdecl->pDeclarationWine + i;
391 vshader_set_input(This, element->Reg, element->Usage, element->UsageIndex);
395 /* Set local constants for d3d8 shaders */
396 static HRESULT WINAPI IWIneD3DVertexShaderImpl_SetLocalConstantsF(IWineD3DVertexShader *iface,
397 UINT start_idx, const float *src_data, UINT count) {
398 IWineD3DVertexShaderImpl *This =(IWineD3DVertexShaderImpl *)iface;
401 TRACE("(%p) : start_idx %u, src_data %p, count %u\n", This, start_idx, src_data, count);
403 end_idx = start_idx + count;
404 if (end_idx > GL_LIMITS(vshader_constantsF)) {
405 WARN("end_idx %u > float constants limit %u\n", end_idx, GL_LIMITS(vshader_constantsF));
406 end_idx = GL_LIMITS(vshader_constantsF);
409 for (i = start_idx; i < end_idx; ++i) {
410 local_constant* lconst = HeapAlloc(GetProcessHeap(), 0, sizeof(local_constant));
411 if (!lconst) return E_OUTOFMEMORY;
414 memcpy(lconst->value, src_data + (i - start_idx) * 4 /* 4 components */, 4 * sizeof(float));
415 list_add_head(&This->baseShader.constantsF, &lconst->entry);
421 HRESULT IWineD3DVertexShaderImpl_CompileShader(IWineD3DVertexShader *iface) {
422 IWineD3DVertexShaderImpl *This = (IWineD3DVertexShaderImpl *)iface;
423 CONST DWORD *function = This->baseShader.function;
424 IWineD3DDeviceImpl *deviceImpl = (IWineD3DDeviceImpl *) This->baseShader.device;
426 TRACE("(%p) : function %p\n", iface, function);
428 /* We're already compiled. */
429 if (This->baseShader.is_compiled) {
430 if ((This->swizzle_map & deviceImpl->strided_streams.use_map) != deviceImpl->strided_streams.swizzle_map)
432 WARN("Recompiling vertex shader %p due to D3DCOLOR input changes\n", This);
439 if(This->recompile_count < 50) {
440 This->recompile_count++;
442 FIXME("Vertexshader %p recompiled more than 50 times\n", This);
445 deviceImpl->shader_backend->shader_destroy((IWineD3DBaseShader *) iface);
448 /* Generate the HW shader */
449 TRACE("(%p) : Generating hardware program\n", This);
450 IWineD3DVertexShaderImpl_GenerateShader(iface, &This->baseShader.reg_maps, function);
452 This->baseShader.is_compiled = TRUE;
457 const IWineD3DVertexShaderVtbl IWineD3DVertexShader_Vtbl =
459 /*** IUnknown methods ***/
460 IWineD3DVertexShaderImpl_QueryInterface,
461 IWineD3DVertexShaderImpl_AddRef,
462 IWineD3DVertexShaderImpl_Release,
463 /*** IWineD3DBase methods ***/
464 IWineD3DVertexShaderImpl_GetParent,
465 /*** IWineD3DBaseShader methods ***/
466 IWineD3DVertexShaderImpl_SetFunction,
467 /*** IWineD3DVertexShader methods ***/
468 IWineD3DVertexShaderImpl_GetDevice,
469 IWineD3DVertexShaderImpl_GetFunction,
470 IWineD3DVertexShaderImpl_FakeSemantics,
471 IWIneD3DVertexShaderImpl_SetLocalConstantsF