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