d3d9: Implement IDirect3DVertexBuffer9 private data handling on top of wined3d_resource.
[wine] / dlls / d3d9 / texture.c
1 /*
2  * IDirect3DTexture9 implementation
3  *
4  * Copyright 2002-2005 Jason Edmeades
5  * Copyright 2002-2005 Raphael Junqueira
6  * Copyright 2005 Oliver Stieber
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 #include "config.h"
24 #include "d3d9_private.h"
25
26 WINE_DEFAULT_DEBUG_CHANNEL(d3d9);
27
28 static inline IDirect3DTexture9Impl *impl_from_IDirect3DTexture9(IDirect3DTexture9 *iface)
29 {
30     return CONTAINING_RECORD(iface, IDirect3DTexture9Impl, IDirect3DTexture9_iface);
31 }
32
33 static HRESULT WINAPI IDirect3DTexture9Impl_QueryInterface(IDirect3DTexture9 *iface, REFIID riid,
34         void **ppobj)
35 {
36     IDirect3DTexture9Impl *This = impl_from_IDirect3DTexture9(iface);
37
38     TRACE("iface %p, riid %s, object %p.\n", iface, debugstr_guid(riid), ppobj);
39
40     if (IsEqualGUID(riid, &IID_IUnknown)
41         || IsEqualGUID(riid, &IID_IDirect3DResource9)
42         || IsEqualGUID(riid, &IID_IDirect3DBaseTexture9)
43         || IsEqualGUID(riid, &IID_IDirect3DTexture9)) {
44         IDirect3DTexture9_AddRef(iface);
45         *ppobj = This;
46         return S_OK;
47     }
48
49     WARN("(%p)->(%s,%p) not found\n", This, debugstr_guid(riid), ppobj);
50     *ppobj = NULL;
51     return E_NOINTERFACE;
52 }
53
54 static ULONG WINAPI IDirect3DTexture9Impl_AddRef(IDirect3DTexture9 *iface)
55 {
56     IDirect3DTexture9Impl *This = impl_from_IDirect3DTexture9(iface);
57     ULONG ref = InterlockedIncrement(&This->ref);
58
59     TRACE("%p increasing refcount to %u.\n", iface, ref);
60
61     if (ref == 1)
62     {
63         IDirect3DDevice9Ex_AddRef(This->parentDevice);
64         wined3d_mutex_lock();
65         wined3d_texture_incref(This->wined3d_texture);
66         wined3d_mutex_unlock();
67     }
68
69     return ref;
70 }
71
72 static ULONG WINAPI IDirect3DTexture9Impl_Release(IDirect3DTexture9 *iface)
73 {
74     IDirect3DTexture9Impl *This = impl_from_IDirect3DTexture9(iface);
75     ULONG ref = InterlockedDecrement(&This->ref);
76
77     TRACE("%p decreasing refcount to %u.\n", iface, ref);
78
79     if (ref == 0) {
80         IDirect3DDevice9Ex *parentDevice = This->parentDevice;
81
82         wined3d_mutex_lock();
83         wined3d_texture_decref(This->wined3d_texture);
84         wined3d_mutex_unlock();
85
86         /* Release the device last, as it may cause the device to be destroyed. */
87         IDirect3DDevice9Ex_Release(parentDevice);
88     }
89     return ref;
90 }
91
92 static HRESULT WINAPI IDirect3DTexture9Impl_GetDevice(IDirect3DTexture9 *iface,
93         IDirect3DDevice9 **device)
94 {
95     IDirect3DTexture9Impl *This = impl_from_IDirect3DTexture9(iface);
96
97     TRACE("iface %p, device %p.\n", iface, device);
98
99     *device = (IDirect3DDevice9 *)This->parentDevice;
100     IDirect3DDevice9_AddRef(*device);
101
102     TRACE("Returning device %p.\n", *device);
103
104     return D3D_OK;
105 }
106
107 static HRESULT WINAPI IDirect3DTexture9Impl_SetPrivateData(IDirect3DTexture9 *iface,
108         REFGUID refguid, const void *pData, DWORD SizeOfData, DWORD Flags)
109 {
110     IDirect3DTexture9Impl *This = impl_from_IDirect3DTexture9(iface);
111     HRESULT hr;
112
113     TRACE("iface %p, guid %s, data %p, data_size %u, flags %#x.\n",
114             iface, debugstr_guid(refguid), pData, SizeOfData, Flags);
115
116     wined3d_mutex_lock();
117     hr = wined3d_texture_set_private_data(This->wined3d_texture, refguid, pData, SizeOfData, Flags);
118     wined3d_mutex_unlock();
119
120     return hr;
121 }
122
123 static HRESULT WINAPI IDirect3DTexture9Impl_GetPrivateData(IDirect3DTexture9 *iface,
124         REFGUID refguid, void *pData, DWORD *pSizeOfData)
125 {
126     IDirect3DTexture9Impl *This = impl_from_IDirect3DTexture9(iface);
127     HRESULT hr;
128
129     TRACE("iface %p, guid %s, data %p, data_size %p.\n",
130             iface, debugstr_guid(refguid), pData, pSizeOfData);
131
132     wined3d_mutex_lock();
133     hr = wined3d_texture_get_private_data(This->wined3d_texture, refguid, pData, pSizeOfData);
134     wined3d_mutex_unlock();
135
136     return hr;
137 }
138
139 static HRESULT WINAPI IDirect3DTexture9Impl_FreePrivateData(IDirect3DTexture9 *iface,
140         REFGUID refguid)
141 {
142     IDirect3DTexture9Impl *This = impl_from_IDirect3DTexture9(iface);
143     HRESULT hr;
144
145     TRACE("iface %p, guid %s.\n", iface, debugstr_guid(refguid));
146
147     wined3d_mutex_lock();
148     hr = wined3d_texture_free_private_data(This->wined3d_texture, refguid);
149     wined3d_mutex_unlock();
150
151     return hr;
152 }
153
154 static DWORD WINAPI IDirect3DTexture9Impl_SetPriority(IDirect3DTexture9 *iface, DWORD PriorityNew)
155 {
156     IDirect3DTexture9Impl *This = impl_from_IDirect3DTexture9(iface);
157     DWORD ret;
158
159     TRACE("iface %p, priority %u.\n", iface, PriorityNew);
160
161     wined3d_mutex_lock();
162     ret = wined3d_texture_set_priority(This->wined3d_texture, PriorityNew);
163     wined3d_mutex_unlock();
164
165     return ret;
166 }
167
168 static DWORD WINAPI IDirect3DTexture9Impl_GetPriority(IDirect3DTexture9 *iface)
169 {
170     IDirect3DTexture9Impl *This = impl_from_IDirect3DTexture9(iface);
171     DWORD ret;
172
173     TRACE("iface %p.\n", iface);
174
175     wined3d_mutex_lock();
176     ret = wined3d_texture_get_priority(This->wined3d_texture);
177     wined3d_mutex_unlock();
178
179     return ret;
180 }
181
182 static void WINAPI IDirect3DTexture9Impl_PreLoad(IDirect3DTexture9 *iface)
183 {
184     IDirect3DTexture9Impl *This = impl_from_IDirect3DTexture9(iface);
185
186     TRACE("iface %p.\n", iface);
187
188     wined3d_mutex_lock();
189     wined3d_texture_preload(This->wined3d_texture);
190     wined3d_mutex_unlock();
191 }
192
193 static D3DRESOURCETYPE WINAPI IDirect3DTexture9Impl_GetType(IDirect3DTexture9 *iface)
194 {
195     TRACE("iface %p.\n", iface);
196
197     return D3DRTYPE_TEXTURE;
198 }
199
200 /* IDirect3DTexture9 IDirect3DBaseTexture9 Interface follow: */
201 static DWORD WINAPI IDirect3DTexture9Impl_SetLOD(IDirect3DTexture9 *iface, DWORD LODNew)
202 {
203     IDirect3DTexture9Impl *This = impl_from_IDirect3DTexture9(iface);
204     DWORD ret;
205
206     TRACE("iface %p, lod %u.\n", iface, LODNew);
207
208     wined3d_mutex_lock();
209     ret = wined3d_texture_set_lod(This->wined3d_texture, LODNew);
210     wined3d_mutex_unlock();
211
212     return ret;
213 }
214
215 static DWORD WINAPI IDirect3DTexture9Impl_GetLOD(IDirect3DTexture9 *iface)
216 {
217     IDirect3DTexture9Impl *This = impl_from_IDirect3DTexture9(iface);
218     DWORD ret;
219
220     TRACE("iface %p.\n", iface);
221
222     wined3d_mutex_lock();
223     ret = wined3d_texture_get_lod(This->wined3d_texture);
224     wined3d_mutex_unlock();
225
226     return ret;
227 }
228
229 static DWORD WINAPI IDirect3DTexture9Impl_GetLevelCount(IDirect3DTexture9 *iface)
230 {
231     IDirect3DTexture9Impl *This = impl_from_IDirect3DTexture9(iface);
232     DWORD ret;
233
234     TRACE("iface %p.\n", iface);
235
236     wined3d_mutex_lock();
237     ret = wined3d_texture_get_level_count(This->wined3d_texture);
238     wined3d_mutex_unlock();
239
240     return ret;
241 }
242
243 static HRESULT WINAPI IDirect3DTexture9Impl_SetAutoGenFilterType(IDirect3DTexture9 *iface,
244         D3DTEXTUREFILTERTYPE FilterType)
245 {
246     IDirect3DTexture9Impl *This = impl_from_IDirect3DTexture9(iface);
247     HRESULT hr;
248
249     TRACE("iface %p, filter_type %#x.\n", iface, FilterType);
250
251     wined3d_mutex_lock();
252     hr = wined3d_texture_set_autogen_filter_type(This->wined3d_texture, (WINED3DTEXTUREFILTERTYPE)FilterType);
253     wined3d_mutex_unlock();
254
255     return hr;
256 }
257
258 static D3DTEXTUREFILTERTYPE WINAPI IDirect3DTexture9Impl_GetAutoGenFilterType(IDirect3DTexture9 *iface)
259 {
260     IDirect3DTexture9Impl *This = impl_from_IDirect3DTexture9(iface);
261     D3DTEXTUREFILTERTYPE ret;
262
263     TRACE("iface %p.\n", iface);
264
265     wined3d_mutex_lock();
266     ret = (D3DTEXTUREFILTERTYPE)wined3d_texture_get_autogen_filter_type(This->wined3d_texture);
267     wined3d_mutex_unlock();
268
269     return ret;
270 }
271
272 static void WINAPI IDirect3DTexture9Impl_GenerateMipSubLevels(IDirect3DTexture9 *iface)
273 {
274     IDirect3DTexture9Impl *This = impl_from_IDirect3DTexture9(iface);
275
276     TRACE("iface %p.\n", iface);
277
278     wined3d_mutex_lock();
279     wined3d_texture_generate_mipmaps(This->wined3d_texture);
280     wined3d_mutex_unlock();
281 }
282
283 static HRESULT WINAPI IDirect3DTexture9Impl_GetLevelDesc(IDirect3DTexture9 *iface,
284         UINT level, D3DSURFACE_DESC *desc)
285 {
286     IDirect3DTexture9Impl *texture = impl_from_IDirect3DTexture9(iface);
287     struct wined3d_resource *sub_resource;
288     HRESULT hr = D3D_OK;
289
290     TRACE("iface %p, level %u, desc %p.\n", iface, level, desc);
291
292     wined3d_mutex_lock();
293     if (!(sub_resource = wined3d_texture_get_sub_resource(texture->wined3d_texture, level)))
294         hr = D3DERR_INVALIDCALL;
295     else
296     {
297         struct wined3d_resource_desc wined3d_desc;
298
299         wined3d_resource_get_desc(sub_resource, &wined3d_desc);
300         desc->Format = d3dformat_from_wined3dformat(wined3d_desc.format);
301         desc->Type = wined3d_desc.resource_type;
302         desc->Usage = wined3d_desc.usage;
303         desc->Pool = wined3d_desc.pool;
304         desc->MultiSampleType = wined3d_desc.multisample_type;
305         desc->MultiSampleQuality = wined3d_desc.multisample_quality;
306         desc->Width = wined3d_desc.width;
307         desc->Height = wined3d_desc.height;
308     }
309     wined3d_mutex_unlock();
310
311     return hr;
312 }
313
314 static HRESULT WINAPI IDirect3DTexture9Impl_GetSurfaceLevel(IDirect3DTexture9 *iface,
315         UINT level, IDirect3DSurface9 **surface)
316 {
317     IDirect3DTexture9Impl *texture = impl_from_IDirect3DTexture9(iface);
318     struct wined3d_resource *sub_resource;
319
320     TRACE("iface %p, level %u, surface %p.\n", iface, level, surface);
321
322     wined3d_mutex_lock();
323     if (!(sub_resource = wined3d_texture_get_sub_resource(texture->wined3d_texture, level)))
324     {
325         wined3d_mutex_unlock();
326         return D3DERR_INVALIDCALL;
327     }
328
329     *surface = wined3d_resource_get_parent(sub_resource);
330     IDirect3DSurface9_AddRef(*surface);
331     wined3d_mutex_unlock();
332
333     return D3D_OK;
334 }
335
336 static HRESULT WINAPI IDirect3DTexture9Impl_LockRect(IDirect3DTexture9 *iface,
337         UINT level, D3DLOCKED_RECT *locked_rect, const RECT *rect, DWORD flags)
338 {
339     IDirect3DTexture9Impl *texture = impl_from_IDirect3DTexture9(iface);
340     struct wined3d_resource *sub_resource;
341     HRESULT hr;
342
343     TRACE("iface %p, level %u, locked_rect %p, rect %p, flags %#x.\n",
344             iface, level, locked_rect, rect, flags);
345
346     wined3d_mutex_lock();
347     if (!(sub_resource = wined3d_texture_get_sub_resource(texture->wined3d_texture, level)))
348         hr = D3DERR_INVALIDCALL;
349     else
350         hr = IDirect3DSurface9_LockRect((IDirect3DSurface9 *)wined3d_resource_get_parent(sub_resource),
351                 locked_rect, rect, flags);
352     wined3d_mutex_unlock();
353
354     return hr;
355 }
356
357 static HRESULT WINAPI IDirect3DTexture9Impl_UnlockRect(IDirect3DTexture9 *iface, UINT level)
358 {
359     IDirect3DTexture9Impl *texture = impl_from_IDirect3DTexture9(iface);
360     struct wined3d_resource *sub_resource;
361     HRESULT hr;
362
363     TRACE("iface %p, level %u.\n", iface, level);
364
365     wined3d_mutex_lock();
366     if (!(sub_resource = wined3d_texture_get_sub_resource(texture->wined3d_texture, level)))
367         hr = D3DERR_INVALIDCALL;
368     else
369         hr = IDirect3DSurface9_UnlockRect((IDirect3DSurface9 *)wined3d_resource_get_parent(sub_resource));
370     wined3d_mutex_unlock();
371
372     return hr;
373 }
374
375 static HRESULT WINAPI IDirect3DTexture9Impl_AddDirtyRect(IDirect3DTexture9 *iface,
376         const RECT *dirty_rect)
377 {
378     IDirect3DTexture9Impl *texture = impl_from_IDirect3DTexture9(iface);
379     HRESULT hr;
380
381     TRACE("iface %p, dirty_rect %s.\n",
382             iface, wine_dbgstr_rect(dirty_rect));
383
384     wined3d_mutex_lock();
385     if (!dirty_rect)
386         hr = wined3d_texture_add_dirty_region(texture->wined3d_texture, 0, NULL);
387     else
388     {
389         WINED3DBOX dirty_region;
390
391         dirty_region.Left = dirty_rect->left;
392         dirty_region.Top = dirty_rect->top;
393         dirty_region.Right = dirty_rect->right;
394         dirty_region.Bottom = dirty_rect->bottom;
395         dirty_region.Front = 0;
396         dirty_region.Back = 1;
397         hr = wined3d_texture_add_dirty_region(texture->wined3d_texture, 0, &dirty_region);
398     }
399     wined3d_mutex_unlock();
400
401     return hr;
402 }
403
404 static const IDirect3DTexture9Vtbl Direct3DTexture9_Vtbl =
405 {
406     /* IUnknown */
407     IDirect3DTexture9Impl_QueryInterface,
408     IDirect3DTexture9Impl_AddRef,
409     IDirect3DTexture9Impl_Release,
410      /* IDirect3DResource9 */
411     IDirect3DTexture9Impl_GetDevice,
412     IDirect3DTexture9Impl_SetPrivateData,
413     IDirect3DTexture9Impl_GetPrivateData,
414     IDirect3DTexture9Impl_FreePrivateData,
415     IDirect3DTexture9Impl_SetPriority,
416     IDirect3DTexture9Impl_GetPriority,
417     IDirect3DTexture9Impl_PreLoad,
418     IDirect3DTexture9Impl_GetType,
419     /* IDirect3dBaseTexture9 */
420     IDirect3DTexture9Impl_SetLOD,
421     IDirect3DTexture9Impl_GetLOD,
422     IDirect3DTexture9Impl_GetLevelCount,
423     IDirect3DTexture9Impl_SetAutoGenFilterType,
424     IDirect3DTexture9Impl_GetAutoGenFilterType,
425     IDirect3DTexture9Impl_GenerateMipSubLevels,
426     /* IDirect3DTexture9 */
427     IDirect3DTexture9Impl_GetLevelDesc,
428     IDirect3DTexture9Impl_GetSurfaceLevel,
429     IDirect3DTexture9Impl_LockRect,
430     IDirect3DTexture9Impl_UnlockRect,
431     IDirect3DTexture9Impl_AddDirtyRect
432 };
433
434 static void STDMETHODCALLTYPE d3d9_texture_wined3d_object_destroyed(void *parent)
435 {
436     HeapFree(GetProcessHeap(), 0, parent);
437 }
438
439 static const struct wined3d_parent_ops d3d9_texture_wined3d_parent_ops =
440 {
441     d3d9_texture_wined3d_object_destroyed,
442 };
443
444 HRESULT texture_init(IDirect3DTexture9Impl *texture, IDirect3DDevice9Impl *device,
445         UINT width, UINT height, UINT levels, DWORD usage, D3DFORMAT format, D3DPOOL pool)
446 {
447     HRESULT hr;
448
449     texture->IDirect3DTexture9_iface.lpVtbl = &Direct3DTexture9_Vtbl;
450     texture->ref = 1;
451
452     wined3d_mutex_lock();
453     hr = wined3d_texture_create_2d(device->wined3d_device, width, height, levels,
454             usage & WINED3DUSAGE_MASK, wined3dformat_from_d3dformat(format), pool,
455             texture, &d3d9_texture_wined3d_parent_ops, &texture->wined3d_texture);
456     wined3d_mutex_unlock();
457     if (FAILED(hr))
458     {
459         WARN("Failed to create wined3d texture, hr %#x.\n", hr);
460         return hr;
461     }
462
463     texture->parentDevice = &device->IDirect3DDevice9Ex_iface;
464     IDirect3DDevice9Ex_AddRef(texture->parentDevice);
465
466     return D3D_OK;
467 }