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