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