wined3d: Introduce a separate structure for stateblock states.
[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 HRESULT WINAPI d3d9_vertexbuffer_QueryInterface(IDirect3DVertexBuffer9 *iface, REFIID riid, void **object)
27 {
28     TRACE("iface %p, riid %s, object %p.\n", iface, debugstr_guid(riid), object);
29
30     if (IsEqualGUID(riid, &IID_IDirect3DVertexBuffer9)
31             || IsEqualGUID(riid, &IID_IDirect3DResource9)
32             || IsEqualGUID(riid, &IID_IUnknown))
33     {
34         IDirect3DVertexBuffer9_AddRef(iface);
35         *object = iface;
36         return S_OK;
37     }
38
39     WARN("%s not implemented, returning E_NOINTERFACE.\n", debugstr_guid(riid));
40
41     *object = NULL;
42     return E_NOINTERFACE;
43 }
44
45 static ULONG WINAPI d3d9_vertexbuffer_AddRef(IDirect3DVertexBuffer9 *iface)
46 {
47     IDirect3DVertexBuffer9Impl *buffer = (IDirect3DVertexBuffer9Impl *)iface;
48     ULONG refcount = InterlockedIncrement(&buffer->ref);
49
50     TRACE("%p increasing refcount to %u.\n", iface, refcount);
51
52     if (refcount == 1)
53     {
54         IDirect3DDevice9Ex_AddRef(buffer->parentDevice);
55         wined3d_mutex_lock();
56         IWineD3DBuffer_AddRef(buffer->wineD3DVertexBuffer);
57         wined3d_mutex_unlock();
58     }
59
60     return refcount;
61 }
62
63 static ULONG WINAPI d3d9_vertexbuffer_Release(IDirect3DVertexBuffer9 *iface)
64 {
65     IDirect3DVertexBuffer9Impl *buffer = (IDirect3DVertexBuffer9Impl *)iface;
66     ULONG refcount = InterlockedDecrement(&buffer->ref);
67
68     TRACE("%p decreasing refcount to %u.\n", iface, refcount);
69
70     if (!refcount)
71     {
72         IDirect3DDevice9Ex *device = buffer->parentDevice;
73
74         wined3d_mutex_lock();
75         IWineD3DBuffer_Release(buffer->wineD3DVertexBuffer);
76         wined3d_mutex_unlock();
77
78         /* Release the device last, as it may cause the device to be destroyed. */
79         IDirect3DDevice9Ex_Release(device);
80     }
81
82     return refcount;
83 }
84
85 static HRESULT WINAPI d3d9_vertexbuffer_GetDevice(IDirect3DVertexBuffer9 *iface, IDirect3DDevice9 **device)
86 {
87     TRACE("iface %p, device %p.\n", iface, device);
88
89     *device = (IDirect3DDevice9 *)((IDirect3DVertexBuffer9Impl *)iface)->parentDevice;
90     IDirect3DDevice9_AddRef(*device);
91
92     TRACE("Returning device %p.\n", *device);
93
94     return D3D_OK;
95 }
96
97 static HRESULT WINAPI d3d9_vertexbuffer_SetPrivateData(IDirect3DVertexBuffer9 *iface,
98         REFGUID guid, const void *data, DWORD data_size, DWORD flags)
99 {
100     HRESULT hr;
101
102     TRACE("iface %p, guid %s, data %p, data_size %u, flags %#x.\n",
103             iface, debugstr_guid(guid), data, data_size, flags);
104
105     wined3d_mutex_lock();
106     hr = IWineD3DBuffer_SetPrivateData(((IDirect3DVertexBuffer9Impl *)iface)->wineD3DVertexBuffer,
107             guid, data, data_size, flags);
108     wined3d_mutex_unlock();
109
110     return hr;
111 }
112
113 static HRESULT WINAPI d3d9_vertexbuffer_GetPrivateData(IDirect3DVertexBuffer9 *iface,
114         REFGUID guid, void *data, DWORD *data_size)
115 {
116     HRESULT hr;
117
118     TRACE("iface %p, guid %s, data %p, data_size %p.\n",
119             iface, debugstr_guid(guid), data, data_size);
120
121     wined3d_mutex_lock();
122     hr = IWineD3DBuffer_GetPrivateData(((IDirect3DVertexBuffer9Impl *)iface)->wineD3DVertexBuffer,
123             guid, data, data_size);
124     wined3d_mutex_unlock();
125
126     return hr;
127 }
128
129 static HRESULT WINAPI d3d9_vertexbuffer_FreePrivateData(IDirect3DVertexBuffer9 *iface, REFGUID guid)
130 {
131     HRESULT hr;
132
133     TRACE("iface %p, guid %s.\n", iface, debugstr_guid(guid));
134
135     wined3d_mutex_lock();
136     hr = IWineD3DBuffer_FreePrivateData(((IDirect3DVertexBuffer9Impl *)iface)->wineD3DVertexBuffer, guid);
137     wined3d_mutex_unlock();
138
139     return hr;
140 }
141
142 static DWORD WINAPI d3d9_vertexbuffer_SetPriority(IDirect3DVertexBuffer9 *iface, DWORD priority)
143 {
144     DWORD previous;
145
146     TRACE("iface %p, priority %u.\n", iface, priority);
147
148     wined3d_mutex_lock();
149     previous = IWineD3DBuffer_SetPriority(((IDirect3DVertexBuffer9Impl *)iface)->wineD3DVertexBuffer, priority);
150     wined3d_mutex_unlock();
151
152     return previous;
153 }
154
155 static DWORD WINAPI d3d9_vertexbuffer_GetPriority(IDirect3DVertexBuffer9 *iface)
156 {
157     DWORD priority;
158
159     TRACE("iface %p.\n", iface);
160
161     wined3d_mutex_lock();
162     priority = IWineD3DBuffer_GetPriority(((IDirect3DVertexBuffer9Impl *)iface)->wineD3DVertexBuffer);
163     wined3d_mutex_unlock();
164
165     return priority;
166 }
167
168 static void WINAPI d3d9_vertexbuffer_PreLoad(IDirect3DVertexBuffer9 *iface)
169 {
170     TRACE("iface %p.\n", iface);
171
172     wined3d_mutex_lock();
173     IWineD3DBuffer_PreLoad(((IDirect3DVertexBuffer9Impl *)iface)->wineD3DVertexBuffer);
174     wined3d_mutex_unlock();
175 }
176
177 static D3DRESOURCETYPE WINAPI d3d9_vertexbuffer_GetType(IDirect3DVertexBuffer9 *iface)
178 {
179     TRACE("iface %p.\n", iface);
180
181     return D3DRTYPE_VERTEXBUFFER;
182 }
183
184 static HRESULT WINAPI d3d9_vertexbuffer_Lock(IDirect3DVertexBuffer9 *iface,
185         UINT offset, UINT size, void **data, DWORD flags)
186 {
187     HRESULT hr;
188
189     TRACE("iface %p, offset %u, size %u, data %p, flags %#x.\n",
190             iface, offset, size, data, flags);
191
192     wined3d_mutex_lock();
193     hr = IWineD3DBuffer_Map(((IDirect3DVertexBuffer9Impl *)iface)->wineD3DVertexBuffer,
194             offset, size, (BYTE **)data, flags);
195     wined3d_mutex_unlock();
196
197     return hr;
198 }
199
200 static HRESULT WINAPI d3d9_vertexbuffer_Unlock(IDirect3DVertexBuffer9 *iface)
201 {
202     HRESULT hr;
203
204     TRACE("iface %p.\n", iface);
205
206     wined3d_mutex_lock();
207     hr = IWineD3DBuffer_Unmap(((IDirect3DVertexBuffer9Impl *)iface)->wineD3DVertexBuffer);
208     wined3d_mutex_unlock();
209
210     return hr;
211 }
212
213 static HRESULT WINAPI d3d9_vertexbuffer_GetDesc(IDirect3DVertexBuffer9 *iface, D3DVERTEXBUFFER_DESC *desc)
214 {
215     IDirect3DVertexBuffer9Impl *buffer = (IDirect3DVertexBuffer9Impl *)iface;
216     WINED3DBUFFER_DESC wined3d_desc;
217
218     TRACE("iface %p, desc %p.\n", iface, desc);
219
220     wined3d_mutex_lock();
221     IWineD3DBuffer_GetDesc(buffer->wineD3DVertexBuffer, &wined3d_desc);
222     wined3d_mutex_unlock();
223
224     desc->Format = D3DFMT_VERTEXDATA;
225     desc->Usage = wined3d_desc.Usage;
226     desc->Pool = wined3d_desc.Pool;
227     desc->Size = wined3d_desc.Size;
228     desc->Type = D3DRTYPE_VERTEXBUFFER;
229     desc->FVF = buffer->fvf;
230
231     return D3D_OK;
232 }
233
234 static const IDirect3DVertexBuffer9Vtbl d3d9_vertexbuffer_vtbl =
235 {
236     /* IUnknown */
237     d3d9_vertexbuffer_QueryInterface,
238     d3d9_vertexbuffer_AddRef,
239     d3d9_vertexbuffer_Release,
240     /* IDirect3DResource9 */
241     d3d9_vertexbuffer_GetDevice,
242     d3d9_vertexbuffer_SetPrivateData,
243     d3d9_vertexbuffer_GetPrivateData,
244     d3d9_vertexbuffer_FreePrivateData,
245     d3d9_vertexbuffer_SetPriority,
246     d3d9_vertexbuffer_GetPriority,
247     d3d9_vertexbuffer_PreLoad,
248     d3d9_vertexbuffer_GetType,
249     /* IDirect3DVertexBuffer9 */
250     d3d9_vertexbuffer_Lock,
251     d3d9_vertexbuffer_Unlock,
252     d3d9_vertexbuffer_GetDesc,
253 };
254
255 static void STDMETHODCALLTYPE d3d9_vertexbuffer_wined3d_object_destroyed(void *parent)
256 {
257     HeapFree(GetProcessHeap(), 0, parent);
258 }
259
260 static const struct wined3d_parent_ops d3d9_vertexbuffer_wined3d_parent_ops =
261 {
262     d3d9_vertexbuffer_wined3d_object_destroyed,
263 };
264
265 HRESULT vertexbuffer_init(IDirect3DVertexBuffer9Impl *buffer, IDirect3DDevice9Impl *device,
266         UINT size, UINT usage, DWORD fvf, D3DPOOL pool)
267 {
268     HRESULT hr;
269
270     buffer->lpVtbl = &d3d9_vertexbuffer_vtbl;
271     buffer->ref = 1;
272     buffer->fvf = fvf;
273
274     wined3d_mutex_lock();
275     hr = IWineD3DDevice_CreateVertexBuffer(device->WineD3DDevice, size, usage & WINED3DUSAGE_MASK,
276             (WINED3DPOOL)pool, buffer, &d3d9_vertexbuffer_wined3d_parent_ops, &buffer->wineD3DVertexBuffer);
277     wined3d_mutex_unlock();
278     if (FAILED(hr))
279     {
280         WARN("Failed to create wined3d buffer, hr %#x.\n", hr);
281         return hr;
282     }
283
284     buffer->parentDevice = (IDirect3DDevice9Ex *)device;
285     IDirect3DDevice9Ex_AddRef(buffer->parentDevice);
286
287     return D3D_OK;
288 }
289
290 static HRESULT WINAPI d3d9_indexbuffer_QueryInterface(IDirect3DIndexBuffer9 *iface, REFIID riid, void **object)
291 {
292     TRACE("iface %p, riid %s, object %p.\n", iface, debugstr_guid(riid), object);
293
294     if (IsEqualGUID(riid, &IID_IDirect3DIndexBuffer9)
295             || IsEqualGUID(riid, &IID_IDirect3DResource9)
296             || IsEqualGUID(riid, &IID_IUnknown))
297     {
298         IDirect3DIndexBuffer9_AddRef(iface);
299         *object = iface;
300         return S_OK;
301     }
302
303     WARN("%s not implemented, returning E_NOINTERFACE.\n", debugstr_guid(riid));
304
305     *object = NULL;
306     return E_NOINTERFACE;
307 }
308
309 static ULONG WINAPI d3d9_indexbuffer_AddRef(IDirect3DIndexBuffer9 *iface)
310 {
311     IDirect3DIndexBuffer9Impl *buffer = (IDirect3DIndexBuffer9Impl *)iface;
312     ULONG refcount = InterlockedIncrement(&buffer->ref);
313
314     TRACE("%p increasing refcount to %u.\n", iface, refcount);
315
316     if (refcount == 1)
317     {
318         IDirect3DDevice9Ex_AddRef(buffer->parentDevice);
319         wined3d_mutex_lock();
320         IWineD3DBuffer_AddRef(buffer->wineD3DIndexBuffer);
321         wined3d_mutex_unlock();
322     }
323
324     return refcount;
325 }
326
327 static ULONG WINAPI d3d9_indexbuffer_Release(IDirect3DIndexBuffer9 *iface)
328 {
329     IDirect3DIndexBuffer9Impl *buffer = (IDirect3DIndexBuffer9Impl *)iface;
330     ULONG refcount = InterlockedDecrement(&buffer->ref);
331
332     TRACE("%p decreasing refcount to %u.\n", iface, refcount);
333
334     if (!refcount)
335     {
336         IDirect3DDevice9Ex *device = buffer->parentDevice;
337
338         wined3d_mutex_lock();
339         IWineD3DBuffer_Release(buffer->wineD3DIndexBuffer);
340         wined3d_mutex_unlock();
341
342         /* Release the device last, as it may cause the device to be destroyed. */
343         IDirect3DDevice9Ex_Release(device);
344     }
345
346     return refcount;
347 }
348
349 static HRESULT WINAPI d3d9_indexbuffer_GetDevice(IDirect3DIndexBuffer9 *iface, IDirect3DDevice9 **device)
350 {
351     TRACE("iface %p, device %p.\n", iface, device);
352
353     *device = (IDirect3DDevice9 *)((IDirect3DIndexBuffer9Impl *)iface)->parentDevice;
354     IDirect3DDevice9_AddRef(*device);
355
356     TRACE("Returning device %p.\n", *device);
357
358     return D3D_OK;
359 }
360
361 static HRESULT WINAPI d3d9_indexbuffer_SetPrivateData(IDirect3DIndexBuffer9 *iface,
362         REFGUID guid, const void *data, DWORD data_size, DWORD flags)
363 {
364     HRESULT hr;
365
366     TRACE("iface %p, guid %s, data %p, data_size %u, flags %#x.\n",
367             iface, debugstr_guid(guid), data, data_size, flags);
368
369     wined3d_mutex_lock();
370     hr = IWineD3DBuffer_SetPrivateData(((IDirect3DIndexBuffer9Impl *)iface)->wineD3DIndexBuffer,
371             guid, data, data_size, flags);
372     wined3d_mutex_unlock();
373
374     return hr;
375 }
376
377 static HRESULT WINAPI d3d9_indexbuffer_GetPrivateData(IDirect3DIndexBuffer9 *iface,
378         REFGUID guid, void *data, DWORD *data_size)
379 {
380     HRESULT hr;
381
382     TRACE("iface %p, guid %s, data %p, data_size %p.\n",
383             iface, debugstr_guid(guid), data, data_size);
384
385     wined3d_mutex_lock();
386     hr = IWineD3DBuffer_GetPrivateData(((IDirect3DIndexBuffer9Impl *)iface)->wineD3DIndexBuffer,
387             guid, data, data_size);
388     wined3d_mutex_unlock();
389
390     return hr;
391 }
392
393 static HRESULT WINAPI d3d9_indexbuffer_FreePrivateData(IDirect3DIndexBuffer9 *iface, REFGUID guid)
394 {
395     HRESULT hr;
396
397     TRACE("iface %p, guid %s.\n", iface, debugstr_guid(guid));
398
399     wined3d_mutex_lock();
400     hr = IWineD3DBuffer_FreePrivateData(((IDirect3DIndexBuffer9Impl *)iface)->wineD3DIndexBuffer, guid);
401     wined3d_mutex_unlock();
402
403     return hr;
404 }
405
406 static DWORD WINAPI d3d9_indexbuffer_SetPriority(IDirect3DIndexBuffer9 *iface, DWORD priority)
407 {
408     DWORD previous;
409
410     TRACE("iface %p, priority %u.\n", iface, priority);
411
412     wined3d_mutex_lock();
413     previous = IWineD3DBuffer_SetPriority(((IDirect3DIndexBuffer9Impl *)iface)->wineD3DIndexBuffer, priority);
414     wined3d_mutex_unlock();
415
416     return previous;
417 }
418
419 static DWORD WINAPI d3d9_indexbuffer_GetPriority(IDirect3DIndexBuffer9 *iface)
420 {
421     DWORD priority;
422
423     TRACE("iface %p.\n", iface);
424
425     wined3d_mutex_lock();
426     priority = IWineD3DBuffer_GetPriority(((IDirect3DIndexBuffer9Impl *)iface)->wineD3DIndexBuffer);
427     wined3d_mutex_unlock();
428
429     return priority;
430 }
431
432 static void WINAPI d3d9_indexbuffer_PreLoad(IDirect3DIndexBuffer9 *iface)
433 {
434     TRACE("iface %p.\n", iface);
435
436     wined3d_mutex_lock();
437     IWineD3DBuffer_PreLoad(((IDirect3DIndexBuffer9Impl *)iface)->wineD3DIndexBuffer);
438     wined3d_mutex_unlock();
439 }
440
441 static D3DRESOURCETYPE WINAPI d3d9_indexbuffer_GetType(IDirect3DIndexBuffer9 *iface)
442 {
443     TRACE("iface %p.\n", iface);
444
445     return D3DRTYPE_INDEXBUFFER;
446 }
447
448 static HRESULT WINAPI d3d9_indexbuffer_Lock(IDirect3DIndexBuffer9 *iface,
449         UINT offset, UINT size, void **data, DWORD flags)
450 {
451     HRESULT hr;
452
453     TRACE("iface %p, offset %u, size %u, data %p, flags %#x.\n",
454             iface, offset, size, data, flags);
455
456     wined3d_mutex_lock();
457     hr = IWineD3DBuffer_Map(((IDirect3DIndexBuffer9Impl *)iface)->wineD3DIndexBuffer,
458             offset, size, (BYTE **)data, flags);
459     wined3d_mutex_unlock();
460
461     return hr;
462 }
463
464 static HRESULT WINAPI d3d9_indexbuffer_Unlock(IDirect3DIndexBuffer9 *iface)
465 {
466     HRESULT hr;
467
468     TRACE("iface %p.\n", iface);
469
470     wined3d_mutex_lock();
471     hr = IWineD3DBuffer_Unmap(((IDirect3DIndexBuffer9Impl *)iface)->wineD3DIndexBuffer);
472     wined3d_mutex_unlock();
473
474     return hr;
475 }
476
477 static HRESULT WINAPI d3d9_indexbuffer_GetDesc(IDirect3DIndexBuffer9 *iface, D3DINDEXBUFFER_DESC *desc)
478 {
479     IDirect3DIndexBuffer9Impl *buffer = (IDirect3DIndexBuffer9Impl *)iface;
480     WINED3DBUFFER_DESC wined3d_desc;
481
482     TRACE("iface %p, desc %p.\n", iface, desc);
483
484     wined3d_mutex_lock();
485     IWineD3DBuffer_GetDesc(buffer->wineD3DIndexBuffer, &wined3d_desc);
486     wined3d_mutex_unlock();
487
488     desc->Format = d3dformat_from_wined3dformat(buffer->format);
489     desc->Usage = wined3d_desc.Usage;
490     desc->Pool = wined3d_desc.Pool;
491     desc->Size = wined3d_desc.Size;
492     desc->Type = D3DRTYPE_INDEXBUFFER;
493
494     return D3D_OK;
495 }
496
497 static const IDirect3DIndexBuffer9Vtbl d3d9_indexbuffer_vtbl =
498 {
499     /* IUnknown */
500     d3d9_indexbuffer_QueryInterface,
501     d3d9_indexbuffer_AddRef,
502     d3d9_indexbuffer_Release,
503     /* IDirect3DResource9 */
504     d3d9_indexbuffer_GetDevice,
505     d3d9_indexbuffer_SetPrivateData,
506     d3d9_indexbuffer_GetPrivateData,
507     d3d9_indexbuffer_FreePrivateData,
508     d3d9_indexbuffer_SetPriority,
509     d3d9_indexbuffer_GetPriority,
510     d3d9_indexbuffer_PreLoad,
511     d3d9_indexbuffer_GetType,
512     /* IDirect3DIndexBuffer9 */
513     d3d9_indexbuffer_Lock,
514     d3d9_indexbuffer_Unlock,
515     d3d9_indexbuffer_GetDesc,
516 };
517
518 static void STDMETHODCALLTYPE d3d9_indexbuffer_wined3d_object_destroyed(void *parent)
519 {
520     HeapFree(GetProcessHeap(), 0, parent);
521 }
522
523 static const struct wined3d_parent_ops d3d9_indexbuffer_wined3d_parent_ops =
524 {
525     d3d9_indexbuffer_wined3d_object_destroyed,
526 };
527
528 HRESULT indexbuffer_init(IDirect3DIndexBuffer9Impl *buffer, IDirect3DDevice9Impl *device,
529         UINT size, DWORD usage, D3DFORMAT format, D3DPOOL pool)
530 {
531     HRESULT hr;
532
533     buffer->lpVtbl = &d3d9_indexbuffer_vtbl;
534     buffer->ref = 1;
535     buffer->format = wined3dformat_from_d3dformat(format);
536
537     wined3d_mutex_lock();
538     hr = IWineD3DDevice_CreateIndexBuffer(device->WineD3DDevice, size, usage & WINED3DUSAGE_MASK,
539             (WINED3DPOOL)pool, buffer, &d3d9_indexbuffer_wined3d_parent_ops, &buffer->wineD3DIndexBuffer);
540     wined3d_mutex_unlock();
541     if (FAILED(hr))
542     {
543         WARN("Failed to create wined3d buffer, hr %#x.\n", hr);
544         return hr;
545     }
546
547     buffer->parentDevice = (IDirect3DDevice9Ex *)device;
548     IDirect3DDevice9Ex_AddRef(buffer->parentDevice);
549
550     return D3D_OK;
551 }