wined3d: Merge vertexbuffer.c with buffer.c.
[wine] / dlls / wined3d / buffer.c
1 /*
2  * Copyright 2002-2005 Jason Edmeades
3  * Copyright 2002-2005 Raphael Junqueira
4  * Copyright 2004 Christian Costa
5  * Copyright 2007 Stefan Dösinger for CodeWeavers
6  * Copyright 2009 Henri Verbeet for CodeWeavers
7  *
8  * This library is free software; you can redistribute it and/or
9  * modify it under the terms of the GNU Lesser General Public
10  * License as published by the Free Software Foundation; either
11  * version 2.1 of the License, or (at your option) any later version.
12  *
13  * This library is distributed in the hope that it will be useful,
14  * but WITHOUT ANY WARRANTY; without even the implied warranty of
15  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
16  * Lesser General Public License for more details.
17  *
18  * You should have received a copy of the GNU Lesser General Public
19  * License along with this library; if not, write to the Free Software
20  * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
21  *
22  */
23
24 #include "config.h"
25 #include "wine/port.h"
26
27 #include "wined3d_private.h"
28
29 WINE_DEFAULT_DEBUG_CHANNEL(d3d);
30
31 #define GLINFO_LOCATION This->resource.wineD3DDevice->adapter->gl_info
32
33 #define VB_MAXDECLCHANGES     100     /* After that number we stop converting */
34 #define VB_RESETDECLCHANGE    1000    /* Reset the changecount after that number of draws */
35
36 /* IUnknown methods */
37
38 static HRESULT STDMETHODCALLTYPE buffer_QueryInterface(IWineD3DBuffer *iface,
39         REFIID riid, void **object)
40 {
41     TRACE("iface %p, riid %s, object %p\n", iface, debugstr_guid(riid), object);
42
43     if (IsEqualGUID(riid, &IID_IWineD3DBuffer)
44             || IsEqualGUID(riid, &IID_IWineD3DResource)
45             || IsEqualGUID(riid, &IID_IWineD3DBase)
46             || IsEqualGUID(riid, &IID_IUnknown))
47     {
48         IUnknown_AddRef(iface);
49         *object = iface;
50         return S_OK;
51     }
52
53     WARN("%s not implemented, returning E_NOINTERFACE\n", debugstr_guid(riid));
54
55     *object = NULL;
56
57     return E_NOINTERFACE;
58 }
59
60 static ULONG STDMETHODCALLTYPE buffer_AddRef(IWineD3DBuffer *iface)
61 {
62     struct wined3d_buffer *This = (struct wined3d_buffer *)iface;
63     ULONG refcount = InterlockedIncrement(&This->resource.ref);
64
65     TRACE("%p increasing refcount to %u\n", This, refcount);
66
67     return refcount;
68 }
69
70 static ULONG STDMETHODCALLTYPE buffer_Release(IWineD3DBuffer *iface)
71 {
72     struct wined3d_buffer *This = (struct wined3d_buffer *)iface;
73     ULONG refcount = InterlockedDecrement(&This->resource.ref);
74
75     TRACE("%p decreasing refcount to %u\n", This, refcount);
76
77     if (!refcount)
78     {
79         resource_cleanup((IWineD3DResource *)iface);
80         HeapFree(GetProcessHeap(), 0, This);
81     }
82
83     return refcount;
84 }
85
86 /* IWineD3DBase methods */
87
88 static HRESULT STDMETHODCALLTYPE buffer_GetParent(IWineD3DBuffer *iface, IUnknown **parent)
89 {
90     return resource_get_parent((IWineD3DResource *)iface, parent);
91 }
92
93 /* IWineD3DResource methods */
94
95 static HRESULT STDMETHODCALLTYPE buffer_GetDevice(IWineD3DBuffer *iface, IWineD3DDevice **device)
96 {
97     return resource_get_device((IWineD3DResource *)iface, device);
98 }
99
100 static HRESULT STDMETHODCALLTYPE buffer_SetPrivateData(IWineD3DBuffer *iface,
101         REFGUID guid, const void *data, DWORD data_size, DWORD flags)
102 {
103     return resource_set_private_data((IWineD3DResource *)iface, guid, data, data_size, flags);
104 }
105
106 static HRESULT STDMETHODCALLTYPE buffer_GetPrivateData(IWineD3DBuffer *iface,
107         REFGUID guid, void *data, DWORD *data_size)
108 {
109     return resource_get_private_data((IWineD3DResource *)iface, guid, data, data_size);
110 }
111
112 static HRESULT STDMETHODCALLTYPE buffer_FreePrivateData(IWineD3DBuffer *iface, REFGUID guid)
113 {
114     return resource_free_private_data((IWineD3DResource *)iface, guid);
115 }
116
117 static DWORD STDMETHODCALLTYPE buffer_SetPriority(IWineD3DBuffer *iface, DWORD priority)
118 {
119     return resource_set_priority((IWineD3DResource *)iface, priority);
120 }
121
122 static DWORD STDMETHODCALLTYPE buffer_GetPriority(IWineD3DBuffer *iface)
123 {
124     return resource_get_priority((IWineD3DResource *)iface);
125 }
126
127 static void STDMETHODCALLTYPE buffer_PreLoad(IWineD3DBuffer *iface)
128 {
129     TRACE("iface %p\n", iface);
130 }
131
132 static void STDMETHODCALLTYPE buffer_UnLoad(IWineD3DBuffer *iface)
133 {
134     TRACE("iface %p\n", iface);
135 }
136
137 static WINED3DRESOURCETYPE STDMETHODCALLTYPE buffer_GetType(IWineD3DBuffer *iface)
138 {
139     return resource_get_type((IWineD3DResource *)iface);
140 }
141
142 const struct IWineD3DBufferVtbl wined3d_buffer_vtbl =
143 {
144     /* IUnknown methods */
145     buffer_QueryInterface,
146     buffer_AddRef,
147     buffer_Release,
148     /* IWineD3DBase methods */
149     buffer_GetParent,
150     /* IWineD3DResource methods */
151     buffer_GetDevice,
152     buffer_SetPrivateData,
153     buffer_GetPrivateData,
154     buffer_FreePrivateData,
155     buffer_SetPriority,
156     buffer_GetPriority,
157     buffer_PreLoad,
158     buffer_UnLoad,
159     buffer_GetType,
160 };
161
162 /* IUnknown methods */
163
164 static HRESULT STDMETHODCALLTYPE IWineD3DVertexBufferImpl_QueryInterface(IWineD3DVertexBuffer *iface,
165         REFIID riid, void **object)
166 {
167     TRACE("iface %p, riid %s, object %p\n", iface, debugstr_guid(riid), object);
168
169     if (IsEqualGUID(riid, &IID_IWineD3DVertexBuffer)
170             || IsEqualGUID(riid, &IID_IWineD3DResource)
171             || IsEqualGUID(riid, &IID_IWineD3DBase)
172             || IsEqualGUID(riid, &IID_IUnknown))
173     {
174         IUnknown_AddRef(iface);
175         *object = iface;
176         return S_OK;
177     }
178
179     WARN("%s not implemented, returning E_NOINTERFACE\n", debugstr_guid(riid));
180
181     *object = NULL;
182
183     return E_NOINTERFACE;
184 }
185
186 static ULONG STDMETHODCALLTYPE IWineD3DVertexBufferImpl_AddRef(IWineD3DVertexBuffer *iface)
187 {
188     IWineD3DVertexBufferImpl *This = (IWineD3DVertexBufferImpl *)iface;
189     ULONG refcount = InterlockedIncrement(&This->resource.ref);
190
191     TRACE("%p increasing refcount to %u\n", This, refcount);
192
193     return refcount;
194 }
195
196 static ULONG STDMETHODCALLTYPE IWineD3DVertexBufferImpl_Release(IWineD3DVertexBuffer *iface)
197 {
198     IWineD3DVertexBufferImpl *This = (IWineD3DVertexBufferImpl *)iface;
199     ULONG refcount = InterlockedDecrement(&This->resource.ref);
200
201     TRACE("%p decreasing refcount to %u\n", This, refcount);
202
203     if (!refcount)
204     {
205         if (This->vbo)
206         {
207             IWineD3DDeviceImpl *device = This->resource.wineD3DDevice;
208
209             ActivateContext(device, device->lastActiveRenderTarget, CTXUSAGE_RESOURCELOAD);
210             ENTER_GL();
211             GL_EXTCALL(glDeleteBuffersARB(1, &This->vbo));
212             checkGLcall("glDeleteBuffersARB");
213             LEAVE_GL();
214         }
215
216         resource_cleanup((IWineD3DResource *)iface);
217         HeapFree(GetProcessHeap(), 0, This);
218     }
219
220     return refcount;
221 }
222
223 /* IWineD3DBase methods */
224
225 static HRESULT STDMETHODCALLTYPE IWineD3DVertexBufferImpl_GetParent(IWineD3DVertexBuffer *iface, IUnknown **parent)
226 {
227     return resource_get_parent((IWineD3DResource *)iface, parent);
228 }
229
230 /* IWineD3DResource methods */
231
232 static HRESULT STDMETHODCALLTYPE IWineD3DVertexBufferImpl_GetDevice(IWineD3DVertexBuffer *iface,
233         IWineD3DDevice **device)
234 {
235     return resource_get_device((IWineD3DResource *)iface, device);
236 }
237
238 static HRESULT STDMETHODCALLTYPE IWineD3DVertexBufferImpl_SetPrivateData(IWineD3DVertexBuffer *iface,
239         REFGUID guid, const void *data, DWORD data_size, DWORD flags)
240 {
241     return resource_set_private_data((IWineD3DResource *)iface, guid, data, data_size, flags);
242 }
243
244 static HRESULT STDMETHODCALLTYPE IWineD3DVertexBufferImpl_GetPrivateData(IWineD3DVertexBuffer *iface,
245         REFGUID guid, void *data, DWORD *data_size)
246 {
247     return resource_get_private_data((IWineD3DResource *)iface, guid, data, data_size);
248 }
249
250 static HRESULT STDMETHODCALLTYPE IWineD3DVertexBufferImpl_FreePrivateData(IWineD3DVertexBuffer *iface, REFGUID guid)
251 {
252     return resource_free_private_data((IWineD3DResource *)iface, guid);
253 }
254
255 static DWORD STDMETHODCALLTYPE IWineD3DVertexBufferImpl_SetPriority(IWineD3DVertexBuffer *iface, DWORD priority)
256 {
257     return resource_set_priority((IWineD3DResource *)iface, priority);
258 }
259
260 static DWORD STDMETHODCALLTYPE IWineD3DVertexBufferImpl_GetPriority(IWineD3DVertexBuffer *iface)
261 {
262     return resource_get_priority((IWineD3DResource *)iface);
263 }
264
265 static inline void fixup_d3dcolor(DWORD *pos)
266 {
267     DWORD srcColor = *pos;
268
269     /* Color conversion like in drawStridedSlow. watch out for little endianity
270      * If we want that stuff to work on big endian machines too we have to consider more things
271      *
272      * 0xff000000: Alpha mask
273      * 0x00ff0000: Blue mask
274      * 0x0000ff00: Green mask
275      * 0x000000ff: Red mask
276      */
277     *pos = 0;
278     *pos |= (srcColor & 0xff00ff00)      ;   /* Alpha Green */
279     *pos |= (srcColor & 0x00ff0000) >> 16;   /* Red */
280     *pos |= (srcColor & 0x000000ff) << 16;   /* Blue */
281 }
282
283 static inline void fixup_transformed_pos(float *p)
284 {
285     float x, y, z, w;
286
287     /* rhw conversion like in drawStridedSlow */
288     if (p[3] == 1.0 || ((p[3] < eps) && (p[3] > -eps)))
289     {
290         x = p[0];
291         y = p[1];
292         z = p[2];
293         w = 1.0;
294     }
295     else
296     {
297         w = 1.0 / p[3];
298         x = p[0] * w;
299         y = p[1] * w;
300         z = p[2] * w;
301     }
302     p[0] = x;
303     p[1] = y;
304     p[2] = z;
305     p[3] = w;
306 }
307
308 static DWORD *find_conversion_shift(IWineD3DVertexBufferImpl *This,
309         const WineDirect3DVertexStridedData *strided, DWORD stride)
310 {
311     DWORD *ret, i, shift, j, type;
312     DWORD orig_type_size;
313
314     if (!stride)
315     {
316         TRACE("No shift\n");
317         return NULL;
318     }
319
320     This->conv_stride = stride;
321     ret = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(DWORD) * stride);
322     for (i = 0; i < MAX_ATTRIBS; ++i)
323     {
324         if (strided->u.input[i].VBO != This->vbo) continue;
325
326         type = strided->u.input[i].dwType;
327         if (type == WINED3DDECLTYPE_FLOAT16_2)
328         {
329             shift = 4;
330         }
331         else if (type == WINED3DDECLTYPE_FLOAT16_4)
332         {
333             shift = 8;
334             /* Pre-shift the last 4 bytes in the FLOAT16_4 by 4 bytes - this makes FLOAT16_2 and FLOAT16_4 conversions
335              * compatible
336              */
337             for (j = 4; j < 8; ++j)
338             {
339                 ret[(DWORD_PTR)strided->u.input[i].lpData + j] += 4;
340             }
341         }
342         else
343         {
344             shift = 0;
345         }
346         This->conv_stride += shift;
347
348         if (shift)
349         {
350             orig_type_size = WINED3D_ATR_TYPESIZE(type) * WINED3D_ATR_SIZE(type);
351             for (j = (DWORD_PTR)strided->u.input[i].lpData + orig_type_size; j < stride; ++j)
352             {
353                 ret[j] += shift;
354             }
355         }
356     }
357
358     if (TRACE_ON(d3d))
359     {
360         TRACE("Dumping conversion shift:\n");
361         for (i = 0; i < stride; ++i)
362         {
363             TRACE("[%d]", ret[i]);
364         }
365         TRACE("\n");
366     }
367
368     return ret;
369 }
370
371 static inline BOOL process_converted_attribute(IWineD3DVertexBufferImpl *This,
372         const enum vbo_conversion_type conv_type, const WineDirect3DStridedData *attrib,
373         DWORD *stride_this_run, const DWORD type)
374 {
375     DWORD attrib_size;
376     BOOL ret = FALSE;
377     int i;
378     DWORD offset = This->resource.wineD3DDevice->stateBlock->streamOffset[attrib->streamNo];
379     DWORD_PTR data;
380
381     /* Check for some valid situations which cause us pain. One is if the buffer is used for
382      * constant attributes(stride = 0), the other one is if the buffer is used on two streams
383      * with different strides. In the 2nd case we might have to drop conversion entirely,
384      * it is possible that the same bytes are once read as FLOAT2 and once as UBYTE4N.
385      */
386     if (attrib->dwStride == 0)
387     {
388         FIXME("%s used with stride 0, let's hope we get the vertex stride from somewhere else\n",
389                 debug_d3ddecltype(type));
390     }
391     else if(attrib->dwStride != *stride_this_run && *stride_this_run)
392     {
393         FIXME("Got two concurrent strides, %d and %d\n", attrib->dwStride, *stride_this_run);
394     }
395     else
396     {
397         *stride_this_run = attrib->dwStride;
398         if (This->stride != *stride_this_run)
399         {
400             /* We rely that this happens only on the first converted attribute that is found,
401              * if at all. See above check
402              */
403             TRACE("Reconverting because converted attributes occur, and the stride changed\n");
404             This->stride = *stride_this_run;
405             HeapFree(GetProcessHeap(), HEAP_ZERO_MEMORY, This->conv_map);
406             This->conv_map = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*This->conv_map) * This->stride);
407             ret = TRUE;
408         }
409     }
410
411     data = (((DWORD_PTR) attrib->lpData) + offset) % This->stride;
412     attrib_size = WINED3D_ATR_SIZE(type) * WINED3D_ATR_TYPESIZE(type);
413     for (i = 0; i < attrib_size; ++i)
414     {
415         if (This->conv_map[data + i] != conv_type)
416         {
417             TRACE("Byte %ld in vertex changed\n", i + data);
418             TRACE("It was type %d, is %d now\n", This->conv_map[data + i], conv_type);
419             ret = TRUE;
420             This->conv_map[data + i] = conv_type;
421         }
422     }
423
424     return ret;
425 }
426
427 static inline BOOL check_attribute(IWineD3DVertexBufferImpl *This,
428         const WineDirect3DStridedData *attrib, const BOOL check_d3dcolor, const BOOL is_ffp_position,
429         const BOOL is_ffp_color, DWORD *stride_this_run, BOOL *float16_used)
430 {
431     BOOL ret = FALSE;
432     DWORD type;
433
434     /* Ignore attributes that do not have our vbo. After that check we can be sure that the attribute is
435      * there, on nonexistent attribs the vbo is 0.
436      */
437     if (attrib->VBO != This->vbo) return FALSE;
438
439     type = attrib->dwType;
440     /* Look for newly appeared conversion */
441     if (!GL_SUPPORT(NV_HALF_FLOAT) && (type == WINED3DDECLTYPE_FLOAT16_2 || type == WINED3DDECLTYPE_FLOAT16_4))
442     {
443         ret = process_converted_attribute(This, CONV_FLOAT16_2, attrib, stride_this_run, type);
444
445         if (is_ffp_position) FIXME("Test FLOAT16 fixed function processing positions\n");
446         else if (is_ffp_color) FIXME("test FLOAT16 fixed function processing colors\n");
447         *float16_used = TRUE;
448     }
449     else if (check_d3dcolor && type == WINED3DDECLTYPE_D3DCOLOR)
450     {
451         ret = process_converted_attribute(This, CONV_D3DCOLOR, attrib, stride_this_run, WINED3DDECLTYPE_D3DCOLOR);
452
453         if (!is_ffp_color) FIXME("Test for non-color fixed function D3DCOLOR type\n");
454     }
455     else if (is_ffp_position && type == WINED3DDECLTYPE_FLOAT4)
456     {
457         ret = process_converted_attribute(This, CONV_POSITIONT, attrib, stride_this_run, WINED3DDECLTYPE_FLOAT4);
458     }
459     else if (This->conv_map)
460     {
461         ret = process_converted_attribute(This, CONV_NONE, attrib, stride_this_run, type);
462     }
463
464     return ret;
465 }
466
467 static inline BOOL IWineD3DVertexBufferImpl_FindDecl(IWineD3DVertexBufferImpl *This)
468 {
469     IWineD3DDeviceImpl *device = This->resource.wineD3DDevice;
470     BOOL ret = FALSE;
471     int i;
472     DWORD stride_this_run = 0;
473     BOOL float16_used = FALSE;
474
475     /* In d3d7 the vertex buffer declaration NEVER changes because it is stored in the d3d7 vertex buffer.
476      * Once we have our declaration there is no need to look it up again.
477      */
478     if (((IWineD3DImpl *)device->wineD3D)->dxVersion == 7 && This->Flags & VBFLAG_HASDESC) return FALSE;
479
480     TRACE("Finding vertex buffer conversion information\n");
481     /* Certain declaration types need some fixups before we can pass them to
482      * opengl. This means D3DCOLOR attributes with fixed function vertex
483      * processing, FLOAT4 POSITIONT with fixed function, and FLOAT16 if
484      * GL_NV_half_float is not supported.
485      *
486      * The vertex buffer FVF doesn't help with finding them, we have to use
487      * the decoded vertex declaration and pick the things that concern the
488      * current buffer. A problem with this is that this can change between
489      * draws, so we have to validate the information and reprocess the buffer
490      * if it changes, and avoid false positives for performance reasons.
491      *
492      * We have to distinguish between vertex shaders and fixed function to
493      * pick the way we access the strided vertex information.
494      *
495      * This code sets up a per-byte array with the size of the detected
496      * stride of the arrays in the buffer. For each byte we have a field
497      * that marks the conversion needed on this byte. For example, the
498      * following declaration with fixed function vertex processing:
499      *
500      *      POSITIONT, FLOAT4
501      *      NORMAL, FLOAT3
502      *      DIFFUSE, FLOAT16_4
503      *      SPECULAR, D3DCOLOR
504      *
505      * Will result in
506      * {                 POSITIONT                    }{             NORMAL                }{    DIFFUSE          }{SPECULAR }
507      * [P][P][P][P][P][P][P][P][P][P][P][P][P][P][P][P][0][0][0][0][0][0][0][0][0][0][0][0][F][F][F][F][F][F][F][F][C][C][C][C]
508      *
509      * Where in this example map P means 4 component position conversion, 0
510      * means no conversion, F means FLOAT16_2 conversion and C means D3DCOLOR
511      * conversion (red / blue swizzle).
512      *
513      * If we're doing conversion and the stride changes we have to reconvert
514      * the whole buffer. Note that we do not mind if the semantic changes,
515      * we only care for the conversion type. So if the NORMAL is replaced
516      * with a TEXCOORD, nothing has to be done, or if the DIFFUSE is replaced
517      * with a D3DCOLOR BLENDWEIGHT we can happily dismiss the change. Some
518      * conversion types depend on the semantic as well, for example a FLOAT4
519      * texcoord needs no conversion while a FLOAT4 positiont needs one
520      */
521     if (use_vs(device->stateBlock))
522     {
523         TRACE("vshader\n");
524         /* If the current vertex declaration is marked for no half float conversion don't bother to
525          * analyse the strided streams in depth, just set them up for no conversion. Return decl changed
526          * if we used conversion before
527          */
528         if (!((IWineD3DVertexDeclarationImpl *) device->stateBlock->vertexDecl)->half_float_conv_needed)
529         {
530             if (This->conv_map)
531             {
532                 TRACE("Now using shaders without conversion, but conversion used before\n");
533                 HeapFree(GetProcessHeap(), 0, This->conv_map);
534                 HeapFree(GetProcessHeap(), 0, This->conv_shift);
535                 This->conv_map = NULL;
536                 This->stride = 0;
537                 This->conv_shift = NULL;
538                 This->conv_stride = 0;
539                 return TRUE;
540             }
541             else
542             {
543                 return FALSE;
544             }
545         }
546         for (i = 0; i < MAX_ATTRIBS; ++i)
547         {
548             ret = check_attribute(This, &device->strided_streams.u.input[i],
549                     FALSE, FALSE, FALSE, &stride_this_run, &float16_used) || ret;
550         }
551
552         /* Recalculate the conversion shift map if the declaration has changed,
553          * and we're using float16 conversion or used it on the last run
554          */
555         if (ret && (float16_used || This->conv_map))
556         {
557             HeapFree(GetProcessHeap(), 0, This->conv_shift);
558             This->conv_shift = find_conversion_shift(This, &device->strided_streams, This->stride);
559         }
560     }
561     else
562     {
563         /* Fixed function is a bit trickier. We have to take care for D3DCOLOR types, FLOAT4 positions and of course
564          * FLOAT16s if not supported. Also, we can't iterate over the array, so use macros to generate code for all
565          * the attributes that our current fixed function pipeline implementation cares for.
566          */
567         BOOL support_d3dcolor = GL_SUPPORT(EXT_VERTEX_ARRAY_BGRA);
568         ret = check_attribute(This, &device->strided_streams.u.s.position,
569                 TRUE, TRUE,  FALSE, &stride_this_run, &float16_used) || ret;
570         ret = check_attribute(This, &device->strided_streams.u.s.normal,
571                 TRUE, FALSE, FALSE, &stride_this_run, &float16_used) || ret;
572         ret = check_attribute(This, &device->strided_streams.u.s.diffuse,
573                 !support_d3dcolor, FALSE, TRUE,  &stride_this_run, &float16_used) || ret;
574         ret = check_attribute(This, &device->strided_streams.u.s.specular,
575                 !support_d3dcolor, FALSE, TRUE,  &stride_this_run, &float16_used) || ret;
576         ret = check_attribute(This, &device->strided_streams.u.s.texCoords[0],
577                 TRUE, FALSE, FALSE, &stride_this_run, &float16_used) || ret;
578         ret = check_attribute(This, &device->strided_streams.u.s.texCoords[1],
579                 TRUE, FALSE, FALSE, &stride_this_run, &float16_used) || ret;
580         ret = check_attribute(This, &device->strided_streams.u.s.texCoords[2],
581                 TRUE, FALSE, FALSE, &stride_this_run, &float16_used) || ret;
582         ret = check_attribute(This, &device->strided_streams.u.s.texCoords[3],
583                 TRUE, FALSE, FALSE, &stride_this_run, &float16_used) || ret;
584         ret = check_attribute(This, &device->strided_streams.u.s.texCoords[4],
585                 TRUE, FALSE, FALSE, &stride_this_run, &float16_used) || ret;
586         ret = check_attribute(This, &device->strided_streams.u.s.texCoords[5],
587                 TRUE, FALSE, FALSE, &stride_this_run, &float16_used) || ret;
588         ret = check_attribute(This, &device->strided_streams.u.s.texCoords[6],
589                 TRUE, FALSE, FALSE, &stride_this_run, &float16_used) || ret;
590         ret = check_attribute(This, &device->strided_streams.u.s.texCoords[7],
591                 TRUE, FALSE, FALSE, &stride_this_run, &float16_used) || ret;
592
593         if (float16_used) FIXME("Float16 conversion used with fixed function vertex processing\n");
594     }
595
596     if (stride_this_run == 0 && This->conv_map)
597     {
598         /* Sanity test */
599         if (!ret) ERR("no converted attributes found, old conversion map exists, and no declaration change?\n");
600         HeapFree(GetProcessHeap(), 0, This->conv_map);
601         This->conv_map = NULL;
602         This->stride = 0;
603     }
604     This->Flags |= VBFLAG_HASDESC;
605
606     if (ret) TRACE("Conversion information changed\n");
607
608     return ret;
609 }
610
611 static void check_vbo_size(IWineD3DVertexBufferImpl *This)
612 {
613     DWORD size = This->conv_stride ? This->conv_stride * (This->resource.size / This->stride) : This->resource.size;
614     if (This->vbo_size != size)
615     {
616         TRACE("Old size %d, creating new size %d\n", This->vbo_size, size);
617         ENTER_GL();
618         GL_EXTCALL(glBindBufferARB(GL_ARRAY_BUFFER_ARB, This->vbo));
619         checkGLcall("glBindBufferARB");
620         GL_EXTCALL(glBufferDataARB(GL_ARRAY_BUFFER_ARB, size, NULL, This->vbo_usage));
621         This->vbo_size = size;
622         checkGLcall("glBufferDataARB");
623         LEAVE_GL();
624     }
625 }
626
627 static void CreateVBO(IWineD3DVertexBufferImpl *This)
628 {
629     GLenum error, glUsage;
630     DWORD vboUsage = This->resource.usage;
631     IWineD3DDeviceImpl *device = This->resource.wineD3DDevice;
632
633     TRACE("Creating an OpenGL vertex buffer object for IWineD3DVertexBuffer %p  Usage(%s)\n",
634             This, debug_d3dusage(vboUsage));
635
636     /* Make sure that a context is there. Needed in a multithreaded environment. Otherwise this call is a nop */
637     ActivateContext(device, device->lastActiveRenderTarget, CTXUSAGE_RESOURCELOAD);
638     ENTER_GL();
639
640     /* Make sure that the gl error is cleared. Do not use checkGLcall
641     * here because checkGLcall just prints a fixme and continues. However,
642     * if an error during VBO creation occurs we can fall back to non-vbo operation
643     * with full functionality(but performance loss)
644     */
645     while(glGetError() != GL_NO_ERROR);
646
647     /* Basically the FVF parameter passed to CreateVertexBuffer is no good
648     * It is the FVF set with IWineD3DDevice::SetFVF or the Vertex Declaration set with
649     * IWineD3DDevice::SetVertexDeclaration that decides how the vertices in the buffer
650     * look like. This means that on each DrawPrimitive call the vertex buffer has to be verified
651     * to check if the rhw and color values are in the correct format.
652     */
653
654     GL_EXTCALL(glGenBuffersARB(1, &This->vbo));
655     error = glGetError();
656     if (This->vbo == 0 || error != GL_NO_ERROR)
657     {
658         WARN("Failed to create a VBO with error %s (%#x)\n", debug_glerror(error), error);
659         goto error;
660     }
661
662     GL_EXTCALL(glBindBufferARB(GL_ARRAY_BUFFER_ARB, This->vbo));
663     error = glGetError();
664     if (error != GL_NO_ERROR)
665     {
666         WARN("Failed to bind the VBO with error %s (%#x)\n", debug_glerror(error), error);
667         goto error;
668     }
669
670     /* Don't use static, because dx apps tend to update the buffer
671     * quite often even if they specify 0 usage. Because we always keep the local copy
672     * we never read from the vbo and can create a write only opengl buffer.
673     */
674     switch(vboUsage & (WINED3DUSAGE_WRITEONLY | WINED3DUSAGE_DYNAMIC))
675     {
676         case WINED3DUSAGE_WRITEONLY | WINED3DUSAGE_DYNAMIC:
677         case WINED3DUSAGE_DYNAMIC:
678             TRACE("Gl usage = GL_STREAM_DRAW\n");
679             glUsage = GL_STREAM_DRAW_ARB;
680             break;
681
682         case WINED3DUSAGE_WRITEONLY:
683         default:
684             TRACE("Gl usage = GL_DYNAMIC_DRAW\n");
685             glUsage = GL_DYNAMIC_DRAW_ARB;
686             break;
687     }
688
689     /* Reserve memory for the buffer. The amount of data won't change
690     * so we are safe with calling glBufferData once with a NULL ptr and
691     * calling glBufferSubData on updates
692     */
693     GL_EXTCALL(glBufferDataARB(GL_ARRAY_BUFFER_ARB, This->resource.size, NULL, glUsage));
694     error = glGetError();
695     if (error != GL_NO_ERROR)
696     {
697         WARN("glBufferDataARB failed with error %s (%#x)\n", debug_glerror(error), error);
698         goto error;
699     }
700     This->vbo_size = This->resource.size;
701     This->vbo_usage = glUsage;
702     This->dirtystart = 0;
703     This->dirtyend = This->resource.size;
704     This->Flags |= VBFLAG_DIRTY;
705
706     LEAVE_GL();
707
708     return;
709
710 error:
711     /* Clean up all vbo init, but continue because we can work without a vbo :-) */
712     FIXME("Failed to create a vertex buffer object. Continuing, but performance issues can occur\n");
713     if (This->vbo) GL_EXTCALL(glDeleteBuffersARB(1, &This->vbo));
714     This->vbo = 0;
715     LEAVE_GL();
716
717     return;
718 }
719
720 static void STDMETHODCALLTYPE IWineD3DVertexBufferImpl_PreLoad(IWineD3DVertexBuffer *iface)
721 {
722     IWineD3DVertexBufferImpl *This = (IWineD3DVertexBufferImpl *) iface;
723     IWineD3DDeviceImpl *device = This->resource.wineD3DDevice;
724     BYTE *data;
725     UINT start = 0, end = 0, vertices;
726     BOOL declChanged = FALSE;
727     int i, j;
728     TRACE("(%p)->()\n", This);
729
730     if (!This->vbo)
731     {
732         /* TODO: Make converting independent from VBOs */
733         if (This->Flags & VBFLAG_CREATEVBO)
734         {
735             CreateVBO(This);
736             This->Flags &= ~VBFLAG_CREATEVBO;
737         }
738         else
739         {
740             return; /* Not doing any conversion */
741         }
742     }
743
744     /* Reading the declaration makes only sense if the stateblock is finalized and the buffer bound to a stream */
745     if (device->isInDraw && This->bindCount > 0)
746     {
747         declChanged = IWineD3DVertexBufferImpl_FindDecl(This);
748     }
749     else if (This->Flags & VBFLAG_HASDESC)
750     {
751         /* Reuse the declaration stored in the buffer. It will most likely not change, and if it does
752          * the stream source state handler will call PreLoad again and the change will be caught
753          */
754     }
755     else
756     {
757         /* Cannot get a declaration, and no declaration is stored in the buffer. It is pointless to preload
758          * now. When the buffer is used, PreLoad will be called by the stream source state handler and a valid
759          * declaration for the buffer can be found
760          */
761         return;
762     }
763
764     /* If applications change the declaration over and over, reconverting all the time is a huge
765      * performance hit. So count the declaration changes and release the VBO if there are too many
766      * of them (and thus stop converting)
767      */
768     if (declChanged)
769     {
770         ++This->declChanges;
771         This->draws = 0;
772
773         if (This->declChanges > VB_MAXDECLCHANGES)
774         {
775             FIXME("Too many declaration changes, stopping converting\n");
776             ActivateContext(device, device->lastActiveRenderTarget, CTXUSAGE_RESOURCELOAD);
777             ENTER_GL();
778             GL_EXTCALL(glDeleteBuffersARB(1, &This->vbo));
779             checkGLcall("glDeleteBuffersARB");
780             LEAVE_GL();
781             This->vbo = 0;
782             HeapFree(GetProcessHeap(), 0, This->conv_shift);
783
784             /* The stream source state handler might have read the memory of the vertex buffer already
785              * and got the memory in the vbo which is not valid any longer. Dirtify the stream source
786              * to force a reload. This happens only once per changed vertexbuffer and should occur rather
787              * rarely
788              */
789             IWineD3DDeviceImpl_MarkStateDirty(device, STATE_STREAMSRC);
790
791             return;
792         }
793         check_vbo_size(This);
794     }
795     else
796     {
797         /* However, it is perfectly fine to change the declaration every now and then. We don't want a game that
798          * changes it every minute drop the VBO after VB_MAX_DECL_CHANGES minutes. So count draws without
799          * decl changes and reset the decl change count after a specific number of them
800          */
801         ++This->draws;
802         if (This->draws > VB_RESETDECLCHANGE) This->declChanges = 0;
803     }
804
805     if (declChanged)
806     {
807         /* The declaration changed, reload the whole buffer */
808         WARN("Reloading buffer because of decl change\n");
809         start = 0;
810         end = This->resource.size;
811     }
812     else if(This->Flags & VBFLAG_DIRTY)
813     {
814         /* No decl change, but dirty data, reload the changed stuff */
815         if (This->conv_shift)
816         {
817             if (This->dirtystart != 0 || This->dirtyend != 0)
818             {
819                 FIXME("Implement partial buffer loading with shifted conversion\n");
820             }
821         }
822         start = This->dirtystart;
823         end = This->dirtyend;
824     }
825     else
826     {
827         /* Desc not changed, buffer not dirty, nothing to do :-) */
828         return;
829     }
830
831     /* Mark the buffer clean */
832     This->Flags &= ~VBFLAG_DIRTY;
833     This->dirtystart = 0;
834     This->dirtyend = 0;
835
836     if (!This->conv_map)
837     {
838         /* That means that there is nothing to fixup. Just upload from This->resource.allocatedMemory
839          * directly into the vbo. Do not free the system memory copy because drawPrimitive may need it if
840          * the stride is 0, for instancing emulation, vertex blending emulation or shader emulation.
841          */
842         TRACE("No conversion needed\n");
843
844         if (!device->isInDraw)
845         {
846             ActivateContext(device, device->lastActiveRenderTarget, CTXUSAGE_RESOURCELOAD);
847         }
848         ENTER_GL();
849         GL_EXTCALL(glBindBufferARB(GL_ARRAY_BUFFER_ARB, This->vbo));
850         checkGLcall("glBindBufferARB");
851         GL_EXTCALL(glBufferSubDataARB(GL_ARRAY_BUFFER_ARB, start, end-start, This->resource.allocatedMemory + start));
852         checkGLcall("glBufferSubDataARB");
853         LEAVE_GL();
854         return;
855     }
856
857     /* Now for each vertex in the buffer that needs conversion */
858     vertices = This->resource.size / This->stride;
859
860     if (This->conv_shift)
861     {
862         TRACE("Shifted conversion\n");
863         data = HeapAlloc(GetProcessHeap(), 0, vertices * This->conv_stride);
864
865         for (i = start / This->stride; i < min((end / This->stride) + 1, vertices); ++i)
866         {
867             for (j = 0; j < This->stride; ++j)
868             {
869                 switch(This->conv_map[j])
870                 {
871                     case CONV_NONE:
872                         data[This->conv_stride * i + j + This->conv_shift[j]] = This->resource.allocatedMemory[This->stride * i + j];
873                         break;
874
875                     case CONV_FLOAT16_2:
876                     {
877                         float *out = (float *)(&data[This->conv_stride * i + j + This->conv_shift[j]]);
878                         const WORD *in = (WORD *)(&This->resource.allocatedMemory[i * This->stride + j]);
879
880                         out[1] = float_16_to_32(in + 1);
881                         out[0] = float_16_to_32(in + 0);
882                         j += 3;    /* Skip 3 additional bytes,as a FLOAT16_2 has 4 bytes */
883                         break;
884                     }
885
886                     default:
887                         FIXME("Unimplemented conversion %d in shifted conversion\n", This->conv_map[j]);
888                 }
889             }
890         }
891
892         ENTER_GL();
893         GL_EXTCALL(glBindBufferARB(GL_ARRAY_BUFFER_ARB, This->vbo));
894         checkGLcall("glBindBufferARB");
895         GL_EXTCALL(glBufferSubDataARB(GL_ARRAY_BUFFER_ARB, 0, vertices * This->conv_stride, data));
896         checkGLcall("glBufferSubDataARB");
897         LEAVE_GL();
898     }
899     else
900     {
901         data = HeapAlloc(GetProcessHeap(), 0, This->resource.size);
902         memcpy(data + start, This->resource.allocatedMemory + start, end - start);
903         for (i = start / This->stride; i < min((end / This->stride) + 1, vertices); ++i)
904         {
905             for (j = 0; j < This->stride; ++j)
906             {
907                 switch(This->conv_map[j])
908                 {
909                     case CONV_NONE:
910                         /* Done already */
911                         j += 3;
912                         break;
913                     case CONV_D3DCOLOR:
914                         fixup_d3dcolor((DWORD *) (data + i * This->stride + j));
915                         j += 3;
916                         break;
917
918                     case CONV_POSITIONT:
919                         fixup_transformed_pos((float *) (data + i * This->stride + j));
920                         j += 15;
921                         break;
922
923                     case CONV_FLOAT16_2:
924                         ERR("Did not expect FLOAT16 conversion in unshifted conversion\n");
925                     default:
926                         FIXME("Unimplemented conversion %d in shifted conversion\n", This->conv_map[j]);
927                 }
928             }
929         }
930
931         ENTER_GL();
932         GL_EXTCALL(glBindBufferARB(GL_ARRAY_BUFFER_ARB, This->vbo));
933         checkGLcall("glBindBufferARB");
934         GL_EXTCALL(glBufferSubDataARB(GL_ARRAY_BUFFER_ARB, start, end - start, data + start));
935         checkGLcall("glBufferSubDataARB");
936         LEAVE_GL();
937     }
938
939     HeapFree(GetProcessHeap(), 0, data);
940 }
941
942 static void STDMETHODCALLTYPE IWineD3DVertexBufferImpl_UnLoad(IWineD3DVertexBuffer *iface)
943 {
944     IWineD3DVertexBufferImpl *This = (IWineD3DVertexBufferImpl *)iface;
945     IWineD3DDeviceImpl *device = This->resource.wineD3DDevice;
946
947     TRACE("(%p)\n", This);
948
949     /* This is easy: The whole content is shadowed in This->resource.allocatedMemory,
950      * so we only have to destroy the vbo. Only do it if we have a vbo, which implies
951      * that vbos are supported
952      */
953     if (This->vbo)
954     {
955         ActivateContext(device, device->lastActiveRenderTarget, CTXUSAGE_RESOURCELOAD);
956         ENTER_GL();
957         GL_EXTCALL(glDeleteBuffersARB(1, &This->vbo));
958         checkGLcall("glDeleteBuffersARB");
959         LEAVE_GL();
960         This->vbo = 0;
961         This->Flags |= VBFLAG_CREATEVBO; /* Recreate the VBO next load */
962     }
963 }
964
965 static WINED3DRESOURCETYPE STDMETHODCALLTYPE IWineD3DVertexBufferImpl_GetType(IWineD3DVertexBuffer *iface)
966 {
967     return resource_get_type((IWineD3DResource *)iface);
968 }
969
970 /* IWineD3DVertexBuffer methods */
971
972 static HRESULT STDMETHODCALLTYPE IWineD3DVertexBufferImpl_Lock(IWineD3DVertexBuffer *iface,
973         UINT OffsetToLock, UINT SizeToLock, BYTE **ppbData, DWORD Flags)
974 {
975     IWineD3DVertexBufferImpl *This = (IWineD3DVertexBufferImpl *)iface;
976     BYTE *data;
977
978     TRACE("(%p)->%d, %d, %p, %08x\n", This, OffsetToLock, SizeToLock, ppbData, Flags);
979
980     InterlockedIncrement(&This->lockcount);
981
982     if (This->Flags & VBFLAG_DIRTY)
983     {
984         if (This->dirtystart > OffsetToLock) This->dirtystart = OffsetToLock;
985         if (SizeToLock)
986         {
987             if (This->dirtyend < OffsetToLock + SizeToLock) This->dirtyend = OffsetToLock + SizeToLock;
988         }
989         else
990         {
991             This->dirtyend = This->resource.size;
992         }
993     }
994     else
995     {
996         This->dirtystart = OffsetToLock;
997         if (SizeToLock) This->dirtyend = OffsetToLock + SizeToLock;
998         else This->dirtyend = This->resource.size;
999     }
1000
1001     data = This->resource.allocatedMemory;
1002     This->Flags |= VBFLAG_DIRTY;
1003     *ppbData = data + OffsetToLock;
1004
1005     TRACE("(%p) : returning memory of %p (base:%p,offset:%u)\n", This, data + OffsetToLock, data, OffsetToLock);
1006     /* TODO: check Flags compatibility with This->currentDesc.Usage (see MSDN) */
1007
1008     return WINED3D_OK;
1009 }
1010
1011 static HRESULT STDMETHODCALLTYPE IWineD3DVertexBufferImpl_Unlock(IWineD3DVertexBuffer *iface)
1012 {
1013     IWineD3DVertexBufferImpl *This = (IWineD3DVertexBufferImpl *)iface;
1014     LONG lockcount;
1015
1016     TRACE("(%p)\n", This);
1017
1018     lockcount = InterlockedDecrement(&This->lockcount);
1019     if (lockcount > 0)
1020     {
1021         /* Delay loading the buffer until everything is unlocked */
1022         TRACE("Ignoring the unlock\n");
1023         return WINED3D_OK;
1024     }
1025
1026     if (This->Flags & VBFLAG_HASDESC)
1027     {
1028         IWineD3DVertexBufferImpl_PreLoad(iface);
1029     }
1030
1031     return WINED3D_OK;
1032 }
1033
1034 static HRESULT STDMETHODCALLTYPE IWineD3DVertexBufferImpl_GetDesc(IWineD3DVertexBuffer *iface,
1035         WINED3DVERTEXBUFFER_DESC *pDesc)
1036 {
1037     IWineD3DVertexBufferImpl *This = (IWineD3DVertexBufferImpl *)iface;
1038
1039     TRACE("(%p)\n", This);
1040
1041     pDesc->Format = This->resource.format;
1042     pDesc->Type = This->resource.resourceType;
1043     pDesc->Usage = This->resource.usage;
1044     pDesc->Pool = This->resource.pool;
1045     pDesc->Size = This->resource.size;
1046     pDesc->FVF = This->fvf;
1047
1048     return WINED3D_OK;
1049 }
1050
1051 const IWineD3DVertexBufferVtbl IWineD3DVertexBuffer_Vtbl =
1052 {
1053     /* IUnknown methods */
1054     IWineD3DVertexBufferImpl_QueryInterface,
1055     IWineD3DVertexBufferImpl_AddRef,
1056     IWineD3DVertexBufferImpl_Release,
1057     /* IWineD3DBase methods */
1058     IWineD3DVertexBufferImpl_GetParent,
1059     /* IWineD3DResource methods */
1060     IWineD3DVertexBufferImpl_GetDevice,
1061     IWineD3DVertexBufferImpl_SetPrivateData,
1062     IWineD3DVertexBufferImpl_GetPrivateData,
1063     IWineD3DVertexBufferImpl_FreePrivateData,
1064     IWineD3DVertexBufferImpl_SetPriority,
1065     IWineD3DVertexBufferImpl_GetPriority,
1066     IWineD3DVertexBufferImpl_PreLoad,
1067     IWineD3DVertexBufferImpl_UnLoad,
1068     IWineD3DVertexBufferImpl_GetType,
1069     /* IWineD3DVertexBuffer methods */
1070     IWineD3DVertexBufferImpl_Lock,
1071     IWineD3DVertexBufferImpl_Unlock,
1072     IWineD3DVertexBufferImpl_GetDesc,
1073 };
1074
1075 const BYTE *IWineD3DVertexBufferImpl_GetMemory(IWineD3DVertexBuffer *iface, DWORD iOffset, GLint *vbo)
1076 {
1077     IWineD3DVertexBufferImpl *This = (IWineD3DVertexBufferImpl *)iface;
1078
1079     *vbo = This->vbo;
1080     if (!This->vbo)
1081     {
1082         if (This->Flags & VBFLAG_CREATEVBO)
1083         {
1084             CreateVBO(This);
1085             This->Flags &= ~VBFLAG_CREATEVBO;
1086             if (This->vbo)
1087             {
1088                 *vbo = This->vbo;
1089                 return (const BYTE *)iOffset;
1090             }
1091         }
1092         return This->resource.allocatedMemory + iOffset;
1093     }
1094     else
1095     {
1096         return (const BYTE *)iOffset;
1097     }
1098 }