xref: /reactos/dll/directx/wine/d3d9/swapchain.c (revision 50cf16b3)
1 /*
2  * IDirect3DSwapChain9 implementation
3  *
4  * Copyright 2002-2003 Jason Edmeades
5  *                     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 DWORD d3dpresentationinterval_from_wined3dswapinterval(enum wined3d_swap_interval interval)
29 {
30     switch (interval)
31     {
32         case WINED3D_SWAP_INTERVAL_IMMEDIATE:
33             return D3DPRESENT_INTERVAL_IMMEDIATE;
34         case WINED3D_SWAP_INTERVAL_ONE:
35             return D3DPRESENT_INTERVAL_ONE;
36         case WINED3D_SWAP_INTERVAL_TWO:
37             return D3DPRESENT_INTERVAL_TWO;
38         case WINED3D_SWAP_INTERVAL_THREE:
39             return D3DPRESENT_INTERVAL_THREE;
40         case WINED3D_SWAP_INTERVAL_FOUR:
41             return D3DPRESENT_INTERVAL_FOUR;
42         default:
43             ERR("Invalid swap interval %#x.\n", interval);
44         case WINED3D_SWAP_INTERVAL_DEFAULT:
45             return D3DPRESENT_INTERVAL_DEFAULT;
46     }
47 }
48 
49 static inline struct d3d9_swapchain *impl_from_IDirect3DSwapChain9Ex(IDirect3DSwapChain9Ex *iface)
50 {
51     return CONTAINING_RECORD(iface, struct d3d9_swapchain, IDirect3DSwapChain9Ex_iface);
52 }
53 
54 static HRESULT WINAPI d3d9_swapchain_QueryInterface(IDirect3DSwapChain9Ex *iface, REFIID riid, void **out)
55 {
56     TRACE("iface %p, riid %s, out %p.\n", iface, debugstr_guid(riid), out);
57 
58     if (IsEqualGUID(riid, &IID_IDirect3DSwapChain9)
59             || IsEqualGUID(riid, &IID_IUnknown))
60     {
61         IDirect3DSwapChain9Ex_AddRef(iface);
62         *out = iface;
63         return S_OK;
64     }
65 
66     if (IsEqualGUID(riid, &IID_IDirect3DSwapChain9Ex))
67     {
68         struct d3d9_swapchain *swapchain = impl_from_IDirect3DSwapChain9Ex(iface);
69         struct d3d9_device *device       = impl_from_IDirect3DDevice9Ex(swapchain->parent_device);
70 
71         /* Find out if the creating d3d9 interface was created with Direct3DCreate9Ex.
72          * It doesn't matter with which function the device was created. */
73         if (!device->d3d_parent->extended)
74         {
75             WARN("IDirect3D9 instance wasn't created with CreateDirect3D9Ex, returning E_NOINTERFACE.\n");
76             *out = NULL;
77             return E_NOINTERFACE;
78         }
79 
80         IDirect3DSwapChain9Ex_AddRef(iface);
81         *out = iface;
82         return S_OK;
83     }
84 
85     WARN("%s not implemented, returning E_NOINTERFACE.\n", debugstr_guid(riid));
86 
87     *out = NULL;
88     return E_NOINTERFACE;
89 }
90 
91 static ULONG WINAPI d3d9_swapchain_AddRef(IDirect3DSwapChain9Ex *iface)
92 {
93     struct d3d9_swapchain *swapchain = impl_from_IDirect3DSwapChain9Ex(iface);
94     ULONG refcount = InterlockedIncrement(&swapchain->refcount);
95 
96     TRACE("%p increasing refcount to %u.\n", iface, refcount);
97 
98     if (refcount == 1)
99     {
100         if (swapchain->parent_device)
101             IDirect3DDevice9Ex_AddRef(swapchain->parent_device);
102 
103         wined3d_mutex_lock();
104         wined3d_swapchain_incref(swapchain->wined3d_swapchain);
105         wined3d_mutex_unlock();
106     }
107 
108     return refcount;
109 }
110 
111 static ULONG WINAPI d3d9_swapchain_Release(IDirect3DSwapChain9Ex *iface)
112 {
113     struct d3d9_swapchain *swapchain = impl_from_IDirect3DSwapChain9Ex(iface);
114     ULONG refcount;
115 
116     if (!swapchain->refcount)
117     {
118         WARN("Swapchain does not have any references.\n");
119         return 0;
120     }
121 
122     refcount = InterlockedDecrement(&swapchain->refcount);
123     TRACE("%p decreasing refcount to %u.\n", iface, refcount);
124 
125     if (!refcount)
126     {
127         IDirect3DDevice9Ex *parent_device = swapchain->parent_device;
128 
129         wined3d_mutex_lock();
130         wined3d_swapchain_decref(swapchain->wined3d_swapchain);
131         wined3d_mutex_unlock();
132 
133         /* Release the device last, as it may cause the device to be destroyed. */
134         if (parent_device)
135             IDirect3DDevice9Ex_Release(parent_device);
136     }
137 
138     return refcount;
139 }
140 
141 static HRESULT WINAPI DECLSPEC_HOTPATCH d3d9_swapchain_Present(IDirect3DSwapChain9Ex *iface,
142         const RECT *src_rect, const RECT *dst_rect, HWND dst_window_override,
143         const RGNDATA *dirty_region, DWORD flags)
144 {
145     struct d3d9_swapchain *swapchain = impl_from_IDirect3DSwapChain9Ex(iface);
146     struct d3d9_device *device = impl_from_IDirect3DDevice9Ex(swapchain->parent_device);
147     HRESULT hr;
148 
149     TRACE("iface %p, src_rect %s, dst_rect %s, dst_window_override %p, dirty_region %p, flags %#x.\n",
150             iface, wine_dbgstr_rect(src_rect), wine_dbgstr_rect(dst_rect),
151             dst_window_override, dirty_region, flags);
152 
153     if (device->device_state != D3D9_DEVICE_STATE_OK)
154         return device->d3d_parent->extended ? S_PRESENT_OCCLUDED : D3DERR_DEVICELOST;
155 
156     if (dirty_region)
157         FIXME("Ignoring dirty_region %p.\n", dirty_region);
158 
159     wined3d_mutex_lock();
160     hr = wined3d_swapchain_present(swapchain->wined3d_swapchain,
161             src_rect, dst_rect, dst_window_override, swapchain->swap_interval, flags);
162     wined3d_mutex_unlock();
163 
164     return hr;
165 }
166 
167 static HRESULT WINAPI d3d9_swapchain_GetFrontBufferData(IDirect3DSwapChain9Ex *iface, IDirect3DSurface9 *surface)
168 {
169     struct d3d9_swapchain *swapchain = impl_from_IDirect3DSwapChain9Ex(iface);
170     struct d3d9_surface *dst = unsafe_impl_from_IDirect3DSurface9(surface);
171     HRESULT hr;
172 
173     TRACE("iface %p, surface %p.\n", iface, surface);
174 
175     wined3d_mutex_lock();
176     hr = wined3d_swapchain_get_front_buffer_data(swapchain->wined3d_swapchain, dst->wined3d_texture, dst->sub_resource_idx);
177     wined3d_mutex_unlock();
178 
179     return hr;
180 }
181 
182 static HRESULT WINAPI d3d9_swapchain_GetBackBuffer(IDirect3DSwapChain9Ex *iface,
183         UINT backbuffer_idx, D3DBACKBUFFER_TYPE backbuffer_type, IDirect3DSurface9 **backbuffer)
184 {
185     struct d3d9_swapchain *swapchain = impl_from_IDirect3DSwapChain9Ex(iface);
186     struct wined3d_texture *wined3d_texture;
187     struct d3d9_surface *surface_impl;
188     HRESULT hr = D3D_OK;
189 
190     TRACE("iface %p, backbuffer_idx %u, backbuffer_type %#x, backbuffer %p.\n",
191             iface, backbuffer_idx, backbuffer_type, backbuffer);
192 
193     /* backbuffer_type is ignored by native. */
194 
195     if (!backbuffer)
196     {
197         WARN("The output pointer is NULL, returning D3DERR_INVALIDCALL.\n");
198         return D3DERR_INVALIDCALL;
199     }
200 
201     wined3d_mutex_lock();
202     if ((wined3d_texture = wined3d_swapchain_get_back_buffer(swapchain->wined3d_swapchain, backbuffer_idx)))
203     {
204         surface_impl = wined3d_texture_get_sub_resource_parent(wined3d_texture, 0);
205         *backbuffer = &surface_impl->IDirect3DSurface9_iface;
206         IDirect3DSurface9_AddRef(*backbuffer);
207     }
208     else
209     {
210         /* Do not set *backbuffer = NULL, see tests/device.c, test_swapchain(). */
211         hr = D3DERR_INVALIDCALL;
212     }
213     wined3d_mutex_unlock();
214 
215     return hr;
216 }
217 
218 static HRESULT WINAPI d3d9_swapchain_GetRasterStatus(IDirect3DSwapChain9Ex *iface, D3DRASTER_STATUS *raster_status)
219 {
220     struct d3d9_swapchain *swapchain = impl_from_IDirect3DSwapChain9Ex(iface);
221     HRESULT hr;
222 
223     TRACE("iface %p, raster_status %p.\n", iface, raster_status);
224 
225     wined3d_mutex_lock();
226     hr = wined3d_swapchain_get_raster_status(swapchain->wined3d_swapchain,
227             (struct wined3d_raster_status *)raster_status);
228     wined3d_mutex_unlock();
229 
230     return hr;
231 }
232 
233 static HRESULT WINAPI d3d9_swapchain_GetDisplayMode(IDirect3DSwapChain9Ex *iface, D3DDISPLAYMODE *mode)
234 {
235     struct d3d9_swapchain *swapchain = impl_from_IDirect3DSwapChain9Ex(iface);
236     struct wined3d_display_mode wined3d_mode;
237     HRESULT hr;
238 
239     TRACE("iface %p, mode %p.\n", iface, mode);
240 
241     wined3d_mutex_lock();
242     hr = wined3d_swapchain_get_display_mode(swapchain->wined3d_swapchain, &wined3d_mode, NULL);
243     wined3d_mutex_unlock();
244 
245     if (SUCCEEDED(hr))
246     {
247         mode->Width = wined3d_mode.width;
248         mode->Height = wined3d_mode.height;
249         mode->RefreshRate = wined3d_mode.refresh_rate;
250         mode->Format = d3dformat_from_wined3dformat(wined3d_mode.format_id);
251     }
252 
253     return hr;
254 }
255 
256 static HRESULT WINAPI d3d9_swapchain_GetDevice(IDirect3DSwapChain9Ex *iface, IDirect3DDevice9 **device)
257 {
258     struct d3d9_swapchain *swapchain = impl_from_IDirect3DSwapChain9Ex(iface);
259 
260     TRACE("iface %p, device %p.\n", iface, device);
261 
262     *device = (IDirect3DDevice9 *)swapchain->parent_device;
263     IDirect3DDevice9_AddRef(*device);
264 
265     TRACE("Returning device %p.\n", *device);
266 
267     return D3D_OK;
268 }
269 
270 static HRESULT WINAPI d3d9_swapchain_GetPresentParameters(IDirect3DSwapChain9Ex *iface,
271         D3DPRESENT_PARAMETERS *parameters)
272 {
273     struct d3d9_swapchain *swapchain = impl_from_IDirect3DSwapChain9Ex(iface);
274     struct wined3d_swapchain_desc desc;
275     DWORD presentation_interval;
276 
277     TRACE("iface %p, parameters %p.\n", iface, parameters);
278 
279     wined3d_mutex_lock();
280     wined3d_swapchain_get_desc(swapchain->wined3d_swapchain, &desc);
281     presentation_interval = d3dpresentationinterval_from_wined3dswapinterval(swapchain->swap_interval);
282     wined3d_mutex_unlock();
283     present_parameters_from_wined3d_swapchain_desc(parameters, &desc, presentation_interval);
284 
285     return D3D_OK;
286 }
287 
288 static HRESULT WINAPI d3d9_swapchain_GetLastPresentCount(IDirect3DSwapChain9Ex *iface,
289         UINT *last_present_count)
290 {
291     FIXME("iface %p, last_present_count %p, stub!\n", iface, last_present_count);
292 
293     if (last_present_count)
294         *last_present_count = 0;
295 
296     return D3D_OK;
297 }
298 
299 static HRESULT WINAPI d3d9_swapchain_GetPresentStatistics(IDirect3DSwapChain9Ex *iface,
300         D3DPRESENTSTATS *present_stats)
301 {
302     FIXME("iface %p, present_stats %p, stub!\n", iface, present_stats);
303 
304     if (present_stats)
305         memset(present_stats, 0, sizeof(*present_stats));
306 
307     return D3D_OK;
308 }
309 
310 static HRESULT WINAPI d3d9_swapchain_GetDisplayModeEx(IDirect3DSwapChain9Ex *iface,
311         D3DDISPLAYMODEEX *mode, D3DDISPLAYROTATION *rotation)
312 {
313     struct d3d9_swapchain *swapchain = impl_from_IDirect3DSwapChain9Ex(iface);
314     struct wined3d_display_mode wined3d_mode;
315     HRESULT hr;
316 
317     TRACE("iface %p, mode %p, rotation %p.\n", iface, mode, rotation);
318 
319     if (mode->Size != sizeof(*mode))
320         return D3DERR_INVALIDCALL;
321 
322     wined3d_mutex_lock();
323     hr = wined3d_swapchain_get_display_mode(swapchain->wined3d_swapchain, &wined3d_mode,
324             (enum wined3d_display_rotation *)rotation);
325     wined3d_mutex_unlock();
326 
327     if (SUCCEEDED(hr))
328     {
329         mode->Width = wined3d_mode.width;
330         mode->Height = wined3d_mode.height;
331         mode->RefreshRate = wined3d_mode.refresh_rate;
332         mode->Format = d3dformat_from_wined3dformat(wined3d_mode.format_id);
333         mode->ScanLineOrdering = wined3d_mode.scanline_ordering;
334     }
335 
336     return hr;
337 }
338 
339 static const struct IDirect3DSwapChain9ExVtbl d3d9_swapchain_vtbl =
340 {
341     /* IUnknown */
342     d3d9_swapchain_QueryInterface,
343     d3d9_swapchain_AddRef,
344     d3d9_swapchain_Release,
345     /* IDirect3DSwapChain9 */
346     d3d9_swapchain_Present,
347     d3d9_swapchain_GetFrontBufferData,
348     d3d9_swapchain_GetBackBuffer,
349     d3d9_swapchain_GetRasterStatus,
350     d3d9_swapchain_GetDisplayMode,
351     d3d9_swapchain_GetDevice,
352     d3d9_swapchain_GetPresentParameters,
353     /* IDirect3DSwapChain9Ex */
354     d3d9_swapchain_GetLastPresentCount,
355     d3d9_swapchain_GetPresentStatistics,
356     d3d9_swapchain_GetDisplayModeEx
357 };
358 
359 static void STDMETHODCALLTYPE d3d9_swapchain_wined3d_object_released(void *parent)
360 {
361     heap_free(parent);
362 }
363 
364 static const struct wined3d_parent_ops d3d9_swapchain_wined3d_parent_ops =
365 {
366     d3d9_swapchain_wined3d_object_released,
367 };
368 
369 static HRESULT swapchain_init(struct d3d9_swapchain *swapchain, struct d3d9_device *device,
370         struct wined3d_swapchain_desc *desc, unsigned int swap_interval)
371 {
372     HRESULT hr;
373 
374     swapchain->refcount = 1;
375     swapchain->IDirect3DSwapChain9Ex_iface.lpVtbl = &d3d9_swapchain_vtbl;
376     swapchain->swap_interval = swap_interval;
377 
378     wined3d_mutex_lock();
379     hr = wined3d_swapchain_create(device->wined3d_device, desc, swapchain,
380             &d3d9_swapchain_wined3d_parent_ops, &swapchain->wined3d_swapchain);
381     wined3d_mutex_unlock();
382 
383     if (FAILED(hr))
384     {
385         WARN("Failed to create wined3d swapchain, hr %#x.\n", hr);
386         return hr;
387     }
388 
389     swapchain->parent_device = &device->IDirect3DDevice9Ex_iface;
390     IDirect3DDevice9Ex_AddRef(swapchain->parent_device);
391 
392     return D3D_OK;
393 }
394 
395 HRESULT d3d9_swapchain_create(struct d3d9_device *device, struct wined3d_swapchain_desc *desc,
396         unsigned int swap_interval, struct d3d9_swapchain **swapchain)
397 {
398     struct d3d9_swapchain *object;
399     HRESULT hr;
400 
401     if (!(object = heap_alloc_zero(sizeof(*object))))
402         return E_OUTOFMEMORY;
403 
404     if (FAILED(hr = swapchain_init(object, device, desc, swap_interval)))
405     {
406         WARN("Failed to initialize swapchain, hr %#x.\n", hr);
407         heap_free(object);
408         return hr;
409     }
410 
411     TRACE("Created swapchain %p.\n", object);
412     *swapchain = object;
413 
414     return D3D_OK;
415 }
416