wined3d: Get rid of D3DCREATESHADEROBJECTINSTANCE.
[wine] / dlls / wined3d / vertexshader.c
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 #include "config.h"
27
28 #include <math.h>
29 #include <stdio.h>
30
31 #include "wined3d_private.h"
32
33 WINE_DEFAULT_DEBUG_CHANNEL(d3d_shader);
34
35 #define GLINFO_LOCATION ((IWineD3DDeviceImpl *)This->baseShader.device)->adapter->gl_info
36
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 */
39
40 #define GLNAME_REQUIRE_GLSL  ((const char *)1)
41
42 CONST SHADER_OPCODE IWineD3DVertexShaderImpl_shader_ins[] = {
43     /* This table is not order or position dependent. */
44
45     /* Arithmetic */
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
73         RCP tmp, vec
74         MUL out, tmp, vec*/
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                    },
79     /* Matrix */
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                    },
107
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                     }
111 };
112
113 static void vshader_set_limits(
114       IWineD3DVertexShaderImpl *This) {
115
116       This->baseShader.limits.texcoord = 0;
117       This->baseShader.limits.attributes = 16;
118       This->baseShader.limits.packed_input = 0;
119
120       /* Must match D3DCAPS9.MaxVertexShaderConst: at least 256 for vs_2_0 */
121       This->baseShader.limits.constant_float = GL_LIMITS(vshader_constantsF);
122
123       switch (This->baseShader.reg_maps.shader_version)
124       {
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;
134                    break;
135       
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;
145                    break;
146
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 */
155                    break;
156
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);
166       }
167 }
168
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
173  */
174 static void vshader_set_input(
175     IWineD3DVertexShaderImpl* This,
176     unsigned int regnum,
177     BYTE usage, BYTE usage_idx) {
178
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);
182
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;
186
187     This->semantics_in[regnum].usage = usage_token;
188     This->semantics_in[regnum].reg = reg_token;
189 }
190
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;
196
197     return FALSE;
198 }
199
200 BOOL vshader_get_input(
201     IWineD3DVertexShader* iface,
202     BYTE usage_req, BYTE usage_idx_req,
203     unsigned int* regnum) {
204
205     IWineD3DVertexShaderImpl* This = (IWineD3DVertexShaderImpl*) iface;
206     int i;
207
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;
212
213         if (usage_token && match_usage(usage, usage_idx, usage_req, usage_idx_req)) {
214             *regnum = i;
215             return TRUE;
216         }
217     }
218     return FALSE;
219 }
220
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)
225 {
226     IWineD3DVertexShaderImpl *This = (IWineD3DVertexShaderImpl *)iface;
227     SHADER_BUFFER buffer;
228
229     This->swizzle_map = ((IWineD3DDeviceImpl *)This->baseShader.device)->strided_streams.swizzle_map;
230
231     shader_buffer_init(&buffer);
232     ((IWineD3DDeviceImpl *)This->baseShader.device)->shader_backend->shader_generate_vshader(iface, &buffer);
233     shader_buffer_free(&buffer);
234 }
235
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);
241
242     if (IsEqualGUID(riid, &IID_IWineD3DVertexShader)
243             || IsEqualGUID(riid, &IID_IWineD3DBaseShader)
244             || IsEqualGUID(riid, &IID_IWineD3DBase)
245             || IsEqualGUID(riid, &IID_IUnknown))
246     {
247         IUnknown_AddRef(iface);
248         *ppobj = iface;
249         return S_OK;
250     }
251
252     WARN("%s not implemented, returning E_NOINTERFACE\n", debugstr_guid(riid));
253
254     *ppobj = NULL;
255     return E_NOINTERFACE;
256 }
257
258 static ULONG  WINAPI IWineD3DVertexShaderImpl_AddRef(IWineD3DVertexShader *iface) {
259     IWineD3DVertexShaderImpl *This = (IWineD3DVertexShaderImpl *)iface;
260     ULONG refcount = InterlockedIncrement(&This->baseShader.ref);
261
262     TRACE("%p increasing refcount to %u\n", This, refcount);
263
264     return refcount;
265 }
266
267 static ULONG WINAPI IWineD3DVertexShaderImpl_Release(IWineD3DVertexShader *iface) {
268     IWineD3DVertexShaderImpl *This = (IWineD3DVertexShaderImpl *)iface;
269     ULONG refcount = InterlockedDecrement(&This->baseShader.ref);
270
271     TRACE("%p decreasing refcount to %u\n", This, refcount);
272
273     if (!refcount)
274     {
275         shader_cleanup((IWineD3DBaseShader *)iface);
276         HeapFree(GetProcessHeap(), 0, This);
277     }
278
279     return refcount;
280 }
281
282 /* *******************************************
283    IWineD3DVertexShader IWineD3DVertexShader parts follow
284    ******************************************* */
285
286 static HRESULT WINAPI IWineD3DVertexShaderImpl_GetParent(IWineD3DVertexShader *iface, IUnknown** parent){
287     IWineD3DVertexShaderImpl *This = (IWineD3DVertexShaderImpl *)iface;
288     
289     *parent = This->parent;
290     IUnknown_AddRef(*parent);
291     TRACE("(%p) : returning %p\n", This, *parent);
292     return WINED3D_OK;
293 }
294
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);
300     return WINED3D_OK;
301 }
302
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);
306
307     if (NULL == pData) {
308         *pSizeOfData = This->baseShader.functionLength;
309         return WINED3D_OK;
310     }
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;
316     }
317
318     TRACE("(%p) : GetFunction copying to %p\n", This, pData);
319     memcpy(pData, This->baseShader.function, This->baseShader.functionLength);
320
321     return WINED3D_OK;
322 }
323
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) {
329
330     IWineD3DVertexShaderImpl *This =(IWineD3DVertexShaderImpl *)iface;
331     IWineD3DDeviceImpl *deviceImpl = (IWineD3DDeviceImpl *) This->baseShader.device;
332     HRESULT hr;
333     shader_reg_maps *reg_maps = &This->baseShader.reg_maps;
334
335     TRACE("(%p) : pFunction %p\n", iface, pFunction);
336
337     /* First pass: trace shader */
338     if (TRACE_ON(d3d_shader)) shader_trace_init(pFunction, This->baseShader.shader_ins);
339
340     /* Initialize immediate constant lists */
341     list_init(&This->baseShader.constantsF);
342     list_init(&This->baseShader.constantsB);
343     list_init(&This->baseShader.constantsI);
344
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;
352
353     vshader_set_limits(This);
354
355     This->baseShader.shader_mode = deviceImpl->vs_selected_mode;
356
357     if(deviceImpl->vs_selected_mode == SHADER_ARB &&
358        (GLINFO_LOCATION).arb_vs_offset_limit      &&
359        This->min_rel_offset <= This->max_rel_offset) {
360
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;
369         } else {
370             This->rel_offset = 0;
371         }
372     }
373     This->baseShader.load_local_constsF = This->baseShader.reg_maps.usesrelconstF && !list_empty(&This->baseShader.constantsF);
374
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);
379
380     return WINED3D_OK;
381 }
382
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;
387
388     int i;
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);
392     }
393 }
394
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;
399     UINT i, end_idx;
400
401     TRACE("(%p) : start_idx %u, src_data %p, count %u\n", This, start_idx, src_data, count);
402
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);
407     }
408
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;
412
413         lconst->idx = i;
414         memcpy(lconst->value, src_data + (i - start_idx) * 4 /* 4 components */, 4 * sizeof(float));
415         list_add_head(&This->baseShader.constantsF, &lconst->entry);
416     }
417
418     return WINED3D_OK;
419 }
420
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;
425
426     TRACE("(%p) : function %p\n", iface, function);
427
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)
431         {
432             WARN("Recompiling vertex shader %p due to D3DCOLOR input changes\n", This);
433             goto recompile;
434         }
435
436         return WINED3D_OK;
437
438         recompile:
439         if(This->recompile_count < 50) {
440             This->recompile_count++;
441         } else {
442             FIXME("Vertexshader %p recompiled more than 50 times\n", This);
443         }
444
445         deviceImpl->shader_backend->shader_destroy((IWineD3DBaseShader *) iface);
446     }
447
448     /* Generate the HW shader */
449     TRACE("(%p) : Generating hardware program\n", This);
450     IWineD3DVertexShaderImpl_GenerateShader(iface, &This->baseShader.reg_maps, function);
451
452     This->baseShader.is_compiled = TRUE;
453
454     return WINED3D_OK;
455 }
456
457 const IWineD3DVertexShaderVtbl IWineD3DVertexShader_Vtbl =
458 {
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
472 };