wined3d: Don't free D3D swapchains until the wined3d swapchain is destroyed.
[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 /* IDirect3DSwapChain IUnknown parts follow: */
29 static HRESULT WINAPI IDirect3DSwapChain9Impl_QueryInterface(LPDIRECT3DSWAPCHAIN9 iface, REFIID riid, LPVOID* ppobj)
30 {
31     IDirect3DSwapChain9Impl *This = (IDirect3DSwapChain9Impl *)iface;
32
33     TRACE("iface %p, riid %s, object %p.\n", iface, debugstr_guid(riid), ppobj);
34
35     if (IsEqualGUID(riid, &IID_IUnknown)
36         || IsEqualGUID(riid, &IID_IDirect3DSwapChain9)) {
37         IDirect3DSwapChain9_AddRef(iface);
38         *ppobj = This;
39         return S_OK;
40     }
41
42     WARN("(%p)->(%s,%p),not found\n", This, debugstr_guid(riid), ppobj);
43     *ppobj = NULL;
44     return E_NOINTERFACE;
45 }
46
47 static ULONG WINAPI IDirect3DSwapChain9Impl_AddRef(LPDIRECT3DSWAPCHAIN9 iface) {
48     IDirect3DSwapChain9Impl *This = (IDirect3DSwapChain9Impl *)iface;
49     ULONG ref = InterlockedIncrement(&This->ref);
50
51     TRACE("%p increasing refcount to %u.\n", iface, ref);
52
53     if (ref == 1)
54     {
55         if (This->parentDevice)
56             IDirect3DDevice9Ex_AddRef(This->parentDevice);
57
58         if (!This->isImplicit)
59         {
60             wined3d_mutex_lock();
61             IWineD3DSwapChain_AddRef(This->wineD3DSwapChain);
62             wined3d_mutex_unlock();
63         }
64     }
65
66     return ref;
67 }
68
69 static ULONG WINAPI IDirect3DSwapChain9Impl_Release(LPDIRECT3DSWAPCHAIN9 iface) {
70     IDirect3DSwapChain9Impl *This = (IDirect3DSwapChain9Impl *)iface;
71     ULONG ref = InterlockedDecrement(&This->ref);
72
73     TRACE("%p decreasing refcount to %u.\n", iface, ref);
74
75     if (ref == 0) {
76         IDirect3DDevice9Ex *parentDevice = This->parentDevice;
77
78         if (!This->isImplicit) {
79             wined3d_mutex_lock();
80             IWineD3DSwapChain_Destroy(This->wineD3DSwapChain);
81             wined3d_mutex_unlock();
82         }
83
84         /* Release the device last, as it may cause the device to be destroyed. */
85         if (parentDevice) IDirect3DDevice9Ex_Release(parentDevice);
86     }
87     return ref;
88 }
89
90 /* IDirect3DSwapChain9 parts follow: */
91 static HRESULT WINAPI DECLSPEC_HOTPATCH IDirect3DSwapChain9Impl_Present(LPDIRECT3DSWAPCHAIN9 iface, CONST RECT* pSourceRect, CONST RECT* pDestRect, HWND hDestWindowOverride, CONST RGNDATA* pDirtyRegion, DWORD dwFlags) {
92     IDirect3DSwapChain9Impl *This = (IDirect3DSwapChain9Impl *)iface;
93     HRESULT hr;
94
95     TRACE("iface %p, src_rect %p, dst_rect %p, dst_window_override %p, dirty_region %p, flags %#x.\n",
96             iface, pSourceRect, pDestRect, hDestWindowOverride, pDirtyRegion, dwFlags);
97
98     wined3d_mutex_lock();
99     hr = IWineD3DSwapChain_Present(This->wineD3DSwapChain, pSourceRect, pDestRect, hDestWindowOverride, pDirtyRegion, dwFlags);
100     wined3d_mutex_unlock();
101
102     return hr;
103 }
104
105 static HRESULT WINAPI IDirect3DSwapChain9Impl_GetFrontBufferData(LPDIRECT3DSWAPCHAIN9 iface, IDirect3DSurface9* pDestSurface) {
106     IDirect3DSwapChain9Impl *This = (IDirect3DSwapChain9Impl *)iface;
107     HRESULT hr;
108
109     TRACE("iface %p, surface %p.\n", iface, pDestSurface);
110
111     wined3d_mutex_lock();
112     hr = IWineD3DSwapChain_GetFrontBufferData(This->wineD3DSwapChain,  ((IDirect3DSurface9Impl *)pDestSurface)->wineD3DSurface);
113     wined3d_mutex_unlock();
114
115     return hr;
116 }
117
118 static HRESULT WINAPI IDirect3DSwapChain9Impl_GetBackBuffer(IDirect3DSwapChain9 *iface,
119         UINT iBackBuffer, D3DBACKBUFFER_TYPE Type, IDirect3DSurface9 **ppBackBuffer)
120 {
121     IDirect3DSwapChain9Impl *This = (IDirect3DSwapChain9Impl *)iface;
122     IWineD3DSurface *mySurface = NULL;
123     HRESULT hr;
124
125     TRACE("iface %p, backbuffer_idx %u, backbuffer_type %#x, backbuffer %p.\n",
126             iface, iBackBuffer, Type, ppBackBuffer);
127
128     wined3d_mutex_lock();
129     hr = IWineD3DSwapChain_GetBackBuffer(This->wineD3DSwapChain, iBackBuffer,
130             (WINED3DBACKBUFFER_TYPE)Type, &mySurface);
131     if (SUCCEEDED(hr) && mySurface)
132     {
133        *ppBackBuffer = IWineD3DSurface_GetParent(mySurface);
134        IDirect3DSurface9_AddRef(*ppBackBuffer);
135        IWineD3DSurface_Release(mySurface);
136     }
137     wined3d_mutex_unlock();
138
139     /* Do not touch the **ppBackBuffer pointer otherwise! (see device test) */
140     return hr;
141 }
142
143 static HRESULT WINAPI IDirect3DSwapChain9Impl_GetRasterStatus(LPDIRECT3DSWAPCHAIN9 iface, D3DRASTER_STATUS* pRasterStatus) {
144     IDirect3DSwapChain9Impl *This = (IDirect3DSwapChain9Impl *)iface;
145     HRESULT hr;
146
147     TRACE("iface %p, raster_status %p.\n", iface, pRasterStatus);
148
149     wined3d_mutex_lock();
150     hr = IWineD3DSwapChain_GetRasterStatus(This->wineD3DSwapChain, (WINED3DRASTER_STATUS *) pRasterStatus);
151     wined3d_mutex_unlock();
152
153     return hr;
154 }
155
156 static HRESULT WINAPI IDirect3DSwapChain9Impl_GetDisplayMode(LPDIRECT3DSWAPCHAIN9 iface, D3DDISPLAYMODE* pMode) {
157     IDirect3DSwapChain9Impl *This = (IDirect3DSwapChain9Impl *)iface;
158     HRESULT hr;
159
160     TRACE("iface %p, mode %p.\n", iface, pMode);
161
162     wined3d_mutex_lock();
163     hr = IWineD3DSwapChain_GetDisplayMode(This->wineD3DSwapChain, (WINED3DDISPLAYMODE *) pMode);
164     wined3d_mutex_unlock();
165
166     if (SUCCEEDED(hr)) pMode->Format = d3dformat_from_wined3dformat(pMode->Format);
167
168     return hr;
169 }
170
171 static HRESULT WINAPI IDirect3DSwapChain9Impl_GetDevice(IDirect3DSwapChain9 *iface, IDirect3DDevice9 **device)
172 {
173     IDirect3DSwapChain9Impl *This = (IDirect3DSwapChain9Impl *)iface;
174
175     TRACE("iface %p, device %p.\n", iface, device);
176
177     *device = (IDirect3DDevice9 *)This->parentDevice;
178     IDirect3DDevice9_AddRef(*device);
179
180     TRACE("Returning device %p.\n", *device);
181
182     return D3D_OK;
183 }
184
185 static HRESULT WINAPI IDirect3DSwapChain9Impl_GetPresentParameters(LPDIRECT3DSWAPCHAIN9 iface, D3DPRESENT_PARAMETERS* pPresentationParameters) {
186     IDirect3DSwapChain9Impl *This = (IDirect3DSwapChain9Impl *)iface;
187     WINED3DPRESENT_PARAMETERS winePresentParameters;
188     HRESULT hr;
189
190     TRACE("iface %p, parameters %p.\n", iface, pPresentationParameters);
191
192     wined3d_mutex_lock();
193     hr = IWineD3DSwapChain_GetPresentParameters(This->wineD3DSwapChain, &winePresentParameters);
194     wined3d_mutex_unlock();
195
196     pPresentationParameters->BackBufferWidth            = winePresentParameters.BackBufferWidth;
197     pPresentationParameters->BackBufferHeight           = winePresentParameters.BackBufferHeight;
198     pPresentationParameters->BackBufferFormat           = d3dformat_from_wined3dformat(winePresentParameters.BackBufferFormat);
199     pPresentationParameters->BackBufferCount            = winePresentParameters.BackBufferCount;
200     pPresentationParameters->MultiSampleType            = winePresentParameters.MultiSampleType;
201     pPresentationParameters->MultiSampleQuality         = winePresentParameters.MultiSampleQuality;
202     pPresentationParameters->SwapEffect                 = winePresentParameters.SwapEffect;
203     pPresentationParameters->hDeviceWindow              = winePresentParameters.hDeviceWindow;
204     pPresentationParameters->Windowed                   = winePresentParameters.Windowed;
205     pPresentationParameters->EnableAutoDepthStencil     = winePresentParameters.EnableAutoDepthStencil;
206     pPresentationParameters->AutoDepthStencilFormat     = d3dformat_from_wined3dformat(winePresentParameters.AutoDepthStencilFormat);
207     pPresentationParameters->Flags                      = winePresentParameters.Flags;
208     pPresentationParameters->FullScreen_RefreshRateInHz = winePresentParameters.FullScreen_RefreshRateInHz;
209     pPresentationParameters->PresentationInterval       = winePresentParameters.PresentationInterval;
210
211     return hr;
212 }
213
214
215 static const IDirect3DSwapChain9Vtbl Direct3DSwapChain9_Vtbl =
216 {
217     IDirect3DSwapChain9Impl_QueryInterface,
218     IDirect3DSwapChain9Impl_AddRef,
219     IDirect3DSwapChain9Impl_Release,
220     IDirect3DSwapChain9Impl_Present,
221     IDirect3DSwapChain9Impl_GetFrontBufferData,
222     IDirect3DSwapChain9Impl_GetBackBuffer,
223     IDirect3DSwapChain9Impl_GetRasterStatus,
224     IDirect3DSwapChain9Impl_GetDisplayMode,
225     IDirect3DSwapChain9Impl_GetDevice,
226     IDirect3DSwapChain9Impl_GetPresentParameters
227 };
228
229 static void STDMETHODCALLTYPE d3d9_swapchain_wined3d_object_released(void *parent)
230 {
231     HeapFree(GetProcessHeap(), 0, parent);
232 }
233
234 static const struct wined3d_parent_ops d3d9_swapchain_wined3d_parent_ops =
235 {
236     d3d9_swapchain_wined3d_object_released,
237 };
238
239 HRESULT swapchain_init(IDirect3DSwapChain9Impl *swapchain, IDirect3DDevice9Impl *device,
240         D3DPRESENT_PARAMETERS *present_parameters)
241 {
242     WINED3DPRESENT_PARAMETERS wined3d_parameters;
243     HRESULT hr;
244
245     swapchain->ref = 1;
246     swapchain->lpVtbl = &Direct3DSwapChain9_Vtbl;
247
248     wined3d_parameters.BackBufferWidth = present_parameters->BackBufferWidth;
249     wined3d_parameters.BackBufferHeight = present_parameters->BackBufferHeight;
250     wined3d_parameters.BackBufferFormat = wined3dformat_from_d3dformat(present_parameters->BackBufferFormat);
251     wined3d_parameters.BackBufferCount = max(1, present_parameters->BackBufferCount);
252     wined3d_parameters.MultiSampleType = present_parameters->MultiSampleType;
253     wined3d_parameters.MultiSampleQuality = present_parameters->MultiSampleQuality;
254     wined3d_parameters.SwapEffect = present_parameters->SwapEffect;
255     wined3d_parameters.hDeviceWindow = present_parameters->hDeviceWindow;
256     wined3d_parameters.Windowed = present_parameters->Windowed;
257     wined3d_parameters.EnableAutoDepthStencil = present_parameters->EnableAutoDepthStencil;
258     wined3d_parameters.AutoDepthStencilFormat = wined3dformat_from_d3dformat(present_parameters->AutoDepthStencilFormat);
259     wined3d_parameters.Flags = present_parameters->Flags;
260     wined3d_parameters.FullScreen_RefreshRateInHz = present_parameters->FullScreen_RefreshRateInHz;
261     wined3d_parameters.PresentationInterval = present_parameters->PresentationInterval;
262     wined3d_parameters.AutoRestoreDisplayMode = TRUE;
263
264     wined3d_mutex_lock();
265     hr = IWineD3DDevice_CreateSwapChain(device->WineD3DDevice, &wined3d_parameters,
266             SURFACE_OPENGL, swapchain, &d3d9_swapchain_wined3d_parent_ops,
267             &swapchain->wineD3DSwapChain);
268     wined3d_mutex_unlock();
269
270     present_parameters->BackBufferWidth = wined3d_parameters.BackBufferWidth;
271     present_parameters->BackBufferHeight = wined3d_parameters.BackBufferHeight;
272     present_parameters->BackBufferFormat = d3dformat_from_wined3dformat(wined3d_parameters.BackBufferFormat);
273     present_parameters->BackBufferCount = wined3d_parameters.BackBufferCount;
274     present_parameters->MultiSampleType = wined3d_parameters.MultiSampleType;
275     present_parameters->MultiSampleQuality = wined3d_parameters.MultiSampleQuality;
276     present_parameters->SwapEffect = wined3d_parameters.SwapEffect;
277     present_parameters->hDeviceWindow = wined3d_parameters.hDeviceWindow;
278     present_parameters->Windowed = wined3d_parameters.Windowed;
279     present_parameters->EnableAutoDepthStencil = wined3d_parameters.EnableAutoDepthStencil;
280     present_parameters->AutoDepthStencilFormat = d3dformat_from_wined3dformat(wined3d_parameters.AutoDepthStencilFormat);
281     present_parameters->Flags = wined3d_parameters.Flags;
282     present_parameters->FullScreen_RefreshRateInHz = wined3d_parameters.FullScreen_RefreshRateInHz;
283     present_parameters->PresentationInterval = wined3d_parameters.PresentationInterval;
284
285     if (FAILED(hr))
286     {
287         WARN("Failed to create wined3d swapchain, hr %#x.\n", hr);
288         return hr;
289     }
290
291     swapchain->parentDevice = (IDirect3DDevice9Ex *)device;
292     IDirect3DDevice9Ex_AddRef(swapchain->parentDevice);
293
294     return D3D_OK;
295 }