shell32: Use Public instead of AllUsersProfile in the registry.
[wine.git] / dlls / dxgi / swapchain.c
blob83e0f256748f4560e331be4513ef8ecf13fe57f3
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 inline struct d3d12_swapchain *d3d12_swapchain_from_IDXGISwapChain3(IDXGISwapChain3 *iface)
914 return CONTAINING_RECORD(iface, struct d3d12_swapchain, IDXGISwapChain3_iface);
917 /* IUnknown methods */
919 static HRESULT STDMETHODCALLTYPE d3d12_swapchain_QueryInterface(IDXGISwapChain3 *iface, REFIID iid, void **object)
921 TRACE("iface %p, iid %s, object %p.\n", iface, debugstr_guid(iid), object);
923 if (IsEqualGUID(iid, &IID_IUnknown)
924 || IsEqualGUID(iid, &IID_IDXGIObject)
925 || IsEqualGUID(iid, &IID_IDXGIDeviceSubObject)
926 || IsEqualGUID(iid, &IID_IDXGISwapChain)
927 || IsEqualGUID(iid, &IID_IDXGISwapChain1)
928 || IsEqualGUID(iid, &IID_IDXGISwapChain2)
929 || IsEqualGUID(iid, &IID_IDXGISwapChain3))
931 IUnknown_AddRef(iface);
932 *object = iface;
933 return S_OK;
936 WARN("%s not implemented, returning E_NOINTERFACE.\n", debugstr_guid(iid));
938 *object = NULL;
939 return E_NOINTERFACE;
942 static ULONG STDMETHODCALLTYPE d3d12_swapchain_AddRef(IDXGISwapChain3 *iface)
944 struct d3d12_swapchain *swapchain = d3d12_swapchain_from_IDXGISwapChain3(iface);
945 ULONG refcount = InterlockedIncrement(&swapchain->refcount);
947 TRACE("%p increasing refcount to %u.\n", swapchain, refcount);
949 return refcount;
952 static void d3d12_swapchain_destroy(struct d3d12_swapchain *swapchain)
954 const struct dxgi_vk_funcs *vk_funcs = &swapchain->vk_funcs;
955 VkQueue vk_queue;
956 unsigned int i;
958 if (swapchain->command_queue)
960 if ((vk_queue = vkd3d_acquire_vk_queue(swapchain->command_queue)))
962 vk_funcs->p_vkQueueWaitIdle(vk_queue);
964 vkd3d_release_vk_queue(swapchain->command_queue);
966 else
968 WARN("Failed to acquire Vulkan queue.\n");
971 ID3D12CommandQueue_Release(swapchain->command_queue);
974 if (swapchain->factory)
975 IWineDXGIFactory_Release(swapchain->factory);
977 wined3d_private_store_cleanup(&swapchain->private_store);
979 for (i = 0; i < swapchain->buffer_count; ++i)
981 if (swapchain->buffers[i])
982 vkd3d_resource_decref(swapchain->buffers[i]);
984 if (swapchain->vk_device)
986 vk_funcs->p_vkDestroyImage(swapchain->vk_device, swapchain->vk_images[i], NULL);
987 vk_funcs->p_vkDestroySemaphore(swapchain->vk_device, swapchain->vk_semaphores[i], NULL);
991 if (swapchain->vk_device)
993 vk_funcs->p_vkDestroyFence(swapchain->vk_device, swapchain->vk_fence, NULL);
994 vk_funcs->p_vkDestroySwapchainKHR(swapchain->vk_device, swapchain->vk_swapchain, NULL);
996 vk_funcs->p_vkFreeMemory(swapchain->vk_device, swapchain->vk_memory, NULL);
997 vk_funcs->p_vkDestroyCommandPool(swapchain->vk_device, swapchain->vk_cmd_pool, NULL);
1000 if (swapchain->vk_instance)
1001 vk_funcs->p_vkDestroySurfaceKHR(swapchain->vk_instance, swapchain->vk_surface, NULL);
1003 if (swapchain->device)
1004 ID3D12Device_Release(swapchain->device);
1007 static ULONG STDMETHODCALLTYPE d3d12_swapchain_Release(IDXGISwapChain3 *iface)
1009 struct d3d12_swapchain *swapchain = d3d12_swapchain_from_IDXGISwapChain3(iface);
1010 ULONG refcount = InterlockedDecrement(&swapchain->refcount);
1012 TRACE("%p decreasing refcount to %u.\n", swapchain, refcount);
1014 if (!refcount)
1016 d3d12_swapchain_destroy(swapchain);
1017 heap_free(swapchain);
1020 return refcount;
1023 /* IDXGIObject methods */
1025 static HRESULT STDMETHODCALLTYPE d3d12_swapchain_SetPrivateData(IDXGISwapChain3 *iface,
1026 REFGUID guid, UINT data_size, const void *data)
1028 struct d3d12_swapchain *swapchain = d3d12_swapchain_from_IDXGISwapChain3(iface);
1030 TRACE("iface %p, guid %s, data_size %u, data %p.\n", iface, debugstr_guid(guid), data_size, data);
1032 return dxgi_set_private_data(&swapchain->private_store, guid, data_size, data);
1035 static HRESULT STDMETHODCALLTYPE d3d12_swapchain_SetPrivateDataInterface(IDXGISwapChain3 *iface,
1036 REFGUID guid, const IUnknown *object)
1038 struct d3d12_swapchain *swapchain = d3d12_swapchain_from_IDXGISwapChain3(iface);
1040 TRACE("iface %p, guid %s, object %p.\n", iface, debugstr_guid(guid), object);
1042 return dxgi_set_private_data_interface(&swapchain->private_store, guid, object);
1045 static HRESULT STDMETHODCALLTYPE d3d12_swapchain_GetPrivateData(IDXGISwapChain3 *iface,
1046 REFGUID guid, UINT *data_size, void *data)
1048 struct d3d12_swapchain *swapchain = d3d12_swapchain_from_IDXGISwapChain3(iface);
1050 TRACE("iface %p, guid %s, data_size %p, data %p.\n", iface, debugstr_guid(guid), data_size, data);
1052 return dxgi_get_private_data(&swapchain->private_store, guid, data_size, data);
1055 static HRESULT STDMETHODCALLTYPE d3d12_swapchain_GetParent(IDXGISwapChain3 *iface, REFIID iid, void **parent)
1057 struct d3d12_swapchain *swapchain = d3d12_swapchain_from_IDXGISwapChain3(iface);
1059 TRACE("iface %p, iid %s, parent %p.\n", iface, debugstr_guid(iid), parent);
1061 return IWineDXGIFactory_QueryInterface(swapchain->factory, iid, parent);
1064 /* IDXGIDeviceSubObject methods */
1066 static HRESULT STDMETHODCALLTYPE d3d12_swapchain_GetDevice(IDXGISwapChain3 *iface, REFIID iid, void **device)
1068 struct d3d12_swapchain *swapchain = d3d12_swapchain_from_IDXGISwapChain3(iface);
1070 TRACE("iface %p, iid %s, device %p.\n", iface, debugstr_guid(iid), device);
1072 return ID3D12Device_QueryInterface(swapchain->device, iid, device);
1075 /* IDXGISwapChain methods */
1077 static HRESULT STDMETHODCALLTYPE d3d12_swapchain_Present(IDXGISwapChain3 *iface, UINT sync_interval, UINT flags)
1079 struct d3d12_swapchain *swapchain = d3d12_swapchain_from_IDXGISwapChain3(iface);
1081 TRACE("iface %p, sync_interval %u, flags %#x.\n", iface, sync_interval, flags);
1083 return IDXGISwapChain3_Present1(&swapchain->IDXGISwapChain3_iface, sync_interval, flags, NULL);
1086 static HRESULT STDMETHODCALLTYPE d3d12_swapchain_GetBuffer(IDXGISwapChain3 *iface,
1087 UINT buffer_idx, REFIID iid, void **surface)
1089 struct d3d12_swapchain *swapchain = d3d12_swapchain_from_IDXGISwapChain3(iface);
1091 TRACE("iface %p, buffer_idx %u, iid %s, surface %p.\n",
1092 iface, buffer_idx, debugstr_guid(iid), surface);
1094 if (buffer_idx >= swapchain->buffer_count)
1096 WARN("Invalid buffer index %u.\n", buffer_idx);
1097 return DXGI_ERROR_INVALID_CALL;
1100 return ID3D12Resource_QueryInterface(swapchain->buffers[buffer_idx], iid, surface);
1103 static HRESULT STDMETHODCALLTYPE DECLSPEC_HOTPATCH d3d12_swapchain_SetFullscreenState(IDXGISwapChain3 *iface,
1104 BOOL fullscreen, IDXGIOutput *target)
1106 FIXME("iface %p, fullscreen %#x, target %p stub!\n", iface, fullscreen, target);
1108 return E_NOTIMPL;
1111 static HRESULT STDMETHODCALLTYPE d3d12_swapchain_GetFullscreenState(IDXGISwapChain3 *iface,
1112 BOOL *fullscreen, IDXGIOutput **target)
1114 FIXME("iface %p, fullscreen %p, target %p stub!\n", iface, fullscreen, target);
1116 return E_NOTIMPL;
1119 static HRESULT STDMETHODCALLTYPE d3d12_swapchain_GetDesc(IDXGISwapChain3 *iface, DXGI_SWAP_CHAIN_DESC *desc)
1121 struct d3d12_swapchain *swapchain = d3d12_swapchain_from_IDXGISwapChain3(iface);
1122 const DXGI_SWAP_CHAIN_FULLSCREEN_DESC *fullscreen_desc = &swapchain->fullscreen_desc;
1123 const DXGI_SWAP_CHAIN_DESC1 *swapchain_desc = &swapchain->desc;
1125 TRACE("iface %p, desc %p.\n", iface, desc);
1127 if (!desc)
1129 WARN("Invalid pointer.\n");
1130 return E_INVALIDARG;
1133 desc->BufferDesc.Width = swapchain_desc->Width;
1134 desc->BufferDesc.Height = swapchain_desc->Height;
1135 desc->BufferDesc.RefreshRate = fullscreen_desc->RefreshRate;
1136 desc->BufferDesc.Format = swapchain_desc->Format;
1137 desc->BufferDesc.ScanlineOrdering = fullscreen_desc->ScanlineOrdering;
1138 desc->BufferDesc.Scaling = fullscreen_desc->Scaling;
1139 desc->SampleDesc = swapchain_desc->SampleDesc;
1140 desc->BufferUsage = swapchain_desc->BufferUsage;
1141 desc->BufferCount = swapchain_desc->BufferCount;
1142 desc->OutputWindow = swapchain->window;
1143 desc->Windowed = fullscreen_desc->Windowed;
1144 desc->SwapEffect = swapchain_desc->SwapEffect;
1145 desc->Flags = swapchain_desc->Flags;
1147 return S_OK;
1150 static HRESULT STDMETHODCALLTYPE d3d12_swapchain_ResizeBuffers(IDXGISwapChain3 *iface,
1151 UINT buffer_count, UINT width, UINT height, DXGI_FORMAT format, UINT flags)
1153 FIXME("iface %p, buffer_count %u, width %u, height %u, format %s, flags %#x stub!\n",
1154 iface, buffer_count, width, height, debug_dxgi_format(format), flags);
1156 return E_NOTIMPL;
1159 static HRESULT STDMETHODCALLTYPE d3d12_swapchain_ResizeTarget(IDXGISwapChain3 *iface,
1160 const DXGI_MODE_DESC *target_mode_desc)
1162 FIXME("iface %p, target_mode_desc %p stub!\n", iface, target_mode_desc);
1164 return E_NOTIMPL;
1167 static HRESULT STDMETHODCALLTYPE d3d12_swapchain_GetContainingOutput(IDXGISwapChain3 *iface,
1168 IDXGIOutput **output)
1170 FIXME("iface %p, output %p stub!\n", iface, output);
1172 return E_NOTIMPL;
1175 static HRESULT STDMETHODCALLTYPE d3d12_swapchain_GetFrameStatistics(IDXGISwapChain3 *iface,
1176 DXGI_FRAME_STATISTICS *stats)
1178 FIXME("iface %p, stats %p stub!\n", iface, stats);
1180 return E_NOTIMPL;
1183 static HRESULT STDMETHODCALLTYPE d3d12_swapchain_GetLastPresentCount(IDXGISwapChain3 *iface,
1184 UINT *last_present_count)
1186 FIXME("iface %p, last_present_count %p stub!\n", iface, last_present_count);
1188 return E_NOTIMPL;
1191 /* IDXGISwapChain1 methods */
1193 static HRESULT STDMETHODCALLTYPE d3d12_swapchain_GetDesc1(IDXGISwapChain3 *iface, DXGI_SWAP_CHAIN_DESC1 *desc)
1195 struct d3d12_swapchain *swapchain = d3d12_swapchain_from_IDXGISwapChain3(iface);
1197 TRACE("iface %p, desc %p.\n", iface, desc);
1199 if (!desc)
1201 WARN("Invalid pointer.\n");
1202 return E_INVALIDARG;
1205 *desc = swapchain->desc;
1206 return S_OK;
1209 static HRESULT STDMETHODCALLTYPE d3d12_swapchain_GetFullscreenDesc(IDXGISwapChain3 *iface,
1210 DXGI_SWAP_CHAIN_FULLSCREEN_DESC *desc)
1212 struct d3d12_swapchain *swapchain = d3d12_swapchain_from_IDXGISwapChain3(iface);
1214 TRACE("iface %p, desc %p.\n", iface, desc);
1216 if (!desc)
1218 WARN("Invalid pointer.\n");
1219 return E_INVALIDARG;
1222 *desc = swapchain->fullscreen_desc;
1223 return S_OK;
1226 static HRESULT STDMETHODCALLTYPE d3d12_swapchain_GetHwnd(IDXGISwapChain3 *iface, HWND *hwnd)
1228 struct d3d12_swapchain *swapchain = d3d12_swapchain_from_IDXGISwapChain3(iface);
1230 TRACE("iface %p, hwnd %p.\n", iface, hwnd);
1232 if (!hwnd)
1234 WARN("Invalid pointer.\n");
1235 return DXGI_ERROR_INVALID_CALL;
1238 *hwnd = swapchain->window;
1239 return S_OK;
1242 static HRESULT STDMETHODCALLTYPE d3d12_swapchain_GetCoreWindow(IDXGISwapChain3 *iface,
1243 REFIID iid, void **core_window)
1245 FIXME("iface %p, iid %s, core_window %p stub!\n", iface, debugstr_guid(iid), core_window);
1247 if (core_window)
1248 *core_window = NULL;
1250 return DXGI_ERROR_INVALID_CALL;
1253 static HRESULT d3d12_swapchain_acquire_next_image(struct d3d12_swapchain *swapchain)
1255 const struct dxgi_vk_funcs *vk_funcs = &swapchain->vk_funcs;
1256 VkDevice vk_device = swapchain->vk_device;
1257 VkFence vk_fence = swapchain->vk_fence;
1258 VkResult vr;
1260 if ((vr = vk_funcs->p_vkAcquireNextImageKHR(vk_device, swapchain->vk_swapchain, UINT64_MAX,
1261 VK_NULL_HANDLE, vk_fence, &swapchain->current_buffer_index)) < 0)
1263 ERR("Failed to acquire next Vulkan image, vr %d.\n", vr);
1264 return hresult_from_vk_result(vr);
1267 if ((vr = vk_funcs->p_vkWaitForFences(vk_device, 1, &vk_fence, VK_TRUE, UINT64_MAX)) != VK_SUCCESS)
1269 ERR("Failed to wait for fence, vr %d.\n", vr);
1270 return hresult_from_vk_result(vr);
1272 if ((vr = vk_funcs->p_vkResetFences(vk_device, 1, &vk_fence)) < 0)
1274 ERR("Failed to reset fence, vr %d.\n", vr);
1275 return hresult_from_vk_result(vr);
1278 return S_OK;
1281 static HRESULT d3d12_swapchain_blit_buffer(struct d3d12_swapchain *swapchain, VkQueue vk_queue)
1283 const struct dxgi_vk_funcs *vk_funcs = &swapchain->vk_funcs;
1284 VkSubmitInfo submit_info;
1285 VkResult vr;
1287 submit_info.sType = VK_STRUCTURE_TYPE_SUBMIT_INFO;
1288 submit_info.pNext = NULL;
1289 submit_info.waitSemaphoreCount = 0;
1290 submit_info.pWaitSemaphores = NULL;
1291 submit_info.pWaitDstStageMask = NULL;
1292 submit_info.commandBufferCount = 1;
1293 submit_info.pCommandBuffers = &swapchain->vk_cmd_buffers[swapchain->current_buffer_index];
1294 submit_info.signalSemaphoreCount = 1;
1295 submit_info.pSignalSemaphores = &swapchain->vk_semaphores[swapchain->current_buffer_index];
1297 if ((vr = vk_funcs->p_vkQueueSubmit(vk_queue, 1, &submit_info, VK_NULL_HANDLE)) < 0)
1298 ERR("Failed to blit swapchain buffer, vr %d.\n", vr);
1299 return hresult_from_vk_result(vr);
1302 static HRESULT d3d12_swapchain_queue_present(struct d3d12_swapchain *swapchain, VkQueue vk_queue)
1304 const struct dxgi_vk_funcs *vk_funcs = &swapchain->vk_funcs;
1305 VkPresentInfoKHR present_info;
1306 VkResult vr;
1308 present_info.sType = VK_STRUCTURE_TYPE_PRESENT_INFO_KHR;
1309 present_info.pNext = NULL;
1310 present_info.waitSemaphoreCount = 0;
1311 present_info.pWaitSemaphores = NULL;
1312 present_info.swapchainCount = 1;
1313 present_info.pSwapchains = &swapchain->vk_swapchain;
1314 present_info.pImageIndices = &swapchain->current_buffer_index;
1315 present_info.pResults = NULL;
1317 if (swapchain->vk_semaphores[swapchain->current_buffer_index])
1319 present_info.waitSemaphoreCount = 1;
1320 present_info.pWaitSemaphores = &swapchain->vk_semaphores[swapchain->current_buffer_index];
1323 if ((vr = vk_funcs->p_vkQueuePresentKHR(vk_queue, &present_info)) < 0)
1324 ERR("Failed to queue present, vr %d.\n", vr);
1325 return hresult_from_vk_result(vr);
1328 static HRESULT STDMETHODCALLTYPE d3d12_swapchain_Present1(IDXGISwapChain3 *iface,
1329 UINT sync_interval, UINT flags, const DXGI_PRESENT_PARAMETERS *present_parameters)
1331 struct d3d12_swapchain *swapchain = d3d12_swapchain_from_IDXGISwapChain3(iface);
1332 VkQueue vk_queue;
1333 HRESULT hr;
1335 TRACE("iface %p, sync_interval %u, flags %#x, present_parameters %p.\n",
1336 iface, sync_interval, flags, present_parameters);
1338 if (sync_interval > 4)
1340 WARN("Invalid sync interval %u.\n", sync_interval);
1341 return DXGI_ERROR_INVALID_CALL;
1343 if (sync_interval != 1)
1344 FIXME("Ignoring sync interval %u.\n", sync_interval);
1346 if (flags & ~DXGI_PRESENT_TEST)
1347 FIXME("Unimplemented flags %#x.\n", flags);
1348 if (flags & DXGI_PRESENT_TEST)
1350 WARN("Returning S_OK for DXGI_PRESENT_TEST.\n");
1351 return S_OK;
1354 if (present_parameters)
1355 FIXME("Ignored present parameters %p.\n", present_parameters);
1357 if (!(vk_queue = vkd3d_acquire_vk_queue(swapchain->command_queue)))
1359 ERR("Failed to acquire Vulkan queue.\n");
1360 return E_FAIL;
1363 if (swapchain->vk_images[swapchain->current_buffer_index])
1365 if (FAILED(hr = d3d12_swapchain_blit_buffer(swapchain, vk_queue)))
1367 vkd3d_release_vk_queue(swapchain->command_queue);
1368 return hr;
1372 if (FAILED(hr = d3d12_swapchain_queue_present(swapchain, vk_queue)))
1374 vkd3d_release_vk_queue(swapchain->command_queue);
1375 return hr;
1378 vkd3d_release_vk_queue(swapchain->command_queue);
1380 return d3d12_swapchain_acquire_next_image(swapchain);
1383 static BOOL STDMETHODCALLTYPE d3d12_swapchain_IsTemporaryMonoSupported(IDXGISwapChain3 *iface)
1385 FIXME("iface %p stub!\n", iface);
1387 return FALSE;
1390 static HRESULT STDMETHODCALLTYPE d3d12_swapchain_GetRestrictToOutput(IDXGISwapChain3 *iface, IDXGIOutput **output)
1392 FIXME("iface %p, output %p stub!\n", iface, output);
1394 if (!output)
1396 WARN("Invalid pointer.\n");
1397 return E_INVALIDARG;
1400 *output = NULL;
1401 return E_NOTIMPL;
1404 static HRESULT STDMETHODCALLTYPE d3d12_swapchain_SetBackgroundColor(IDXGISwapChain3 *iface, const DXGI_RGBA *color)
1406 FIXME("iface %p, color %p stub!\n", iface, color);
1408 return E_NOTIMPL;
1411 static HRESULT STDMETHODCALLTYPE d3d12_swapchain_GetBackgroundColor(IDXGISwapChain3 *iface, DXGI_RGBA *color)
1413 FIXME("iface %p, color %p stub!\n", iface, color);
1415 return E_NOTIMPL;
1418 static HRESULT STDMETHODCALLTYPE d3d12_swapchain_SetRotation(IDXGISwapChain3 *iface, DXGI_MODE_ROTATION rotation)
1420 FIXME("iface %p, rotation %#x stub!\n", iface, rotation);
1422 return E_NOTIMPL;
1425 static HRESULT STDMETHODCALLTYPE d3d12_swapchain_GetRotation(IDXGISwapChain3 *iface, DXGI_MODE_ROTATION *rotation)
1427 FIXME("iface %p, rotation %p stub!\n", iface, rotation);
1429 return E_NOTIMPL;
1432 /* IDXGISwapChain2 methods */
1434 static HRESULT STDMETHODCALLTYPE d3d12_swapchain_SetSourceSize(IDXGISwapChain3 *iface, UINT width, UINT height)
1436 FIXME("iface %p, width %u, height %u stub!\n", iface, width, height);
1438 return E_NOTIMPL;
1441 static HRESULT STDMETHODCALLTYPE d3d12_swapchain_GetSourceSize(IDXGISwapChain3 *iface, UINT *width, UINT *height)
1443 FIXME("iface %p, width %p, height %p stub!\n", iface, width, height);
1445 return E_NOTIMPL;
1448 static HRESULT STDMETHODCALLTYPE d3d12_swapchain_SetMaximumFrameLatency(IDXGISwapChain3 *iface, UINT max_latency)
1450 FIXME("iface %p, max_latency %u stub!\n", iface, max_latency);
1452 return E_NOTIMPL;
1455 static HRESULT STDMETHODCALLTYPE d3d12_swapchain_GetMaximumFrameLatency(IDXGISwapChain3 *iface, UINT *max_latency)
1457 FIXME("iface %p, max_latency %p stub!\n", iface, max_latency);
1459 return E_NOTIMPL;
1462 static HANDLE STDMETHODCALLTYPE d3d12_swapchain_GetFrameLatencyWaitableObject(IDXGISwapChain3 *iface)
1464 FIXME("iface %p stub!\n", iface);
1466 return NULL;
1469 static HRESULT STDMETHODCALLTYPE d3d12_swapchain_SetMatrixTransform(IDXGISwapChain3 *iface,
1470 const DXGI_MATRIX_3X2_F *matrix)
1472 FIXME("iface %p, matrix %p stub!\n", iface, matrix);
1474 return E_NOTIMPL;
1477 static HRESULT STDMETHODCALLTYPE d3d12_swapchain_GetMatrixTransform(IDXGISwapChain3 *iface,
1478 DXGI_MATRIX_3X2_F *matrix)
1480 FIXME("iface %p, matrix %p stub!\n", iface, matrix);
1482 return E_NOTIMPL;
1485 /* IDXGISwapChain3 methods */
1487 static UINT STDMETHODCALLTYPE d3d12_swapchain_GetCurrentBackBufferIndex(IDXGISwapChain3 *iface)
1489 struct d3d12_swapchain *swapchain = d3d12_swapchain_from_IDXGISwapChain3(iface);
1491 TRACE("iface %p.\n", iface);
1493 return swapchain->current_buffer_index;
1496 static HRESULT STDMETHODCALLTYPE d3d12_swapchain_CheckColorSpaceSupport(IDXGISwapChain3 *iface,
1497 DXGI_COLOR_SPACE_TYPE colour_space, UINT *colour_space_support)
1499 FIXME("iface %p, colour_space %#x, colour_space_support %p stub!\n",
1500 iface, colour_space, colour_space_support);
1502 return E_NOTIMPL;
1505 static HRESULT STDMETHODCALLTYPE d3d12_swapchain_SetColorSpace1(IDXGISwapChain3 *iface,
1506 DXGI_COLOR_SPACE_TYPE colour_space)
1508 FIXME("iface %p, colour_space %#x stub!\n", iface, colour_space);
1510 return E_NOTIMPL;
1513 static HRESULT STDMETHODCALLTYPE d3d12_swapchain_ResizeBuffers1(IDXGISwapChain3 *iface,
1514 UINT buffer_count, UINT width, UINT height, DXGI_FORMAT format, UINT flags,
1515 const UINT *node_mask, IUnknown * const *present_queue)
1517 FIXME("iface %p, buffer_count %u, width %u, height %u, format %s, flags %#x, "
1518 "node_mask %p, present_queue %p stub!\n",
1519 iface, buffer_count, width, height, debug_dxgi_format(format), flags, node_mask, present_queue);
1521 return E_NOTIMPL;
1524 static const struct IDXGISwapChain3Vtbl d3d12_swapchain_vtbl =
1526 /* IUnknown methods */
1527 d3d12_swapchain_QueryInterface,
1528 d3d12_swapchain_AddRef,
1529 d3d12_swapchain_Release,
1530 /* IDXGIObject methods */
1531 d3d12_swapchain_SetPrivateData,
1532 d3d12_swapchain_SetPrivateDataInterface,
1533 d3d12_swapchain_GetPrivateData,
1534 d3d12_swapchain_GetParent,
1535 /* IDXGIDeviceSubObject methods */
1536 d3d12_swapchain_GetDevice,
1537 /* IDXGISwapChain methods */
1538 d3d12_swapchain_Present,
1539 d3d12_swapchain_GetBuffer,
1540 d3d12_swapchain_SetFullscreenState,
1541 d3d12_swapchain_GetFullscreenState,
1542 d3d12_swapchain_GetDesc,
1543 d3d12_swapchain_ResizeBuffers,
1544 d3d12_swapchain_ResizeTarget,
1545 d3d12_swapchain_GetContainingOutput,
1546 d3d12_swapchain_GetFrameStatistics,
1547 d3d12_swapchain_GetLastPresentCount,
1548 /* IDXGISwapChain1 methods */
1549 d3d12_swapchain_GetDesc1,
1550 d3d12_swapchain_GetFullscreenDesc,
1551 d3d12_swapchain_GetHwnd,
1552 d3d12_swapchain_GetCoreWindow,
1553 d3d12_swapchain_Present1,
1554 d3d12_swapchain_IsTemporaryMonoSupported,
1555 d3d12_swapchain_GetRestrictToOutput,
1556 d3d12_swapchain_SetBackgroundColor,
1557 d3d12_swapchain_GetBackgroundColor,
1558 d3d12_swapchain_SetRotation,
1559 d3d12_swapchain_GetRotation,
1560 /* IDXGISwapChain2 methods */
1561 d3d12_swapchain_SetSourceSize,
1562 d3d12_swapchain_GetSourceSize,
1563 d3d12_swapchain_SetMaximumFrameLatency,
1564 d3d12_swapchain_GetMaximumFrameLatency,
1565 d3d12_swapchain_GetFrameLatencyWaitableObject,
1566 d3d12_swapchain_SetMatrixTransform,
1567 d3d12_swapchain_GetMatrixTransform,
1568 /* IDXGISwapChain3 methods */
1569 d3d12_swapchain_GetCurrentBackBufferIndex,
1570 d3d12_swapchain_CheckColorSpaceSupport,
1571 d3d12_swapchain_SetColorSpace1,
1572 d3d12_swapchain_ResizeBuffers1,
1575 static const struct vulkan_funcs *get_vk_funcs(void)
1577 const struct vulkan_funcs *vk_funcs;
1578 HDC hdc;
1580 hdc = GetDC(0);
1581 vk_funcs = __wine_get_vulkan_driver(hdc, WINE_VULKAN_DRIVER_VERSION);
1582 ReleaseDC(0, hdc);
1583 return vk_funcs;
1586 static BOOL load_vkd3d_functions(void *vkd3d_handle)
1588 #define LOAD_FUNCPTR(f) if (!(f = wine_dlsym(vkd3d_handle, #f, NULL, 0))) return FALSE;
1589 LOAD_FUNCPTR(vkd3d_acquire_vk_queue)
1590 LOAD_FUNCPTR(vkd3d_create_image_resource)
1591 LOAD_FUNCPTR(vkd3d_get_vk_device)
1592 LOAD_FUNCPTR(vkd3d_get_vk_format)
1593 LOAD_FUNCPTR(vkd3d_get_vk_physical_device)
1594 LOAD_FUNCPTR(vkd3d_get_vk_queue_family_index)
1595 LOAD_FUNCPTR(vkd3d_instance_from_device)
1596 LOAD_FUNCPTR(vkd3d_instance_get_vk_instance)
1597 LOAD_FUNCPTR(vkd3d_release_vk_queue)
1598 LOAD_FUNCPTR(vkd3d_resource_decref)
1599 LOAD_FUNCPTR(vkd3d_resource_incref)
1600 #undef LOAD_FUNCPTR
1602 return TRUE;
1605 static void *vkd3d_handle;
1607 static BOOL WINAPI init_vkd3d_once(INIT_ONCE *once, void *param, void **context)
1609 TRACE("Loading vkd3d %s.\n", SONAME_LIBVKD3D);
1611 if (!(vkd3d_handle = wine_dlopen(SONAME_LIBVKD3D, RTLD_NOW, NULL, 0)))
1612 return FALSE;
1614 if (!load_vkd3d_functions(vkd3d_handle))
1616 ERR("Failed to load vkd3d functions.\n");
1617 wine_dlclose(vkd3d_handle, NULL, 0);
1618 vkd3d_handle = NULL;
1619 return FALSE;
1622 return TRUE;
1625 static BOOL init_vkd3d(void)
1627 static INIT_ONCE init_once = INIT_ONCE_STATIC_INIT;
1628 InitOnceExecuteOnce(&init_once, init_vkd3d_once, NULL, NULL);
1629 return !!vkd3d_handle;
1632 static BOOL init_vk_funcs(struct dxgi_vk_funcs *dxgi, VkInstance vk_instance, VkDevice vk_device)
1634 const struct vulkan_funcs *vk;
1636 if (!(vk = get_vk_funcs()))
1638 ERR_(winediag)("Failed to load Wine Vulkan driver.\n");
1639 return FALSE;
1642 dxgi->p_vkGetInstanceProcAddr = (PFN_vkGetInstanceProcAddr)vk->p_vkGetInstanceProcAddr;
1644 #define LOAD_INSTANCE_PFN(name) \
1645 if (!(dxgi->p_##name = vk->p_vkGetInstanceProcAddr(vk_instance, #name))) \
1647 ERR("Failed to get instance proc "#name".\n"); \
1648 return FALSE; \
1650 LOAD_INSTANCE_PFN(vkCreateWin32SurfaceKHR)
1651 LOAD_INSTANCE_PFN(vkDestroySurfaceKHR)
1652 LOAD_INSTANCE_PFN(vkGetPhysicalDeviceMemoryProperties)
1653 LOAD_INSTANCE_PFN(vkGetPhysicalDeviceSurfaceCapabilitiesKHR)
1654 LOAD_INSTANCE_PFN(vkGetPhysicalDeviceSurfaceFormatsKHR)
1655 LOAD_INSTANCE_PFN(vkGetPhysicalDeviceSurfacePresentModesKHR)
1656 LOAD_INSTANCE_PFN(vkGetPhysicalDeviceSurfaceSupportKHR)
1657 LOAD_INSTANCE_PFN(vkGetPhysicalDeviceWin32PresentationSupportKHR)
1658 #undef LOAD_INSTANCE_PFN
1660 #define LOAD_DEVICE_PFN(name) \
1661 if (!(dxgi->p_##name = vk->p_vkGetDeviceProcAddr(vk_device, #name))) \
1663 ERR("Failed to get device proc "#name".\n"); \
1664 return FALSE; \
1666 LOAD_DEVICE_PFN(vkAcquireNextImageKHR)
1667 LOAD_DEVICE_PFN(vkAllocateCommandBuffers)
1668 LOAD_DEVICE_PFN(vkAllocateMemory)
1669 LOAD_DEVICE_PFN(vkBeginCommandBuffer)
1670 LOAD_DEVICE_PFN(vkBindImageMemory)
1671 LOAD_DEVICE_PFN(vkCmdBlitImage)
1672 LOAD_DEVICE_PFN(vkCmdPipelineBarrier)
1673 LOAD_DEVICE_PFN(vkCreateCommandPool)
1674 LOAD_DEVICE_PFN(vkCreateFence)
1675 LOAD_DEVICE_PFN(vkCreateImage)
1676 LOAD_DEVICE_PFN(vkCreateSemaphore)
1677 LOAD_DEVICE_PFN(vkCreateSwapchainKHR)
1678 LOAD_DEVICE_PFN(vkDestroyCommandPool)
1679 LOAD_DEVICE_PFN(vkDestroyFence)
1680 LOAD_DEVICE_PFN(vkDestroyImage)
1681 LOAD_DEVICE_PFN(vkDestroySemaphore)
1682 LOAD_DEVICE_PFN(vkDestroySwapchainKHR)
1683 LOAD_DEVICE_PFN(vkEndCommandBuffer)
1684 LOAD_DEVICE_PFN(vkFreeMemory)
1685 LOAD_DEVICE_PFN(vkGetImageMemoryRequirements)
1686 LOAD_DEVICE_PFN(vkGetSwapchainImagesKHR)
1687 LOAD_DEVICE_PFN(vkQueuePresentKHR)
1688 LOAD_DEVICE_PFN(vkQueueSubmit)
1689 LOAD_DEVICE_PFN(vkQueueWaitIdle)
1690 LOAD_DEVICE_PFN(vkResetFences)
1691 LOAD_DEVICE_PFN(vkWaitForFences)
1692 #undef LOAD_DEVICE_PFN
1694 return TRUE;
1697 static HRESULT select_vk_format(const struct dxgi_vk_funcs *vk_funcs,
1698 VkPhysicalDevice vk_physical_device, VkSurfaceKHR vk_surface,
1699 const DXGI_SWAP_CHAIN_DESC1 *swapchain_desc, VkFormat *vk_format)
1701 VkSurfaceFormatKHR *formats;
1702 uint32_t format_count;
1703 VkFormat format;
1704 unsigned int i;
1705 VkResult vr;
1707 *vk_format = VK_FORMAT_UNDEFINED;
1709 format = vkd3d_get_vk_format(swapchain_desc->Format);
1711 vr = vk_funcs->p_vkGetPhysicalDeviceSurfaceFormatsKHR(vk_physical_device, vk_surface, &format_count, NULL);
1712 if (vr < 0 || !format_count)
1714 WARN("Failed to get supported surface formats, vr %d.\n", vr);
1715 return DXGI_ERROR_INVALID_CALL;
1718 if (!(formats = heap_calloc(format_count, sizeof(*formats))))
1719 return E_OUTOFMEMORY;
1721 if ((vr = vk_funcs->p_vkGetPhysicalDeviceSurfaceFormatsKHR(vk_physical_device,
1722 vk_surface, &format_count, formats)) < 0)
1724 WARN("Failed to enumerate supported surface formats, vr %d.\n", vr);
1725 heap_free(formats);
1726 return hresult_from_vk_result(vr);
1729 for (i = 0; i < format_count; ++i)
1731 if (formats[i].format == format && formats[i].colorSpace == VK_COLOR_SPACE_SRGB_NONLINEAR_KHR)
1732 break;
1734 if (i == format_count)
1736 /* Try to create a swapchain with format conversion. */
1737 WARN("Failed to find Vulkan swapchain format for %s.\n", debug_dxgi_format(swapchain_desc->Format));
1738 for (i = 0; i < format_count; ++i)
1740 if (formats[i].colorSpace == VK_COLOR_SPACE_SRGB_NONLINEAR_KHR)
1742 format = formats[i].format;
1743 break;
1747 heap_free(formats);
1748 if (i == format_count)
1750 FIXME("Failed to find Vulkan swapchain format for %s.\n", debug_dxgi_format(swapchain_desc->Format));
1751 return DXGI_ERROR_UNSUPPORTED;
1754 TRACE("Using Vulkan swapchain format %#x.\n", format);
1756 *vk_format = format;
1757 return S_OK;
1760 static DXGI_FORMAT dxgi_format_from_vk_format(VkFormat vk_format)
1762 switch (vk_format)
1764 case VK_FORMAT_B8G8R8A8_SRGB: return DXGI_FORMAT_B8G8R8A8_UNORM_SRGB;
1765 case VK_FORMAT_B8G8R8A8_UNORM: return DXGI_FORMAT_B8G8R8A8_UNORM;
1766 case VK_FORMAT_R8G8B8A8_SRGB: return DXGI_FORMAT_R8G8B8A8_UNORM_SRGB;
1767 case VK_FORMAT_R8G8B8A8_UNORM: return DXGI_FORMAT_R8G8B8A8_UNORM;
1768 default:
1769 FIXME("Unhandled format %#x.\n", vk_format);
1770 return DXGI_FORMAT_UNKNOWN;
1774 static HRESULT vk_select_memory_type(const struct dxgi_vk_funcs *vk_funcs,
1775 VkPhysicalDevice vk_physical_device, uint32_t memory_type_mask,
1776 VkMemoryPropertyFlags flags, uint32_t *memory_type_index)
1778 VkPhysicalDeviceMemoryProperties memory_properties;
1779 unsigned int i;
1781 vk_funcs->p_vkGetPhysicalDeviceMemoryProperties(vk_physical_device, &memory_properties);
1782 for (i = 0; i < memory_properties.memoryTypeCount; ++i)
1784 if (!(memory_type_mask & (1u << i)))
1785 continue;
1787 if ((memory_properties.memoryTypes[i].propertyFlags & flags) == flags)
1789 *memory_type_index = i;
1790 return S_OK;
1794 FIXME("Failed to find memory type (allowed types %#x).\n", memory_type_mask);
1795 return E_FAIL;
1798 static HRESULT d3d12_swapchain_create_user_buffers(struct d3d12_swapchain *swapchain,
1799 const DXGI_SWAP_CHAIN_DESC1 *swapchain_desc, VkFormat vk_format)
1801 const struct dxgi_vk_funcs *vk_funcs = &swapchain->vk_funcs;
1802 VkDeviceSize image_offset[DXGI_MAX_SWAP_CHAIN_BUFFERS];
1803 VkDevice vk_device = swapchain->vk_device;
1804 VkMemoryAllocateInfo allocate_info;
1805 VkMemoryRequirements requirements;
1806 VkImageCreateInfo image_info;
1807 uint32_t memory_type_mask;
1808 VkDeviceSize memory_size;
1809 unsigned int i;
1810 VkResult vr;
1811 HRESULT hr;
1813 memset(&image_info, 0, sizeof(image_info));
1814 image_info.sType = VK_STRUCTURE_TYPE_IMAGE_CREATE_INFO;
1815 image_info.flags = VK_IMAGE_CREATE_MUTABLE_FORMAT_BIT;
1816 image_info.imageType = VK_IMAGE_TYPE_2D;
1817 image_info.format = vk_format;
1818 image_info.extent.width = swapchain_desc->Width;
1819 image_info.extent.height = swapchain_desc->Height;
1820 image_info.extent.depth = 1;
1821 image_info.mipLevels = 1;
1822 image_info.arrayLayers = 1;
1823 image_info.samples = VK_SAMPLE_COUNT_1_BIT;
1824 image_info.tiling = VK_IMAGE_TILING_OPTIMAL;
1825 image_info.usage = VK_IMAGE_USAGE_TRANSFER_SRC_BIT
1826 | VK_IMAGE_USAGE_TRANSFER_DST_BIT
1827 | VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT;
1828 image_info.sharingMode = VK_SHARING_MODE_EXCLUSIVE;
1829 image_info.queueFamilyIndexCount = 0;
1830 image_info.pQueueFamilyIndices = NULL;
1831 image_info.initialLayout = VK_IMAGE_LAYOUT_UNDEFINED;
1833 for (i = 0; i < swapchain->buffer_count; ++i)
1835 if ((vr = vk_funcs->p_vkCreateImage(vk_device, &image_info, NULL, &swapchain->vk_images[i])) < 0)
1837 WARN("Failed to create Vulkan image, vr %d.\n", vr);
1838 swapchain->vk_images[i] = VK_NULL_HANDLE;
1839 return hresult_from_vk_result(vr);
1843 memory_size = 0;
1844 memory_type_mask = ~0u;
1845 for (i = 0; i < swapchain->buffer_count; ++i)
1847 vk_funcs->p_vkGetImageMemoryRequirements(vk_device, swapchain->vk_images[i], &requirements);
1849 TRACE("Size %s, alignment %s, memory types %#x.\n",
1850 wine_dbgstr_longlong(requirements.size), wine_dbgstr_longlong(requirements.alignment),
1851 requirements.memoryTypeBits);
1853 image_offset[i] = (memory_size + (requirements.alignment - 1)) & ~(requirements.alignment - 1);
1854 memory_size = image_offset[i] + requirements.size;
1856 memory_type_mask &= requirements.memoryTypeBits;
1859 TRACE("Allocating %s bytes for user images.\n", wine_dbgstr_longlong(memory_size));
1861 allocate_info.sType = VK_STRUCTURE_TYPE_MEMORY_ALLOCATE_INFO;
1862 allocate_info.pNext = NULL;
1863 allocate_info.allocationSize = memory_size;
1865 if (FAILED(hr = vk_select_memory_type(vk_funcs, swapchain->vk_physical_device,
1866 memory_type_mask, VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT, &allocate_info.memoryTypeIndex)))
1867 return hr;
1869 if ((vr = vk_funcs->p_vkAllocateMemory(vk_device, &allocate_info, NULL, &swapchain->vk_memory)) < 0)
1871 WARN("Failed to allocate device memory, vr %d.\n", vr);
1872 swapchain->vk_memory = VK_NULL_HANDLE;
1873 return hresult_from_vk_result(vr);
1876 for (i = 0; i < swapchain->buffer_count; ++i)
1878 if ((vr = vk_funcs->p_vkBindImageMemory(vk_device, swapchain->vk_images[i],
1879 swapchain->vk_memory, image_offset[i])) < 0)
1881 WARN("Failed to bind image memory, vr %d.\n", vr);
1882 return hresult_from_vk_result(vr);
1886 return S_OK;
1889 static void vk_cmd_image_barrier(const struct dxgi_vk_funcs *vk_funcs, VkCommandBuffer cmd_buffer,
1890 VkPipelineStageFlags src_stage_mask, VkPipelineStageFlags dst_stage_mask,
1891 VkAccessFlags src_access_mask, VkAccessFlags dst_access_mask,
1892 VkImageLayout old_layout, VkImageLayout new_layout, VkImage image)
1894 VkImageMemoryBarrier barrier;
1896 barrier.sType = VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER;
1897 barrier.pNext = NULL;
1898 barrier.srcAccessMask = src_access_mask;
1899 barrier.dstAccessMask = dst_access_mask;
1900 barrier.oldLayout = old_layout;
1901 barrier.newLayout = new_layout;
1902 barrier.srcQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED;
1903 barrier.dstQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED;
1904 barrier.image = image;
1905 barrier.subresourceRange.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT;
1906 barrier.subresourceRange.baseMipLevel = 0;
1907 barrier.subresourceRange.levelCount = VK_REMAINING_MIP_LEVELS;
1908 barrier.subresourceRange.baseArrayLayer = 0;
1909 barrier.subresourceRange.layerCount = VK_REMAINING_ARRAY_LAYERS;
1911 vk_funcs->p_vkCmdPipelineBarrier(cmd_buffer,
1912 src_stage_mask, dst_stage_mask, 0, 0, NULL, 0, NULL, 1, &barrier);
1915 static HRESULT d3d12_swapchain_prepare_command_buffers(struct d3d12_swapchain *swapchain,
1916 const DXGI_SWAP_CHAIN_DESC1 *swapchain_desc, uint32_t queue_family_index,
1917 VkImage vk_swapchain_images[DXGI_MAX_SWAP_CHAIN_BUFFERS])
1919 const struct dxgi_vk_funcs *vk_funcs = &swapchain->vk_funcs;
1920 VkDevice vk_device = swapchain->vk_device;
1921 VkCommandBufferAllocateInfo allocate_info;
1922 VkSemaphoreCreateInfo semaphore_info;
1923 VkCommandBufferBeginInfo begin_info;
1924 VkCommandPoolCreateInfo pool_info;
1925 VkImageBlit blit;
1926 unsigned int i;
1927 VkResult vr;
1929 pool_info.sType = VK_STRUCTURE_TYPE_COMMAND_POOL_CREATE_INFO;
1930 pool_info.pNext = NULL;
1931 pool_info.flags = 0;
1932 pool_info.queueFamilyIndex = queue_family_index;
1934 if ((vr = vk_funcs->p_vkCreateCommandPool(vk_device, &pool_info,
1935 NULL, &swapchain->vk_cmd_pool)) < 0)
1937 WARN("Failed to create command pool, vr %d.\n", vr);
1938 swapchain->vk_cmd_pool = VK_NULL_HANDLE;
1939 return hresult_from_vk_result(vr);
1942 allocate_info.sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_ALLOCATE_INFO;
1943 allocate_info.pNext = NULL;
1944 allocate_info.commandPool = swapchain->vk_cmd_pool;
1945 allocate_info.level = VK_COMMAND_BUFFER_LEVEL_PRIMARY;
1946 allocate_info.commandBufferCount = swapchain->buffer_count;
1948 if ((vr = vk_funcs->p_vkAllocateCommandBuffers(vk_device, &allocate_info,
1949 swapchain->vk_cmd_buffers)) < 0)
1951 WARN("Failed to allocate command buffers, vr %d.\n", vr);
1952 return hresult_from_vk_result(vr);
1955 for (i = 0; i < swapchain->buffer_count; ++i)
1957 VkCommandBuffer vk_cmd_buffer = swapchain->vk_cmd_buffers[i];
1959 begin_info.sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_BEGIN_INFO;
1960 begin_info.pNext = NULL;
1961 begin_info.flags = 0;
1962 begin_info.pInheritanceInfo = NULL;
1964 if ((vr = vk_funcs->p_vkBeginCommandBuffer(vk_cmd_buffer, &begin_info)) < 0)
1966 WARN("Failed to begin command buffer, vr %d.\n", vr);
1967 return hresult_from_vk_result(vr);
1970 vk_cmd_image_barrier(vk_funcs, vk_cmd_buffer,
1971 VK_PIPELINE_STAGE_TOP_OF_PIPE_BIT, VK_PIPELINE_STAGE_TRANSFER_BIT,
1972 0, VK_ACCESS_TRANSFER_WRITE_BIT,
1973 VK_IMAGE_LAYOUT_UNDEFINED, VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL,
1974 vk_swapchain_images[i]);
1976 blit.srcSubresource.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT;
1977 blit.srcSubresource.mipLevel = 0;
1978 blit.srcSubresource.baseArrayLayer = 0;
1979 blit.srcSubresource.layerCount = 1;
1980 blit.srcOffsets[0].x = 0;
1981 blit.srcOffsets[0].y = 0;
1982 blit.srcOffsets[0].z = 0;
1983 blit.srcOffsets[1].x = swapchain_desc->Width;
1984 blit.srcOffsets[1].y = swapchain_desc->Height;
1985 blit.srcOffsets[1].z = 1;
1986 blit.dstSubresource = blit.srcSubresource;
1987 blit.dstOffsets[0] = blit.srcOffsets[0];
1988 blit.dstOffsets[1] = blit.srcOffsets[1];
1990 vk_funcs->p_vkCmdBlitImage(vk_cmd_buffer,
1991 swapchain->vk_images[i], VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL,
1992 vk_swapchain_images[i], VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL,
1993 1, &blit, VK_FILTER_NEAREST);
1995 vk_cmd_image_barrier(vk_funcs, vk_cmd_buffer,
1996 VK_PIPELINE_STAGE_TRANSFER_BIT, VK_PIPELINE_STAGE_BOTTOM_OF_PIPE_BIT,
1997 VK_ACCESS_TRANSFER_WRITE_BIT, 0,
1998 VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, VK_IMAGE_LAYOUT_PRESENT_SRC_KHR,
1999 vk_swapchain_images[i]);
2001 if ((vr = vk_funcs->p_vkEndCommandBuffer(vk_cmd_buffer)) < 0)
2003 WARN("Failed to end command buffer, vr %d.\n", vr);
2004 return hresult_from_vk_result(vr);
2008 for (i = 0; i < swapchain->buffer_count; ++i)
2010 semaphore_info.sType = VK_STRUCTURE_TYPE_SEMAPHORE_CREATE_INFO;
2011 semaphore_info.pNext = NULL;
2012 semaphore_info.flags = 0;
2014 if ((vr = vk_funcs->p_vkCreateSemaphore(vk_device, &semaphore_info,
2015 NULL, &swapchain->vk_semaphores[i])) < 0)
2017 WARN("Failed to create semaphore, vr %d.\n", vr);
2018 swapchain->vk_semaphores[i] = VK_NULL_HANDLE;
2019 return hresult_from_vk_result(vr);
2023 return S_OK;
2026 static HRESULT d3d12_swapchain_create_buffers(struct d3d12_swapchain *swapchain,
2027 ID3D12Device *device, ID3D12CommandQueue *queue,
2028 const DXGI_SWAP_CHAIN_DESC1 *swapchain_desc, VkFormat vk_swapchain_format, VkFormat vk_format)
2030 const struct dxgi_vk_funcs *vk_funcs = &swapchain->vk_funcs;
2031 VkImage vk_swapchain_images[DXGI_MAX_SWAP_CHAIN_BUFFERS];
2032 struct vkd3d_image_resource_create_info resource_info;
2033 VkSwapchainKHR vk_swapchain = swapchain->vk_swapchain;
2034 VkDevice vk_device = swapchain->vk_device;
2035 uint32_t image_count, queue_family_index;
2036 D3D12_COMMAND_QUEUE_DESC queue_desc;
2037 unsigned int i;
2038 VkResult vr;
2039 HRESULT hr;
2041 if ((vr = vk_funcs->p_vkGetSwapchainImagesKHR(vk_device, vk_swapchain, &image_count, NULL)) < 0)
2043 WARN("Failed to get Vulkan swapchain images, vr %d.\n", vr);
2044 return hresult_from_vk_result(vr);
2046 if (image_count != swapchain_desc->BufferCount)
2047 FIXME("Got %u swapchain images, expected %u.\n", image_count, swapchain_desc->BufferCount);
2048 if (image_count > ARRAY_SIZE(vk_swapchain_images))
2049 return E_FAIL;
2050 swapchain->buffer_count = image_count;
2051 if ((vr = vk_funcs->p_vkGetSwapchainImagesKHR(vk_device, vk_swapchain,
2052 &image_count, vk_swapchain_images)) < 0)
2054 WARN("Failed to get Vulkan swapchain images, vr %d.\n", vr);
2055 return hresult_from_vk_result(vr);
2058 resource_info.type = VKD3D_STRUCTURE_TYPE_IMAGE_RESOURCE_CREATE_INFO;
2059 resource_info.next = NULL;
2060 resource_info.desc.Dimension = D3D12_RESOURCE_DIMENSION_TEXTURE2D;
2061 resource_info.desc.Alignment = 0;
2062 resource_info.desc.Width = swapchain_desc->Width;
2063 resource_info.desc.Height = swapchain_desc->Height;
2064 resource_info.desc.DepthOrArraySize = 1;
2065 resource_info.desc.MipLevels = 1;
2066 resource_info.desc.Format = dxgi_format_from_vk_format(vk_format);
2067 resource_info.desc.SampleDesc.Count = 1;
2068 resource_info.desc.SampleDesc.Quality = 0;
2069 resource_info.desc.Layout = D3D12_TEXTURE_LAYOUT_UNKNOWN;
2070 resource_info.desc.Flags = D3D12_RESOURCE_FLAG_ALLOW_RENDER_TARGET;
2071 resource_info.flags = VKD3D_RESOURCE_INITIAL_STATE_TRANSITION | VKD3D_RESOURCE_PRESENT_STATE_TRANSITION;
2073 if (vk_swapchain_format != vk_format)
2075 queue_desc = ID3D12CommandQueue_GetDesc(queue);
2076 if (queue_desc.Type != D3D12_COMMAND_LIST_TYPE_DIRECT)
2078 /* vkCmdBlitImage() is only supported for Graphics queues. */
2079 FIXME("Format conversion not implemented for command queue type %#x.\n", queue_desc.Type);
2080 return E_NOTIMPL;
2082 queue_family_index = vkd3d_get_vk_queue_family_index(queue);
2084 TRACE("Creating user swapchain buffers for format conversion.\n");
2086 if (FAILED(hr = d3d12_swapchain_create_user_buffers(swapchain, swapchain_desc, vk_format)))
2087 return hr;
2089 if (FAILED(hr = d3d12_swapchain_prepare_command_buffers(swapchain, swapchain_desc,
2090 queue_family_index, vk_swapchain_images)))
2091 return hr;
2094 for (i = 0; i < swapchain->buffer_count; ++i)
2096 if (swapchain->vk_images[i])
2098 resource_info.vk_image = swapchain->vk_images[i];
2099 resource_info.present_state = D3D12_RESOURCE_STATE_COPY_SOURCE;
2101 else
2103 resource_info.vk_image = vk_swapchain_images[i];
2104 resource_info.present_state = D3D12_RESOURCE_STATE_PRESENT;
2107 if (FAILED(hr = vkd3d_create_image_resource(device, &resource_info, &swapchain->buffers[i])))
2109 WARN("Failed to create vkd3d resource for Vulkan image %u, hr %#x.\n", i, hr);
2110 return hr;
2113 vkd3d_resource_incref(swapchain->buffers[i]);
2114 ID3D12Resource_Release(swapchain->buffers[i]);
2117 return S_OK;
2120 static HRESULT d3d12_swapchain_init(struct d3d12_swapchain *swapchain, IWineDXGIFactory *factory,
2121 ID3D12Device *device, ID3D12CommandQueue *queue, HWND window,
2122 const DXGI_SWAP_CHAIN_DESC1 *swapchain_desc, const DXGI_SWAP_CHAIN_FULLSCREEN_DESC *fullscreen_desc)
2124 const struct dxgi_vk_funcs *vk_funcs = &swapchain->vk_funcs;
2125 struct VkSwapchainCreateInfoKHR vk_swapchain_desc;
2126 struct VkWin32SurfaceCreateInfoKHR surface_desc;
2127 VkSwapchainKHR vk_swapchain = VK_NULL_HANDLE;
2128 VkSurfaceKHR vk_surface = VK_NULL_HANDLE;
2129 VkFormat vk_swapchain_format, vk_format;
2130 VkSurfaceCapabilitiesKHR surface_caps;
2131 VkPhysicalDevice vk_physical_device;
2132 VkFence vk_fence = VK_NULL_HANDLE;
2133 VkFenceCreateInfo fence_desc;
2134 uint32_t queue_family_index;
2135 VkImageUsageFlags usage;
2136 VkInstance vk_instance;
2137 VkBool32 supported;
2138 VkDevice vk_device;
2139 VkResult vr;
2140 HRESULT hr;
2142 swapchain->IDXGISwapChain3_iface.lpVtbl = &d3d12_swapchain_vtbl;
2143 swapchain->refcount = 1;
2145 swapchain->window = window;
2146 swapchain->desc = *swapchain_desc;
2147 swapchain->fullscreen_desc = *fullscreen_desc;
2149 switch (swapchain_desc->SwapEffect)
2151 case DXGI_SWAP_EFFECT_FLIP_SEQUENTIAL:
2152 case DXGI_SWAP_EFFECT_FLIP_DISCARD:
2153 FIXME("Ignoring swap effect %#x.\n", swapchain_desc->SwapEffect);
2154 break;
2155 default:
2156 WARN("Invalid swap effect %#x.\n", swapchain_desc->SwapEffect);
2157 return DXGI_ERROR_INVALID_CALL;
2160 if (!init_vkd3d())
2162 ERR_(winediag)("libvkd3d could not be loaded.\n");
2163 return DXGI_ERROR_UNSUPPORTED;
2166 if (!(vk_format = vkd3d_get_vk_format(swapchain_desc->Format)))
2168 WARN("Invalid format %#x.\n", swapchain_desc->Format);
2169 return DXGI_ERROR_INVALID_CALL;
2172 if (swapchain_desc->BufferUsage && swapchain_desc->BufferUsage != DXGI_USAGE_RENDER_TARGET_OUTPUT)
2173 FIXME("Ignoring buffer usage %#x.\n", swapchain_desc->BufferUsage);
2174 if (swapchain_desc->Scaling != DXGI_SCALING_STRETCH)
2175 FIXME("Ignoring scaling %#x.\n", swapchain_desc->Scaling);
2176 if (swapchain_desc->AlphaMode && swapchain_desc->AlphaMode != DXGI_ALPHA_MODE_IGNORE)
2177 FIXME("Ignoring alpha mode %#x.\n", swapchain_desc->AlphaMode);
2178 if (swapchain_desc->Flags)
2179 FIXME("Ignoring swapchain flags %#x.\n", swapchain_desc->Flags);
2181 FIXME("Ignoring refresh rate.\n");
2182 if (fullscreen_desc->ScanlineOrdering)
2183 FIXME("Unhandled scanline ordering %#x.\n", fullscreen_desc->ScanlineOrdering);
2184 if (fullscreen_desc->Scaling)
2185 FIXME("Unhandled mode scaling %#x.\n", fullscreen_desc->Scaling);
2186 if (!fullscreen_desc->Windowed)
2187 FIXME("Fullscreen not supported yet.\n");
2189 vk_instance = vkd3d_instance_get_vk_instance(vkd3d_instance_from_device(device));
2190 vk_physical_device = vkd3d_get_vk_physical_device(device);
2191 vk_device = vkd3d_get_vk_device(device);
2193 swapchain->vk_instance = vk_instance;
2194 swapchain->vk_device = vk_device;
2195 swapchain->vk_physical_device = vk_physical_device;
2197 if (!init_vk_funcs(&swapchain->vk_funcs, vk_instance, vk_device))
2198 return E_FAIL;
2200 wined3d_private_store_init(&swapchain->private_store);
2202 surface_desc.sType = VK_STRUCTURE_TYPE_WIN32_SURFACE_CREATE_INFO_KHR;
2203 surface_desc.pNext = NULL;
2204 surface_desc.flags = 0;
2205 surface_desc.hinstance = GetModuleHandleA("dxgi.dll");
2206 surface_desc.hwnd = window;
2207 if ((vr = vk_funcs->p_vkCreateWin32SurfaceKHR(vk_instance, &surface_desc, NULL, &vk_surface)) < 0)
2209 WARN("Failed to create Vulkan surface, vr %d.\n", vr);
2210 d3d12_swapchain_destroy(swapchain);
2211 return hresult_from_vk_result(vr);
2213 swapchain->vk_surface = vk_surface;
2215 queue_family_index = vkd3d_get_vk_queue_family_index(queue);
2216 if ((vr = vk_funcs->p_vkGetPhysicalDeviceSurfaceSupportKHR(vk_physical_device,
2217 queue_family_index, vk_surface, &supported)) < 0 || !supported)
2219 FIXME("Queue family does not support presentation, vr %d.\n", vr);
2220 d3d12_swapchain_destroy(swapchain);
2221 return DXGI_ERROR_UNSUPPORTED;
2224 if (FAILED(hr = select_vk_format(vk_funcs, vk_physical_device,
2225 vk_surface, swapchain_desc, &vk_swapchain_format)))
2227 d3d12_swapchain_destroy(swapchain);
2228 return hr;
2231 if ((vr = vk_funcs->p_vkGetPhysicalDeviceSurfaceCapabilitiesKHR(vk_physical_device,
2232 vk_surface, &surface_caps)) < 0)
2234 WARN("Failed to get surface capabilities, vr %d.\n", vr);
2235 d3d12_swapchain_destroy(swapchain);
2236 return hresult_from_vk_result(vr);
2239 if (surface_caps.maxImageCount && (swapchain_desc->BufferCount > surface_caps.maxImageCount
2240 || swapchain_desc->BufferCount < surface_caps.minImageCount))
2242 WARN("Buffer count %u is not supported (%u-%u).\n", swapchain_desc->BufferCount,
2243 surface_caps.minImageCount, surface_caps.maxImageCount);
2244 d3d12_swapchain_destroy(swapchain);
2245 return DXGI_ERROR_UNSUPPORTED;
2248 if (swapchain_desc->Width > surface_caps.maxImageExtent.width
2249 || swapchain_desc->Width < surface_caps.minImageExtent.width
2250 || swapchain_desc->Height > surface_caps.maxImageExtent.height
2251 || swapchain_desc->Height < surface_caps.minImageExtent.height)
2253 FIXME("Swapchain dimensions %ux%u are not supported (%u-%u x %u-%u).\n",
2254 swapchain_desc->Width, swapchain_desc->Height,
2255 surface_caps.minImageExtent.width, surface_caps.maxImageExtent.width,
2256 surface_caps.minImageExtent.height, surface_caps.maxImageExtent.height);
2259 if (!(surface_caps.supportedCompositeAlpha & VK_COMPOSITE_ALPHA_OPAQUE_BIT_KHR))
2261 FIXME("Unsupported alpha mode.\n");
2262 d3d12_swapchain_destroy(swapchain);
2263 return DXGI_ERROR_UNSUPPORTED;
2266 usage = VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT;
2267 usage |= surface_caps.supportedUsageFlags & VK_IMAGE_USAGE_TRANSFER_SRC_BIT;
2268 usage |= surface_caps.supportedUsageFlags & VK_IMAGE_USAGE_TRANSFER_DST_BIT;
2269 if (!(usage & VK_IMAGE_USAGE_TRANSFER_SRC_BIT) || !(usage & VK_IMAGE_USAGE_TRANSFER_DST_BIT))
2270 WARN("Transfer not supported for swapchain images.\n");
2272 vk_swapchain_desc.sType = VK_STRUCTURE_TYPE_SWAPCHAIN_CREATE_INFO_KHR;
2273 vk_swapchain_desc.pNext = NULL;
2274 vk_swapchain_desc.flags = 0;
2275 vk_swapchain_desc.surface = vk_surface;
2276 vk_swapchain_desc.minImageCount = swapchain_desc->BufferCount;
2277 vk_swapchain_desc.imageFormat = vk_swapchain_format;
2278 vk_swapchain_desc.imageColorSpace = VK_COLOR_SPACE_SRGB_NONLINEAR_KHR;
2279 vk_swapchain_desc.imageExtent.width = swapchain_desc->Width;
2280 vk_swapchain_desc.imageExtent.height = swapchain_desc->Height;
2281 vk_swapchain_desc.imageArrayLayers = 1;
2282 vk_swapchain_desc.imageUsage = usage;
2283 vk_swapchain_desc.imageSharingMode = VK_SHARING_MODE_EXCLUSIVE;
2284 vk_swapchain_desc.queueFamilyIndexCount = 0;
2285 vk_swapchain_desc.pQueueFamilyIndices = NULL;
2286 vk_swapchain_desc.preTransform = surface_caps.currentTransform;
2287 vk_swapchain_desc.compositeAlpha = VK_COMPOSITE_ALPHA_OPAQUE_BIT_KHR;
2288 vk_swapchain_desc.presentMode = VK_PRESENT_MODE_FIFO_KHR;
2289 vk_swapchain_desc.clipped = VK_TRUE;
2290 vk_swapchain_desc.oldSwapchain = VK_NULL_HANDLE;
2291 if ((vr = vk_funcs->p_vkCreateSwapchainKHR(vk_device, &vk_swapchain_desc, NULL, &vk_swapchain)) < 0)
2293 WARN("Failed to create Vulkan swapchain, vr %d.\n", vr);
2294 d3d12_swapchain_destroy(swapchain);
2295 return hresult_from_vk_result(vr);
2297 swapchain->vk_swapchain = vk_swapchain;
2299 fence_desc.sType = VK_STRUCTURE_TYPE_FENCE_CREATE_INFO;
2300 fence_desc.pNext = NULL;
2301 fence_desc.flags = 0;
2302 if ((vr = vk_funcs->p_vkCreateFence(vk_device, &fence_desc, NULL, &vk_fence)) < 0)
2304 WARN("Failed to create Vulkan fence, vr %d.\n", vr);
2305 d3d12_swapchain_destroy(swapchain);
2306 return hresult_from_vk_result(vr);
2308 swapchain->vk_fence = vk_fence;
2310 if (FAILED(hr = d3d12_swapchain_create_buffers(swapchain, device, queue,
2311 swapchain_desc, vk_swapchain_format, vk_format)))
2313 d3d12_swapchain_destroy(swapchain);
2314 return hr;
2317 if (FAILED(hr = d3d12_swapchain_acquire_next_image(swapchain)))
2319 WARN("Failed to acquire Vulkan image, hr %#x.\n", hr);
2320 d3d12_swapchain_destroy(swapchain);
2321 return hr;
2324 ID3D12CommandQueue_AddRef(swapchain->command_queue = queue);
2325 ID3D12Device_AddRef(swapchain->device = device);
2326 IWineDXGIFactory_AddRef(swapchain->factory = factory);
2328 return S_OK;
2331 HRESULT d3d12_swapchain_create(IWineDXGIFactory *factory, ID3D12CommandQueue *queue, HWND window,
2332 const DXGI_SWAP_CHAIN_DESC1 *swapchain_desc, const DXGI_SWAP_CHAIN_FULLSCREEN_DESC *fullscreen_desc,
2333 IDXGISwapChain1 **swapchain)
2335 DXGI_SWAP_CHAIN_FULLSCREEN_DESC default_fullscreen_desc;
2336 struct d3d12_swapchain *object;
2337 ID3D12Device *device;
2338 HRESULT hr;
2340 if (!fullscreen_desc)
2342 memset(&default_fullscreen_desc, 0, sizeof(default_fullscreen_desc));
2343 default_fullscreen_desc.Windowed = TRUE;
2344 fullscreen_desc = &default_fullscreen_desc;
2347 if (!(object = heap_alloc_zero(sizeof(*object))))
2348 return E_OUTOFMEMORY;
2350 if (FAILED(hr = ID3D12CommandQueue_GetDevice(queue, &IID_ID3D12Device, (void **)&device)))
2352 ERR("Failed to get D3D12 device, hr %#x.\n", hr);
2353 heap_free(object);
2354 return hr;
2357 hr = d3d12_swapchain_init(object, factory, device, queue, window, swapchain_desc, fullscreen_desc);
2358 ID3D12Device_Release(device);
2359 if (FAILED(hr))
2361 heap_free(object);
2362 return hr;
2365 TRACE("Created swapchain %p.\n", object);
2367 *swapchain = (IDXGISwapChain1 *)&object->IDXGISwapChain3_iface;
2369 return S_OK;
2372 #else
2374 HRESULT d3d12_swapchain_create(IWineDXGIFactory *factory, ID3D12CommandQueue *queue, HWND window,
2375 const DXGI_SWAP_CHAIN_DESC1 *swapchain_desc, const DXGI_SWAP_CHAIN_FULLSCREEN_DESC *fullscreen_desc,
2376 IDXGISwapChain1 **swapchain)
2378 ERR_(winediag)("Wine was built without Direct3D 12 support.\n");
2379 return DXGI_ERROR_UNSUPPORTED;
2382 #endif /* SONAME_LIBVKD3D */