2 * Copyright 2008 Henri Verbeet for CodeWeavers
4 * This library is free software; you can redistribute it and/or
5 * modify it under the terms of the GNU Lesser General Public
6 * License as published by the Free Software Foundation; either
7 * version 2.1 of the License, or (at your option) any later version.
9 * This library is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
12 * Lesser General Public License for more details.
14 * You should have received a copy of the GNU Lesser General Public
15 * License along with this library; if not, write to the Free Software
16 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
21 #include "wine/port.h"
23 #include "dxgi_private.h"
25 WINE_DEFAULT_DEBUG_CHANNEL(dxgi
);
27 static inline struct dxgi_swapchain
*impl_from_IDXGISwapChain(IDXGISwapChain
*iface
)
29 return CONTAINING_RECORD(iface
, struct dxgi_swapchain
, IDXGISwapChain_iface
);
32 /* IUnknown methods */
34 static HRESULT STDMETHODCALLTYPE
dxgi_swapchain_QueryInterface(IDXGISwapChain
*iface
, REFIID riid
, void **object
)
36 TRACE("iface %p, riid %s, object %p\n", iface
, debugstr_guid(riid
), object
);
38 if (IsEqualGUID(riid
, &IID_IUnknown
)
39 || IsEqualGUID(riid
, &IID_IDXGIObject
)
40 || IsEqualGUID(riid
, &IID_IDXGIDeviceSubObject
)
41 || IsEqualGUID(riid
, &IID_IDXGISwapChain
))
43 IUnknown_AddRef(iface
);
48 WARN("%s not implemented, returning E_NOINTERFACE\n", debugstr_guid(riid
));
54 static ULONG STDMETHODCALLTYPE
dxgi_swapchain_AddRef(IDXGISwapChain
*iface
)
56 struct dxgi_swapchain
*This
= impl_from_IDXGISwapChain(iface
);
57 ULONG refcount
= InterlockedIncrement(&This
->refcount
);
59 TRACE("%p increasing refcount to %u\n", This
, refcount
);
64 wined3d_swapchain_incref(This
->wined3d_swapchain
);
65 wined3d_mutex_unlock();
71 static ULONG STDMETHODCALLTYPE
dxgi_swapchain_Release(IDXGISwapChain
*iface
)
73 struct dxgi_swapchain
*swapchain
= impl_from_IDXGISwapChain(iface
);
74 ULONG refcount
= InterlockedDecrement(&swapchain
->refcount
);
76 TRACE("%p decreasing refcount to %u.\n", swapchain
, refcount
);
80 IWineDXGIDevice
*device
= swapchain
->device
;
81 if (swapchain
->target
)
83 WARN("Releasing fullscreen swapchain.\n");
84 IDXGIOutput_Release(swapchain
->target
);
86 if (swapchain
->factory
)
87 IDXGIFactory_Release(swapchain
->factory
);
89 wined3d_swapchain_decref(swapchain
->wined3d_swapchain
);
90 wined3d_mutex_unlock();
92 IWineDXGIDevice_Release(device
);
98 /* IDXGIObject methods */
100 static HRESULT STDMETHODCALLTYPE
dxgi_swapchain_SetPrivateData(IDXGISwapChain
*iface
,
101 REFGUID guid
, UINT data_size
, const void *data
)
103 struct dxgi_swapchain
*swapchain
= impl_from_IDXGISwapChain(iface
);
105 TRACE("iface %p, guid %s, data_size %u, data %p.\n", iface
, debugstr_guid(guid
), data_size
, data
);
107 return dxgi_set_private_data(&swapchain
->private_store
, guid
, data_size
, data
);
110 static HRESULT STDMETHODCALLTYPE
dxgi_swapchain_SetPrivateDataInterface(IDXGISwapChain
*iface
,
111 REFGUID guid
, const IUnknown
*object
)
113 struct dxgi_swapchain
*swapchain
= impl_from_IDXGISwapChain(iface
);
115 TRACE("iface %p, guid %s, object %p.\n", iface
, debugstr_guid(guid
), object
);
117 return dxgi_set_private_data_interface(&swapchain
->private_store
, guid
, object
);
120 static HRESULT STDMETHODCALLTYPE
dxgi_swapchain_GetPrivateData(IDXGISwapChain
*iface
,
121 REFGUID guid
, UINT
*data_size
, void *data
)
123 struct dxgi_swapchain
*swapchain
= impl_from_IDXGISwapChain(iface
);
125 TRACE("iface %p, guid %s, data_size %p, data %p.\n", iface
, debugstr_guid(guid
), data_size
, data
);
127 return dxgi_get_private_data(&swapchain
->private_store
, guid
, data_size
, data
);
130 static HRESULT STDMETHODCALLTYPE
dxgi_swapchain_GetParent(IDXGISwapChain
*iface
, REFIID riid
, void **parent
)
132 struct dxgi_swapchain
*swapchain
= impl_from_IDXGISwapChain(iface
);
134 TRACE("iface %p, riid %s, parent %p.\n", iface
, debugstr_guid(riid
), parent
);
136 if (!swapchain
->factory
)
138 ERR("Implicit swapchain does not store reference to parent.\n");
140 return E_NOINTERFACE
;
143 return IDXGIFactory_QueryInterface(swapchain
->factory
, riid
, parent
);
146 /* IDXGIDeviceSubObject methods */
148 static HRESULT STDMETHODCALLTYPE
dxgi_swapchain_GetDevice(IDXGISwapChain
*iface
, REFIID riid
, void **device
)
150 struct dxgi_swapchain
*swapchain
= impl_from_IDXGISwapChain(iface
);
152 TRACE("iface %p, riid %s, device %p.\n", iface
, debugstr_guid(riid
), device
);
154 if (!swapchain
->device
)
156 ERR("Implicit swapchain does not store reference to device.\n");
158 return E_NOINTERFACE
;
161 return IWineDXGIDevice_QueryInterface(swapchain
->device
, riid
, device
);
164 /* IDXGISwapChain methods */
166 static HRESULT STDMETHODCALLTYPE
dxgi_swapchain_Present(IDXGISwapChain
*iface
, UINT sync_interval
, UINT flags
)
168 struct dxgi_swapchain
*This
= impl_from_IDXGISwapChain(iface
);
171 TRACE("iface %p, sync_interval %u, flags %#x\n", iface
, sync_interval
, flags
);
173 if (sync_interval
) FIXME("Unimplemented sync interval %u\n", sync_interval
);
174 if (flags
) FIXME("Unimplemented flags %#x\n", flags
);
176 wined3d_mutex_lock();
177 hr
= wined3d_swapchain_present(This
->wined3d_swapchain
, NULL
, NULL
, NULL
, 0);
178 wined3d_mutex_unlock();
183 static HRESULT STDMETHODCALLTYPE
dxgi_swapchain_GetBuffer(IDXGISwapChain
*iface
,
184 UINT buffer_idx
, REFIID riid
, void **surface
)
186 struct dxgi_swapchain
*This
= impl_from_IDXGISwapChain(iface
);
187 struct wined3d_texture
*texture
;
191 TRACE("iface %p, buffer_idx %u, riid %s, surface %p\n",
192 iface
, buffer_idx
, debugstr_guid(riid
), surface
);
194 wined3d_mutex_lock();
196 if (!(texture
= wined3d_swapchain_get_back_buffer(This
->wined3d_swapchain
, buffer_idx
)))
198 wined3d_mutex_unlock();
199 return DXGI_ERROR_INVALID_CALL
;
202 parent
= wined3d_texture_get_parent(texture
);
203 hr
= IUnknown_QueryInterface(parent
, riid
, surface
);
204 wined3d_mutex_unlock();
209 static HRESULT STDMETHODCALLTYPE DECLSPEC_HOTPATCH
dxgi_swapchain_SetFullscreenState(IDXGISwapChain
*iface
,
210 BOOL fullscreen
, IDXGIOutput
*target
)
212 struct dxgi_swapchain
*swapchain
= impl_from_IDXGISwapChain(iface
);
213 struct wined3d_swapchain_desc swapchain_desc
;
216 TRACE("iface %p, fullscreen %#x, target %p.\n", iface
, fullscreen
, target
);
218 if (!fullscreen
&& target
)
220 WARN("Invalid call.\n");
221 return DXGI_ERROR_INVALID_CALL
;
228 IDXGIOutput_AddRef(target
);
230 else if (FAILED(hr
= IDXGISwapChain_GetContainingOutput(iface
, &target
)))
232 WARN("Failed to get default target output for swapchain, hr %#x.\n", hr
);
237 wined3d_mutex_lock();
238 wined3d_swapchain_get_desc(swapchain
->wined3d_swapchain
, &swapchain_desc
);
239 swapchain_desc
.windowed
= !fullscreen
;
240 hr
= wined3d_swapchain_set_fullscreen(swapchain
->wined3d_swapchain
, &swapchain_desc
, NULL
);
241 wined3d_mutex_unlock();
245 swapchain
->fullscreen
= fullscreen
;
246 if (swapchain
->target
)
247 IDXGIOutput_Release(swapchain
->target
);
248 swapchain
->target
= target
;
252 IDXGIOutput_Release(target
);
258 static HRESULT STDMETHODCALLTYPE
dxgi_swapchain_GetFullscreenState(IDXGISwapChain
*iface
,
259 BOOL
*fullscreen
, IDXGIOutput
**target
)
261 struct dxgi_swapchain
*swapchain
= impl_from_IDXGISwapChain(iface
);
263 TRACE("iface %p, fullscreen %p, target %p.\n", iface
, fullscreen
, target
);
266 *fullscreen
= swapchain
->fullscreen
;
270 *target
= swapchain
->target
;
272 IDXGIOutput_AddRef(*target
);
278 static HRESULT STDMETHODCALLTYPE
dxgi_swapchain_GetDesc(IDXGISwapChain
*iface
, DXGI_SWAP_CHAIN_DESC
*desc
)
280 struct dxgi_swapchain
*swapchain
= impl_from_IDXGISwapChain(iface
);
281 struct wined3d_swapchain_desc wined3d_desc
;
283 FIXME("iface %p, desc %p partial stub!\n", iface
, desc
);
288 wined3d_mutex_lock();
289 wined3d_swapchain_get_desc(swapchain
->wined3d_swapchain
, &wined3d_desc
);
290 wined3d_mutex_unlock();
292 FIXME("Ignoring ScanlineOrdering, Scaling and SwapEffect.\n");
294 desc
->BufferDesc
.Width
= wined3d_desc
.backbuffer_width
;
295 desc
->BufferDesc
.Height
= wined3d_desc
.backbuffer_height
;
296 desc
->BufferDesc
.RefreshRate
.Numerator
= wined3d_desc
.refresh_rate
;
297 desc
->BufferDesc
.RefreshRate
.Denominator
= 1;
298 desc
->BufferDesc
.Format
= dxgi_format_from_wined3dformat(wined3d_desc
.backbuffer_format
);
299 desc
->BufferDesc
.ScanlineOrdering
= DXGI_MODE_SCANLINE_ORDER_UNSPECIFIED
;
300 desc
->BufferDesc
.Scaling
= DXGI_MODE_SCALING_UNSPECIFIED
;
301 dxgi_sample_desc_from_wined3d(&desc
->SampleDesc
, wined3d_desc
.multisample_type
, wined3d_desc
.multisample_quality
);
302 desc
->BufferCount
= wined3d_desc
.backbuffer_count
;
303 desc
->OutputWindow
= wined3d_desc
.device_window
;
304 desc
->Windowed
= wined3d_desc
.windowed
;
305 desc
->SwapEffect
= DXGI_SWAP_EFFECT_DISCARD
;
306 desc
->Flags
= dxgi_swapchain_flags_from_wined3d(wined3d_desc
.flags
);
311 static HRESULT STDMETHODCALLTYPE
dxgi_swapchain_ResizeBuffers(IDXGISwapChain
*iface
,
312 UINT buffer_count
, UINT width
, UINT height
, DXGI_FORMAT format
, UINT flags
)
314 struct dxgi_swapchain
*swapchain
= impl_from_IDXGISwapChain(iface
);
315 struct wined3d_swapchain_desc wined3d_desc
;
316 struct wined3d_texture
*texture
;
321 TRACE("iface %p, buffer_count %u, width %u, height %u, format %s, flags %#x.\n",
322 iface
, buffer_count
, width
, height
, debug_dxgi_format(format
), flags
);
325 FIXME("Ignoring flags %#x.\n", flags
);
327 wined3d_mutex_lock();
328 wined3d_swapchain_get_desc(swapchain
->wined3d_swapchain
, &wined3d_desc
);
329 for (i
= 0; i
< wined3d_desc
.backbuffer_count
; ++i
)
331 texture
= wined3d_swapchain_get_back_buffer(swapchain
->wined3d_swapchain
, i
);
332 parent
= wined3d_texture_get_parent(texture
);
333 IUnknown_AddRef(parent
);
334 if (IUnknown_Release(parent
))
336 wined3d_mutex_unlock();
337 return DXGI_ERROR_INVALID_CALL
;
340 if (format
!= DXGI_FORMAT_UNKNOWN
)
341 wined3d_desc
.backbuffer_format
= wined3dformat_from_dxgi_format(format
);
342 hr
= wined3d_swapchain_resize_buffers(swapchain
->wined3d_swapchain
, buffer_count
, width
, height
,
343 wined3d_desc
.backbuffer_format
, wined3d_desc
.multisample_type
, wined3d_desc
.multisample_quality
);
344 wined3d_mutex_unlock();
349 static HRESULT STDMETHODCALLTYPE
dxgi_swapchain_ResizeTarget(IDXGISwapChain
*iface
,
350 const DXGI_MODE_DESC
*target_mode_desc
)
352 struct dxgi_swapchain
*swapchain
= impl_from_IDXGISwapChain(iface
);
353 struct wined3d_display_mode mode
;
356 TRACE("iface %p, target_mode_desc %p.\n", iface
, target_mode_desc
);
358 if (!target_mode_desc
)
359 return DXGI_ERROR_INVALID_CALL
;
361 TRACE("Mode: %s.\n", debug_dxgi_mode(target_mode_desc
));
363 if (target_mode_desc
->Scaling
)
364 FIXME("Ignoring scaling %#x.\n", target_mode_desc
->Scaling
);
366 wined3d_display_mode_from_dxgi(&mode
, target_mode_desc
);
368 wined3d_mutex_lock();
369 hr
= wined3d_swapchain_resize_target(swapchain
->wined3d_swapchain
, &mode
);
370 wined3d_mutex_unlock();
375 static HRESULT STDMETHODCALLTYPE
dxgi_swapchain_GetContainingOutput(IDXGISwapChain
*iface
, IDXGIOutput
**output
)
377 struct dxgi_swapchain
*swapchain
= impl_from_IDXGISwapChain(iface
);
378 IDXGIAdapter
*adapter
;
382 TRACE("iface %p, output %p.\n", iface
, output
);
384 if (swapchain
->target
)
386 IDXGIOutput_AddRef(*output
= swapchain
->target
);
390 if (FAILED(hr
= dxgi_swapchain_GetDevice(iface
, &IID_IDXGIDevice
, (void **)&device
)))
393 hr
= IDXGIDevice_GetAdapter(device
, &adapter
);
394 IDXGIDevice_Release(device
);
397 WARN("GetAdapter failed, hr %#x.\n", hr
);
401 if (SUCCEEDED(IDXGIAdapter_EnumOutputs(adapter
, 1, output
)))
403 FIXME("Adapter has got multiple outputs, returning the first one.\n");
404 IDXGIOutput_Release(*output
);
407 hr
= IDXGIAdapter_EnumOutputs(adapter
, 0, output
);
408 IDXGIAdapter_Release(adapter
);
412 static HRESULT STDMETHODCALLTYPE
dxgi_swapchain_GetFrameStatistics(IDXGISwapChain
*iface
, DXGI_FRAME_STATISTICS
*stats
)
414 FIXME("iface %p, stats %p stub!\n", iface
, stats
);
419 static HRESULT STDMETHODCALLTYPE
dxgi_swapchain_GetLastPresentCount(IDXGISwapChain
*iface
, UINT
*last_present_count
)
421 FIXME("iface %p, last_present_count %p stub!\n", iface
, last_present_count
);
426 static const struct IDXGISwapChainVtbl dxgi_swapchain_vtbl
=
428 /* IUnknown methods */
429 dxgi_swapchain_QueryInterface
,
430 dxgi_swapchain_AddRef
,
431 dxgi_swapchain_Release
,
432 /* IDXGIObject methods */
433 dxgi_swapchain_SetPrivateData
,
434 dxgi_swapchain_SetPrivateDataInterface
,
435 dxgi_swapchain_GetPrivateData
,
436 dxgi_swapchain_GetParent
,
437 /* IDXGIDeviceSubObject methods */
438 dxgi_swapchain_GetDevice
,
439 /* IDXGISwapChain methods */
440 dxgi_swapchain_Present
,
441 dxgi_swapchain_GetBuffer
,
442 dxgi_swapchain_SetFullscreenState
,
443 dxgi_swapchain_GetFullscreenState
,
444 dxgi_swapchain_GetDesc
,
445 dxgi_swapchain_ResizeBuffers
,
446 dxgi_swapchain_ResizeTarget
,
447 dxgi_swapchain_GetContainingOutput
,
448 dxgi_swapchain_GetFrameStatistics
,
449 dxgi_swapchain_GetLastPresentCount
,
452 static void STDMETHODCALLTYPE
dxgi_swapchain_wined3d_object_released(void *parent
)
454 struct dxgi_swapchain
*swapchain
= parent
;
456 wined3d_private_store_cleanup(&swapchain
->private_store
);
457 HeapFree(GetProcessHeap(), 0, parent
);
460 static const struct wined3d_parent_ops dxgi_swapchain_wined3d_parent_ops
=
462 dxgi_swapchain_wined3d_object_released
,
465 HRESULT
dxgi_swapchain_init(struct dxgi_swapchain
*swapchain
, struct dxgi_device
*device
,
466 struct wined3d_swapchain_desc
*desc
, BOOL implicit
)
471 * A reference to the implicit swapchain is held by the wined3d device.
472 * In order to avoid circular references we do not keep a reference
473 * to the device in the implicit swapchain.
477 if (FAILED(hr
= IDXGIAdapter1_GetParent(device
->adapter
, &IID_IDXGIFactory
,
478 (void **)&swapchain
->factory
)))
480 WARN("Failed to get adapter parent, hr %#x.\n", hr
);
483 IWineDXGIDevice_AddRef(swapchain
->device
= &device
->IWineDXGIDevice_iface
);
487 swapchain
->device
= NULL
;
488 swapchain
->factory
= NULL
;
491 swapchain
->IDXGISwapChain_iface
.lpVtbl
= &dxgi_swapchain_vtbl
;
492 swapchain
->refcount
= 1;
493 wined3d_mutex_lock();
494 wined3d_private_store_init(&swapchain
->private_store
);
496 if (!desc
->windowed
&& (!desc
->backbuffer_width
|| !desc
->backbuffer_height
))
497 FIXME("Fullscreen swapchain with back buffer width/height equal to 0 not supported properly.\n");
499 swapchain
->fullscreen
= !desc
->windowed
;
500 desc
->windowed
= TRUE
;
501 if (FAILED(hr
= wined3d_swapchain_create(device
->wined3d_device
, desc
, swapchain
,
502 &dxgi_swapchain_wined3d_parent_ops
, &swapchain
->wined3d_swapchain
)))
504 WARN("Failed to create wined3d swapchain, hr %#x.\n", hr
);
508 swapchain
->target
= NULL
;
509 if (swapchain
->fullscreen
)
511 desc
->windowed
= FALSE
;
512 if (FAILED(hr
= wined3d_swapchain_set_fullscreen(swapchain
->wined3d_swapchain
,
515 WARN("Failed to set fullscreen state, hr %#x.\n", hr
);
516 wined3d_swapchain_decref(swapchain
->wined3d_swapchain
);
520 if (FAILED(hr
= IDXGISwapChain_GetContainingOutput(&swapchain
->IDXGISwapChain_iface
,
521 &swapchain
->target
)))
523 WARN("Failed to get target output for fullscreen swapchain, hr %#x.\n", hr
);
524 wined3d_swapchain_decref(swapchain
->wined3d_swapchain
);
528 wined3d_mutex_unlock();
533 wined3d_private_store_cleanup(&swapchain
->private_store
);
534 wined3d_mutex_unlock();
535 if (swapchain
->factory
)
536 IDXGIFactory_Release(swapchain
->factory
);
537 if (swapchain
->device
)
538 IWineDXGIDevice_Release(swapchain
->device
);