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