d3d9: Implement IDirect3DVertexBuffer9 private data handling on top of wined3d_resource.
[wine] / dlls / d3d9 / buffer.c
1 /*
2  * Copyright 2002-2004 Jason Edmeades
3  * Copyright 2002-2004 Raphael Junqueira
4  * Copyright 2005 Oliver Stieber
5  *
6  * This library is free software; you can redistribute it and/or
7  * modify it under the terms of the GNU Lesser General Public
8  * License as published by the Free Software Foundation; either
9  * version 2.1 of the License, or (at your option) any later version.
10  *
11  * This library is distributed in the hope that it will be useful,
12  * but WITHOUT ANY WARRANTY; without even the implied warranty of
13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
14  * Lesser General Public License for more details.
15  *
16  * You should have received a copy of the GNU Lesser General Public
17  * License along with this library; if not, write to the Free Software
18  * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
19  */
20
21 #include "config.h"
22 #include "d3d9_private.h"
23
24 WINE_DEFAULT_DEBUG_CHANNEL(d3d9);
25
26 static inline IDirect3DVertexBuffer9Impl *impl_from_IDirect3DVertexBuffer9(IDirect3DVertexBuffer9 *iface)
27 {
28     return CONTAINING_RECORD(iface, IDirect3DVertexBuffer9Impl, lpVtbl);
29 }
30
31 static HRESULT WINAPI d3d9_vertexbuffer_QueryInterface(IDirect3DVertexBuffer9 *iface, REFIID riid, void **object)
32 {
33     TRACE("iface %p, riid %s, object %p.\n", iface, debugstr_guid(riid), object);
34
35     if (IsEqualGUID(riid, &IID_IDirect3DVertexBuffer9)
36             || IsEqualGUID(riid, &IID_IDirect3DResource9)
37             || IsEqualGUID(riid, &IID_IUnknown))
38     {
39         IDirect3DVertexBuffer9_AddRef(iface);
40         *object = iface;
41         return S_OK;
42     }
43
44     WARN("%s not implemented, returning E_NOINTERFACE.\n", debugstr_guid(riid));
45
46     *object = NULL;
47     return E_NOINTERFACE;
48 }
49
50 static ULONG WINAPI d3d9_vertexbuffer_AddRef(IDirect3DVertexBuffer9 *iface)
51 {
52     IDirect3DVertexBuffer9Impl *buffer = (IDirect3DVertexBuffer9Impl *)iface;
53     ULONG refcount = InterlockedIncrement(&buffer->ref);
54
55     TRACE("%p increasing refcount to %u.\n", iface, refcount);
56
57     if (refcount == 1)
58     {
59         IDirect3DDevice9Ex_AddRef(buffer->parentDevice);
60         wined3d_mutex_lock();
61         wined3d_buffer_incref(buffer->wineD3DVertexBuffer);
62         wined3d_mutex_unlock();
63     }
64
65     return refcount;
66 }
67
68 static ULONG WINAPI d3d9_vertexbuffer_Release(IDirect3DVertexBuffer9 *iface)
69 {
70     IDirect3DVertexBuffer9Impl *buffer = (IDirect3DVertexBuffer9Impl *)iface;
71     ULONG refcount = InterlockedDecrement(&buffer->ref);
72
73     TRACE("%p decreasing refcount to %u.\n", iface, refcount);
74
75     if (!refcount)
76     {
77         IDirect3DDevice9Ex *device = buffer->parentDevice;
78
79         wined3d_mutex_lock();
80         wined3d_buffer_decref(buffer->wineD3DVertexBuffer);
81         wined3d_mutex_unlock();
82
83         /* Release the device last, as it may cause the device to be destroyed. */
84         IDirect3DDevice9Ex_Release(device);
85     }
86
87     return refcount;
88 }
89
90 static HRESULT WINAPI d3d9_vertexbuffer_GetDevice(IDirect3DVertexBuffer9 *iface, IDirect3DDevice9 **device)
91 {
92     TRACE("iface %p, device %p.\n", iface, device);
93
94     *device = (IDirect3DDevice9 *)((IDirect3DVertexBuffer9Impl *)iface)->parentDevice;
95     IDirect3DDevice9_AddRef(*device);
96
97     TRACE("Returning device %p.\n", *device);
98
99     return D3D_OK;
100 }
101
102 static HRESULT WINAPI d3d9_vertexbuffer_SetPrivateData(IDirect3DVertexBuffer9 *iface,
103         REFGUID guid, const void *data, DWORD data_size, DWORD flags)
104 {
105     IDirect3DVertexBuffer9Impl *buffer = impl_from_IDirect3DVertexBuffer9(iface);
106     struct wined3d_resource *resource;
107     HRESULT hr;
108
109     TRACE("iface %p, guid %s, data %p, data_size %u, flags %#x.\n",
110             iface, debugstr_guid(guid), data, data_size, flags);
111
112     wined3d_mutex_lock();
113     resource = wined3d_buffer_get_resource(buffer->wineD3DVertexBuffer);
114     hr = wined3d_resource_set_private_data(resource, guid, data, data_size, flags);
115     wined3d_mutex_unlock();
116
117     return hr;
118 }
119
120 static HRESULT WINAPI d3d9_vertexbuffer_GetPrivateData(IDirect3DVertexBuffer9 *iface,
121         REFGUID guid, void *data, DWORD *data_size)
122 {
123     IDirect3DVertexBuffer9Impl *buffer = impl_from_IDirect3DVertexBuffer9(iface);
124     struct wined3d_resource *resource;
125     HRESULT hr;
126
127     TRACE("iface %p, guid %s, data %p, data_size %p.\n",
128             iface, debugstr_guid(guid), data, data_size);
129
130     wined3d_mutex_lock();
131     resource = wined3d_buffer_get_resource(buffer->wineD3DVertexBuffer);
132     hr = wined3d_resource_get_private_data(resource, guid, data, data_size);
133     wined3d_mutex_unlock();
134
135     return hr;
136 }
137
138 static HRESULT WINAPI d3d9_vertexbuffer_FreePrivateData(IDirect3DVertexBuffer9 *iface, REFGUID guid)
139 {
140     IDirect3DVertexBuffer9Impl *buffer = impl_from_IDirect3DVertexBuffer9(iface);
141     struct wined3d_resource *resource;
142     HRESULT hr;
143
144     TRACE("iface %p, guid %s.\n", iface, debugstr_guid(guid));
145
146     wined3d_mutex_lock();
147     resource = wined3d_buffer_get_resource(buffer->wineD3DVertexBuffer);
148     hr = wined3d_resource_free_private_data(resource, guid);
149     wined3d_mutex_unlock();
150
151     return hr;
152 }
153
154 static DWORD WINAPI d3d9_vertexbuffer_SetPriority(IDirect3DVertexBuffer9 *iface, DWORD priority)
155 {
156     DWORD previous;
157
158     TRACE("iface %p, priority %u.\n", iface, priority);
159
160     wined3d_mutex_lock();
161     previous = wined3d_buffer_set_priority(((IDirect3DVertexBuffer9Impl *)iface)->wineD3DVertexBuffer, priority);
162     wined3d_mutex_unlock();
163
164     return previous;
165 }
166
167 static DWORD WINAPI d3d9_vertexbuffer_GetPriority(IDirect3DVertexBuffer9 *iface)
168 {
169     DWORD priority;
170
171     TRACE("iface %p.\n", iface);
172
173     wined3d_mutex_lock();
174     priority = wined3d_buffer_get_priority(((IDirect3DVertexBuffer9Impl *)iface)->wineD3DVertexBuffer);
175     wined3d_mutex_unlock();
176
177     return priority;
178 }
179
180 static void WINAPI d3d9_vertexbuffer_PreLoad(IDirect3DVertexBuffer9 *iface)
181 {
182     TRACE("iface %p.\n", iface);
183
184     wined3d_mutex_lock();
185     wined3d_buffer_preload(((IDirect3DVertexBuffer9Impl *)iface)->wineD3DVertexBuffer);
186     wined3d_mutex_unlock();
187 }
188
189 static D3DRESOURCETYPE WINAPI d3d9_vertexbuffer_GetType(IDirect3DVertexBuffer9 *iface)
190 {
191     TRACE("iface %p.\n", iface);
192
193     return D3DRTYPE_VERTEXBUFFER;
194 }
195
196 static HRESULT WINAPI d3d9_vertexbuffer_Lock(IDirect3DVertexBuffer9 *iface,
197         UINT offset, UINT size, void **data, DWORD flags)
198 {
199     HRESULT hr;
200
201     TRACE("iface %p, offset %u, size %u, data %p, flags %#x.\n",
202             iface, offset, size, data, flags);
203
204     wined3d_mutex_lock();
205     hr = wined3d_buffer_map(((IDirect3DVertexBuffer9Impl *)iface)->wineD3DVertexBuffer,
206             offset, size, (BYTE **)data, flags);
207     wined3d_mutex_unlock();
208
209     return hr;
210 }
211
212 static HRESULT WINAPI d3d9_vertexbuffer_Unlock(IDirect3DVertexBuffer9 *iface)
213 {
214     TRACE("iface %p.\n", iface);
215
216     wined3d_mutex_lock();
217     wined3d_buffer_unmap(((IDirect3DVertexBuffer9Impl *)iface)->wineD3DVertexBuffer);
218     wined3d_mutex_unlock();
219
220     return D3D_OK;
221 }
222
223 static HRESULT WINAPI d3d9_vertexbuffer_GetDesc(IDirect3DVertexBuffer9 *iface, D3DVERTEXBUFFER_DESC *desc)
224 {
225     IDirect3DVertexBuffer9Impl *buffer = (IDirect3DVertexBuffer9Impl *)iface;
226     struct wined3d_resource_desc wined3d_desc;
227     struct wined3d_resource *wined3d_resource;
228
229     TRACE("iface %p, desc %p.\n", iface, desc);
230
231     wined3d_mutex_lock();
232     wined3d_resource = wined3d_buffer_get_resource(buffer->wineD3DVertexBuffer);
233     wined3d_resource_get_desc(wined3d_resource, &wined3d_desc);
234     wined3d_mutex_unlock();
235
236     desc->Format = D3DFMT_VERTEXDATA;
237     desc->Usage = wined3d_desc.usage;
238     desc->Pool = wined3d_desc.pool;
239     desc->Size = wined3d_desc.size;
240     desc->Type = D3DRTYPE_VERTEXBUFFER;
241     desc->FVF = buffer->fvf;
242
243     return D3D_OK;
244 }
245
246 static const IDirect3DVertexBuffer9Vtbl d3d9_vertexbuffer_vtbl =
247 {
248     /* IUnknown */
249     d3d9_vertexbuffer_QueryInterface,
250     d3d9_vertexbuffer_AddRef,
251     d3d9_vertexbuffer_Release,
252     /* IDirect3DResource9 */
253     d3d9_vertexbuffer_GetDevice,
254     d3d9_vertexbuffer_SetPrivateData,
255     d3d9_vertexbuffer_GetPrivateData,
256     d3d9_vertexbuffer_FreePrivateData,
257     d3d9_vertexbuffer_SetPriority,
258     d3d9_vertexbuffer_GetPriority,
259     d3d9_vertexbuffer_PreLoad,
260     d3d9_vertexbuffer_GetType,
261     /* IDirect3DVertexBuffer9 */
262     d3d9_vertexbuffer_Lock,
263     d3d9_vertexbuffer_Unlock,
264     d3d9_vertexbuffer_GetDesc,
265 };
266
267 static void STDMETHODCALLTYPE d3d9_vertexbuffer_wined3d_object_destroyed(void *parent)
268 {
269     HeapFree(GetProcessHeap(), 0, parent);
270 }
271
272 static const struct wined3d_parent_ops d3d9_vertexbuffer_wined3d_parent_ops =
273 {
274     d3d9_vertexbuffer_wined3d_object_destroyed,
275 };
276
277 HRESULT vertexbuffer_init(IDirect3DVertexBuffer9Impl *buffer, IDirect3DDevice9Impl *device,
278         UINT size, UINT usage, DWORD fvf, D3DPOOL pool)
279 {
280     HRESULT hr;
281
282     buffer->lpVtbl = &d3d9_vertexbuffer_vtbl;
283     buffer->ref = 1;
284     buffer->fvf = fvf;
285
286     wined3d_mutex_lock();
287     hr = wined3d_buffer_create_vb(device->wined3d_device, size, usage & WINED3DUSAGE_MASK,
288             (WINED3DPOOL)pool, buffer, &d3d9_vertexbuffer_wined3d_parent_ops, &buffer->wineD3DVertexBuffer);
289     wined3d_mutex_unlock();
290     if (FAILED(hr))
291     {
292         WARN("Failed to create wined3d buffer, hr %#x.\n", hr);
293         return hr;
294     }
295
296     buffer->parentDevice = &device->IDirect3DDevice9Ex_iface;
297     IDirect3DDevice9Ex_AddRef(buffer->parentDevice);
298
299     return D3D_OK;
300 }
301
302 static HRESULT WINAPI d3d9_indexbuffer_QueryInterface(IDirect3DIndexBuffer9 *iface, REFIID riid, void **object)
303 {
304     TRACE("iface %p, riid %s, object %p.\n", iface, debugstr_guid(riid), object);
305
306     if (IsEqualGUID(riid, &IID_IDirect3DIndexBuffer9)
307             || IsEqualGUID(riid, &IID_IDirect3DResource9)
308             || IsEqualGUID(riid, &IID_IUnknown))
309     {
310         IDirect3DIndexBuffer9_AddRef(iface);
311         *object = iface;
312         return S_OK;
313     }
314
315     WARN("%s not implemented, returning E_NOINTERFACE.\n", debugstr_guid(riid));
316
317     *object = NULL;
318     return E_NOINTERFACE;
319 }
320
321 static ULONG WINAPI d3d9_indexbuffer_AddRef(IDirect3DIndexBuffer9 *iface)
322 {
323     IDirect3DIndexBuffer9Impl *buffer = (IDirect3DIndexBuffer9Impl *)iface;
324     ULONG refcount = InterlockedIncrement(&buffer->ref);
325
326     TRACE("%p increasing refcount to %u.\n", iface, refcount);
327
328     if (refcount == 1)
329     {
330         IDirect3DDevice9Ex_AddRef(buffer->parentDevice);
331         wined3d_mutex_lock();
332         wined3d_buffer_incref(buffer->wineD3DIndexBuffer);
333         wined3d_mutex_unlock();
334     }
335
336     return refcount;
337 }
338
339 static ULONG WINAPI d3d9_indexbuffer_Release(IDirect3DIndexBuffer9 *iface)
340 {
341     IDirect3DIndexBuffer9Impl *buffer = (IDirect3DIndexBuffer9Impl *)iface;
342     ULONG refcount = InterlockedDecrement(&buffer->ref);
343
344     TRACE("%p decreasing refcount to %u.\n", iface, refcount);
345
346     if (!refcount)
347     {
348         IDirect3DDevice9Ex *device = buffer->parentDevice;
349
350         wined3d_mutex_lock();
351         wined3d_buffer_decref(buffer->wineD3DIndexBuffer);
352         wined3d_mutex_unlock();
353
354         /* Release the device last, as it may cause the device to be destroyed. */
355         IDirect3DDevice9Ex_Release(device);
356     }
357
358     return refcount;
359 }
360
361 static HRESULT WINAPI d3d9_indexbuffer_GetDevice(IDirect3DIndexBuffer9 *iface, IDirect3DDevice9 **device)
362 {
363     TRACE("iface %p, device %p.\n", iface, device);
364
365     *device = (IDirect3DDevice9 *)((IDirect3DIndexBuffer9Impl *)iface)->parentDevice;
366     IDirect3DDevice9_AddRef(*device);
367
368     TRACE("Returning device %p.\n", *device);
369
370     return D3D_OK;
371 }
372
373 static HRESULT WINAPI d3d9_indexbuffer_SetPrivateData(IDirect3DIndexBuffer9 *iface,
374         REFGUID guid, const void *data, DWORD data_size, DWORD flags)
375 {
376     HRESULT hr;
377
378     TRACE("iface %p, guid %s, data %p, data_size %u, flags %#x.\n",
379             iface, debugstr_guid(guid), data, data_size, flags);
380
381     wined3d_mutex_lock();
382     hr = wined3d_buffer_set_private_data(((IDirect3DIndexBuffer9Impl *)iface)->wineD3DIndexBuffer,
383             guid, data, data_size, flags);
384     wined3d_mutex_unlock();
385
386     return hr;
387 }
388
389 static HRESULT WINAPI d3d9_indexbuffer_GetPrivateData(IDirect3DIndexBuffer9 *iface,
390         REFGUID guid, void *data, DWORD *data_size)
391 {
392     HRESULT hr;
393
394     TRACE("iface %p, guid %s, data %p, data_size %p.\n",
395             iface, debugstr_guid(guid), data, data_size);
396
397     wined3d_mutex_lock();
398     hr = wined3d_buffer_get_private_data(((IDirect3DIndexBuffer9Impl *)iface)->wineD3DIndexBuffer,
399             guid, data, data_size);
400     wined3d_mutex_unlock();
401
402     return hr;
403 }
404
405 static HRESULT WINAPI d3d9_indexbuffer_FreePrivateData(IDirect3DIndexBuffer9 *iface, REFGUID guid)
406 {
407     HRESULT hr;
408
409     TRACE("iface %p, guid %s.\n", iface, debugstr_guid(guid));
410
411     wined3d_mutex_lock();
412     hr = wined3d_buffer_free_private_data(((IDirect3DIndexBuffer9Impl *)iface)->wineD3DIndexBuffer, guid);
413     wined3d_mutex_unlock();
414
415     return hr;
416 }
417
418 static DWORD WINAPI d3d9_indexbuffer_SetPriority(IDirect3DIndexBuffer9 *iface, DWORD priority)
419 {
420     DWORD previous;
421
422     TRACE("iface %p, priority %u.\n", iface, priority);
423
424     wined3d_mutex_lock();
425     previous = wined3d_buffer_set_priority(((IDirect3DIndexBuffer9Impl *)iface)->wineD3DIndexBuffer, priority);
426     wined3d_mutex_unlock();
427
428     return previous;
429 }
430
431 static DWORD WINAPI d3d9_indexbuffer_GetPriority(IDirect3DIndexBuffer9 *iface)
432 {
433     DWORD priority;
434
435     TRACE("iface %p.\n", iface);
436
437     wined3d_mutex_lock();
438     priority = wined3d_buffer_get_priority(((IDirect3DIndexBuffer9Impl *)iface)->wineD3DIndexBuffer);
439     wined3d_mutex_unlock();
440
441     return priority;
442 }
443
444 static void WINAPI d3d9_indexbuffer_PreLoad(IDirect3DIndexBuffer9 *iface)
445 {
446     TRACE("iface %p.\n", iface);
447
448     wined3d_mutex_lock();
449     wined3d_buffer_preload(((IDirect3DIndexBuffer9Impl *)iface)->wineD3DIndexBuffer);
450     wined3d_mutex_unlock();
451 }
452
453 static D3DRESOURCETYPE WINAPI d3d9_indexbuffer_GetType(IDirect3DIndexBuffer9 *iface)
454 {
455     TRACE("iface %p.\n", iface);
456
457     return D3DRTYPE_INDEXBUFFER;
458 }
459
460 static HRESULT WINAPI d3d9_indexbuffer_Lock(IDirect3DIndexBuffer9 *iface,
461         UINT offset, UINT size, void **data, DWORD flags)
462 {
463     HRESULT hr;
464
465     TRACE("iface %p, offset %u, size %u, data %p, flags %#x.\n",
466             iface, offset, size, data, flags);
467
468     wined3d_mutex_lock();
469     hr = wined3d_buffer_map(((IDirect3DIndexBuffer9Impl *)iface)->wineD3DIndexBuffer,
470             offset, size, (BYTE **)data, flags);
471     wined3d_mutex_unlock();
472
473     return hr;
474 }
475
476 static HRESULT WINAPI d3d9_indexbuffer_Unlock(IDirect3DIndexBuffer9 *iface)
477 {
478     TRACE("iface %p.\n", iface);
479
480     wined3d_mutex_lock();
481     wined3d_buffer_unmap(((IDirect3DIndexBuffer9Impl *)iface)->wineD3DIndexBuffer);
482     wined3d_mutex_unlock();
483
484     return D3D_OK;
485 }
486
487 static HRESULT WINAPI d3d9_indexbuffer_GetDesc(IDirect3DIndexBuffer9 *iface, D3DINDEXBUFFER_DESC *desc)
488 {
489     IDirect3DIndexBuffer9Impl *buffer = (IDirect3DIndexBuffer9Impl *)iface;
490     struct wined3d_resource_desc wined3d_desc;
491     struct wined3d_resource *wined3d_resource;
492
493     TRACE("iface %p, desc %p.\n", iface, desc);
494
495     wined3d_mutex_lock();
496     wined3d_resource = wined3d_buffer_get_resource(buffer->wineD3DIndexBuffer);
497     wined3d_resource_get_desc(wined3d_resource, &wined3d_desc);
498     wined3d_mutex_unlock();
499
500     desc->Format = d3dformat_from_wined3dformat(buffer->format);
501     desc->Usage = wined3d_desc.usage;
502     desc->Pool = wined3d_desc.pool;
503     desc->Size = wined3d_desc.size;
504     desc->Type = D3DRTYPE_INDEXBUFFER;
505
506     return D3D_OK;
507 }
508
509 static const IDirect3DIndexBuffer9Vtbl d3d9_indexbuffer_vtbl =
510 {
511     /* IUnknown */
512     d3d9_indexbuffer_QueryInterface,
513     d3d9_indexbuffer_AddRef,
514     d3d9_indexbuffer_Release,
515     /* IDirect3DResource9 */
516     d3d9_indexbuffer_GetDevice,
517     d3d9_indexbuffer_SetPrivateData,
518     d3d9_indexbuffer_GetPrivateData,
519     d3d9_indexbuffer_FreePrivateData,
520     d3d9_indexbuffer_SetPriority,
521     d3d9_indexbuffer_GetPriority,
522     d3d9_indexbuffer_PreLoad,
523     d3d9_indexbuffer_GetType,
524     /* IDirect3DIndexBuffer9 */
525     d3d9_indexbuffer_Lock,
526     d3d9_indexbuffer_Unlock,
527     d3d9_indexbuffer_GetDesc,
528 };
529
530 static void STDMETHODCALLTYPE d3d9_indexbuffer_wined3d_object_destroyed(void *parent)
531 {
532     HeapFree(GetProcessHeap(), 0, parent);
533 }
534
535 static const struct wined3d_parent_ops d3d9_indexbuffer_wined3d_parent_ops =
536 {
537     d3d9_indexbuffer_wined3d_object_destroyed,
538 };
539
540 HRESULT indexbuffer_init(IDirect3DIndexBuffer9Impl *buffer, IDirect3DDevice9Impl *device,
541         UINT size, DWORD usage, D3DFORMAT format, D3DPOOL pool)
542 {
543     HRESULT hr;
544
545     buffer->lpVtbl = &d3d9_indexbuffer_vtbl;
546     buffer->ref = 1;
547     buffer->format = wined3dformat_from_d3dformat(format);
548
549     wined3d_mutex_lock();
550     hr = wined3d_buffer_create_ib(device->wined3d_device, size, usage & WINED3DUSAGE_MASK,
551             (WINED3DPOOL)pool, buffer, &d3d9_indexbuffer_wined3d_parent_ops, &buffer->wineD3DIndexBuffer);
552     wined3d_mutex_unlock();
553     if (FAILED(hr))
554     {
555         WARN("Failed to create wined3d buffer, hr %#x.\n", hr);
556         return hr;
557     }
558
559     buffer->parentDevice = &device->IDirect3DDevice9Ex_iface;
560     IDirect3DDevice9Ex_AddRef(buffer->parentDevice);
561
562     return D3D_OK;
563 }