strmbase: do not lock in BaseOutputPinImpl_GetDeliveryBuffer the MemInputPin will...
[wine] / dlls / d3d9 / swapchain.c
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 inline IDirect3DSwapChain9Impl *impl_from_IDirect3DSwapChain9(IDirect3DSwapChain9 *iface)
29 {
30     return CONTAINING_RECORD(iface, IDirect3DSwapChain9Impl, IDirect3DSwapChain9_iface);
31 }
32
33 static HRESULT WINAPI IDirect3DSwapChain9Impl_QueryInterface(IDirect3DSwapChain9 *iface, REFIID riid, void **out)
34 {
35     TRACE("iface %p, riid %s, out %p.\n", iface, debugstr_guid(riid), out);
36
37     if (IsEqualGUID(riid, &IID_IDirect3DSwapChain9)
38             || IsEqualGUID(riid, &IID_IUnknown))
39     {
40         IDirect3DSwapChain9_AddRef(iface);
41         *out = iface;
42         return S_OK;
43     }
44
45     WARN("%s not implemented, returning E_NOINTERFACE.\n", debugstr_guid(riid));
46
47     *out = NULL;
48     return E_NOINTERFACE;
49 }
50
51 static ULONG WINAPI IDirect3DSwapChain9Impl_AddRef(IDirect3DSwapChain9 *iface)
52 {
53     IDirect3DSwapChain9Impl *swapchain = impl_from_IDirect3DSwapChain9(iface);
54     ULONG ref = InterlockedIncrement(&swapchain->ref);
55
56     TRACE("%p increasing refcount to %u.\n", iface, ref);
57
58     if (ref == 1)
59     {
60         if (swapchain->parentDevice)
61             IDirect3DDevice9Ex_AddRef(swapchain->parentDevice);
62
63         wined3d_mutex_lock();
64         wined3d_swapchain_incref(swapchain->wined3d_swapchain);
65         wined3d_mutex_unlock();
66     }
67
68     return ref;
69 }
70
71 static ULONG WINAPI IDirect3DSwapChain9Impl_Release(IDirect3DSwapChain9 *iface)
72 {
73     IDirect3DSwapChain9Impl *swapchain = impl_from_IDirect3DSwapChain9(iface);
74     ULONG ref = InterlockedDecrement(&swapchain->ref);
75
76     TRACE("%p decreasing refcount to %u.\n", iface, ref);
77
78     if (ref == 0) {
79         IDirect3DDevice9Ex *parentDevice = swapchain->parentDevice;
80
81         wined3d_mutex_lock();
82         wined3d_swapchain_decref(swapchain->wined3d_swapchain);
83         wined3d_mutex_unlock();
84
85         /* Release the device last, as it may cause the device to be destroyed. */
86         if (parentDevice) IDirect3DDevice9Ex_Release(parentDevice);
87     }
88     return ref;
89 }
90
91 /* IDirect3DSwapChain9 parts follow: */
92 static HRESULT WINAPI DECLSPEC_HOTPATCH IDirect3DSwapChain9Impl_Present(IDirect3DSwapChain9 *iface,
93         const RECT *src_rect, const RECT *dst_rect, HWND dst_window_override,
94         const RGNDATA *dirty_region, DWORD flags)
95 {
96     IDirect3DSwapChain9Impl *swapchain = impl_from_IDirect3DSwapChain9(iface);
97     HRESULT hr;
98
99     TRACE("iface %p, src_rect %s, dst_rect %s, dst_window_override %p, dirty_region %p, flags %#x.\n",
100             iface, wine_dbgstr_rect(src_rect), wine_dbgstr_rect(dst_rect),
101             dst_window_override, dirty_region, flags);
102
103     wined3d_mutex_lock();
104     hr = wined3d_swapchain_present(swapchain->wined3d_swapchain, src_rect,
105             dst_rect, dst_window_override, dirty_region, flags);
106     wined3d_mutex_unlock();
107
108     return hr;
109 }
110
111 static HRESULT WINAPI IDirect3DSwapChain9Impl_GetFrontBufferData(IDirect3DSwapChain9 *iface,
112         IDirect3DSurface9 *pDestSurface)
113 {
114     IDirect3DSwapChain9Impl *swapchain = impl_from_IDirect3DSwapChain9(iface);
115     IDirect3DSurface9Impl *dst = unsafe_impl_from_IDirect3DSurface9(pDestSurface);
116     HRESULT hr;
117
118     TRACE("iface %p, surface %p.\n", iface, pDestSurface);
119
120     wined3d_mutex_lock();
121     hr = wined3d_swapchain_get_front_buffer_data(swapchain->wined3d_swapchain, dst->wined3d_surface);
122     wined3d_mutex_unlock();
123
124     return hr;
125 }
126
127 static HRESULT WINAPI IDirect3DSwapChain9Impl_GetBackBuffer(IDirect3DSwapChain9 *iface,
128         UINT iBackBuffer, D3DBACKBUFFER_TYPE Type, IDirect3DSurface9 **ppBackBuffer)
129 {
130     IDirect3DSwapChain9Impl *swapchain = impl_from_IDirect3DSwapChain9(iface);
131     struct wined3d_surface *wined3d_surface = NULL;
132     IDirect3DSurface9Impl *surface_impl;
133     HRESULT hr;
134
135     TRACE("iface %p, backbuffer_idx %u, backbuffer_type %#x, backbuffer %p.\n",
136             iface, iBackBuffer, Type, ppBackBuffer);
137
138     wined3d_mutex_lock();
139     hr = wined3d_swapchain_get_back_buffer(swapchain->wined3d_swapchain,
140             iBackBuffer, (enum wined3d_backbuffer_type)Type, &wined3d_surface);
141     if (SUCCEEDED(hr) && wined3d_surface)
142     {
143        surface_impl = wined3d_surface_get_parent(wined3d_surface);
144        *ppBackBuffer = &surface_impl->IDirect3DSurface9_iface;
145        IDirect3DSurface9_AddRef(*ppBackBuffer);
146        wined3d_surface_decref(wined3d_surface);
147     }
148     wined3d_mutex_unlock();
149
150     /* Do not touch the **ppBackBuffer pointer otherwise! (see device test) */
151     return hr;
152 }
153
154 static HRESULT WINAPI IDirect3DSwapChain9Impl_GetRasterStatus(IDirect3DSwapChain9 *iface,
155         D3DRASTER_STATUS *raster_status)
156 {
157     IDirect3DSwapChain9Impl *swapchain = impl_from_IDirect3DSwapChain9(iface);
158     HRESULT hr;
159
160     TRACE("iface %p, raster_status %p.\n", iface, raster_status);
161
162     wined3d_mutex_lock();
163     hr = wined3d_swapchain_get_raster_status(swapchain->wined3d_swapchain,
164             (struct wined3d_raster_status *)raster_status);
165     wined3d_mutex_unlock();
166
167     return hr;
168 }
169
170 static HRESULT WINAPI IDirect3DSwapChain9Impl_GetDisplayMode(IDirect3DSwapChain9 *iface, D3DDISPLAYMODE *mode)
171 {
172     IDirect3DSwapChain9Impl *swapchain = impl_from_IDirect3DSwapChain9(iface);
173     HRESULT hr;
174
175     TRACE("iface %p, mode %p.\n", iface, mode);
176
177     wined3d_mutex_lock();
178     hr = wined3d_swapchain_get_display_mode(swapchain->wined3d_swapchain, (struct wined3d_display_mode *)mode);
179     wined3d_mutex_unlock();
180
181     if (SUCCEEDED(hr))
182         mode->Format = d3dformat_from_wined3dformat(mode->Format);
183
184     return hr;
185 }
186
187 static HRESULT WINAPI IDirect3DSwapChain9Impl_GetDevice(IDirect3DSwapChain9 *iface, IDirect3DDevice9 **device)
188 {
189     IDirect3DSwapChain9Impl *swapchain = impl_from_IDirect3DSwapChain9(iface);
190
191     TRACE("iface %p, device %p.\n", iface, device);
192
193     *device = (IDirect3DDevice9 *)swapchain->parentDevice;
194     IDirect3DDevice9_AddRef(*device);
195
196     TRACE("Returning device %p.\n", *device);
197
198     return D3D_OK;
199 }
200
201 static HRESULT WINAPI IDirect3DSwapChain9Impl_GetPresentParameters(IDirect3DSwapChain9 *iface,
202         D3DPRESENT_PARAMETERS *pPresentationParameters)
203 {
204     IDirect3DSwapChain9Impl *swapchain = impl_from_IDirect3DSwapChain9(iface);
205     struct wined3d_swapchain_desc desc;
206     HRESULT hr;
207
208     TRACE("iface %p, parameters %p.\n", iface, pPresentationParameters);
209
210     wined3d_mutex_lock();
211     hr = wined3d_swapchain_get_desc(swapchain->wined3d_swapchain, &desc);
212     wined3d_mutex_unlock();
213
214     pPresentationParameters->BackBufferWidth = desc.backbuffer_width;
215     pPresentationParameters->BackBufferHeight = desc.backbuffer_height;
216     pPresentationParameters->BackBufferFormat = d3dformat_from_wined3dformat(desc.backbuffer_format);
217     pPresentationParameters->BackBufferCount = desc.backbuffer_count;
218     pPresentationParameters->MultiSampleType = desc.multisample_type;
219     pPresentationParameters->MultiSampleQuality = desc.multisample_quality;
220     pPresentationParameters->SwapEffect = desc.swap_effect;
221     pPresentationParameters->hDeviceWindow = desc.device_window;
222     pPresentationParameters->Windowed = desc.windowed;
223     pPresentationParameters->EnableAutoDepthStencil = desc.enable_auto_depth_stencil;
224     pPresentationParameters->AutoDepthStencilFormat = d3dformat_from_wined3dformat(desc.auto_depth_stencil_format);
225     pPresentationParameters->Flags = desc.flags;
226     pPresentationParameters->FullScreen_RefreshRateInHz = desc.refresh_rate;
227     pPresentationParameters->PresentationInterval = desc.swap_interval;
228
229     return hr;
230 }
231
232
233 static const IDirect3DSwapChain9Vtbl Direct3DSwapChain9_Vtbl =
234 {
235     IDirect3DSwapChain9Impl_QueryInterface,
236     IDirect3DSwapChain9Impl_AddRef,
237     IDirect3DSwapChain9Impl_Release,
238     IDirect3DSwapChain9Impl_Present,
239     IDirect3DSwapChain9Impl_GetFrontBufferData,
240     IDirect3DSwapChain9Impl_GetBackBuffer,
241     IDirect3DSwapChain9Impl_GetRasterStatus,
242     IDirect3DSwapChain9Impl_GetDisplayMode,
243     IDirect3DSwapChain9Impl_GetDevice,
244     IDirect3DSwapChain9Impl_GetPresentParameters
245 };
246
247 static void STDMETHODCALLTYPE d3d9_swapchain_wined3d_object_released(void *parent)
248 {
249     HeapFree(GetProcessHeap(), 0, parent);
250 }
251
252 static const struct wined3d_parent_ops d3d9_swapchain_wined3d_parent_ops =
253 {
254     d3d9_swapchain_wined3d_object_released,
255 };
256
257 static HRESULT swapchain_init(IDirect3DSwapChain9Impl *swapchain, IDirect3DDevice9Impl *device,
258         D3DPRESENT_PARAMETERS *present_parameters)
259 {
260     struct wined3d_swapchain_desc desc;
261     HRESULT hr;
262
263     swapchain->ref = 1;
264     swapchain->IDirect3DSwapChain9_iface.lpVtbl = &Direct3DSwapChain9_Vtbl;
265
266     desc.backbuffer_width = present_parameters->BackBufferWidth;
267     desc.backbuffer_height = present_parameters->BackBufferHeight;
268     desc.backbuffer_format = wined3dformat_from_d3dformat(present_parameters->BackBufferFormat);
269     desc.backbuffer_count = max(1, present_parameters->BackBufferCount);
270     desc.multisample_type = present_parameters->MultiSampleType;
271     desc.multisample_quality = present_parameters->MultiSampleQuality;
272     desc.swap_effect = present_parameters->SwapEffect;
273     desc.device_window = present_parameters->hDeviceWindow;
274     desc.windowed = present_parameters->Windowed;
275     desc.enable_auto_depth_stencil = present_parameters->EnableAutoDepthStencil;
276     desc.auto_depth_stencil_format = wined3dformat_from_d3dformat(present_parameters->AutoDepthStencilFormat);
277     desc.flags = present_parameters->Flags;
278     desc.refresh_rate = present_parameters->FullScreen_RefreshRateInHz;
279     desc.swap_interval = present_parameters->PresentationInterval;
280     desc.auto_restore_display_mode = TRUE;
281
282     wined3d_mutex_lock();
283     hr = wined3d_swapchain_create(device->wined3d_device, &desc,
284             WINED3D_SURFACE_TYPE_OPENGL, swapchain, &d3d9_swapchain_wined3d_parent_ops,
285             &swapchain->wined3d_swapchain);
286     wined3d_mutex_unlock();
287
288     present_parameters->BackBufferWidth = desc.backbuffer_width;
289     present_parameters->BackBufferHeight = desc.backbuffer_height;
290     present_parameters->BackBufferFormat = d3dformat_from_wined3dformat(desc.backbuffer_format);
291     present_parameters->BackBufferCount = desc.backbuffer_count;
292     present_parameters->MultiSampleType = desc.multisample_type;
293     present_parameters->MultiSampleQuality = desc.multisample_quality;
294     present_parameters->SwapEffect = desc.swap_effect;
295     present_parameters->hDeviceWindow = desc.device_window;
296     present_parameters->Windowed = desc.windowed;
297     present_parameters->EnableAutoDepthStencil = desc.enable_auto_depth_stencil;
298     present_parameters->AutoDepthStencilFormat = d3dformat_from_wined3dformat(desc.auto_depth_stencil_format);
299     present_parameters->Flags = desc.flags;
300     present_parameters->FullScreen_RefreshRateInHz = desc.refresh_rate;
301     present_parameters->PresentationInterval = desc.swap_interval;
302
303     if (FAILED(hr))
304     {
305         WARN("Failed to create wined3d swapchain, hr %#x.\n", hr);
306         return hr;
307     }
308
309     swapchain->parentDevice = &device->IDirect3DDevice9Ex_iface;
310     IDirect3DDevice9Ex_AddRef(swapchain->parentDevice);
311
312     return D3D_OK;
313 }
314
315 HRESULT d3d9_swapchain_create(IDirect3DDevice9Impl *device, D3DPRESENT_PARAMETERS *present_parameters,
316         IDirect3DSwapChain9Impl **swapchain)
317 {
318     IDirect3DSwapChain9Impl *object;
319     HRESULT hr;
320
321     if (!(object = HeapAlloc(GetProcessHeap(),  HEAP_ZERO_MEMORY, sizeof(*object))))
322     {
323         ERR("Failed to allocate swapchain memory.\n");
324         return E_OUTOFMEMORY;
325     }
326
327     if (FAILED(hr = swapchain_init(object, device, present_parameters)))
328     {
329         WARN("Failed to initialize swapchain, hr %#x.\n", hr);
330         HeapFree(GetProcessHeap(), 0, object);
331         return hr;
332     }
333
334     TRACE("Created swapchain %p.\n", object);
335     *swapchain = object;
336
337     return D3D_OK;
338 }