wined3d: Add a flags parameter to wined3d_surface_create().
[wine] / dlls / d3d9 / surface.c
1 /*
2  * IDirect3DSurface9 implementation
3  *
4  * Copyright 2002-2005 Jason Edmeades
5  *                     Raphael Junqueira
6  *
7  * This library is free software; you can redistribute it and/or
8  * modify it under the terms of the GNU Lesser General Public
9  * License as published by the Free Software Foundation; either
10  * version 2.1 of the License, or (at your option) any later version.
11  *
12  * This library is distributed in the hope that it will be useful,
13  * but WITHOUT ANY WARRANTY; without even the implied warranty of
14  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
15  * Lesser General Public License for more details.
16  *
17  * You should have received a copy of the GNU Lesser General Public
18  * License along with this library; if not, write to the Free Software
19  * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
20  */
21
22 #include "config.h"
23 #include <assert.h>
24 #include "d3d9_private.h"
25
26 WINE_DEFAULT_DEBUG_CHANNEL(d3d9);
27
28 static inline IDirect3DSurface9Impl *impl_from_IDirect3DSurface9(IDirect3DSurface9 *iface)
29 {
30     return CONTAINING_RECORD(iface, IDirect3DSurface9Impl, IDirect3DSurface9_iface);
31 }
32
33 /* IDirect3DSurface9 IUnknown parts follow: */
34 static HRESULT WINAPI IDirect3DSurface9Impl_QueryInterface(IDirect3DSurface9 *iface, REFIID riid,
35         void **ppobj)
36 {
37     IDirect3DSurface9Impl *This = impl_from_IDirect3DSurface9(iface);
38
39     TRACE("iface %p, riid %s, object %p.\n", iface, debugstr_guid(riid), ppobj);
40
41     if (IsEqualGUID(riid, &IID_IUnknown)
42         || IsEqualGUID(riid, &IID_IDirect3DResource9)
43         || IsEqualGUID(riid, &IID_IDirect3DSurface9)) {
44         IDirect3DSurface9_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 IDirect3DSurface9Impl_AddRef(IDirect3DSurface9 *iface)
55 {
56     IDirect3DSurface9Impl *This = impl_from_IDirect3DSurface9(iface);
57
58     TRACE("iface %p.\n", iface);
59
60     if (This->forwardReference) {
61         /* Forward refcounting */
62         TRACE("(%p) : Forwarding to %p\n", This, This->forwardReference);
63         return IUnknown_AddRef(This->forwardReference);
64     } else {
65         /* No container, handle our own refcounting */
66         ULONG ref = InterlockedIncrement(&This->ref);
67
68         TRACE("%p increasing refcount to %u.\n", iface, ref);
69
70         if (ref == 1)
71         {
72             if (This->parentDevice) IDirect3DDevice9Ex_AddRef(This->parentDevice);
73             wined3d_mutex_lock();
74             wined3d_surface_incref(This->wined3d_surface);
75             wined3d_mutex_unlock();
76         }
77
78         return ref;
79     }
80
81 }
82
83 static ULONG WINAPI IDirect3DSurface9Impl_Release(IDirect3DSurface9 *iface)
84 {
85     IDirect3DSurface9Impl *This = impl_from_IDirect3DSurface9(iface);
86
87     TRACE("iface %p.\n", iface);
88
89     if (This->forwardReference) {
90         /* Forward to the containerParent */
91         TRACE("(%p) : Forwarding to %p\n", This, This->forwardReference);
92         return IUnknown_Release(This->forwardReference);
93     } else {
94         /* No container, handle our own refcounting */
95         ULONG ref = InterlockedDecrement(&This->ref);
96
97         TRACE("%p decreasing refcount to %u.\n", iface, ref);
98
99         if (ref == 0) {
100             IDirect3DDevice9Ex *parentDevice = This->parentDevice;
101
102             wined3d_mutex_lock();
103             wined3d_surface_decref(This->wined3d_surface);
104             wined3d_mutex_unlock();
105
106             /* Release the device last, as it may cause the device to be destroyed. */
107             if (parentDevice) IDirect3DDevice9Ex_Release(parentDevice);
108         }
109
110         return ref;
111     }
112 }
113
114 /* IDirect3DSurface9 IDirect3DResource9 Interface follow: */
115 static HRESULT WINAPI IDirect3DSurface9Impl_GetDevice(IDirect3DSurface9 *iface,
116         IDirect3DDevice9 **device)
117 {
118     IDirect3DSurface9Impl *This = impl_from_IDirect3DSurface9(iface);
119
120     TRACE("iface %p, device %p.\n", iface, device);
121
122     if (This->forwardReference)
123     {
124         IDirect3DResource9 *resource;
125         HRESULT hr;
126
127         hr = IUnknown_QueryInterface(This->forwardReference, &IID_IDirect3DResource9, (void **)&resource);
128         if (SUCCEEDED(hr))
129         {
130             hr = IDirect3DResource9_GetDevice(resource, device);
131             IDirect3DResource9_Release(resource);
132
133             TRACE("Returning device %p.\n", *device);
134         }
135
136         return hr;
137     }
138
139     *device = (IDirect3DDevice9 *)This->parentDevice;
140     IDirect3DDevice9_AddRef(*device);
141
142     TRACE("Returning device %p.\n", *device);
143
144     return D3D_OK;
145 }
146
147 static HRESULT WINAPI IDirect3DSurface9Impl_SetPrivateData(IDirect3DSurface9 *iface, REFGUID guid,
148         const void *data, DWORD data_size, DWORD flags)
149 {
150     IDirect3DSurface9Impl *surface = impl_from_IDirect3DSurface9(iface);
151     struct wined3d_resource *resource;
152     HRESULT hr;
153
154     TRACE("iface %p, guid %s, data %p, data_size %u, flags %#x.\n",
155             iface, debugstr_guid(guid), data, data_size, flags);
156
157     wined3d_mutex_lock();
158     resource = wined3d_surface_get_resource(surface->wined3d_surface);
159     hr = wined3d_resource_set_private_data(resource, guid, data, data_size, flags);
160     wined3d_mutex_unlock();
161
162     return hr;
163 }
164
165 static HRESULT WINAPI IDirect3DSurface9Impl_GetPrivateData(IDirect3DSurface9 *iface, REFGUID guid,
166         void *data, DWORD *data_size)
167 {
168     IDirect3DSurface9Impl *surface = impl_from_IDirect3DSurface9(iface);
169     struct wined3d_resource *resource;
170     HRESULT hr;
171
172     TRACE("iface %p, guid %s, data %p, data_size %p.\n",
173             iface, debugstr_guid(guid), data, data_size);
174
175     wined3d_mutex_lock();
176     resource = wined3d_surface_get_resource(surface->wined3d_surface);
177     hr = wined3d_resource_get_private_data(resource, guid, data, data_size);
178     wined3d_mutex_unlock();
179
180     return hr;
181 }
182
183 static HRESULT WINAPI IDirect3DSurface9Impl_FreePrivateData(IDirect3DSurface9 *iface, REFGUID guid)
184 {
185     IDirect3DSurface9Impl *surface = impl_from_IDirect3DSurface9(iface);
186     struct wined3d_resource *resource;
187     HRESULT hr;
188
189     TRACE("iface %p, guid %s.\n", iface, debugstr_guid(guid));
190
191     wined3d_mutex_lock();
192     resource = wined3d_surface_get_resource(surface->wined3d_surface);
193     hr = wined3d_resource_free_private_data(resource, guid);
194     wined3d_mutex_unlock();
195
196     return hr;
197 }
198
199 static DWORD WINAPI IDirect3DSurface9Impl_SetPriority(IDirect3DSurface9 *iface, DWORD PriorityNew)
200 {
201     IDirect3DSurface9Impl *This = impl_from_IDirect3DSurface9(iface);
202     HRESULT hr;
203
204     TRACE("iface %p, priority %u.\n", iface, PriorityNew);
205
206     wined3d_mutex_lock();
207     hr = wined3d_surface_set_priority(This->wined3d_surface, PriorityNew);
208     wined3d_mutex_unlock();
209
210     return hr;
211 }
212
213 static DWORD WINAPI IDirect3DSurface9Impl_GetPriority(IDirect3DSurface9 *iface)
214 {
215     IDirect3DSurface9Impl *This = impl_from_IDirect3DSurface9(iface);
216     HRESULT hr;
217
218     TRACE("iface %p.\n", iface);
219
220     wined3d_mutex_lock();
221     hr = wined3d_surface_get_priority(This->wined3d_surface);
222     wined3d_mutex_unlock();
223
224     return hr;
225 }
226
227 static void WINAPI IDirect3DSurface9Impl_PreLoad(IDirect3DSurface9 *iface)
228 {
229     IDirect3DSurface9Impl *This = impl_from_IDirect3DSurface9(iface);
230
231     TRACE("iface %p.\n", iface);
232
233     wined3d_mutex_lock();
234     wined3d_surface_preload(This->wined3d_surface);
235     wined3d_mutex_unlock();
236 }
237
238 static D3DRESOURCETYPE WINAPI IDirect3DSurface9Impl_GetType(IDirect3DSurface9 *iface)
239 {
240     TRACE("iface %p.\n", iface);
241
242     return D3DRTYPE_SURFACE;
243 }
244
245 /* IDirect3DSurface9 Interface follow: */
246 static HRESULT WINAPI IDirect3DSurface9Impl_GetContainer(IDirect3DSurface9 *iface, REFIID riid,
247         void **ppContainer)
248 {
249     IDirect3DSurface9Impl *This = impl_from_IDirect3DSurface9(iface);
250     HRESULT res;
251
252     TRACE("iface %p, riid %s, container %p.\n", iface, debugstr_guid(riid), ppContainer);
253
254     if (!This->container) return E_NOINTERFACE;
255
256     res = IUnknown_QueryInterface(This->container, riid, ppContainer);
257
258     TRACE("Returning ppContainer %p, *ppContainer %p\n", ppContainer, *ppContainer);
259
260     return res;
261 }
262
263 static HRESULT WINAPI IDirect3DSurface9Impl_GetDesc(IDirect3DSurface9 *iface, D3DSURFACE_DESC *desc)
264 {
265     IDirect3DSurface9Impl *This = impl_from_IDirect3DSurface9(iface);
266     struct wined3d_resource_desc wined3d_desc;
267     struct wined3d_resource *wined3d_resource;
268
269     TRACE("iface %p, desc %p.\n", iface, desc);
270
271     wined3d_mutex_lock();
272     wined3d_resource = wined3d_surface_get_resource(This->wined3d_surface);
273     wined3d_resource_get_desc(wined3d_resource, &wined3d_desc);
274     wined3d_mutex_unlock();
275
276     desc->Format = d3dformat_from_wined3dformat(wined3d_desc.format);
277     desc->Type = wined3d_desc.resource_type;
278     desc->Usage = wined3d_desc.usage;
279     desc->Pool = wined3d_desc.pool;
280     desc->MultiSampleType = wined3d_desc.multisample_type;
281     desc->MultiSampleQuality = wined3d_desc.multisample_quality;
282     desc->Width = wined3d_desc.width;
283     desc->Height = wined3d_desc.height;
284
285     return D3D_OK;
286 }
287
288 static HRESULT WINAPI IDirect3DSurface9Impl_LockRect(IDirect3DSurface9 *iface,
289         D3DLOCKED_RECT *pLockedRect, const RECT *pRect, DWORD Flags)
290 {
291     IDirect3DSurface9Impl *This = impl_from_IDirect3DSurface9(iface);
292     HRESULT hr;
293
294     TRACE("iface %p, locked_rect %p, rect %p, flags %#x.\n", iface, pLockedRect, pRect, Flags);
295
296     wined3d_mutex_lock();
297     hr = wined3d_surface_map(This->wined3d_surface, (WINED3DLOCKED_RECT *)pLockedRect, pRect, Flags);
298     wined3d_mutex_unlock();
299
300     return hr;
301 }
302
303 static HRESULT WINAPI IDirect3DSurface9Impl_UnlockRect(IDirect3DSurface9 *iface)
304 {
305     IDirect3DSurface9Impl *This = impl_from_IDirect3DSurface9(iface);
306     HRESULT hr;
307
308     TRACE("iface %p.\n", iface);
309
310     wined3d_mutex_lock();
311     hr = wined3d_surface_unmap(This->wined3d_surface);
312     wined3d_mutex_unlock();
313
314     switch(hr)
315     {
316         case WINEDDERR_NOTLOCKED:       return D3DERR_INVALIDCALL;
317         default:                        return hr;
318     }
319 }
320
321 static HRESULT WINAPI IDirect3DSurface9Impl_GetDC(IDirect3DSurface9 *iface, HDC* phdc)
322 {
323     IDirect3DSurface9Impl *This = impl_from_IDirect3DSurface9(iface);
324     HRESULT hr;
325
326     TRACE("iface %p, hdc %p.\n", iface, phdc);
327
328     if(!This->getdc_supported)
329     {
330         WARN("Surface does not support GetDC, returning D3DERR_INVALIDCALL\n");
331         /* Don't touch the DC */
332         return D3DERR_INVALIDCALL;
333     }
334
335     wined3d_mutex_lock();
336     hr = wined3d_surface_getdc(This->wined3d_surface, phdc);
337     wined3d_mutex_unlock();
338
339     return hr;
340 }
341
342 static HRESULT WINAPI IDirect3DSurface9Impl_ReleaseDC(IDirect3DSurface9 *iface, HDC hdc)
343 {
344     IDirect3DSurface9Impl *This = impl_from_IDirect3DSurface9(iface);
345     HRESULT hr;
346
347     TRACE("iface %p, hdc %p.\n", iface, hdc);
348
349     wined3d_mutex_lock();
350     hr = wined3d_surface_releasedc(This->wined3d_surface, hdc);
351     wined3d_mutex_unlock();
352
353     switch (hr)
354     {
355         case WINEDDERR_NODC:    return D3DERR_INVALIDCALL;
356         default:                return hr;
357     }
358 }
359
360 static const IDirect3DSurface9Vtbl Direct3DSurface9_Vtbl =
361 {
362     /* IUnknown */
363     IDirect3DSurface9Impl_QueryInterface,
364     IDirect3DSurface9Impl_AddRef,
365     IDirect3DSurface9Impl_Release,
366     /* IDirect3DResource9 */
367     IDirect3DSurface9Impl_GetDevice,
368     IDirect3DSurface9Impl_SetPrivateData,
369     IDirect3DSurface9Impl_GetPrivateData,
370     IDirect3DSurface9Impl_FreePrivateData,
371     IDirect3DSurface9Impl_SetPriority,
372     IDirect3DSurface9Impl_GetPriority,
373     IDirect3DSurface9Impl_PreLoad,
374     IDirect3DSurface9Impl_GetType,
375     /* IDirect3DSurface9 */
376     IDirect3DSurface9Impl_GetContainer,
377     IDirect3DSurface9Impl_GetDesc,
378     IDirect3DSurface9Impl_LockRect,
379     IDirect3DSurface9Impl_UnlockRect,
380     IDirect3DSurface9Impl_GetDC,
381     IDirect3DSurface9Impl_ReleaseDC
382 };
383
384 static void STDMETHODCALLTYPE surface_wined3d_object_destroyed(void *parent)
385 {
386     HeapFree(GetProcessHeap(), 0, parent);
387 }
388
389 static const struct wined3d_parent_ops d3d9_surface_wined3d_parent_ops =
390 {
391     surface_wined3d_object_destroyed,
392 };
393
394 HRESULT surface_init(IDirect3DSurface9Impl *surface, IDirect3DDevice9Impl *device,
395         UINT width, UINT height, D3DFORMAT format, BOOL lockable, BOOL discard, UINT level,
396         DWORD usage, D3DPOOL pool, D3DMULTISAMPLE_TYPE multisample_type, DWORD multisample_quality)
397 {
398     DWORD flags = 0;
399     HRESULT hr;
400
401     surface->IDirect3DSurface9_iface.lpVtbl = &Direct3DSurface9_Vtbl;
402     surface->ref = 1;
403
404     switch (format)
405     {
406         case D3DFMT_A8R8G8B8:
407         case D3DFMT_X8R8G8B8:
408         case D3DFMT_R5G6B5:
409         case D3DFMT_X1R5G5B5:
410         case D3DFMT_A1R5G5B5:
411         case D3DFMT_R8G8B8:
412             surface->getdc_supported = TRUE;
413             break;
414
415         default:
416             surface->getdc_supported = FALSE;
417             break;
418     }
419
420     /* FIXME: Check MAX bounds of MultisampleQuality. */
421     if (multisample_quality > 0)
422     {
423         FIXME("Multisample quality set to %u, substituting 0.\n", multisample_quality);
424         multisample_quality = 0;
425     }
426
427     if (lockable)
428         flags |= WINED3D_SURFACE_MAPPABLE;
429     if (discard)
430         flags |= WINED3D_SURFACE_DISCARD;
431
432     wined3d_mutex_lock();
433     hr = wined3d_surface_create(device->wined3d_device, width, height, wined3dformat_from_d3dformat(format),
434             level, usage & WINED3DUSAGE_MASK, (WINED3DPOOL)pool, multisample_type, multisample_quality,
435             SURFACE_OPENGL, flags, surface, &d3d9_surface_wined3d_parent_ops, &surface->wined3d_surface);
436     wined3d_mutex_unlock();
437     if (FAILED(hr))
438     {
439         WARN("Failed to create wined3d surface, hr %#x.\n", hr);
440         return hr;
441     }
442
443     surface->parentDevice = &device->IDirect3DDevice9Ex_iface;
444     IDirect3DDevice9Ex_AddRef(surface->parentDevice);
445
446     return D3D_OK;
447 }
448
449 IDirect3DSurface9Impl *unsafe_impl_from_IDirect3DSurface9(IDirect3DSurface9 *iface)
450 {
451     if (!iface)
452         return NULL;
453     assert(iface->lpVtbl == &Direct3DSurface9_Vtbl);
454
455     return impl_from_IDirect3DSurface9(iface);
456 }