dxgi: Factor out d3d12_swapchain_destroy_buffers().
[wine.git] / dlls / dxgi / swapchain.c
blob0b651c4853bd3d404fa8bb02572d0fb68f2ce541
1 /*
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
20 #include "config.h"
21 #include "wine/port.h"
23 #include "dxgi_private.h"
25 #ifdef SONAME_LIBVKD3D
26 #define VK_NO_PROTOTYPES
27 #define VKD3D_NO_PROTOTYPES
28 #define VKD3D_NO_VULKAN_H
29 #define VKD3D_NO_WIN32_TYPES
30 #define WINE_VK_HOST
31 #include "wine/library.h"
32 #include "wine/vulkan.h"
33 #include "wine/vulkan_driver.h"
34 #include <vkd3d.h>
35 #endif
37 WINE_DEFAULT_DEBUG_CHANNEL(dxgi);
38 WINE_DECLARE_DEBUG_CHANNEL(winediag);
40 static inline struct d3d11_swapchain *d3d11_swapchain_from_IDXGISwapChain1(IDXGISwapChain1 *iface)
42 return CONTAINING_RECORD(iface, struct d3d11_swapchain, IDXGISwapChain1_iface);
45 /* IUnknown methods */
47 static HRESULT STDMETHODCALLTYPE d3d11_swapchain_QueryInterface(IDXGISwapChain1 *iface, REFIID riid, void **object)
49 TRACE("iface %p, riid %s, object %p\n", iface, debugstr_guid(riid), object);
51 if (IsEqualGUID(riid, &IID_IUnknown)
52 || IsEqualGUID(riid, &IID_IDXGIObject)
53 || IsEqualGUID(riid, &IID_IDXGIDeviceSubObject)
54 || IsEqualGUID(riid, &IID_IDXGISwapChain)
55 || IsEqualGUID(riid, &IID_IDXGISwapChain1))
57 IUnknown_AddRef(iface);
58 *object = iface;
59 return S_OK;
62 WARN("%s not implemented, returning E_NOINTERFACE\n", debugstr_guid(riid));
64 *object = NULL;
65 return E_NOINTERFACE;
68 static ULONG STDMETHODCALLTYPE d3d11_swapchain_AddRef(IDXGISwapChain1 *iface)
70 struct d3d11_swapchain *swapchain = d3d11_swapchain_from_IDXGISwapChain1(iface);
71 ULONG refcount = InterlockedIncrement(&swapchain->refcount);
73 TRACE("%p increasing refcount to %u\n", swapchain, refcount);
75 if (refcount == 1)
77 wined3d_mutex_lock();
78 wined3d_swapchain_incref(swapchain->wined3d_swapchain);
79 wined3d_mutex_unlock();
82 return refcount;
85 static ULONG STDMETHODCALLTYPE d3d11_swapchain_Release(IDXGISwapChain1 *iface)
87 struct d3d11_swapchain *swapchain = d3d11_swapchain_from_IDXGISwapChain1(iface);
88 ULONG refcount = InterlockedDecrement(&swapchain->refcount);
90 TRACE("%p decreasing refcount to %u.\n", swapchain, refcount);
92 if (!refcount)
94 IWineDXGIDevice *device = swapchain->device;
95 if (swapchain->target)
97 WARN("Releasing fullscreen swapchain.\n");
98 IDXGIOutput_Release(swapchain->target);
100 if (swapchain->factory)
101 IDXGIFactory_Release(swapchain->factory);
102 wined3d_mutex_lock();
103 wined3d_swapchain_decref(swapchain->wined3d_swapchain);
104 wined3d_mutex_unlock();
105 if (device)
106 IWineDXGIDevice_Release(device);
109 return refcount;
112 /* IDXGIObject methods */
114 static HRESULT STDMETHODCALLTYPE d3d11_swapchain_SetPrivateData(IDXGISwapChain1 *iface,
115 REFGUID guid, UINT data_size, const void *data)
117 struct d3d11_swapchain *swapchain = d3d11_swapchain_from_IDXGISwapChain1(iface);
119 TRACE("iface %p, guid %s, data_size %u, data %p.\n", iface, debugstr_guid(guid), data_size, data);
121 return dxgi_set_private_data(&swapchain->private_store, guid, data_size, data);
124 static HRESULT STDMETHODCALLTYPE d3d11_swapchain_SetPrivateDataInterface(IDXGISwapChain1 *iface,
125 REFGUID guid, const IUnknown *object)
127 struct d3d11_swapchain *swapchain = d3d11_swapchain_from_IDXGISwapChain1(iface);
129 TRACE("iface %p, guid %s, object %p.\n", iface, debugstr_guid(guid), object);
131 return dxgi_set_private_data_interface(&swapchain->private_store, guid, object);
134 static HRESULT STDMETHODCALLTYPE d3d11_swapchain_GetPrivateData(IDXGISwapChain1 *iface,
135 REFGUID guid, UINT *data_size, void *data)
137 struct d3d11_swapchain *swapchain = d3d11_swapchain_from_IDXGISwapChain1(iface);
139 TRACE("iface %p, guid %s, data_size %p, data %p.\n", iface, debugstr_guid(guid), data_size, data);
141 return dxgi_get_private_data(&swapchain->private_store, guid, data_size, data);
144 static HRESULT STDMETHODCALLTYPE d3d11_swapchain_GetParent(IDXGISwapChain1 *iface, REFIID riid, void **parent)
146 struct d3d11_swapchain *swapchain = d3d11_swapchain_from_IDXGISwapChain1(iface);
148 TRACE("iface %p, riid %s, parent %p.\n", iface, debugstr_guid(riid), parent);
150 if (!swapchain->factory)
152 ERR("Implicit swapchain does not store reference to parent.\n");
153 *parent = NULL;
154 return E_NOINTERFACE;
157 return IDXGIFactory_QueryInterface(swapchain->factory, riid, parent);
160 /* IDXGIDeviceSubObject methods */
162 static HRESULT STDMETHODCALLTYPE d3d11_swapchain_GetDevice(IDXGISwapChain1 *iface, REFIID riid, void **device)
164 struct d3d11_swapchain *swapchain = d3d11_swapchain_from_IDXGISwapChain1(iface);
166 TRACE("iface %p, riid %s, device %p.\n", iface, debugstr_guid(riid), device);
168 if (!swapchain->device)
170 ERR("Implicit swapchain does not store reference to device.\n");
171 *device = NULL;
172 return E_NOINTERFACE;
175 return IWineDXGIDevice_QueryInterface(swapchain->device, riid, device);
178 /* IDXGISwapChain1 methods */
180 static HRESULT STDMETHODCALLTYPE d3d11_swapchain_Present(IDXGISwapChain1 *iface, UINT sync_interval, UINT flags)
182 struct d3d11_swapchain *swapchain = d3d11_swapchain_from_IDXGISwapChain1(iface);
184 TRACE("iface %p, sync_interval %u, flags %#x.\n", iface, sync_interval, flags);
186 return IDXGISwapChain1_Present1(&swapchain->IDXGISwapChain1_iface, sync_interval, flags, NULL);
189 static HRESULT STDMETHODCALLTYPE d3d11_swapchain_GetBuffer(IDXGISwapChain1 *iface,
190 UINT buffer_idx, REFIID riid, void **surface)
192 struct d3d11_swapchain *swapchain = d3d11_swapchain_from_IDXGISwapChain1(iface);
193 struct wined3d_texture *texture;
194 IUnknown *parent;
195 HRESULT hr;
197 TRACE("iface %p, buffer_idx %u, riid %s, surface %p\n",
198 iface, buffer_idx, debugstr_guid(riid), surface);
200 wined3d_mutex_lock();
202 if (!(texture = wined3d_swapchain_get_back_buffer(swapchain->wined3d_swapchain, buffer_idx)))
204 wined3d_mutex_unlock();
205 return DXGI_ERROR_INVALID_CALL;
208 parent = wined3d_texture_get_parent(texture);
209 hr = IUnknown_QueryInterface(parent, riid, surface);
210 wined3d_mutex_unlock();
212 return hr;
215 static HRESULT STDMETHODCALLTYPE DECLSPEC_HOTPATCH d3d11_swapchain_SetFullscreenState(IDXGISwapChain1 *iface,
216 BOOL fullscreen, IDXGIOutput *target)
218 struct d3d11_swapchain *swapchain = d3d11_swapchain_from_IDXGISwapChain1(iface);
219 struct wined3d_swapchain_desc swapchain_desc;
220 HRESULT hr;
222 TRACE("iface %p, fullscreen %#x, target %p.\n", iface, fullscreen, target);
224 if (!fullscreen && target)
226 WARN("Invalid call.\n");
227 return DXGI_ERROR_INVALID_CALL;
230 if (fullscreen)
232 if (target)
234 IDXGIOutput_AddRef(target);
236 else if (FAILED(hr = IDXGISwapChain1_GetContainingOutput(iface, &target)))
238 WARN("Failed to get default target output for swapchain, hr %#x.\n", hr);
239 return hr;
243 wined3d_mutex_lock();
244 wined3d_swapchain_get_desc(swapchain->wined3d_swapchain, &swapchain_desc);
245 swapchain_desc.windowed = !fullscreen;
246 hr = wined3d_swapchain_set_fullscreen(swapchain->wined3d_swapchain, &swapchain_desc, NULL);
247 wined3d_mutex_unlock();
249 if (SUCCEEDED(hr))
251 swapchain->fullscreen = fullscreen;
252 if (swapchain->target)
253 IDXGIOutput_Release(swapchain->target);
254 swapchain->target = target;
255 return S_OK;
258 if (target)
259 IDXGIOutput_Release(target);
260 return hr;
263 static HRESULT STDMETHODCALLTYPE d3d11_swapchain_GetFullscreenState(IDXGISwapChain1 *iface,
264 BOOL *fullscreen, IDXGIOutput **target)
266 struct d3d11_swapchain *swapchain = d3d11_swapchain_from_IDXGISwapChain1(iface);
268 TRACE("iface %p, fullscreen %p, target %p.\n", iface, fullscreen, target);
270 if (fullscreen)
271 *fullscreen = swapchain->fullscreen;
273 if (target)
275 *target = swapchain->target;
276 if (*target)
277 IDXGIOutput_AddRef(*target);
280 return S_OK;
283 static HRESULT STDMETHODCALLTYPE d3d11_swapchain_GetDesc(IDXGISwapChain1 *iface, DXGI_SWAP_CHAIN_DESC *desc)
285 struct d3d11_swapchain *swapchain = d3d11_swapchain_from_IDXGISwapChain1(iface);
286 struct wined3d_swapchain_desc wined3d_desc;
288 TRACE("iface %p, desc %p.\n", iface, desc);
290 if (!desc)
292 WARN("Invalid pointer.\n");
293 return E_INVALIDARG;
296 wined3d_mutex_lock();
297 wined3d_swapchain_get_desc(swapchain->wined3d_swapchain, &wined3d_desc);
298 wined3d_mutex_unlock();
300 FIXME("Ignoring ScanlineOrdering, Scaling and SwapEffect.\n");
302 desc->BufferDesc.Width = wined3d_desc.backbuffer_width;
303 desc->BufferDesc.Height = wined3d_desc.backbuffer_height;
304 desc->BufferDesc.RefreshRate.Numerator = wined3d_desc.refresh_rate;
305 desc->BufferDesc.RefreshRate.Denominator = 1;
306 desc->BufferDesc.Format = dxgi_format_from_wined3dformat(wined3d_desc.backbuffer_format);
307 desc->BufferDesc.ScanlineOrdering = DXGI_MODE_SCANLINE_ORDER_UNSPECIFIED;
308 desc->BufferDesc.Scaling = DXGI_MODE_SCALING_UNSPECIFIED;
309 dxgi_sample_desc_from_wined3d(&desc->SampleDesc,
310 wined3d_desc.multisample_type, wined3d_desc.multisample_quality);
311 desc->BufferUsage = dxgi_usage_from_wined3d_usage(wined3d_desc.backbuffer_usage);
312 desc->BufferCount = wined3d_desc.backbuffer_count;
313 desc->OutputWindow = wined3d_desc.device_window;
314 desc->Windowed = wined3d_desc.windowed;
315 desc->SwapEffect = DXGI_SWAP_EFFECT_DISCARD;
316 desc->Flags = dxgi_swapchain_flags_from_wined3d(wined3d_desc.flags);
318 return S_OK;
321 static HRESULT STDMETHODCALLTYPE d3d11_swapchain_ResizeBuffers(IDXGISwapChain1 *iface,
322 UINT buffer_count, UINT width, UINT height, DXGI_FORMAT format, UINT flags)
324 struct d3d11_swapchain *swapchain = d3d11_swapchain_from_IDXGISwapChain1(iface);
325 struct wined3d_swapchain_desc wined3d_desc;
326 struct wined3d_texture *texture;
327 IUnknown *parent;
328 unsigned int i;
329 HRESULT hr;
331 TRACE("iface %p, buffer_count %u, width %u, height %u, format %s, flags %#x.\n",
332 iface, buffer_count, width, height, debug_dxgi_format(format), flags);
334 if (flags)
335 FIXME("Ignoring flags %#x.\n", flags);
337 wined3d_mutex_lock();
338 wined3d_swapchain_get_desc(swapchain->wined3d_swapchain, &wined3d_desc);
339 for (i = 0; i < wined3d_desc.backbuffer_count; ++i)
341 texture = wined3d_swapchain_get_back_buffer(swapchain->wined3d_swapchain, i);
342 parent = wined3d_texture_get_parent(texture);
343 IUnknown_AddRef(parent);
344 if (IUnknown_Release(parent))
346 wined3d_mutex_unlock();
347 return DXGI_ERROR_INVALID_CALL;
350 if (format != DXGI_FORMAT_UNKNOWN)
351 wined3d_desc.backbuffer_format = wined3dformat_from_dxgi_format(format);
352 hr = wined3d_swapchain_resize_buffers(swapchain->wined3d_swapchain, buffer_count, width, height,
353 wined3d_desc.backbuffer_format, wined3d_desc.multisample_type, wined3d_desc.multisample_quality);
354 wined3d_mutex_unlock();
356 return hr;
359 static HRESULT STDMETHODCALLTYPE d3d11_swapchain_ResizeTarget(IDXGISwapChain1 *iface,
360 const DXGI_MODE_DESC *target_mode_desc)
362 struct d3d11_swapchain *swapchain = d3d11_swapchain_from_IDXGISwapChain1(iface);
363 struct wined3d_display_mode mode;
364 HRESULT hr;
366 TRACE("iface %p, target_mode_desc %p.\n", iface, target_mode_desc);
368 if (!target_mode_desc)
370 WARN("Invalid pointer.\n");
371 return DXGI_ERROR_INVALID_CALL;
374 TRACE("Mode: %s.\n", debug_dxgi_mode(target_mode_desc));
376 if (target_mode_desc->Scaling)
377 FIXME("Ignoring scaling %#x.\n", target_mode_desc->Scaling);
379 wined3d_display_mode_from_dxgi(&mode, target_mode_desc);
381 wined3d_mutex_lock();
382 hr = wined3d_swapchain_resize_target(swapchain->wined3d_swapchain, &mode);
383 wined3d_mutex_unlock();
385 return hr;
388 static HRESULT STDMETHODCALLTYPE d3d11_swapchain_GetContainingOutput(IDXGISwapChain1 *iface, IDXGIOutput **output)
390 struct d3d11_swapchain *swapchain = d3d11_swapchain_from_IDXGISwapChain1(iface);
391 IDXGIAdapter *adapter;
392 IDXGIDevice *device;
393 HRESULT hr;
395 TRACE("iface %p, output %p.\n", iface, output);
397 if (swapchain->target)
399 IDXGIOutput_AddRef(*output = swapchain->target);
400 return S_OK;
403 if (FAILED(hr = d3d11_swapchain_GetDevice(iface, &IID_IDXGIDevice, (void **)&device)))
404 return hr;
406 hr = IDXGIDevice_GetAdapter(device, &adapter);
407 IDXGIDevice_Release(device);
408 if (FAILED(hr))
410 WARN("GetAdapter failed, hr %#x.\n", hr);
411 return hr;
414 if (SUCCEEDED(IDXGIAdapter_EnumOutputs(adapter, 1, output)))
416 FIXME("Adapter has got multiple outputs, returning the first one.\n");
417 IDXGIOutput_Release(*output);
420 hr = IDXGIAdapter_EnumOutputs(adapter, 0, output);
421 IDXGIAdapter_Release(adapter);
422 return hr;
425 static HRESULT STDMETHODCALLTYPE d3d11_swapchain_GetFrameStatistics(IDXGISwapChain1 *iface,
426 DXGI_FRAME_STATISTICS *stats)
428 FIXME("iface %p, stats %p stub!\n", iface, stats);
430 return E_NOTIMPL;
433 static HRESULT STDMETHODCALLTYPE d3d11_swapchain_GetLastPresentCount(IDXGISwapChain1 *iface,
434 UINT *last_present_count)
436 FIXME("iface %p, last_present_count %p stub!\n", iface, last_present_count);
438 return E_NOTIMPL;
441 /* IDXGISwapChain1 methods */
443 static HRESULT STDMETHODCALLTYPE d3d11_swapchain_GetDesc1(IDXGISwapChain1 *iface, DXGI_SWAP_CHAIN_DESC1 *desc)
445 struct d3d11_swapchain *swapchain = d3d11_swapchain_from_IDXGISwapChain1(iface);
446 struct wined3d_swapchain_desc wined3d_desc;
448 TRACE("iface %p, desc %p.\n", iface, desc);
450 if (!desc)
452 WARN("Invalid pointer.\n");
453 return E_INVALIDARG;
456 wined3d_mutex_lock();
457 wined3d_swapchain_get_desc(swapchain->wined3d_swapchain, &wined3d_desc);
458 wined3d_mutex_unlock();
460 FIXME("Ignoring Stereo, Scaling, SwapEffect and AlphaMode.\n");
462 desc->Width = wined3d_desc.backbuffer_width;
463 desc->Height = wined3d_desc.backbuffer_height;
464 desc->Format = dxgi_format_from_wined3dformat(wined3d_desc.backbuffer_format);
465 desc->Stereo = FALSE;
466 dxgi_sample_desc_from_wined3d(&desc->SampleDesc,
467 wined3d_desc.multisample_type, wined3d_desc.multisample_quality);
468 desc->BufferUsage = dxgi_usage_from_wined3d_usage(wined3d_desc.backbuffer_usage);
469 desc->BufferCount = wined3d_desc.backbuffer_count;
470 desc->Scaling = DXGI_SCALING_STRETCH;
471 desc->SwapEffect = DXGI_SWAP_EFFECT_DISCARD;
472 desc->AlphaMode = DXGI_ALPHA_MODE_IGNORE;
473 desc->Flags = dxgi_swapchain_flags_from_wined3d(wined3d_desc.flags);
475 return S_OK;
478 static HRESULT STDMETHODCALLTYPE d3d11_swapchain_GetFullscreenDesc(IDXGISwapChain1 *iface,
479 DXGI_SWAP_CHAIN_FULLSCREEN_DESC *desc)
481 struct d3d11_swapchain *swapchain = d3d11_swapchain_from_IDXGISwapChain1(iface);
482 struct wined3d_swapchain_desc wined3d_desc;
484 TRACE("iface %p, desc %p.\n", iface, desc);
486 if (!desc)
488 WARN("Invalid pointer.\n");
489 return E_INVALIDARG;
492 wined3d_mutex_lock();
493 wined3d_swapchain_get_desc(swapchain->wined3d_swapchain, &wined3d_desc);
494 wined3d_mutex_unlock();
496 FIXME("Ignoring ScanlineOrdering and Scaling.\n");
498 desc->RefreshRate.Numerator = wined3d_desc.refresh_rate;
499 desc->RefreshRate.Denominator = 1;
500 desc->ScanlineOrdering = DXGI_MODE_SCANLINE_ORDER_UNSPECIFIED;
501 desc->Scaling = DXGI_MODE_SCALING_UNSPECIFIED;
502 desc->Windowed = wined3d_desc.windowed;
504 return S_OK;
507 static HRESULT STDMETHODCALLTYPE d3d11_swapchain_GetHwnd(IDXGISwapChain1 *iface, HWND *hwnd)
509 struct d3d11_swapchain *swapchain = d3d11_swapchain_from_IDXGISwapChain1(iface);
510 struct wined3d_swapchain_desc wined3d_desc;
512 TRACE("iface %p, hwnd %p.\n", iface, hwnd);
514 if (!hwnd)
516 WARN("Invalid pointer.\n");
517 return DXGI_ERROR_INVALID_CALL;
520 wined3d_mutex_lock();
521 wined3d_swapchain_get_desc(swapchain->wined3d_swapchain, &wined3d_desc);
522 wined3d_mutex_unlock();
524 *hwnd = wined3d_desc.device_window;
525 return S_OK;
528 static HRESULT STDMETHODCALLTYPE d3d11_swapchain_GetCoreWindow(IDXGISwapChain1 *iface,
529 REFIID iid, void **core_window)
531 FIXME("iface %p, iid %s, core_window %p stub!\n", iface, debugstr_guid(iid), core_window);
533 if (core_window)
534 *core_window = NULL;
536 return DXGI_ERROR_INVALID_CALL;
539 static HRESULT STDMETHODCALLTYPE d3d11_swapchain_Present1(IDXGISwapChain1 *iface,
540 UINT sync_interval, UINT flags, const DXGI_PRESENT_PARAMETERS *present_parameters)
542 struct d3d11_swapchain *swapchain = d3d11_swapchain_from_IDXGISwapChain1(iface);
543 HRESULT hr;
545 TRACE("iface %p, sync_interval %u, flags %#x, present_parameters %p.\n",
546 iface, sync_interval, flags, present_parameters);
548 if (sync_interval > 4)
550 WARN("Invalid sync interval %u.\n", sync_interval);
551 return DXGI_ERROR_INVALID_CALL;
554 if (flags & ~DXGI_PRESENT_TEST)
555 FIXME("Unimplemented flags %#x.\n", flags);
556 if (flags & DXGI_PRESENT_TEST)
558 WARN("Returning S_OK for DXGI_PRESENT_TEST.\n");
559 return S_OK;
562 if (present_parameters)
563 FIXME("Ignored present parameters %p.\n", present_parameters);
565 wined3d_mutex_lock();
566 hr = wined3d_swapchain_present(swapchain->wined3d_swapchain, NULL, NULL, NULL, sync_interval, 0);
567 wined3d_mutex_unlock();
569 return hr;
572 static BOOL STDMETHODCALLTYPE d3d11_swapchain_IsTemporaryMonoSupported(IDXGISwapChain1 *iface)
574 FIXME("iface %p stub!\n", iface);
576 return FALSE;
579 static HRESULT STDMETHODCALLTYPE d3d11_swapchain_GetRestrictToOutput(IDXGISwapChain1 *iface, IDXGIOutput **output)
581 FIXME("iface %p, output %p stub!\n", iface, output);
583 if (!output)
585 WARN("Invalid pointer.\n");
586 return E_INVALIDARG;
589 *output = NULL;
590 return E_NOTIMPL;
593 static HRESULT STDMETHODCALLTYPE d3d11_swapchain_SetBackgroundColor(IDXGISwapChain1 *iface, const DXGI_RGBA *color)
595 FIXME("iface %p, color %p stub!\n", iface, color);
597 return E_NOTIMPL;
600 static HRESULT STDMETHODCALLTYPE d3d11_swapchain_GetBackgroundColor(IDXGISwapChain1 *iface, DXGI_RGBA *color)
602 FIXME("iface %p, color %p stub!\n", iface, color);
604 return E_NOTIMPL;
607 static HRESULT STDMETHODCALLTYPE d3d11_swapchain_SetRotation(IDXGISwapChain1 *iface, DXGI_MODE_ROTATION rotation)
609 FIXME("iface %p, rotation %#x stub!\n", iface, rotation);
611 return E_NOTIMPL;
614 static HRESULT STDMETHODCALLTYPE d3d11_swapchain_GetRotation(IDXGISwapChain1 *iface, DXGI_MODE_ROTATION *rotation)
616 FIXME("iface %p, rotation %p stub!\n", iface, rotation);
618 return E_NOTIMPL;
621 static const struct IDXGISwapChain1Vtbl d3d11_swapchain_vtbl =
623 /* IUnknown methods */
624 d3d11_swapchain_QueryInterface,
625 d3d11_swapchain_AddRef,
626 d3d11_swapchain_Release,
627 /* IDXGIObject methods */
628 d3d11_swapchain_SetPrivateData,
629 d3d11_swapchain_SetPrivateDataInterface,
630 d3d11_swapchain_GetPrivateData,
631 d3d11_swapchain_GetParent,
632 /* IDXGIDeviceSubObject methods */
633 d3d11_swapchain_GetDevice,
634 /* IDXGISwapChain methods */
635 d3d11_swapchain_Present,
636 d3d11_swapchain_GetBuffer,
637 d3d11_swapchain_SetFullscreenState,
638 d3d11_swapchain_GetFullscreenState,
639 d3d11_swapchain_GetDesc,
640 d3d11_swapchain_ResizeBuffers,
641 d3d11_swapchain_ResizeTarget,
642 d3d11_swapchain_GetContainingOutput,
643 d3d11_swapchain_GetFrameStatistics,
644 d3d11_swapchain_GetLastPresentCount,
645 /* IDXGISwapChain1 methods */
646 d3d11_swapchain_GetDesc1,
647 d3d11_swapchain_GetFullscreenDesc,
648 d3d11_swapchain_GetHwnd,
649 d3d11_swapchain_GetCoreWindow,
650 d3d11_swapchain_Present1,
651 d3d11_swapchain_IsTemporaryMonoSupported,
652 d3d11_swapchain_GetRestrictToOutput,
653 d3d11_swapchain_SetBackgroundColor,
654 d3d11_swapchain_GetBackgroundColor,
655 d3d11_swapchain_SetRotation,
656 d3d11_swapchain_GetRotation,
659 static void STDMETHODCALLTYPE d3d11_swapchain_wined3d_object_released(void *parent)
661 struct d3d11_swapchain *swapchain = parent;
663 wined3d_private_store_cleanup(&swapchain->private_store);
664 heap_free(parent);
667 static const struct wined3d_parent_ops d3d11_swapchain_wined3d_parent_ops =
669 d3d11_swapchain_wined3d_object_released,
672 HRESULT d3d11_swapchain_init(struct d3d11_swapchain *swapchain, struct dxgi_device *device,
673 struct wined3d_swapchain_desc *desc, BOOL implicit)
675 HRESULT hr;
678 * A reference to the implicit swapchain is held by the wined3d device.
679 * In order to avoid circular references we do not keep a reference
680 * to the device in the implicit swapchain.
682 if (!implicit)
684 if (FAILED(hr = IWineDXGIAdapter_GetParent(device->adapter, &IID_IDXGIFactory,
685 (void **)&swapchain->factory)))
687 WARN("Failed to get adapter parent, hr %#x.\n", hr);
688 return hr;
690 IWineDXGIDevice_AddRef(swapchain->device = &device->IWineDXGIDevice_iface);
692 else
694 swapchain->device = NULL;
695 swapchain->factory = NULL;
698 swapchain->IDXGISwapChain1_iface.lpVtbl = &d3d11_swapchain_vtbl;
699 swapchain->refcount = 1;
700 wined3d_mutex_lock();
701 wined3d_private_store_init(&swapchain->private_store);
703 if (!desc->windowed && (!desc->backbuffer_width || !desc->backbuffer_height))
704 FIXME("Fullscreen swapchain with back buffer width/height equal to 0 not supported properly.\n");
706 swapchain->fullscreen = !desc->windowed;
707 desc->windowed = TRUE;
708 if (FAILED(hr = wined3d_swapchain_create(device->wined3d_device, desc, swapchain,
709 &d3d11_swapchain_wined3d_parent_ops, &swapchain->wined3d_swapchain)))
711 WARN("Failed to create wined3d swapchain, hr %#x.\n", hr);
712 goto cleanup;
715 swapchain->target = NULL;
716 if (swapchain->fullscreen)
718 desc->windowed = FALSE;
719 if (FAILED(hr = wined3d_swapchain_set_fullscreen(swapchain->wined3d_swapchain,
720 desc, NULL)))
722 WARN("Failed to set fullscreen state, hr %#x.\n", hr);
723 wined3d_swapchain_decref(swapchain->wined3d_swapchain);
724 goto cleanup;
727 if (FAILED(hr = IDXGISwapChain1_GetContainingOutput(&swapchain->IDXGISwapChain1_iface,
728 &swapchain->target)))
730 WARN("Failed to get target output for fullscreen swapchain, hr %#x.\n", hr);
731 wined3d_swapchain_decref(swapchain->wined3d_swapchain);
732 goto cleanup;
735 wined3d_mutex_unlock();
737 return S_OK;
739 cleanup:
740 wined3d_private_store_cleanup(&swapchain->private_store);
741 wined3d_mutex_unlock();
742 if (swapchain->factory)
743 IDXGIFactory_Release(swapchain->factory);
744 if (swapchain->device)
745 IWineDXGIDevice_Release(swapchain->device);
746 return hr;
749 HRESULT d3d11_swapchain_create(IWineDXGIDevice *device, HWND window, const DXGI_SWAP_CHAIN_DESC1 *swapchain_desc,
750 const DXGI_SWAP_CHAIN_FULLSCREEN_DESC *fullscreen_desc, IDXGISwapChain1 **swapchain)
752 struct wined3d_swapchain *wined3d_swapchain;
753 struct wined3d_swapchain_desc wined3d_desc;
754 HRESULT hr;
756 if (swapchain_desc->Scaling != DXGI_SCALING_STRETCH)
757 FIXME("Ignoring scaling %#x.\n", swapchain_desc->Scaling);
758 if (swapchain_desc->AlphaMode != DXGI_ALPHA_MODE_IGNORE)
759 FIXME("Ignoring alpha mode %#x.\n", swapchain_desc->AlphaMode);
760 if (fullscreen_desc && fullscreen_desc->ScanlineOrdering)
761 FIXME("Unhandled scanline ordering %#x.\n", fullscreen_desc->ScanlineOrdering);
762 if (fullscreen_desc && fullscreen_desc->Scaling)
763 FIXME("Unhandled mode scaling %#x.\n", fullscreen_desc->Scaling);
765 switch (swapchain_desc->SwapEffect)
767 case DXGI_SWAP_EFFECT_DISCARD:
768 wined3d_desc.swap_effect = WINED3D_SWAP_EFFECT_DISCARD;
769 break;
770 case DXGI_SWAP_EFFECT_SEQUENTIAL:
771 wined3d_desc.swap_effect = WINED3D_SWAP_EFFECT_SEQUENTIAL;
772 break;
773 case DXGI_SWAP_EFFECT_FLIP_DISCARD:
774 wined3d_desc.swap_effect = WINED3D_SWAP_EFFECT_FLIP_DISCARD;
775 break;
776 case DXGI_SWAP_EFFECT_FLIP_SEQUENTIAL:
777 wined3d_desc.swap_effect = WINED3D_SWAP_EFFECT_FLIP_SEQUENTIAL;
778 break;
779 default:
780 WARN("Invalid swap effect %#x.\n", swapchain_desc->SwapEffect);
781 return DXGI_ERROR_INVALID_CALL;
784 wined3d_desc.backbuffer_width = swapchain_desc->Width;
785 wined3d_desc.backbuffer_height = swapchain_desc->Height;
786 wined3d_desc.backbuffer_format = wined3dformat_from_dxgi_format(swapchain_desc->Format);
787 wined3d_desc.backbuffer_count = swapchain_desc->BufferCount;
788 wined3d_desc.backbuffer_usage = wined3d_usage_from_dxgi_usage(swapchain_desc->BufferUsage);
789 wined3d_sample_desc_from_dxgi(&wined3d_desc.multisample_type,
790 &wined3d_desc.multisample_quality, &swapchain_desc->SampleDesc);
791 wined3d_desc.device_window = window;
792 wined3d_desc.windowed = fullscreen_desc ? fullscreen_desc->Windowed : TRUE;
793 wined3d_desc.enable_auto_depth_stencil = FALSE;
794 wined3d_desc.auto_depth_stencil_format = 0;
795 wined3d_desc.flags = wined3d_swapchain_flags_from_dxgi(swapchain_desc->Flags);
796 wined3d_desc.refresh_rate = fullscreen_desc ? dxgi_rational_to_uint(&fullscreen_desc->RefreshRate) : 0;
797 wined3d_desc.auto_restore_display_mode = TRUE;
799 if (FAILED(hr = IWineDXGIDevice_create_swapchain(device, &wined3d_desc, FALSE, &wined3d_swapchain)))
801 WARN("Failed to create swapchain, hr %#x.\n", hr);
802 return hr;
805 wined3d_mutex_lock();
806 *swapchain = wined3d_swapchain_get_parent(wined3d_swapchain);
807 wined3d_mutex_unlock();
809 return S_OK;
812 #ifdef SONAME_LIBVKD3D
814 static PFN_vkd3d_acquire_vk_queue vkd3d_acquire_vk_queue;
815 static PFN_vkd3d_create_image_resource vkd3d_create_image_resource;
816 static PFN_vkd3d_get_vk_device vkd3d_get_vk_device;
817 static PFN_vkd3d_get_vk_format vkd3d_get_vk_format;
818 static PFN_vkd3d_get_vk_physical_device vkd3d_get_vk_physical_device;
819 static PFN_vkd3d_get_vk_queue_family_index vkd3d_get_vk_queue_family_index;
820 static PFN_vkd3d_instance_from_device vkd3d_instance_from_device;
821 static PFN_vkd3d_instance_get_vk_instance vkd3d_instance_get_vk_instance;
822 static PFN_vkd3d_release_vk_queue vkd3d_release_vk_queue;
823 static PFN_vkd3d_resource_decref vkd3d_resource_decref;
824 static PFN_vkd3d_resource_incref vkd3d_resource_incref;
826 struct dxgi_vk_funcs
828 PFN_vkAcquireNextImageKHR p_vkAcquireNextImageKHR;
829 PFN_vkAllocateCommandBuffers p_vkAllocateCommandBuffers;
830 PFN_vkAllocateMemory p_vkAllocateMemory;
831 PFN_vkBeginCommandBuffer p_vkBeginCommandBuffer;
832 PFN_vkBindImageMemory p_vkBindImageMemory;
833 PFN_vkCmdBlitImage p_vkCmdBlitImage;
834 PFN_vkCmdPipelineBarrier p_vkCmdPipelineBarrier;
835 PFN_vkCreateCommandPool p_vkCreateCommandPool;
836 PFN_vkCreateFence p_vkCreateFence;
837 PFN_vkCreateImage p_vkCreateImage;
838 PFN_vkCreateSemaphore p_vkCreateSemaphore;
839 PFN_vkCreateSwapchainKHR p_vkCreateSwapchainKHR;
840 PFN_vkCreateWin32SurfaceKHR p_vkCreateWin32SurfaceKHR;
841 PFN_vkDestroyCommandPool p_vkDestroyCommandPool;
842 PFN_vkDestroyFence p_vkDestroyFence;
843 PFN_vkDestroyImage p_vkDestroyImage;
844 PFN_vkDestroySemaphore p_vkDestroySemaphore;
845 PFN_vkDestroySurfaceKHR p_vkDestroySurfaceKHR;
846 PFN_vkDestroySwapchainKHR p_vkDestroySwapchainKHR;
847 PFN_vkEndCommandBuffer p_vkEndCommandBuffer;
848 PFN_vkFreeMemory p_vkFreeMemory;
849 PFN_vkGetImageMemoryRequirements p_vkGetImageMemoryRequirements;
850 PFN_vkGetInstanceProcAddr p_vkGetInstanceProcAddr;
851 PFN_vkGetPhysicalDeviceMemoryProperties p_vkGetPhysicalDeviceMemoryProperties;
852 PFN_vkGetPhysicalDeviceSurfaceCapabilitiesKHR p_vkGetPhysicalDeviceSurfaceCapabilitiesKHR;
853 PFN_vkGetPhysicalDeviceSurfaceFormatsKHR p_vkGetPhysicalDeviceSurfaceFormatsKHR;
854 PFN_vkGetPhysicalDeviceSurfacePresentModesKHR p_vkGetPhysicalDeviceSurfacePresentModesKHR;
855 PFN_vkGetPhysicalDeviceSurfaceSupportKHR p_vkGetPhysicalDeviceSurfaceSupportKHR;
856 PFN_vkGetPhysicalDeviceWin32PresentationSupportKHR p_vkGetPhysicalDeviceWin32PresentationSupportKHR;
857 PFN_vkGetSwapchainImagesKHR p_vkGetSwapchainImagesKHR;
858 PFN_vkQueuePresentKHR p_vkQueuePresentKHR;
859 PFN_vkQueueSubmit p_vkQueueSubmit;
860 PFN_vkQueueWaitIdle p_vkQueueWaitIdle;
861 PFN_vkResetFences p_vkResetFences;
862 PFN_vkWaitForFences p_vkWaitForFences;
865 static HRESULT hresult_from_vk_result(VkResult vr)
867 switch (vr)
869 case VK_SUCCESS:
870 return S_OK;
871 case VK_ERROR_OUT_OF_HOST_MEMORY:
872 case VK_ERROR_OUT_OF_DEVICE_MEMORY:
873 return E_OUTOFMEMORY;
874 default:
875 FIXME("Unhandled VkResult %d.\n", vr);
876 return E_FAIL;
880 struct d3d12_swapchain
882 IDXGISwapChain3 IDXGISwapChain3_iface;
883 LONG refcount;
884 struct wined3d_private_store private_store;
886 VkSwapchainKHR vk_swapchain;
887 VkSurfaceKHR vk_surface;
888 VkFence vk_fence;
889 VkInstance vk_instance;
890 VkDevice vk_device;
891 VkPhysicalDevice vk_physical_device;
892 VkDeviceMemory vk_memory;
893 VkCommandPool vk_cmd_pool;
894 VkImage vk_images[DXGI_MAX_SWAP_CHAIN_BUFFERS];
895 VkCommandBuffer vk_cmd_buffers[DXGI_MAX_SWAP_CHAIN_BUFFERS];
896 VkSemaphore vk_semaphores[DXGI_MAX_SWAP_CHAIN_BUFFERS];
897 ID3D12Resource *buffers[DXGI_MAX_SWAP_CHAIN_BUFFERS];
898 unsigned int buffer_count;
900 uint32_t current_buffer_index;
901 struct dxgi_vk_funcs vk_funcs;
903 ID3D12CommandQueue *command_queue;
904 ID3D12Device *device;
905 IWineDXGIFactory *factory;
907 HWND window;
908 DXGI_SWAP_CHAIN_DESC1 desc;
909 DXGI_SWAP_CHAIN_FULLSCREEN_DESC fullscreen_desc;
912 static DXGI_FORMAT dxgi_format_from_vk_format(VkFormat vk_format)
914 switch (vk_format)
916 case VK_FORMAT_B8G8R8A8_SRGB: return DXGI_FORMAT_B8G8R8A8_UNORM_SRGB;
917 case VK_FORMAT_B8G8R8A8_UNORM: return DXGI_FORMAT_B8G8R8A8_UNORM;
918 case VK_FORMAT_R8G8B8A8_SRGB: return DXGI_FORMAT_R8G8B8A8_UNORM_SRGB;
919 case VK_FORMAT_R8G8B8A8_UNORM: return DXGI_FORMAT_R8G8B8A8_UNORM;
920 default:
921 WARN("Unhandled format %#x.\n", vk_format);
922 return DXGI_FORMAT_UNKNOWN;
926 static VkFormat get_swapchain_fallback_format(VkFormat vk_format)
928 switch (vk_format)
930 case VK_FORMAT_R8G8B8A8_SRGB: return VK_FORMAT_B8G8R8A8_SRGB;
931 case VK_FORMAT_R8G8B8A8_UNORM: return VK_FORMAT_B8G8R8A8_UNORM;
932 default:
933 WARN("Unhandled format %#x.\n", vk_format);
934 return VK_FORMAT_UNDEFINED;
938 static HRESULT select_vk_format(const struct dxgi_vk_funcs *vk_funcs,
939 VkPhysicalDevice vk_physical_device, VkSurfaceKHR vk_surface,
940 const DXGI_SWAP_CHAIN_DESC1 *swapchain_desc, VkFormat *vk_format)
942 VkSurfaceFormatKHR *formats;
943 uint32_t format_count;
944 VkFormat format;
945 unsigned int i;
946 VkResult vr;
948 *vk_format = VK_FORMAT_UNDEFINED;
950 format = vkd3d_get_vk_format(swapchain_desc->Format);
952 vr = vk_funcs->p_vkGetPhysicalDeviceSurfaceFormatsKHR(vk_physical_device, vk_surface, &format_count, NULL);
953 if (vr < 0 || !format_count)
955 WARN("Failed to get supported surface formats, vr %d.\n", vr);
956 return DXGI_ERROR_INVALID_CALL;
959 if (!(formats = heap_calloc(format_count, sizeof(*formats))))
960 return E_OUTOFMEMORY;
962 if ((vr = vk_funcs->p_vkGetPhysicalDeviceSurfaceFormatsKHR(vk_physical_device,
963 vk_surface, &format_count, formats)) < 0)
965 WARN("Failed to enumerate supported surface formats, vr %d.\n", vr);
966 heap_free(formats);
967 return hresult_from_vk_result(vr);
970 for (i = 0; i < format_count; ++i)
972 if (formats[i].format == format && formats[i].colorSpace == VK_COLOR_SPACE_SRGB_NONLINEAR_KHR)
973 break;
975 if (i == format_count)
977 /* Try to create a swapchain with format conversion. */
978 format = get_swapchain_fallback_format(format);
979 WARN("Failed to find Vulkan swapchain format for %s.\n", debug_dxgi_format(swapchain_desc->Format));
980 for (i = 0; i < format_count; ++i)
982 if (formats[i].format == format && formats[i].colorSpace == VK_COLOR_SPACE_SRGB_NONLINEAR_KHR)
984 format = formats[i].format;
985 break;
989 heap_free(formats);
990 if (i == format_count)
992 FIXME("Failed to find Vulkan swapchain format for %s.\n", debug_dxgi_format(swapchain_desc->Format));
993 return DXGI_ERROR_UNSUPPORTED;
996 TRACE("Using Vulkan swapchain format %#x.\n", format);
998 *vk_format = format;
999 return S_OK;
1002 static HRESULT vk_select_memory_type(const struct dxgi_vk_funcs *vk_funcs,
1003 VkPhysicalDevice vk_physical_device, uint32_t memory_type_mask,
1004 VkMemoryPropertyFlags flags, uint32_t *memory_type_index)
1006 VkPhysicalDeviceMemoryProperties memory_properties;
1007 unsigned int i;
1009 vk_funcs->p_vkGetPhysicalDeviceMemoryProperties(vk_physical_device, &memory_properties);
1010 for (i = 0; i < memory_properties.memoryTypeCount; ++i)
1012 if (!(memory_type_mask & (1u << i)))
1013 continue;
1015 if ((memory_properties.memoryTypes[i].propertyFlags & flags) == flags)
1017 *memory_type_index = i;
1018 return S_OK;
1022 FIXME("Failed to find memory type (allowed types %#x).\n", memory_type_mask);
1023 return E_FAIL;
1026 static HRESULT d3d12_swapchain_create_user_buffers(struct d3d12_swapchain *swapchain,
1027 const DXGI_SWAP_CHAIN_DESC1 *swapchain_desc, VkFormat vk_format)
1029 const struct dxgi_vk_funcs *vk_funcs = &swapchain->vk_funcs;
1030 VkDeviceSize image_offset[DXGI_MAX_SWAP_CHAIN_BUFFERS];
1031 VkDevice vk_device = swapchain->vk_device;
1032 VkMemoryAllocateInfo allocate_info;
1033 VkMemoryRequirements requirements;
1034 VkImageCreateInfo image_info;
1035 uint32_t memory_type_mask;
1036 VkDeviceSize memory_size;
1037 unsigned int i;
1038 VkResult vr;
1039 HRESULT hr;
1041 memset(&image_info, 0, sizeof(image_info));
1042 image_info.sType = VK_STRUCTURE_TYPE_IMAGE_CREATE_INFO;
1043 image_info.flags = VK_IMAGE_CREATE_MUTABLE_FORMAT_BIT;
1044 image_info.imageType = VK_IMAGE_TYPE_2D;
1045 image_info.format = vk_format;
1046 image_info.extent.width = swapchain_desc->Width;
1047 image_info.extent.height = swapchain_desc->Height;
1048 image_info.extent.depth = 1;
1049 image_info.mipLevels = 1;
1050 image_info.arrayLayers = 1;
1051 image_info.samples = VK_SAMPLE_COUNT_1_BIT;
1052 image_info.tiling = VK_IMAGE_TILING_OPTIMAL;
1053 image_info.usage = VK_IMAGE_USAGE_TRANSFER_SRC_BIT
1054 | VK_IMAGE_USAGE_TRANSFER_DST_BIT
1055 | VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT;
1056 image_info.sharingMode = VK_SHARING_MODE_EXCLUSIVE;
1057 image_info.queueFamilyIndexCount = 0;
1058 image_info.pQueueFamilyIndices = NULL;
1059 image_info.initialLayout = VK_IMAGE_LAYOUT_UNDEFINED;
1061 for (i = 0; i < swapchain->buffer_count; ++i)
1063 if ((vr = vk_funcs->p_vkCreateImage(vk_device, &image_info, NULL, &swapchain->vk_images[i])) < 0)
1065 WARN("Failed to create Vulkan image, vr %d.\n", vr);
1066 swapchain->vk_images[i] = VK_NULL_HANDLE;
1067 return hresult_from_vk_result(vr);
1071 memory_size = 0;
1072 memory_type_mask = ~0u;
1073 for (i = 0; i < swapchain->buffer_count; ++i)
1075 vk_funcs->p_vkGetImageMemoryRequirements(vk_device, swapchain->vk_images[i], &requirements);
1077 TRACE("Size %s, alignment %s, memory types %#x.\n",
1078 wine_dbgstr_longlong(requirements.size), wine_dbgstr_longlong(requirements.alignment),
1079 requirements.memoryTypeBits);
1081 image_offset[i] = (memory_size + (requirements.alignment - 1)) & ~(requirements.alignment - 1);
1082 memory_size = image_offset[i] + requirements.size;
1084 memory_type_mask &= requirements.memoryTypeBits;
1087 TRACE("Allocating %s bytes for user images.\n", wine_dbgstr_longlong(memory_size));
1089 allocate_info.sType = VK_STRUCTURE_TYPE_MEMORY_ALLOCATE_INFO;
1090 allocate_info.pNext = NULL;
1091 allocate_info.allocationSize = memory_size;
1093 if (FAILED(hr = vk_select_memory_type(vk_funcs, swapchain->vk_physical_device,
1094 memory_type_mask, VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT, &allocate_info.memoryTypeIndex)))
1095 return hr;
1097 if ((vr = vk_funcs->p_vkAllocateMemory(vk_device, &allocate_info, NULL, &swapchain->vk_memory)) < 0)
1099 WARN("Failed to allocate device memory, vr %d.\n", vr);
1100 swapchain->vk_memory = VK_NULL_HANDLE;
1101 return hresult_from_vk_result(vr);
1104 for (i = 0; i < swapchain->buffer_count; ++i)
1106 if ((vr = vk_funcs->p_vkBindImageMemory(vk_device, swapchain->vk_images[i],
1107 swapchain->vk_memory, image_offset[i])) < 0)
1109 WARN("Failed to bind image memory, vr %d.\n", vr);
1110 return hresult_from_vk_result(vr);
1114 return S_OK;
1117 static void vk_cmd_image_barrier(const struct dxgi_vk_funcs *vk_funcs, VkCommandBuffer cmd_buffer,
1118 VkPipelineStageFlags src_stage_mask, VkPipelineStageFlags dst_stage_mask,
1119 VkAccessFlags src_access_mask, VkAccessFlags dst_access_mask,
1120 VkImageLayout old_layout, VkImageLayout new_layout, VkImage image)
1122 VkImageMemoryBarrier barrier;
1124 barrier.sType = VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER;
1125 barrier.pNext = NULL;
1126 barrier.srcAccessMask = src_access_mask;
1127 barrier.dstAccessMask = dst_access_mask;
1128 barrier.oldLayout = old_layout;
1129 barrier.newLayout = new_layout;
1130 barrier.srcQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED;
1131 barrier.dstQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED;
1132 barrier.image = image;
1133 barrier.subresourceRange.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT;
1134 barrier.subresourceRange.baseMipLevel = 0;
1135 barrier.subresourceRange.levelCount = VK_REMAINING_MIP_LEVELS;
1136 barrier.subresourceRange.baseArrayLayer = 0;
1137 barrier.subresourceRange.layerCount = VK_REMAINING_ARRAY_LAYERS;
1139 vk_funcs->p_vkCmdPipelineBarrier(cmd_buffer,
1140 src_stage_mask, dst_stage_mask, 0, 0, NULL, 0, NULL, 1, &barrier);
1143 static HRESULT d3d12_swapchain_prepare_command_buffers(struct d3d12_swapchain *swapchain,
1144 const DXGI_SWAP_CHAIN_DESC1 *swapchain_desc, uint32_t queue_family_index,
1145 VkImage vk_swapchain_images[DXGI_MAX_SWAP_CHAIN_BUFFERS])
1147 const struct dxgi_vk_funcs *vk_funcs = &swapchain->vk_funcs;
1148 VkDevice vk_device = swapchain->vk_device;
1149 VkCommandBufferAllocateInfo allocate_info;
1150 VkSemaphoreCreateInfo semaphore_info;
1151 VkCommandBufferBeginInfo begin_info;
1152 VkCommandPoolCreateInfo pool_info;
1153 VkImageBlit blit;
1154 unsigned int i;
1155 VkResult vr;
1157 pool_info.sType = VK_STRUCTURE_TYPE_COMMAND_POOL_CREATE_INFO;
1158 pool_info.pNext = NULL;
1159 pool_info.flags = 0;
1160 pool_info.queueFamilyIndex = queue_family_index;
1162 if ((vr = vk_funcs->p_vkCreateCommandPool(vk_device, &pool_info,
1163 NULL, &swapchain->vk_cmd_pool)) < 0)
1165 WARN("Failed to create command pool, vr %d.\n", vr);
1166 swapchain->vk_cmd_pool = VK_NULL_HANDLE;
1167 return hresult_from_vk_result(vr);
1170 allocate_info.sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_ALLOCATE_INFO;
1171 allocate_info.pNext = NULL;
1172 allocate_info.commandPool = swapchain->vk_cmd_pool;
1173 allocate_info.level = VK_COMMAND_BUFFER_LEVEL_PRIMARY;
1174 allocate_info.commandBufferCount = swapchain->buffer_count;
1176 if ((vr = vk_funcs->p_vkAllocateCommandBuffers(vk_device, &allocate_info,
1177 swapchain->vk_cmd_buffers)) < 0)
1179 WARN("Failed to allocate command buffers, vr %d.\n", vr);
1180 return hresult_from_vk_result(vr);
1183 for (i = 0; i < swapchain->buffer_count; ++i)
1185 VkCommandBuffer vk_cmd_buffer = swapchain->vk_cmd_buffers[i];
1187 begin_info.sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_BEGIN_INFO;
1188 begin_info.pNext = NULL;
1189 begin_info.flags = 0;
1190 begin_info.pInheritanceInfo = NULL;
1192 if ((vr = vk_funcs->p_vkBeginCommandBuffer(vk_cmd_buffer, &begin_info)) < 0)
1194 WARN("Failed to begin command buffer, vr %d.\n", vr);
1195 return hresult_from_vk_result(vr);
1198 vk_cmd_image_barrier(vk_funcs, vk_cmd_buffer,
1199 VK_PIPELINE_STAGE_TOP_OF_PIPE_BIT, VK_PIPELINE_STAGE_TRANSFER_BIT,
1200 0, VK_ACCESS_TRANSFER_WRITE_BIT,
1201 VK_IMAGE_LAYOUT_UNDEFINED, VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL,
1202 vk_swapchain_images[i]);
1204 blit.srcSubresource.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT;
1205 blit.srcSubresource.mipLevel = 0;
1206 blit.srcSubresource.baseArrayLayer = 0;
1207 blit.srcSubresource.layerCount = 1;
1208 blit.srcOffsets[0].x = 0;
1209 blit.srcOffsets[0].y = 0;
1210 blit.srcOffsets[0].z = 0;
1211 blit.srcOffsets[1].x = swapchain_desc->Width;
1212 blit.srcOffsets[1].y = swapchain_desc->Height;
1213 blit.srcOffsets[1].z = 1;
1214 blit.dstSubresource = blit.srcSubresource;
1215 blit.dstOffsets[0] = blit.srcOffsets[0];
1216 blit.dstOffsets[1] = blit.srcOffsets[1];
1218 vk_funcs->p_vkCmdBlitImage(vk_cmd_buffer,
1219 swapchain->vk_images[i], VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL,
1220 vk_swapchain_images[i], VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL,
1221 1, &blit, VK_FILTER_NEAREST);
1223 vk_cmd_image_barrier(vk_funcs, vk_cmd_buffer,
1224 VK_PIPELINE_STAGE_TRANSFER_BIT, VK_PIPELINE_STAGE_BOTTOM_OF_PIPE_BIT,
1225 VK_ACCESS_TRANSFER_WRITE_BIT, 0,
1226 VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, VK_IMAGE_LAYOUT_PRESENT_SRC_KHR,
1227 vk_swapchain_images[i]);
1229 if ((vr = vk_funcs->p_vkEndCommandBuffer(vk_cmd_buffer)) < 0)
1231 WARN("Failed to end command buffer, vr %d.\n", vr);
1232 return hresult_from_vk_result(vr);
1236 for (i = 0; i < swapchain->buffer_count; ++i)
1238 semaphore_info.sType = VK_STRUCTURE_TYPE_SEMAPHORE_CREATE_INFO;
1239 semaphore_info.pNext = NULL;
1240 semaphore_info.flags = 0;
1242 if ((vr = vk_funcs->p_vkCreateSemaphore(vk_device, &semaphore_info,
1243 NULL, &swapchain->vk_semaphores[i])) < 0)
1245 WARN("Failed to create semaphore, vr %d.\n", vr);
1246 swapchain->vk_semaphores[i] = VK_NULL_HANDLE;
1247 return hresult_from_vk_result(vr);
1251 return S_OK;
1254 static HRESULT d3d12_swapchain_create_buffers(struct d3d12_swapchain *swapchain,
1255 ID3D12Device *device, ID3D12CommandQueue *queue,
1256 const DXGI_SWAP_CHAIN_DESC1 *swapchain_desc, VkFormat vk_swapchain_format, VkFormat vk_format)
1258 const struct dxgi_vk_funcs *vk_funcs = &swapchain->vk_funcs;
1259 VkImage vk_swapchain_images[DXGI_MAX_SWAP_CHAIN_BUFFERS];
1260 struct vkd3d_image_resource_create_info resource_info;
1261 VkSwapchainKHR vk_swapchain = swapchain->vk_swapchain;
1262 VkDevice vk_device = swapchain->vk_device;
1263 uint32_t image_count, queue_family_index;
1264 D3D12_COMMAND_QUEUE_DESC queue_desc;
1265 unsigned int i;
1266 VkResult vr;
1267 HRESULT hr;
1269 if ((vr = vk_funcs->p_vkGetSwapchainImagesKHR(vk_device, vk_swapchain, &image_count, NULL)) < 0)
1271 WARN("Failed to get Vulkan swapchain images, vr %d.\n", vr);
1272 return hresult_from_vk_result(vr);
1274 if (image_count != swapchain_desc->BufferCount)
1275 FIXME("Got %u swapchain images, expected %u.\n", image_count, swapchain_desc->BufferCount);
1276 if (image_count > ARRAY_SIZE(vk_swapchain_images))
1277 return E_FAIL;
1278 swapchain->buffer_count = image_count;
1279 if ((vr = vk_funcs->p_vkGetSwapchainImagesKHR(vk_device, vk_swapchain,
1280 &image_count, vk_swapchain_images)) < 0)
1282 WARN("Failed to get Vulkan swapchain images, vr %d.\n", vr);
1283 return hresult_from_vk_result(vr);
1286 resource_info.type = VKD3D_STRUCTURE_TYPE_IMAGE_RESOURCE_CREATE_INFO;
1287 resource_info.next = NULL;
1288 resource_info.desc.Dimension = D3D12_RESOURCE_DIMENSION_TEXTURE2D;
1289 resource_info.desc.Alignment = 0;
1290 resource_info.desc.Width = swapchain_desc->Width;
1291 resource_info.desc.Height = swapchain_desc->Height;
1292 resource_info.desc.DepthOrArraySize = 1;
1293 resource_info.desc.MipLevels = 1;
1294 resource_info.desc.Format = dxgi_format_from_vk_format(vk_format);
1295 resource_info.desc.SampleDesc.Count = 1;
1296 resource_info.desc.SampleDesc.Quality = 0;
1297 resource_info.desc.Layout = D3D12_TEXTURE_LAYOUT_UNKNOWN;
1298 resource_info.desc.Flags = D3D12_RESOURCE_FLAG_ALLOW_RENDER_TARGET;
1299 resource_info.flags = VKD3D_RESOURCE_INITIAL_STATE_TRANSITION | VKD3D_RESOURCE_PRESENT_STATE_TRANSITION;
1301 if (vk_swapchain_format != vk_format)
1303 queue_desc = ID3D12CommandQueue_GetDesc(queue);
1304 if (queue_desc.Type != D3D12_COMMAND_LIST_TYPE_DIRECT)
1306 /* vkCmdBlitImage() is only supported for Graphics queues. */
1307 FIXME("Format conversion not implemented for command queue type %#x.\n", queue_desc.Type);
1308 return E_NOTIMPL;
1310 queue_family_index = vkd3d_get_vk_queue_family_index(queue);
1312 TRACE("Creating user swapchain buffers for format conversion.\n");
1314 if (FAILED(hr = d3d12_swapchain_create_user_buffers(swapchain, swapchain_desc, vk_format)))
1315 return hr;
1317 if (FAILED(hr = d3d12_swapchain_prepare_command_buffers(swapchain, swapchain_desc,
1318 queue_family_index, vk_swapchain_images)))
1319 return hr;
1322 for (i = 0; i < swapchain->buffer_count; ++i)
1324 if (swapchain->vk_images[i])
1326 resource_info.vk_image = swapchain->vk_images[i];
1327 resource_info.present_state = D3D12_RESOURCE_STATE_COPY_SOURCE;
1329 else
1331 resource_info.vk_image = vk_swapchain_images[i];
1332 resource_info.present_state = D3D12_RESOURCE_STATE_PRESENT;
1335 if (FAILED(hr = vkd3d_create_image_resource(device, &resource_info, &swapchain->buffers[i])))
1337 WARN("Failed to create vkd3d resource for Vulkan image %u, hr %#x.\n", i, hr);
1338 return hr;
1341 vkd3d_resource_incref(swapchain->buffers[i]);
1342 ID3D12Resource_Release(swapchain->buffers[i]);
1345 return S_OK;
1348 static void d3d12_swapchain_destroy_buffers(struct d3d12_swapchain *swapchain)
1350 const struct dxgi_vk_funcs *vk_funcs = &swapchain->vk_funcs;
1351 VkQueue vk_queue;
1352 unsigned int i;
1354 if (swapchain->command_queue)
1356 if ((vk_queue = vkd3d_acquire_vk_queue(swapchain->command_queue)))
1358 vk_funcs->p_vkQueueWaitIdle(vk_queue);
1360 vkd3d_release_vk_queue(swapchain->command_queue);
1362 else
1364 WARN("Failed to acquire Vulkan queue.\n");
1368 for (i = 0; i < swapchain->buffer_count; ++i)
1370 if (swapchain->buffers[i])
1372 vkd3d_resource_decref(swapchain->buffers[i]);
1373 swapchain->buffers[i] = NULL;
1376 if (swapchain->vk_device)
1378 vk_funcs->p_vkDestroyImage(swapchain->vk_device, swapchain->vk_images[i], NULL);
1379 swapchain->vk_images[i] = VK_NULL_HANDLE;
1380 vk_funcs->p_vkDestroySemaphore(swapchain->vk_device, swapchain->vk_semaphores[i], NULL);
1381 swapchain->vk_semaphores[i] = VK_NULL_HANDLE;
1385 if (swapchain->vk_device)
1387 vk_funcs->p_vkFreeMemory(swapchain->vk_device, swapchain->vk_memory, NULL);
1388 swapchain->vk_memory = VK_NULL_HANDLE;
1389 vk_funcs->p_vkDestroyCommandPool(swapchain->vk_device, swapchain->vk_cmd_pool, NULL);
1390 swapchain->vk_cmd_pool = VK_NULL_HANDLE;
1394 static inline struct d3d12_swapchain *d3d12_swapchain_from_IDXGISwapChain3(IDXGISwapChain3 *iface)
1396 return CONTAINING_RECORD(iface, struct d3d12_swapchain, IDXGISwapChain3_iface);
1399 /* IUnknown methods */
1401 static HRESULT STDMETHODCALLTYPE d3d12_swapchain_QueryInterface(IDXGISwapChain3 *iface, REFIID iid, void **object)
1403 TRACE("iface %p, iid %s, object %p.\n", iface, debugstr_guid(iid), object);
1405 if (IsEqualGUID(iid, &IID_IUnknown)
1406 || IsEqualGUID(iid, &IID_IDXGIObject)
1407 || IsEqualGUID(iid, &IID_IDXGIDeviceSubObject)
1408 || IsEqualGUID(iid, &IID_IDXGISwapChain)
1409 || IsEqualGUID(iid, &IID_IDXGISwapChain1)
1410 || IsEqualGUID(iid, &IID_IDXGISwapChain2)
1411 || IsEqualGUID(iid, &IID_IDXGISwapChain3))
1413 IUnknown_AddRef(iface);
1414 *object = iface;
1415 return S_OK;
1418 WARN("%s not implemented, returning E_NOINTERFACE.\n", debugstr_guid(iid));
1420 *object = NULL;
1421 return E_NOINTERFACE;
1424 static ULONG STDMETHODCALLTYPE d3d12_swapchain_AddRef(IDXGISwapChain3 *iface)
1426 struct d3d12_swapchain *swapchain = d3d12_swapchain_from_IDXGISwapChain3(iface);
1427 ULONG refcount = InterlockedIncrement(&swapchain->refcount);
1429 TRACE("%p increasing refcount to %u.\n", swapchain, refcount);
1431 return refcount;
1434 static void d3d12_swapchain_destroy(struct d3d12_swapchain *swapchain)
1436 const struct dxgi_vk_funcs *vk_funcs = &swapchain->vk_funcs;
1438 d3d12_swapchain_destroy_buffers(swapchain);
1440 if (swapchain->command_queue)
1441 ID3D12CommandQueue_Release(swapchain->command_queue);
1443 wined3d_private_store_cleanup(&swapchain->private_store);
1445 if (swapchain->vk_device)
1447 vk_funcs->p_vkDestroyFence(swapchain->vk_device, swapchain->vk_fence, NULL);
1448 vk_funcs->p_vkDestroySwapchainKHR(swapchain->vk_device, swapchain->vk_swapchain, NULL);
1451 if (swapchain->vk_instance)
1452 vk_funcs->p_vkDestroySurfaceKHR(swapchain->vk_instance, swapchain->vk_surface, NULL);
1454 if (swapchain->device)
1455 ID3D12Device_Release(swapchain->device);
1457 if (swapchain->factory)
1458 IWineDXGIFactory_Release(swapchain->factory);
1461 static ULONG STDMETHODCALLTYPE d3d12_swapchain_Release(IDXGISwapChain3 *iface)
1463 struct d3d12_swapchain *swapchain = d3d12_swapchain_from_IDXGISwapChain3(iface);
1464 ULONG refcount = InterlockedDecrement(&swapchain->refcount);
1466 TRACE("%p decreasing refcount to %u.\n", swapchain, refcount);
1468 if (!refcount)
1470 d3d12_swapchain_destroy(swapchain);
1471 heap_free(swapchain);
1474 return refcount;
1477 /* IDXGIObject methods */
1479 static HRESULT STDMETHODCALLTYPE d3d12_swapchain_SetPrivateData(IDXGISwapChain3 *iface,
1480 REFGUID guid, UINT data_size, const void *data)
1482 struct d3d12_swapchain *swapchain = d3d12_swapchain_from_IDXGISwapChain3(iface);
1484 TRACE("iface %p, guid %s, data_size %u, data %p.\n", iface, debugstr_guid(guid), data_size, data);
1486 return dxgi_set_private_data(&swapchain->private_store, guid, data_size, data);
1489 static HRESULT STDMETHODCALLTYPE d3d12_swapchain_SetPrivateDataInterface(IDXGISwapChain3 *iface,
1490 REFGUID guid, const IUnknown *object)
1492 struct d3d12_swapchain *swapchain = d3d12_swapchain_from_IDXGISwapChain3(iface);
1494 TRACE("iface %p, guid %s, object %p.\n", iface, debugstr_guid(guid), object);
1496 return dxgi_set_private_data_interface(&swapchain->private_store, guid, object);
1499 static HRESULT STDMETHODCALLTYPE d3d12_swapchain_GetPrivateData(IDXGISwapChain3 *iface,
1500 REFGUID guid, UINT *data_size, void *data)
1502 struct d3d12_swapchain *swapchain = d3d12_swapchain_from_IDXGISwapChain3(iface);
1504 TRACE("iface %p, guid %s, data_size %p, data %p.\n", iface, debugstr_guid(guid), data_size, data);
1506 return dxgi_get_private_data(&swapchain->private_store, guid, data_size, data);
1509 static HRESULT STDMETHODCALLTYPE d3d12_swapchain_GetParent(IDXGISwapChain3 *iface, REFIID iid, void **parent)
1511 struct d3d12_swapchain *swapchain = d3d12_swapchain_from_IDXGISwapChain3(iface);
1513 TRACE("iface %p, iid %s, parent %p.\n", iface, debugstr_guid(iid), parent);
1515 return IWineDXGIFactory_QueryInterface(swapchain->factory, iid, parent);
1518 /* IDXGIDeviceSubObject methods */
1520 static HRESULT STDMETHODCALLTYPE d3d12_swapchain_GetDevice(IDXGISwapChain3 *iface, REFIID iid, void **device)
1522 struct d3d12_swapchain *swapchain = d3d12_swapchain_from_IDXGISwapChain3(iface);
1524 TRACE("iface %p, iid %s, device %p.\n", iface, debugstr_guid(iid), device);
1526 return ID3D12Device_QueryInterface(swapchain->device, iid, device);
1529 /* IDXGISwapChain methods */
1531 static HRESULT STDMETHODCALLTYPE d3d12_swapchain_Present(IDXGISwapChain3 *iface, UINT sync_interval, UINT flags)
1533 struct d3d12_swapchain *swapchain = d3d12_swapchain_from_IDXGISwapChain3(iface);
1535 TRACE("iface %p, sync_interval %u, flags %#x.\n", iface, sync_interval, flags);
1537 return IDXGISwapChain3_Present1(&swapchain->IDXGISwapChain3_iface, sync_interval, flags, NULL);
1540 static HRESULT STDMETHODCALLTYPE d3d12_swapchain_GetBuffer(IDXGISwapChain3 *iface,
1541 UINT buffer_idx, REFIID iid, void **surface)
1543 struct d3d12_swapchain *swapchain = d3d12_swapchain_from_IDXGISwapChain3(iface);
1545 TRACE("iface %p, buffer_idx %u, iid %s, surface %p.\n",
1546 iface, buffer_idx, debugstr_guid(iid), surface);
1548 if (buffer_idx >= swapchain->buffer_count)
1550 WARN("Invalid buffer index %u.\n", buffer_idx);
1551 return DXGI_ERROR_INVALID_CALL;
1554 return ID3D12Resource_QueryInterface(swapchain->buffers[buffer_idx], iid, surface);
1557 static HRESULT STDMETHODCALLTYPE DECLSPEC_HOTPATCH d3d12_swapchain_SetFullscreenState(IDXGISwapChain3 *iface,
1558 BOOL fullscreen, IDXGIOutput *target)
1560 FIXME("iface %p, fullscreen %#x, target %p stub!\n", iface, fullscreen, target);
1562 return E_NOTIMPL;
1565 static HRESULT STDMETHODCALLTYPE d3d12_swapchain_GetFullscreenState(IDXGISwapChain3 *iface,
1566 BOOL *fullscreen, IDXGIOutput **target)
1568 FIXME("iface %p, fullscreen %p, target %p stub!\n", iface, fullscreen, target);
1570 return E_NOTIMPL;
1573 static HRESULT STDMETHODCALLTYPE d3d12_swapchain_GetDesc(IDXGISwapChain3 *iface, DXGI_SWAP_CHAIN_DESC *desc)
1575 struct d3d12_swapchain *swapchain = d3d12_swapchain_from_IDXGISwapChain3(iface);
1576 const DXGI_SWAP_CHAIN_FULLSCREEN_DESC *fullscreen_desc = &swapchain->fullscreen_desc;
1577 const DXGI_SWAP_CHAIN_DESC1 *swapchain_desc = &swapchain->desc;
1579 TRACE("iface %p, desc %p.\n", iface, desc);
1581 if (!desc)
1583 WARN("Invalid pointer.\n");
1584 return E_INVALIDARG;
1587 desc->BufferDesc.Width = swapchain_desc->Width;
1588 desc->BufferDesc.Height = swapchain_desc->Height;
1589 desc->BufferDesc.RefreshRate = fullscreen_desc->RefreshRate;
1590 desc->BufferDesc.Format = swapchain_desc->Format;
1591 desc->BufferDesc.ScanlineOrdering = fullscreen_desc->ScanlineOrdering;
1592 desc->BufferDesc.Scaling = fullscreen_desc->Scaling;
1593 desc->SampleDesc = swapchain_desc->SampleDesc;
1594 desc->BufferUsage = swapchain_desc->BufferUsage;
1595 desc->BufferCount = swapchain_desc->BufferCount;
1596 desc->OutputWindow = swapchain->window;
1597 desc->Windowed = fullscreen_desc->Windowed;
1598 desc->SwapEffect = swapchain_desc->SwapEffect;
1599 desc->Flags = swapchain_desc->Flags;
1601 return S_OK;
1604 static HRESULT STDMETHODCALLTYPE d3d12_swapchain_ResizeBuffers(IDXGISwapChain3 *iface,
1605 UINT buffer_count, UINT width, UINT height, DXGI_FORMAT format, UINT flags)
1607 FIXME("iface %p, buffer_count %u, width %u, height %u, format %s, flags %#x stub!\n",
1608 iface, buffer_count, width, height, debug_dxgi_format(format), flags);
1610 return E_NOTIMPL;
1613 static HRESULT STDMETHODCALLTYPE d3d12_swapchain_ResizeTarget(IDXGISwapChain3 *iface,
1614 const DXGI_MODE_DESC *target_mode_desc)
1616 FIXME("iface %p, target_mode_desc %p stub!\n", iface, target_mode_desc);
1618 return E_NOTIMPL;
1621 static HRESULT STDMETHODCALLTYPE d3d12_swapchain_GetContainingOutput(IDXGISwapChain3 *iface,
1622 IDXGIOutput **output)
1624 FIXME("iface %p, output %p stub!\n", iface, output);
1626 return E_NOTIMPL;
1629 static HRESULT STDMETHODCALLTYPE d3d12_swapchain_GetFrameStatistics(IDXGISwapChain3 *iface,
1630 DXGI_FRAME_STATISTICS *stats)
1632 FIXME("iface %p, stats %p stub!\n", iface, stats);
1634 return E_NOTIMPL;
1637 static HRESULT STDMETHODCALLTYPE d3d12_swapchain_GetLastPresentCount(IDXGISwapChain3 *iface,
1638 UINT *last_present_count)
1640 FIXME("iface %p, last_present_count %p stub!\n", iface, last_present_count);
1642 return E_NOTIMPL;
1645 /* IDXGISwapChain1 methods */
1647 static HRESULT STDMETHODCALLTYPE d3d12_swapchain_GetDesc1(IDXGISwapChain3 *iface, DXGI_SWAP_CHAIN_DESC1 *desc)
1649 struct d3d12_swapchain *swapchain = d3d12_swapchain_from_IDXGISwapChain3(iface);
1651 TRACE("iface %p, desc %p.\n", iface, desc);
1653 if (!desc)
1655 WARN("Invalid pointer.\n");
1656 return E_INVALIDARG;
1659 *desc = swapchain->desc;
1660 return S_OK;
1663 static HRESULT STDMETHODCALLTYPE d3d12_swapchain_GetFullscreenDesc(IDXGISwapChain3 *iface,
1664 DXGI_SWAP_CHAIN_FULLSCREEN_DESC *desc)
1666 struct d3d12_swapchain *swapchain = d3d12_swapchain_from_IDXGISwapChain3(iface);
1668 TRACE("iface %p, desc %p.\n", iface, desc);
1670 if (!desc)
1672 WARN("Invalid pointer.\n");
1673 return E_INVALIDARG;
1676 *desc = swapchain->fullscreen_desc;
1677 return S_OK;
1680 static HRESULT STDMETHODCALLTYPE d3d12_swapchain_GetHwnd(IDXGISwapChain3 *iface, HWND *hwnd)
1682 struct d3d12_swapchain *swapchain = d3d12_swapchain_from_IDXGISwapChain3(iface);
1684 TRACE("iface %p, hwnd %p.\n", iface, hwnd);
1686 if (!hwnd)
1688 WARN("Invalid pointer.\n");
1689 return DXGI_ERROR_INVALID_CALL;
1692 *hwnd = swapchain->window;
1693 return S_OK;
1696 static HRESULT STDMETHODCALLTYPE d3d12_swapchain_GetCoreWindow(IDXGISwapChain3 *iface,
1697 REFIID iid, void **core_window)
1699 FIXME("iface %p, iid %s, core_window %p stub!\n", iface, debugstr_guid(iid), core_window);
1701 if (core_window)
1702 *core_window = NULL;
1704 return DXGI_ERROR_INVALID_CALL;
1707 static HRESULT d3d12_swapchain_acquire_next_image(struct d3d12_swapchain *swapchain)
1709 const struct dxgi_vk_funcs *vk_funcs = &swapchain->vk_funcs;
1710 VkDevice vk_device = swapchain->vk_device;
1711 VkFence vk_fence = swapchain->vk_fence;
1712 VkResult vr;
1714 if ((vr = vk_funcs->p_vkAcquireNextImageKHR(vk_device, swapchain->vk_swapchain, UINT64_MAX,
1715 VK_NULL_HANDLE, vk_fence, &swapchain->current_buffer_index)) < 0)
1717 ERR("Failed to acquire next Vulkan image, vr %d.\n", vr);
1718 return hresult_from_vk_result(vr);
1721 if ((vr = vk_funcs->p_vkWaitForFences(vk_device, 1, &vk_fence, VK_TRUE, UINT64_MAX)) != VK_SUCCESS)
1723 ERR("Failed to wait for fence, vr %d.\n", vr);
1724 return hresult_from_vk_result(vr);
1726 if ((vr = vk_funcs->p_vkResetFences(vk_device, 1, &vk_fence)) < 0)
1728 ERR("Failed to reset fence, vr %d.\n", vr);
1729 return hresult_from_vk_result(vr);
1732 return S_OK;
1735 static HRESULT d3d12_swapchain_blit_buffer(struct d3d12_swapchain *swapchain, VkQueue vk_queue)
1737 const struct dxgi_vk_funcs *vk_funcs = &swapchain->vk_funcs;
1738 VkSubmitInfo submit_info;
1739 VkResult vr;
1741 submit_info.sType = VK_STRUCTURE_TYPE_SUBMIT_INFO;
1742 submit_info.pNext = NULL;
1743 submit_info.waitSemaphoreCount = 0;
1744 submit_info.pWaitSemaphores = NULL;
1745 submit_info.pWaitDstStageMask = NULL;
1746 submit_info.commandBufferCount = 1;
1747 submit_info.pCommandBuffers = &swapchain->vk_cmd_buffers[swapchain->current_buffer_index];
1748 submit_info.signalSemaphoreCount = 1;
1749 submit_info.pSignalSemaphores = &swapchain->vk_semaphores[swapchain->current_buffer_index];
1751 if ((vr = vk_funcs->p_vkQueueSubmit(vk_queue, 1, &submit_info, VK_NULL_HANDLE)) < 0)
1752 ERR("Failed to blit swapchain buffer, vr %d.\n", vr);
1753 return hresult_from_vk_result(vr);
1756 static HRESULT d3d12_swapchain_queue_present(struct d3d12_swapchain *swapchain, VkQueue vk_queue)
1758 const struct dxgi_vk_funcs *vk_funcs = &swapchain->vk_funcs;
1759 VkPresentInfoKHR present_info;
1760 VkResult vr;
1762 present_info.sType = VK_STRUCTURE_TYPE_PRESENT_INFO_KHR;
1763 present_info.pNext = NULL;
1764 present_info.waitSemaphoreCount = 0;
1765 present_info.pWaitSemaphores = NULL;
1766 present_info.swapchainCount = 1;
1767 present_info.pSwapchains = &swapchain->vk_swapchain;
1768 present_info.pImageIndices = &swapchain->current_buffer_index;
1769 present_info.pResults = NULL;
1771 if (swapchain->vk_semaphores[swapchain->current_buffer_index])
1773 present_info.waitSemaphoreCount = 1;
1774 present_info.pWaitSemaphores = &swapchain->vk_semaphores[swapchain->current_buffer_index];
1777 if ((vr = vk_funcs->p_vkQueuePresentKHR(vk_queue, &present_info)) < 0)
1778 ERR("Failed to queue present, vr %d.\n", vr);
1779 return hresult_from_vk_result(vr);
1782 static HRESULT STDMETHODCALLTYPE d3d12_swapchain_Present1(IDXGISwapChain3 *iface,
1783 UINT sync_interval, UINT flags, const DXGI_PRESENT_PARAMETERS *present_parameters)
1785 struct d3d12_swapchain *swapchain = d3d12_swapchain_from_IDXGISwapChain3(iface);
1786 VkQueue vk_queue;
1787 HRESULT hr;
1789 TRACE("iface %p, sync_interval %u, flags %#x, present_parameters %p.\n",
1790 iface, sync_interval, flags, present_parameters);
1792 if (sync_interval > 4)
1794 WARN("Invalid sync interval %u.\n", sync_interval);
1795 return DXGI_ERROR_INVALID_CALL;
1797 if (sync_interval != 1)
1798 FIXME("Ignoring sync interval %u.\n", sync_interval);
1800 if (flags & ~DXGI_PRESENT_TEST)
1801 FIXME("Unimplemented flags %#x.\n", flags);
1802 if (flags & DXGI_PRESENT_TEST)
1804 WARN("Returning S_OK for DXGI_PRESENT_TEST.\n");
1805 return S_OK;
1808 if (present_parameters)
1809 FIXME("Ignored present parameters %p.\n", present_parameters);
1811 if (!(vk_queue = vkd3d_acquire_vk_queue(swapchain->command_queue)))
1813 ERR("Failed to acquire Vulkan queue.\n");
1814 return E_FAIL;
1817 if (swapchain->vk_images[swapchain->current_buffer_index])
1819 if (FAILED(hr = d3d12_swapchain_blit_buffer(swapchain, vk_queue)))
1821 vkd3d_release_vk_queue(swapchain->command_queue);
1822 return hr;
1826 if (FAILED(hr = d3d12_swapchain_queue_present(swapchain, vk_queue)))
1828 vkd3d_release_vk_queue(swapchain->command_queue);
1829 return hr;
1832 vkd3d_release_vk_queue(swapchain->command_queue);
1834 return d3d12_swapchain_acquire_next_image(swapchain);
1837 static BOOL STDMETHODCALLTYPE d3d12_swapchain_IsTemporaryMonoSupported(IDXGISwapChain3 *iface)
1839 FIXME("iface %p stub!\n", iface);
1841 return FALSE;
1844 static HRESULT STDMETHODCALLTYPE d3d12_swapchain_GetRestrictToOutput(IDXGISwapChain3 *iface, IDXGIOutput **output)
1846 FIXME("iface %p, output %p stub!\n", iface, output);
1848 if (!output)
1850 WARN("Invalid pointer.\n");
1851 return E_INVALIDARG;
1854 *output = NULL;
1855 return E_NOTIMPL;
1858 static HRESULT STDMETHODCALLTYPE d3d12_swapchain_SetBackgroundColor(IDXGISwapChain3 *iface, const DXGI_RGBA *color)
1860 FIXME("iface %p, color %p stub!\n", iface, color);
1862 return E_NOTIMPL;
1865 static HRESULT STDMETHODCALLTYPE d3d12_swapchain_GetBackgroundColor(IDXGISwapChain3 *iface, DXGI_RGBA *color)
1867 FIXME("iface %p, color %p stub!\n", iface, color);
1869 return E_NOTIMPL;
1872 static HRESULT STDMETHODCALLTYPE d3d12_swapchain_SetRotation(IDXGISwapChain3 *iface, DXGI_MODE_ROTATION rotation)
1874 FIXME("iface %p, rotation %#x stub!\n", iface, rotation);
1876 return E_NOTIMPL;
1879 static HRESULT STDMETHODCALLTYPE d3d12_swapchain_GetRotation(IDXGISwapChain3 *iface, DXGI_MODE_ROTATION *rotation)
1881 FIXME("iface %p, rotation %p stub!\n", iface, rotation);
1883 return E_NOTIMPL;
1886 /* IDXGISwapChain2 methods */
1888 static HRESULT STDMETHODCALLTYPE d3d12_swapchain_SetSourceSize(IDXGISwapChain3 *iface, UINT width, UINT height)
1890 FIXME("iface %p, width %u, height %u stub!\n", iface, width, height);
1892 return E_NOTIMPL;
1895 static HRESULT STDMETHODCALLTYPE d3d12_swapchain_GetSourceSize(IDXGISwapChain3 *iface, UINT *width, UINT *height)
1897 FIXME("iface %p, width %p, height %p stub!\n", iface, width, height);
1899 return E_NOTIMPL;
1902 static HRESULT STDMETHODCALLTYPE d3d12_swapchain_SetMaximumFrameLatency(IDXGISwapChain3 *iface, UINT max_latency)
1904 FIXME("iface %p, max_latency %u stub!\n", iface, max_latency);
1906 return E_NOTIMPL;
1909 static HRESULT STDMETHODCALLTYPE d3d12_swapchain_GetMaximumFrameLatency(IDXGISwapChain3 *iface, UINT *max_latency)
1911 FIXME("iface %p, max_latency %p stub!\n", iface, max_latency);
1913 return E_NOTIMPL;
1916 static HANDLE STDMETHODCALLTYPE d3d12_swapchain_GetFrameLatencyWaitableObject(IDXGISwapChain3 *iface)
1918 FIXME("iface %p stub!\n", iface);
1920 return NULL;
1923 static HRESULT STDMETHODCALLTYPE d3d12_swapchain_SetMatrixTransform(IDXGISwapChain3 *iface,
1924 const DXGI_MATRIX_3X2_F *matrix)
1926 FIXME("iface %p, matrix %p stub!\n", iface, matrix);
1928 return E_NOTIMPL;
1931 static HRESULT STDMETHODCALLTYPE d3d12_swapchain_GetMatrixTransform(IDXGISwapChain3 *iface,
1932 DXGI_MATRIX_3X2_F *matrix)
1934 FIXME("iface %p, matrix %p stub!\n", iface, matrix);
1936 return E_NOTIMPL;
1939 /* IDXGISwapChain3 methods */
1941 static UINT STDMETHODCALLTYPE d3d12_swapchain_GetCurrentBackBufferIndex(IDXGISwapChain3 *iface)
1943 struct d3d12_swapchain *swapchain = d3d12_swapchain_from_IDXGISwapChain3(iface);
1945 TRACE("iface %p.\n", iface);
1947 return swapchain->current_buffer_index;
1950 static HRESULT STDMETHODCALLTYPE d3d12_swapchain_CheckColorSpaceSupport(IDXGISwapChain3 *iface,
1951 DXGI_COLOR_SPACE_TYPE colour_space, UINT *colour_space_support)
1953 FIXME("iface %p, colour_space %#x, colour_space_support %p stub!\n",
1954 iface, colour_space, colour_space_support);
1956 return E_NOTIMPL;
1959 static HRESULT STDMETHODCALLTYPE d3d12_swapchain_SetColorSpace1(IDXGISwapChain3 *iface,
1960 DXGI_COLOR_SPACE_TYPE colour_space)
1962 FIXME("iface %p, colour_space %#x stub!\n", iface, colour_space);
1964 return E_NOTIMPL;
1967 static HRESULT STDMETHODCALLTYPE d3d12_swapchain_ResizeBuffers1(IDXGISwapChain3 *iface,
1968 UINT buffer_count, UINT width, UINT height, DXGI_FORMAT format, UINT flags,
1969 const UINT *node_mask, IUnknown * const *present_queue)
1971 FIXME("iface %p, buffer_count %u, width %u, height %u, format %s, flags %#x, "
1972 "node_mask %p, present_queue %p stub!\n",
1973 iface, buffer_count, width, height, debug_dxgi_format(format), flags, node_mask, present_queue);
1975 return E_NOTIMPL;
1978 static const struct IDXGISwapChain3Vtbl d3d12_swapchain_vtbl =
1980 /* IUnknown methods */
1981 d3d12_swapchain_QueryInterface,
1982 d3d12_swapchain_AddRef,
1983 d3d12_swapchain_Release,
1984 /* IDXGIObject methods */
1985 d3d12_swapchain_SetPrivateData,
1986 d3d12_swapchain_SetPrivateDataInterface,
1987 d3d12_swapchain_GetPrivateData,
1988 d3d12_swapchain_GetParent,
1989 /* IDXGIDeviceSubObject methods */
1990 d3d12_swapchain_GetDevice,
1991 /* IDXGISwapChain methods */
1992 d3d12_swapchain_Present,
1993 d3d12_swapchain_GetBuffer,
1994 d3d12_swapchain_SetFullscreenState,
1995 d3d12_swapchain_GetFullscreenState,
1996 d3d12_swapchain_GetDesc,
1997 d3d12_swapchain_ResizeBuffers,
1998 d3d12_swapchain_ResizeTarget,
1999 d3d12_swapchain_GetContainingOutput,
2000 d3d12_swapchain_GetFrameStatistics,
2001 d3d12_swapchain_GetLastPresentCount,
2002 /* IDXGISwapChain1 methods */
2003 d3d12_swapchain_GetDesc1,
2004 d3d12_swapchain_GetFullscreenDesc,
2005 d3d12_swapchain_GetHwnd,
2006 d3d12_swapchain_GetCoreWindow,
2007 d3d12_swapchain_Present1,
2008 d3d12_swapchain_IsTemporaryMonoSupported,
2009 d3d12_swapchain_GetRestrictToOutput,
2010 d3d12_swapchain_SetBackgroundColor,
2011 d3d12_swapchain_GetBackgroundColor,
2012 d3d12_swapchain_SetRotation,
2013 d3d12_swapchain_GetRotation,
2014 /* IDXGISwapChain2 methods */
2015 d3d12_swapchain_SetSourceSize,
2016 d3d12_swapchain_GetSourceSize,
2017 d3d12_swapchain_SetMaximumFrameLatency,
2018 d3d12_swapchain_GetMaximumFrameLatency,
2019 d3d12_swapchain_GetFrameLatencyWaitableObject,
2020 d3d12_swapchain_SetMatrixTransform,
2021 d3d12_swapchain_GetMatrixTransform,
2022 /* IDXGISwapChain3 methods */
2023 d3d12_swapchain_GetCurrentBackBufferIndex,
2024 d3d12_swapchain_CheckColorSpaceSupport,
2025 d3d12_swapchain_SetColorSpace1,
2026 d3d12_swapchain_ResizeBuffers1,
2029 static const struct vulkan_funcs *get_vk_funcs(void)
2031 const struct vulkan_funcs *vk_funcs;
2032 HDC hdc;
2034 hdc = GetDC(0);
2035 vk_funcs = __wine_get_vulkan_driver(hdc, WINE_VULKAN_DRIVER_VERSION);
2036 ReleaseDC(0, hdc);
2037 return vk_funcs;
2040 static BOOL load_vkd3d_functions(void *vkd3d_handle)
2042 #define LOAD_FUNCPTR(f) if (!(f = wine_dlsym(vkd3d_handle, #f, NULL, 0))) return FALSE;
2043 LOAD_FUNCPTR(vkd3d_acquire_vk_queue)
2044 LOAD_FUNCPTR(vkd3d_create_image_resource)
2045 LOAD_FUNCPTR(vkd3d_get_vk_device)
2046 LOAD_FUNCPTR(vkd3d_get_vk_format)
2047 LOAD_FUNCPTR(vkd3d_get_vk_physical_device)
2048 LOAD_FUNCPTR(vkd3d_get_vk_queue_family_index)
2049 LOAD_FUNCPTR(vkd3d_instance_from_device)
2050 LOAD_FUNCPTR(vkd3d_instance_get_vk_instance)
2051 LOAD_FUNCPTR(vkd3d_release_vk_queue)
2052 LOAD_FUNCPTR(vkd3d_resource_decref)
2053 LOAD_FUNCPTR(vkd3d_resource_incref)
2054 #undef LOAD_FUNCPTR
2056 return TRUE;
2059 static void *vkd3d_handle;
2061 static BOOL WINAPI init_vkd3d_once(INIT_ONCE *once, void *param, void **context)
2063 TRACE("Loading vkd3d %s.\n", SONAME_LIBVKD3D);
2065 if (!(vkd3d_handle = wine_dlopen(SONAME_LIBVKD3D, RTLD_NOW, NULL, 0)))
2066 return FALSE;
2068 if (!load_vkd3d_functions(vkd3d_handle))
2070 ERR("Failed to load vkd3d functions.\n");
2071 wine_dlclose(vkd3d_handle, NULL, 0);
2072 vkd3d_handle = NULL;
2073 return FALSE;
2076 return TRUE;
2079 static BOOL init_vkd3d(void)
2081 static INIT_ONCE init_once = INIT_ONCE_STATIC_INIT;
2082 InitOnceExecuteOnce(&init_once, init_vkd3d_once, NULL, NULL);
2083 return !!vkd3d_handle;
2086 static BOOL init_vk_funcs(struct dxgi_vk_funcs *dxgi, VkInstance vk_instance, VkDevice vk_device)
2088 const struct vulkan_funcs *vk;
2090 if (!(vk = get_vk_funcs()))
2092 ERR_(winediag)("Failed to load Wine Vulkan driver.\n");
2093 return FALSE;
2096 dxgi->p_vkGetInstanceProcAddr = (PFN_vkGetInstanceProcAddr)vk->p_vkGetInstanceProcAddr;
2098 #define LOAD_INSTANCE_PFN(name) \
2099 if (!(dxgi->p_##name = vk->p_vkGetInstanceProcAddr(vk_instance, #name))) \
2101 ERR("Failed to get instance proc "#name".\n"); \
2102 return FALSE; \
2104 LOAD_INSTANCE_PFN(vkCreateWin32SurfaceKHR)
2105 LOAD_INSTANCE_PFN(vkDestroySurfaceKHR)
2106 LOAD_INSTANCE_PFN(vkGetPhysicalDeviceMemoryProperties)
2107 LOAD_INSTANCE_PFN(vkGetPhysicalDeviceSurfaceCapabilitiesKHR)
2108 LOAD_INSTANCE_PFN(vkGetPhysicalDeviceSurfaceFormatsKHR)
2109 LOAD_INSTANCE_PFN(vkGetPhysicalDeviceSurfacePresentModesKHR)
2110 LOAD_INSTANCE_PFN(vkGetPhysicalDeviceSurfaceSupportKHR)
2111 LOAD_INSTANCE_PFN(vkGetPhysicalDeviceWin32PresentationSupportKHR)
2112 #undef LOAD_INSTANCE_PFN
2114 #define LOAD_DEVICE_PFN(name) \
2115 if (!(dxgi->p_##name = vk->p_vkGetDeviceProcAddr(vk_device, #name))) \
2117 ERR("Failed to get device proc "#name".\n"); \
2118 return FALSE; \
2120 LOAD_DEVICE_PFN(vkAcquireNextImageKHR)
2121 LOAD_DEVICE_PFN(vkAllocateCommandBuffers)
2122 LOAD_DEVICE_PFN(vkAllocateMemory)
2123 LOAD_DEVICE_PFN(vkBeginCommandBuffer)
2124 LOAD_DEVICE_PFN(vkBindImageMemory)
2125 LOAD_DEVICE_PFN(vkCmdBlitImage)
2126 LOAD_DEVICE_PFN(vkCmdPipelineBarrier)
2127 LOAD_DEVICE_PFN(vkCreateCommandPool)
2128 LOAD_DEVICE_PFN(vkCreateFence)
2129 LOAD_DEVICE_PFN(vkCreateImage)
2130 LOAD_DEVICE_PFN(vkCreateSemaphore)
2131 LOAD_DEVICE_PFN(vkCreateSwapchainKHR)
2132 LOAD_DEVICE_PFN(vkDestroyCommandPool)
2133 LOAD_DEVICE_PFN(vkDestroyFence)
2134 LOAD_DEVICE_PFN(vkDestroyImage)
2135 LOAD_DEVICE_PFN(vkDestroySemaphore)
2136 LOAD_DEVICE_PFN(vkDestroySwapchainKHR)
2137 LOAD_DEVICE_PFN(vkEndCommandBuffer)
2138 LOAD_DEVICE_PFN(vkFreeMemory)
2139 LOAD_DEVICE_PFN(vkGetImageMemoryRequirements)
2140 LOAD_DEVICE_PFN(vkGetSwapchainImagesKHR)
2141 LOAD_DEVICE_PFN(vkQueuePresentKHR)
2142 LOAD_DEVICE_PFN(vkQueueSubmit)
2143 LOAD_DEVICE_PFN(vkQueueWaitIdle)
2144 LOAD_DEVICE_PFN(vkResetFences)
2145 LOAD_DEVICE_PFN(vkWaitForFences)
2146 #undef LOAD_DEVICE_PFN
2148 return TRUE;
2151 static HRESULT d3d12_swapchain_init(struct d3d12_swapchain *swapchain, IWineDXGIFactory *factory,
2152 ID3D12Device *device, ID3D12CommandQueue *queue, HWND window,
2153 const DXGI_SWAP_CHAIN_DESC1 *swapchain_desc, const DXGI_SWAP_CHAIN_FULLSCREEN_DESC *fullscreen_desc)
2155 const struct dxgi_vk_funcs *vk_funcs = &swapchain->vk_funcs;
2156 struct VkSwapchainCreateInfoKHR vk_swapchain_desc;
2157 struct VkWin32SurfaceCreateInfoKHR surface_desc;
2158 VkSwapchainKHR vk_swapchain = VK_NULL_HANDLE;
2159 VkSurfaceKHR vk_surface = VK_NULL_HANDLE;
2160 VkFormat vk_swapchain_format, vk_format;
2161 VkSurfaceCapabilitiesKHR surface_caps;
2162 VkPhysicalDevice vk_physical_device;
2163 VkFence vk_fence = VK_NULL_HANDLE;
2164 VkFenceCreateInfo fence_desc;
2165 uint32_t queue_family_index;
2166 VkImageUsageFlags usage;
2167 VkInstance vk_instance;
2168 VkBool32 supported;
2169 VkDevice vk_device;
2170 VkResult vr;
2171 HRESULT hr;
2173 swapchain->IDXGISwapChain3_iface.lpVtbl = &d3d12_swapchain_vtbl;
2174 swapchain->refcount = 1;
2176 swapchain->window = window;
2177 swapchain->desc = *swapchain_desc;
2178 swapchain->fullscreen_desc = *fullscreen_desc;
2180 switch (swapchain_desc->SwapEffect)
2182 case DXGI_SWAP_EFFECT_FLIP_SEQUENTIAL:
2183 case DXGI_SWAP_EFFECT_FLIP_DISCARD:
2184 FIXME("Ignoring swap effect %#x.\n", swapchain_desc->SwapEffect);
2185 break;
2186 default:
2187 WARN("Invalid swap effect %#x.\n", swapchain_desc->SwapEffect);
2188 return DXGI_ERROR_INVALID_CALL;
2191 if (!init_vkd3d())
2193 ERR_(winediag)("libvkd3d could not be loaded.\n");
2194 return DXGI_ERROR_UNSUPPORTED;
2197 if (!(vk_format = vkd3d_get_vk_format(swapchain_desc->Format)))
2199 WARN("Invalid format %#x.\n", swapchain_desc->Format);
2200 return DXGI_ERROR_INVALID_CALL;
2203 if (swapchain_desc->BufferUsage && swapchain_desc->BufferUsage != DXGI_USAGE_RENDER_TARGET_OUTPUT)
2204 FIXME("Ignoring buffer usage %#x.\n", swapchain_desc->BufferUsage);
2205 if (swapchain_desc->Scaling != DXGI_SCALING_STRETCH)
2206 FIXME("Ignoring scaling %#x.\n", swapchain_desc->Scaling);
2207 if (swapchain_desc->AlphaMode && swapchain_desc->AlphaMode != DXGI_ALPHA_MODE_IGNORE)
2208 FIXME("Ignoring alpha mode %#x.\n", swapchain_desc->AlphaMode);
2209 if (swapchain_desc->Flags)
2210 FIXME("Ignoring swapchain flags %#x.\n", swapchain_desc->Flags);
2212 FIXME("Ignoring refresh rate.\n");
2213 if (fullscreen_desc->ScanlineOrdering)
2214 FIXME("Unhandled scanline ordering %#x.\n", fullscreen_desc->ScanlineOrdering);
2215 if (fullscreen_desc->Scaling)
2216 FIXME("Unhandled mode scaling %#x.\n", fullscreen_desc->Scaling);
2217 if (!fullscreen_desc->Windowed)
2218 FIXME("Fullscreen not supported yet.\n");
2220 vk_instance = vkd3d_instance_get_vk_instance(vkd3d_instance_from_device(device));
2221 vk_physical_device = vkd3d_get_vk_physical_device(device);
2222 vk_device = vkd3d_get_vk_device(device);
2224 swapchain->vk_instance = vk_instance;
2225 swapchain->vk_device = vk_device;
2226 swapchain->vk_physical_device = vk_physical_device;
2228 if (!init_vk_funcs(&swapchain->vk_funcs, vk_instance, vk_device))
2229 return E_FAIL;
2231 wined3d_private_store_init(&swapchain->private_store);
2233 surface_desc.sType = VK_STRUCTURE_TYPE_WIN32_SURFACE_CREATE_INFO_KHR;
2234 surface_desc.pNext = NULL;
2235 surface_desc.flags = 0;
2236 surface_desc.hinstance = GetModuleHandleA("dxgi.dll");
2237 surface_desc.hwnd = window;
2238 if ((vr = vk_funcs->p_vkCreateWin32SurfaceKHR(vk_instance, &surface_desc, NULL, &vk_surface)) < 0)
2240 WARN("Failed to create Vulkan surface, vr %d.\n", vr);
2241 d3d12_swapchain_destroy(swapchain);
2242 return hresult_from_vk_result(vr);
2244 swapchain->vk_surface = vk_surface;
2246 queue_family_index = vkd3d_get_vk_queue_family_index(queue);
2247 if ((vr = vk_funcs->p_vkGetPhysicalDeviceSurfaceSupportKHR(vk_physical_device,
2248 queue_family_index, vk_surface, &supported)) < 0 || !supported)
2250 FIXME("Queue family does not support presentation, vr %d.\n", vr);
2251 d3d12_swapchain_destroy(swapchain);
2252 return DXGI_ERROR_UNSUPPORTED;
2255 if (FAILED(hr = select_vk_format(vk_funcs, vk_physical_device,
2256 vk_surface, swapchain_desc, &vk_swapchain_format)))
2258 d3d12_swapchain_destroy(swapchain);
2259 return hr;
2262 if ((vr = vk_funcs->p_vkGetPhysicalDeviceSurfaceCapabilitiesKHR(vk_physical_device,
2263 vk_surface, &surface_caps)) < 0)
2265 WARN("Failed to get surface capabilities, vr %d.\n", vr);
2266 d3d12_swapchain_destroy(swapchain);
2267 return hresult_from_vk_result(vr);
2270 if (surface_caps.maxImageCount && (swapchain_desc->BufferCount > surface_caps.maxImageCount
2271 || swapchain_desc->BufferCount < surface_caps.minImageCount))
2273 WARN("Buffer count %u is not supported (%u-%u).\n", swapchain_desc->BufferCount,
2274 surface_caps.minImageCount, surface_caps.maxImageCount);
2275 d3d12_swapchain_destroy(swapchain);
2276 return DXGI_ERROR_UNSUPPORTED;
2279 if (swapchain_desc->Width > surface_caps.maxImageExtent.width
2280 || swapchain_desc->Width < surface_caps.minImageExtent.width
2281 || swapchain_desc->Height > surface_caps.maxImageExtent.height
2282 || swapchain_desc->Height < surface_caps.minImageExtent.height)
2284 FIXME("Swapchain dimensions %ux%u are not supported (%u-%u x %u-%u).\n",
2285 swapchain_desc->Width, swapchain_desc->Height,
2286 surface_caps.minImageExtent.width, surface_caps.maxImageExtent.width,
2287 surface_caps.minImageExtent.height, surface_caps.maxImageExtent.height);
2290 if (!(surface_caps.supportedCompositeAlpha & VK_COMPOSITE_ALPHA_OPAQUE_BIT_KHR))
2292 FIXME("Unsupported alpha mode.\n");
2293 d3d12_swapchain_destroy(swapchain);
2294 return DXGI_ERROR_UNSUPPORTED;
2297 usage = VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT;
2298 usage |= surface_caps.supportedUsageFlags & VK_IMAGE_USAGE_TRANSFER_SRC_BIT;
2299 usage |= surface_caps.supportedUsageFlags & VK_IMAGE_USAGE_TRANSFER_DST_BIT;
2300 if (!(usage & VK_IMAGE_USAGE_TRANSFER_SRC_BIT) || !(usage & VK_IMAGE_USAGE_TRANSFER_DST_BIT))
2301 WARN("Transfer not supported for swapchain images.\n");
2303 vk_swapchain_desc.sType = VK_STRUCTURE_TYPE_SWAPCHAIN_CREATE_INFO_KHR;
2304 vk_swapchain_desc.pNext = NULL;
2305 vk_swapchain_desc.flags = 0;
2306 vk_swapchain_desc.surface = vk_surface;
2307 vk_swapchain_desc.minImageCount = swapchain_desc->BufferCount;
2308 vk_swapchain_desc.imageFormat = vk_swapchain_format;
2309 vk_swapchain_desc.imageColorSpace = VK_COLOR_SPACE_SRGB_NONLINEAR_KHR;
2310 vk_swapchain_desc.imageExtent.width = swapchain_desc->Width;
2311 vk_swapchain_desc.imageExtent.height = swapchain_desc->Height;
2312 vk_swapchain_desc.imageArrayLayers = 1;
2313 vk_swapchain_desc.imageUsage = usage;
2314 vk_swapchain_desc.imageSharingMode = VK_SHARING_MODE_EXCLUSIVE;
2315 vk_swapchain_desc.queueFamilyIndexCount = 0;
2316 vk_swapchain_desc.pQueueFamilyIndices = NULL;
2317 vk_swapchain_desc.preTransform = surface_caps.currentTransform;
2318 vk_swapchain_desc.compositeAlpha = VK_COMPOSITE_ALPHA_OPAQUE_BIT_KHR;
2319 vk_swapchain_desc.presentMode = VK_PRESENT_MODE_FIFO_KHR;
2320 vk_swapchain_desc.clipped = VK_TRUE;
2321 vk_swapchain_desc.oldSwapchain = VK_NULL_HANDLE;
2322 if ((vr = vk_funcs->p_vkCreateSwapchainKHR(vk_device, &vk_swapchain_desc, NULL, &vk_swapchain)) < 0)
2324 WARN("Failed to create Vulkan swapchain, vr %d.\n", vr);
2325 d3d12_swapchain_destroy(swapchain);
2326 return hresult_from_vk_result(vr);
2328 swapchain->vk_swapchain = vk_swapchain;
2330 fence_desc.sType = VK_STRUCTURE_TYPE_FENCE_CREATE_INFO;
2331 fence_desc.pNext = NULL;
2332 fence_desc.flags = 0;
2333 if ((vr = vk_funcs->p_vkCreateFence(vk_device, &fence_desc, NULL, &vk_fence)) < 0)
2335 WARN("Failed to create Vulkan fence, vr %d.\n", vr);
2336 d3d12_swapchain_destroy(swapchain);
2337 return hresult_from_vk_result(vr);
2339 swapchain->vk_fence = vk_fence;
2341 if (FAILED(hr = d3d12_swapchain_create_buffers(swapchain, device, queue,
2342 swapchain_desc, vk_swapchain_format, vk_format)))
2344 d3d12_swapchain_destroy(swapchain);
2345 return hr;
2348 if (FAILED(hr = d3d12_swapchain_acquire_next_image(swapchain)))
2350 WARN("Failed to acquire Vulkan image, hr %#x.\n", hr);
2351 d3d12_swapchain_destroy(swapchain);
2352 return hr;
2355 ID3D12CommandQueue_AddRef(swapchain->command_queue = queue);
2356 ID3D12Device_AddRef(swapchain->device = device);
2357 IWineDXGIFactory_AddRef(swapchain->factory = factory);
2359 return S_OK;
2362 HRESULT d3d12_swapchain_create(IWineDXGIFactory *factory, ID3D12CommandQueue *queue, HWND window,
2363 const DXGI_SWAP_CHAIN_DESC1 *swapchain_desc, const DXGI_SWAP_CHAIN_FULLSCREEN_DESC *fullscreen_desc,
2364 IDXGISwapChain1 **swapchain)
2366 DXGI_SWAP_CHAIN_FULLSCREEN_DESC default_fullscreen_desc;
2367 struct d3d12_swapchain *object;
2368 ID3D12Device *device;
2369 HRESULT hr;
2371 if (!fullscreen_desc)
2373 memset(&default_fullscreen_desc, 0, sizeof(default_fullscreen_desc));
2374 default_fullscreen_desc.Windowed = TRUE;
2375 fullscreen_desc = &default_fullscreen_desc;
2378 if (!(object = heap_alloc_zero(sizeof(*object))))
2379 return E_OUTOFMEMORY;
2381 if (FAILED(hr = ID3D12CommandQueue_GetDevice(queue, &IID_ID3D12Device, (void **)&device)))
2383 ERR("Failed to get D3D12 device, hr %#x.\n", hr);
2384 heap_free(object);
2385 return hr;
2388 hr = d3d12_swapchain_init(object, factory, device, queue, window, swapchain_desc, fullscreen_desc);
2389 ID3D12Device_Release(device);
2390 if (FAILED(hr))
2392 heap_free(object);
2393 return hr;
2396 TRACE("Created swapchain %p.\n", object);
2398 *swapchain = (IDXGISwapChain1 *)&object->IDXGISwapChain3_iface;
2400 return S_OK;
2403 #else
2405 HRESULT d3d12_swapchain_create(IWineDXGIFactory *factory, ID3D12CommandQueue *queue, HWND window,
2406 const DXGI_SWAP_CHAIN_DESC1 *swapchain_desc, const DXGI_SWAP_CHAIN_FULLSCREEN_DESC *fullscreen_desc,
2407 IDXGISwapChain1 **swapchain)
2409 ERR_(winediag)("Wine was built without Direct3D 12 support.\n");
2410 return DXGI_ERROR_UNSUPPORTED;
2413 #endif /* SONAME_LIBVKD3D */