makefiles: Output rules for building generated .rc files.
[wine.git] / dlls / dxgi / swapchain.c
blob4dfa06873351eb6fb9a5fe314a50a705aaa84820
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 DXGI_SWAP_EFFECT dxgi_swap_effect_from_wined3d(enum wined3d_swap_effect swap_effect)
42 switch (swap_effect)
44 case WINED3D_SWAP_EFFECT_DISCARD:
45 return DXGI_SWAP_EFFECT_DISCARD;
46 case WINED3D_SWAP_EFFECT_SEQUENTIAL:
47 return DXGI_SWAP_EFFECT_SEQUENTIAL;
48 case WINED3D_SWAP_EFFECT_FLIP_DISCARD:
49 return DXGI_SWAP_EFFECT_FLIP_DISCARD;
50 case WINED3D_SWAP_EFFECT_FLIP_SEQUENTIAL:
51 return DXGI_SWAP_EFFECT_FLIP_SEQUENTIAL;
52 default:
53 FIXME("Invalid swap effect %#x.\n", swap_effect);
54 return DXGI_SWAP_EFFECT_DISCARD;
58 static BOOL dxgi_validate_flip_swap_effect_format(DXGI_FORMAT format)
60 switch (format)
62 case DXGI_FORMAT_R16G16B16A16_FLOAT:
63 case DXGI_FORMAT_R10G10B10A2_UNORM:
64 case DXGI_FORMAT_R8G8B8A8_UNORM:
65 case DXGI_FORMAT_B8G8R8A8_UNORM:
66 return TRUE;
67 default:
68 WARN("Invalid swapchain format %#x for flip presentation model.\n", format);
69 return FALSE;
73 BOOL dxgi_validate_swapchain_desc(const DXGI_SWAP_CHAIN_DESC1 *desc)
75 unsigned int min_buffer_count;
77 switch (desc->SwapEffect)
79 case DXGI_SWAP_EFFECT_DISCARD:
80 case DXGI_SWAP_EFFECT_SEQUENTIAL:
81 min_buffer_count = 1;
82 break;
84 case DXGI_SWAP_EFFECT_FLIP_DISCARD:
85 case DXGI_SWAP_EFFECT_FLIP_SEQUENTIAL:
86 min_buffer_count = 2;
88 if (!dxgi_validate_flip_swap_effect_format(desc->Format))
89 return FALSE;
91 if (desc->SampleDesc.Count != 1 || desc->SampleDesc.Quality)
93 WARN("Invalid sample desc %u, %u for swap effect %#x.\n",
94 desc->SampleDesc.Count, desc->SampleDesc.Quality, desc->SwapEffect);
95 return FALSE;
97 break;
99 default:
100 WARN("Invalid swap effect %u used.\n", desc->SwapEffect);
101 return FALSE;
104 if (desc->BufferCount < min_buffer_count || desc->BufferCount > DXGI_MAX_SWAP_CHAIN_BUFFERS)
106 WARN("BufferCount is %u.\n", desc->BufferCount);
107 return FALSE;
110 return TRUE;
113 static inline struct d3d11_swapchain *d3d11_swapchain_from_IDXGISwapChain1(IDXGISwapChain1 *iface)
115 return CONTAINING_RECORD(iface, struct d3d11_swapchain, IDXGISwapChain1_iface);
118 /* IUnknown methods */
120 static HRESULT STDMETHODCALLTYPE d3d11_swapchain_QueryInterface(IDXGISwapChain1 *iface, REFIID riid, void **object)
122 TRACE("iface %p, riid %s, object %p\n", iface, debugstr_guid(riid), object);
124 if (IsEqualGUID(riid, &IID_IUnknown)
125 || IsEqualGUID(riid, &IID_IDXGIObject)
126 || IsEqualGUID(riid, &IID_IDXGIDeviceSubObject)
127 || IsEqualGUID(riid, &IID_IDXGISwapChain)
128 || IsEqualGUID(riid, &IID_IDXGISwapChain1))
130 IUnknown_AddRef(iface);
131 *object = iface;
132 return S_OK;
135 WARN("%s not implemented, returning E_NOINTERFACE\n", debugstr_guid(riid));
137 *object = NULL;
138 return E_NOINTERFACE;
141 static ULONG STDMETHODCALLTYPE d3d11_swapchain_AddRef(IDXGISwapChain1 *iface)
143 struct d3d11_swapchain *swapchain = d3d11_swapchain_from_IDXGISwapChain1(iface);
144 ULONG refcount = InterlockedIncrement(&swapchain->refcount);
146 TRACE("%p increasing refcount to %u.\n", swapchain, refcount);
148 if (refcount == 1)
149 wined3d_swapchain_incref(swapchain->wined3d_swapchain);
151 return refcount;
154 static ULONG STDMETHODCALLTYPE d3d11_swapchain_Release(IDXGISwapChain1 *iface)
156 struct d3d11_swapchain *swapchain = d3d11_swapchain_from_IDXGISwapChain1(iface);
157 ULONG refcount = InterlockedDecrement(&swapchain->refcount);
159 TRACE("%p decreasing refcount to %u.\n", swapchain, refcount);
161 if (!refcount)
163 IWineDXGIDevice *device = swapchain->device;
164 if (swapchain->target)
166 WARN("Releasing fullscreen swapchain.\n");
167 IDXGIOutput_Release(swapchain->target);
169 if (swapchain->factory)
170 IDXGIFactory_Release(swapchain->factory);
171 wined3d_swapchain_decref(swapchain->wined3d_swapchain);
172 if (device)
173 IWineDXGIDevice_Release(device);
176 return refcount;
179 /* IDXGIObject methods */
181 static HRESULT STDMETHODCALLTYPE d3d11_swapchain_SetPrivateData(IDXGISwapChain1 *iface,
182 REFGUID guid, UINT data_size, const void *data)
184 struct d3d11_swapchain *swapchain = d3d11_swapchain_from_IDXGISwapChain1(iface);
186 TRACE("iface %p, guid %s, data_size %u, data %p.\n", iface, debugstr_guid(guid), data_size, data);
188 return dxgi_set_private_data(&swapchain->private_store, guid, data_size, data);
191 static HRESULT STDMETHODCALLTYPE d3d11_swapchain_SetPrivateDataInterface(IDXGISwapChain1 *iface,
192 REFGUID guid, const IUnknown *object)
194 struct d3d11_swapchain *swapchain = d3d11_swapchain_from_IDXGISwapChain1(iface);
196 TRACE("iface %p, guid %s, object %p.\n", iface, debugstr_guid(guid), object);
198 return dxgi_set_private_data_interface(&swapchain->private_store, guid, object);
201 static HRESULT STDMETHODCALLTYPE d3d11_swapchain_GetPrivateData(IDXGISwapChain1 *iface,
202 REFGUID guid, UINT *data_size, void *data)
204 struct d3d11_swapchain *swapchain = d3d11_swapchain_from_IDXGISwapChain1(iface);
206 TRACE("iface %p, guid %s, data_size %p, data %p.\n", iface, debugstr_guid(guid), data_size, data);
208 return dxgi_get_private_data(&swapchain->private_store, guid, data_size, data);
211 static HRESULT STDMETHODCALLTYPE d3d11_swapchain_GetParent(IDXGISwapChain1 *iface, REFIID riid, void **parent)
213 struct d3d11_swapchain *swapchain = d3d11_swapchain_from_IDXGISwapChain1(iface);
215 TRACE("iface %p, riid %s, parent %p.\n", iface, debugstr_guid(riid), parent);
217 if (!swapchain->factory)
219 ERR("Implicit swapchain does not store reference to parent.\n");
220 *parent = NULL;
221 return E_NOINTERFACE;
224 return IDXGIFactory_QueryInterface(swapchain->factory, riid, parent);
227 /* IDXGIDeviceSubObject methods */
229 static HRESULT STDMETHODCALLTYPE d3d11_swapchain_GetDevice(IDXGISwapChain1 *iface, REFIID riid, void **device)
231 struct d3d11_swapchain *swapchain = d3d11_swapchain_from_IDXGISwapChain1(iface);
233 TRACE("iface %p, riid %s, device %p.\n", iface, debugstr_guid(riid), device);
235 if (!swapchain->device)
237 ERR("Implicit swapchain does not store reference to device.\n");
238 *device = NULL;
239 return E_NOINTERFACE;
242 return IWineDXGIDevice_QueryInterface(swapchain->device, riid, device);
245 /* IDXGISwapChain1 methods */
247 static HRESULT STDMETHODCALLTYPE d3d11_swapchain_Present(IDXGISwapChain1 *iface, UINT sync_interval, UINT flags)
249 struct d3d11_swapchain *swapchain = d3d11_swapchain_from_IDXGISwapChain1(iface);
251 TRACE("iface %p, sync_interval %u, flags %#x.\n", iface, sync_interval, flags);
253 return IDXGISwapChain1_Present1(&swapchain->IDXGISwapChain1_iface, sync_interval, flags, NULL);
256 static HRESULT STDMETHODCALLTYPE d3d11_swapchain_GetBuffer(IDXGISwapChain1 *iface,
257 UINT buffer_idx, REFIID riid, void **surface)
259 struct d3d11_swapchain *swapchain = d3d11_swapchain_from_IDXGISwapChain1(iface);
260 struct wined3d_texture *texture;
261 IUnknown *parent;
262 HRESULT hr;
264 TRACE("iface %p, buffer_idx %u, riid %s, surface %p\n",
265 iface, buffer_idx, debugstr_guid(riid), surface);
267 wined3d_mutex_lock();
269 if (!(texture = wined3d_swapchain_get_back_buffer(swapchain->wined3d_swapchain, buffer_idx)))
271 wined3d_mutex_unlock();
272 return DXGI_ERROR_INVALID_CALL;
275 parent = wined3d_texture_get_parent(texture);
276 hr = IUnknown_QueryInterface(parent, riid, surface);
277 wined3d_mutex_unlock();
279 return hr;
282 static HRESULT STDMETHODCALLTYPE DECLSPEC_HOTPATCH d3d11_swapchain_SetFullscreenState(IDXGISwapChain1 *iface,
283 BOOL fullscreen, IDXGIOutput *target)
285 struct d3d11_swapchain *swapchain = d3d11_swapchain_from_IDXGISwapChain1(iface);
286 struct wined3d_swapchain_desc swapchain_desc;
287 HRESULT hr;
289 TRACE("iface %p, fullscreen %#x, target %p.\n", iface, fullscreen, target);
291 if (!fullscreen && target)
293 WARN("Invalid call.\n");
294 return DXGI_ERROR_INVALID_CALL;
297 if (fullscreen)
299 if (target)
301 IDXGIOutput_AddRef(target);
303 else if (FAILED(hr = IDXGISwapChain1_GetContainingOutput(iface, &target)))
305 WARN("Failed to get default target output for swapchain, hr %#x.\n", hr);
306 return hr;
310 wined3d_mutex_lock();
311 wined3d_swapchain_get_desc(swapchain->wined3d_swapchain, &swapchain_desc);
312 swapchain_desc.windowed = !fullscreen;
313 hr = wined3d_swapchain_set_fullscreen(swapchain->wined3d_swapchain, &swapchain_desc, NULL);
314 wined3d_mutex_unlock();
316 if (SUCCEEDED(hr))
318 swapchain->fullscreen = fullscreen;
319 if (swapchain->target)
320 IDXGIOutput_Release(swapchain->target);
321 swapchain->target = target;
322 return S_OK;
325 if (target)
326 IDXGIOutput_Release(target);
327 return hr;
330 static HRESULT STDMETHODCALLTYPE d3d11_swapchain_GetFullscreenState(IDXGISwapChain1 *iface,
331 BOOL *fullscreen, IDXGIOutput **target)
333 struct d3d11_swapchain *swapchain = d3d11_swapchain_from_IDXGISwapChain1(iface);
335 TRACE("iface %p, fullscreen %p, target %p.\n", iface, fullscreen, target);
337 if (fullscreen)
338 *fullscreen = swapchain->fullscreen;
340 if (target)
342 *target = swapchain->target;
343 if (*target)
344 IDXGIOutput_AddRef(*target);
347 return S_OK;
350 static HRESULT STDMETHODCALLTYPE d3d11_swapchain_GetDesc(IDXGISwapChain1 *iface, DXGI_SWAP_CHAIN_DESC *desc)
352 struct d3d11_swapchain *swapchain = d3d11_swapchain_from_IDXGISwapChain1(iface);
353 struct wined3d_swapchain_desc wined3d_desc;
355 TRACE("iface %p, desc %p.\n", iface, desc);
357 if (!desc)
359 WARN("Invalid pointer.\n");
360 return E_INVALIDARG;
363 wined3d_mutex_lock();
364 wined3d_swapchain_get_desc(swapchain->wined3d_swapchain, &wined3d_desc);
365 wined3d_mutex_unlock();
367 FIXME("Ignoring ScanlineOrdering and Scaling.\n");
369 desc->BufferDesc.Width = wined3d_desc.backbuffer_width;
370 desc->BufferDesc.Height = wined3d_desc.backbuffer_height;
371 desc->BufferDesc.RefreshRate.Numerator = wined3d_desc.refresh_rate;
372 desc->BufferDesc.RefreshRate.Denominator = 1;
373 desc->BufferDesc.Format = dxgi_format_from_wined3dformat(wined3d_desc.backbuffer_format);
374 desc->BufferDesc.ScanlineOrdering = DXGI_MODE_SCANLINE_ORDER_UNSPECIFIED;
375 desc->BufferDesc.Scaling = DXGI_MODE_SCALING_UNSPECIFIED;
376 dxgi_sample_desc_from_wined3d(&desc->SampleDesc,
377 wined3d_desc.multisample_type, wined3d_desc.multisample_quality);
378 desc->BufferUsage = dxgi_usage_from_wined3d_bind_flags(wined3d_desc.backbuffer_bind_flags);
379 desc->BufferCount = wined3d_desc.backbuffer_count;
380 desc->OutputWindow = wined3d_desc.device_window;
381 desc->Windowed = wined3d_desc.windowed;
382 desc->SwapEffect = dxgi_swap_effect_from_wined3d(wined3d_desc.swap_effect);
383 desc->Flags = dxgi_swapchain_flags_from_wined3d(wined3d_desc.flags);
385 return S_OK;
388 static HRESULT STDMETHODCALLTYPE d3d11_swapchain_ResizeBuffers(IDXGISwapChain1 *iface,
389 UINT buffer_count, UINT width, UINT height, DXGI_FORMAT format, UINT flags)
391 struct d3d11_swapchain *swapchain = d3d11_swapchain_from_IDXGISwapChain1(iface);
392 struct wined3d_swapchain_desc wined3d_desc;
393 struct wined3d_texture *texture;
394 IUnknown *parent;
395 unsigned int i;
396 HRESULT hr;
398 TRACE("iface %p, buffer_count %u, width %u, height %u, format %s, flags %#x.\n",
399 iface, buffer_count, width, height, debug_dxgi_format(format), flags);
401 if (flags)
402 FIXME("Ignoring flags %#x.\n", flags);
404 wined3d_mutex_lock();
405 wined3d_swapchain_get_desc(swapchain->wined3d_swapchain, &wined3d_desc);
406 for (i = 0; i < wined3d_desc.backbuffer_count; ++i)
408 texture = wined3d_swapchain_get_back_buffer(swapchain->wined3d_swapchain, i);
409 parent = wined3d_texture_get_parent(texture);
410 IUnknown_AddRef(parent);
411 if (IUnknown_Release(parent))
413 wined3d_mutex_unlock();
414 return DXGI_ERROR_INVALID_CALL;
417 if (format != DXGI_FORMAT_UNKNOWN)
418 wined3d_desc.backbuffer_format = wined3dformat_from_dxgi_format(format);
419 hr = wined3d_swapchain_resize_buffers(swapchain->wined3d_swapchain, buffer_count, width, height,
420 wined3d_desc.backbuffer_format, wined3d_desc.multisample_type, wined3d_desc.multisample_quality);
421 wined3d_mutex_unlock();
423 return hr;
426 static HRESULT STDMETHODCALLTYPE d3d11_swapchain_ResizeTarget(IDXGISwapChain1 *iface,
427 const DXGI_MODE_DESC *target_mode_desc)
429 struct d3d11_swapchain *swapchain = d3d11_swapchain_from_IDXGISwapChain1(iface);
430 struct wined3d_display_mode mode;
432 TRACE("iface %p, target_mode_desc %p.\n", iface, target_mode_desc);
434 if (!target_mode_desc)
436 WARN("Invalid pointer.\n");
437 return DXGI_ERROR_INVALID_CALL;
440 TRACE("Mode: %s.\n", debug_dxgi_mode(target_mode_desc));
442 if (target_mode_desc->Scaling)
443 FIXME("Ignoring scaling %#x.\n", target_mode_desc->Scaling);
445 wined3d_display_mode_from_dxgi(&mode, target_mode_desc);
447 return wined3d_swapchain_resize_target(swapchain->wined3d_swapchain, &mode);
450 static HRESULT STDMETHODCALLTYPE d3d11_swapchain_GetContainingOutput(IDXGISwapChain1 *iface, IDXGIOutput **output)
452 struct d3d11_swapchain *swapchain = d3d11_swapchain_from_IDXGISwapChain1(iface);
453 IDXGIAdapter *adapter;
454 IDXGIDevice *device;
455 HRESULT hr;
457 TRACE("iface %p, output %p.\n", iface, output);
459 if (swapchain->target)
461 IDXGIOutput_AddRef(*output = swapchain->target);
462 return S_OK;
465 if (FAILED(hr = d3d11_swapchain_GetDevice(iface, &IID_IDXGIDevice, (void **)&device)))
466 return hr;
468 hr = IDXGIDevice_GetAdapter(device, &adapter);
469 IDXGIDevice_Release(device);
470 if (FAILED(hr))
472 WARN("GetAdapter failed, hr %#x.\n", hr);
473 return hr;
476 if (SUCCEEDED(IDXGIAdapter_EnumOutputs(adapter, 1, output)))
478 FIXME("Adapter has got multiple outputs, returning the first one.\n");
479 IDXGIOutput_Release(*output);
482 hr = IDXGIAdapter_EnumOutputs(adapter, 0, output);
483 IDXGIAdapter_Release(adapter);
484 return hr;
487 static HRESULT STDMETHODCALLTYPE d3d11_swapchain_GetFrameStatistics(IDXGISwapChain1 *iface,
488 DXGI_FRAME_STATISTICS *stats)
490 FIXME("iface %p, stats %p stub!\n", iface, stats);
492 return E_NOTIMPL;
495 static HRESULT STDMETHODCALLTYPE d3d11_swapchain_GetLastPresentCount(IDXGISwapChain1 *iface,
496 UINT *last_present_count)
498 FIXME("iface %p, last_present_count %p stub!\n", iface, last_present_count);
500 return E_NOTIMPL;
503 /* IDXGISwapChain1 methods */
505 static HRESULT STDMETHODCALLTYPE d3d11_swapchain_GetDesc1(IDXGISwapChain1 *iface, DXGI_SWAP_CHAIN_DESC1 *desc)
507 struct d3d11_swapchain *swapchain = d3d11_swapchain_from_IDXGISwapChain1(iface);
508 struct wined3d_swapchain_desc wined3d_desc;
510 TRACE("iface %p, desc %p.\n", iface, desc);
512 if (!desc)
514 WARN("Invalid pointer.\n");
515 return E_INVALIDARG;
518 wined3d_mutex_lock();
519 wined3d_swapchain_get_desc(swapchain->wined3d_swapchain, &wined3d_desc);
520 wined3d_mutex_unlock();
522 FIXME("Ignoring Stereo, Scaling and AlphaMode.\n");
524 desc->Width = wined3d_desc.backbuffer_width;
525 desc->Height = wined3d_desc.backbuffer_height;
526 desc->Format = dxgi_format_from_wined3dformat(wined3d_desc.backbuffer_format);
527 desc->Stereo = FALSE;
528 dxgi_sample_desc_from_wined3d(&desc->SampleDesc,
529 wined3d_desc.multisample_type, wined3d_desc.multisample_quality);
530 desc->BufferUsage = dxgi_usage_from_wined3d_bind_flags(wined3d_desc.backbuffer_bind_flags);
531 desc->BufferCount = wined3d_desc.backbuffer_count;
532 desc->Scaling = DXGI_SCALING_STRETCH;
533 desc->SwapEffect = dxgi_swap_effect_from_wined3d(wined3d_desc.swap_effect);
534 desc->AlphaMode = DXGI_ALPHA_MODE_IGNORE;
535 desc->Flags = dxgi_swapchain_flags_from_wined3d(wined3d_desc.flags);
537 return S_OK;
540 static HRESULT STDMETHODCALLTYPE d3d11_swapchain_GetFullscreenDesc(IDXGISwapChain1 *iface,
541 DXGI_SWAP_CHAIN_FULLSCREEN_DESC *desc)
543 struct d3d11_swapchain *swapchain = d3d11_swapchain_from_IDXGISwapChain1(iface);
544 struct wined3d_swapchain_desc wined3d_desc;
546 TRACE("iface %p, desc %p.\n", iface, desc);
548 if (!desc)
550 WARN("Invalid pointer.\n");
551 return E_INVALIDARG;
554 wined3d_mutex_lock();
555 wined3d_swapchain_get_desc(swapchain->wined3d_swapchain, &wined3d_desc);
556 wined3d_mutex_unlock();
558 FIXME("Ignoring ScanlineOrdering and Scaling.\n");
560 desc->RefreshRate.Numerator = wined3d_desc.refresh_rate;
561 desc->RefreshRate.Denominator = 1;
562 desc->ScanlineOrdering = DXGI_MODE_SCANLINE_ORDER_UNSPECIFIED;
563 desc->Scaling = DXGI_MODE_SCALING_UNSPECIFIED;
564 desc->Windowed = wined3d_desc.windowed;
566 return S_OK;
569 static HRESULT STDMETHODCALLTYPE d3d11_swapchain_GetHwnd(IDXGISwapChain1 *iface, HWND *hwnd)
571 struct d3d11_swapchain *swapchain = d3d11_swapchain_from_IDXGISwapChain1(iface);
572 struct wined3d_swapchain_desc wined3d_desc;
574 TRACE("iface %p, hwnd %p.\n", iface, hwnd);
576 if (!hwnd)
578 WARN("Invalid pointer.\n");
579 return DXGI_ERROR_INVALID_CALL;
582 wined3d_mutex_lock();
583 wined3d_swapchain_get_desc(swapchain->wined3d_swapchain, &wined3d_desc);
584 wined3d_mutex_unlock();
586 *hwnd = wined3d_desc.device_window;
587 return S_OK;
590 static HRESULT STDMETHODCALLTYPE d3d11_swapchain_GetCoreWindow(IDXGISwapChain1 *iface,
591 REFIID iid, void **core_window)
593 FIXME("iface %p, iid %s, core_window %p stub!\n", iface, debugstr_guid(iid), core_window);
595 if (core_window)
596 *core_window = NULL;
598 return DXGI_ERROR_INVALID_CALL;
601 static HRESULT STDMETHODCALLTYPE d3d11_swapchain_Present1(IDXGISwapChain1 *iface,
602 UINT sync_interval, UINT flags, const DXGI_PRESENT_PARAMETERS *present_parameters)
604 struct d3d11_swapchain *swapchain = d3d11_swapchain_from_IDXGISwapChain1(iface);
605 HRESULT hr;
607 TRACE("iface %p, sync_interval %u, flags %#x, present_parameters %p.\n",
608 iface, sync_interval, flags, present_parameters);
610 if (sync_interval > 4)
612 WARN("Invalid sync interval %u.\n", sync_interval);
613 return DXGI_ERROR_INVALID_CALL;
616 if (flags & ~DXGI_PRESENT_TEST)
617 FIXME("Unimplemented flags %#x.\n", flags);
618 if (flags & DXGI_PRESENT_TEST)
620 WARN("Returning S_OK for DXGI_PRESENT_TEST.\n");
621 return S_OK;
624 if (present_parameters)
625 FIXME("Ignored present parameters %p.\n", present_parameters);
627 wined3d_mutex_lock();
628 hr = wined3d_swapchain_present(swapchain->wined3d_swapchain, NULL, NULL, NULL, sync_interval, 0);
629 wined3d_mutex_unlock();
631 return hr;
634 static BOOL STDMETHODCALLTYPE d3d11_swapchain_IsTemporaryMonoSupported(IDXGISwapChain1 *iface)
636 FIXME("iface %p stub!\n", iface);
638 return FALSE;
641 static HRESULT STDMETHODCALLTYPE d3d11_swapchain_GetRestrictToOutput(IDXGISwapChain1 *iface, IDXGIOutput **output)
643 FIXME("iface %p, output %p stub!\n", iface, output);
645 if (!output)
647 WARN("Invalid pointer.\n");
648 return E_INVALIDARG;
651 *output = NULL;
652 return E_NOTIMPL;
655 static HRESULT STDMETHODCALLTYPE d3d11_swapchain_SetBackgroundColor(IDXGISwapChain1 *iface, const DXGI_RGBA *color)
657 FIXME("iface %p, color %p stub!\n", iface, color);
659 return E_NOTIMPL;
662 static HRESULT STDMETHODCALLTYPE d3d11_swapchain_GetBackgroundColor(IDXGISwapChain1 *iface, DXGI_RGBA *color)
664 FIXME("iface %p, color %p stub!\n", iface, color);
666 return E_NOTIMPL;
669 static HRESULT STDMETHODCALLTYPE d3d11_swapchain_SetRotation(IDXGISwapChain1 *iface, DXGI_MODE_ROTATION rotation)
671 FIXME("iface %p, rotation %#x stub!\n", iface, rotation);
673 return E_NOTIMPL;
676 static HRESULT STDMETHODCALLTYPE d3d11_swapchain_GetRotation(IDXGISwapChain1 *iface, DXGI_MODE_ROTATION *rotation)
678 FIXME("iface %p, rotation %p stub!\n", iface, rotation);
680 return E_NOTIMPL;
683 static const struct IDXGISwapChain1Vtbl d3d11_swapchain_vtbl =
685 /* IUnknown methods */
686 d3d11_swapchain_QueryInterface,
687 d3d11_swapchain_AddRef,
688 d3d11_swapchain_Release,
689 /* IDXGIObject methods */
690 d3d11_swapchain_SetPrivateData,
691 d3d11_swapchain_SetPrivateDataInterface,
692 d3d11_swapchain_GetPrivateData,
693 d3d11_swapchain_GetParent,
694 /* IDXGIDeviceSubObject methods */
695 d3d11_swapchain_GetDevice,
696 /* IDXGISwapChain methods */
697 d3d11_swapchain_Present,
698 d3d11_swapchain_GetBuffer,
699 d3d11_swapchain_SetFullscreenState,
700 d3d11_swapchain_GetFullscreenState,
701 d3d11_swapchain_GetDesc,
702 d3d11_swapchain_ResizeBuffers,
703 d3d11_swapchain_ResizeTarget,
704 d3d11_swapchain_GetContainingOutput,
705 d3d11_swapchain_GetFrameStatistics,
706 d3d11_swapchain_GetLastPresentCount,
707 /* IDXGISwapChain1 methods */
708 d3d11_swapchain_GetDesc1,
709 d3d11_swapchain_GetFullscreenDesc,
710 d3d11_swapchain_GetHwnd,
711 d3d11_swapchain_GetCoreWindow,
712 d3d11_swapchain_Present1,
713 d3d11_swapchain_IsTemporaryMonoSupported,
714 d3d11_swapchain_GetRestrictToOutput,
715 d3d11_swapchain_SetBackgroundColor,
716 d3d11_swapchain_GetBackgroundColor,
717 d3d11_swapchain_SetRotation,
718 d3d11_swapchain_GetRotation,
721 static void STDMETHODCALLTYPE d3d11_swapchain_wined3d_object_released(void *parent)
723 struct d3d11_swapchain *swapchain = parent;
725 wined3d_private_store_cleanup(&swapchain->private_store);
726 heap_free(parent);
729 static const struct wined3d_parent_ops d3d11_swapchain_wined3d_parent_ops =
731 d3d11_swapchain_wined3d_object_released,
734 HRESULT d3d11_swapchain_init(struct d3d11_swapchain *swapchain, struct dxgi_device *device,
735 struct wined3d_swapchain_desc *desc, BOOL implicit)
737 HRESULT hr;
740 * A reference to the implicit swapchain is held by the wined3d device.
741 * In order to avoid circular references we do not keep a reference
742 * to the device in the implicit swapchain.
744 if (!implicit)
746 if (FAILED(hr = IWineDXGIAdapter_GetParent(device->adapter, &IID_IDXGIFactory,
747 (void **)&swapchain->factory)))
749 WARN("Failed to get adapter parent, hr %#x.\n", hr);
750 return hr;
752 IWineDXGIDevice_AddRef(swapchain->device = &device->IWineDXGIDevice_iface);
754 else
756 swapchain->device = NULL;
757 swapchain->factory = NULL;
760 swapchain->IDXGISwapChain1_iface.lpVtbl = &d3d11_swapchain_vtbl;
761 swapchain->refcount = 1;
762 wined3d_mutex_lock();
763 wined3d_private_store_init(&swapchain->private_store);
765 if (!desc->windowed && (!desc->backbuffer_width || !desc->backbuffer_height))
766 FIXME("Fullscreen swapchain with back buffer width/height equal to 0 not supported properly.\n");
768 swapchain->fullscreen = !desc->windowed;
769 desc->windowed = TRUE;
770 if (FAILED(hr = wined3d_swapchain_create(device->wined3d_device, desc, swapchain,
771 &d3d11_swapchain_wined3d_parent_ops, &swapchain->wined3d_swapchain)))
773 WARN("Failed to create wined3d swapchain, hr %#x.\n", hr);
774 goto cleanup;
777 swapchain->target = NULL;
778 if (swapchain->fullscreen)
780 desc->windowed = FALSE;
781 if (FAILED(hr = wined3d_swapchain_set_fullscreen(swapchain->wined3d_swapchain,
782 desc, NULL)))
784 WARN("Failed to set fullscreen state, hr %#x.\n", hr);
785 wined3d_swapchain_decref(swapchain->wined3d_swapchain);
786 goto cleanup;
789 if (FAILED(hr = IDXGISwapChain1_GetContainingOutput(&swapchain->IDXGISwapChain1_iface,
790 &swapchain->target)))
792 WARN("Failed to get target output for fullscreen swapchain, hr %#x.\n", hr);
793 wined3d_swapchain_decref(swapchain->wined3d_swapchain);
794 goto cleanup;
797 wined3d_mutex_unlock();
799 return S_OK;
801 cleanup:
802 wined3d_private_store_cleanup(&swapchain->private_store);
803 wined3d_mutex_unlock();
804 if (swapchain->factory)
805 IDXGIFactory_Release(swapchain->factory);
806 if (swapchain->device)
807 IWineDXGIDevice_Release(swapchain->device);
808 return hr;
811 HRESULT d3d11_swapchain_create(IWineDXGIDevice *device, HWND window, const DXGI_SWAP_CHAIN_DESC1 *swapchain_desc,
812 const DXGI_SWAP_CHAIN_FULLSCREEN_DESC *fullscreen_desc, IDXGISwapChain1 **swapchain)
814 struct wined3d_swapchain *wined3d_swapchain;
815 struct wined3d_swapchain_desc wined3d_desc;
816 HRESULT hr;
818 if (swapchain_desc->Scaling != DXGI_SCALING_STRETCH)
819 FIXME("Ignoring scaling %#x.\n", swapchain_desc->Scaling);
820 if (swapchain_desc->AlphaMode != DXGI_ALPHA_MODE_IGNORE)
821 FIXME("Ignoring alpha mode %#x.\n", swapchain_desc->AlphaMode);
822 if (fullscreen_desc && fullscreen_desc->ScanlineOrdering)
823 FIXME("Unhandled scanline ordering %#x.\n", fullscreen_desc->ScanlineOrdering);
824 if (fullscreen_desc && fullscreen_desc->Scaling)
825 FIXME("Unhandled mode scaling %#x.\n", fullscreen_desc->Scaling);
827 switch (swapchain_desc->SwapEffect)
829 case DXGI_SWAP_EFFECT_DISCARD:
830 wined3d_desc.swap_effect = WINED3D_SWAP_EFFECT_DISCARD;
831 break;
832 case DXGI_SWAP_EFFECT_SEQUENTIAL:
833 wined3d_desc.swap_effect = WINED3D_SWAP_EFFECT_SEQUENTIAL;
834 break;
835 case DXGI_SWAP_EFFECT_FLIP_DISCARD:
836 wined3d_desc.swap_effect = WINED3D_SWAP_EFFECT_FLIP_DISCARD;
837 break;
838 case DXGI_SWAP_EFFECT_FLIP_SEQUENTIAL:
839 wined3d_desc.swap_effect = WINED3D_SWAP_EFFECT_FLIP_SEQUENTIAL;
840 break;
841 default:
842 WARN("Invalid swap effect %#x.\n", swapchain_desc->SwapEffect);
843 return DXGI_ERROR_INVALID_CALL;
846 wined3d_desc.backbuffer_width = swapchain_desc->Width;
847 wined3d_desc.backbuffer_height = swapchain_desc->Height;
848 wined3d_desc.backbuffer_format = wined3dformat_from_dxgi_format(swapchain_desc->Format);
849 wined3d_desc.backbuffer_count = swapchain_desc->BufferCount;
850 wined3d_desc.backbuffer_bind_flags = wined3d_bind_flags_from_dxgi_usage(swapchain_desc->BufferUsage);
851 wined3d_sample_desc_from_dxgi(&wined3d_desc.multisample_type,
852 &wined3d_desc.multisample_quality, &swapchain_desc->SampleDesc);
853 wined3d_desc.device_window = window;
854 wined3d_desc.windowed = fullscreen_desc ? fullscreen_desc->Windowed : TRUE;
855 wined3d_desc.enable_auto_depth_stencil = FALSE;
856 wined3d_desc.auto_depth_stencil_format = 0;
857 wined3d_desc.flags = wined3d_swapchain_flags_from_dxgi(swapchain_desc->Flags);
858 wined3d_desc.refresh_rate = fullscreen_desc ? dxgi_rational_to_uint(&fullscreen_desc->RefreshRate) : 0;
859 wined3d_desc.auto_restore_display_mode = TRUE;
861 if (FAILED(hr = IWineDXGIDevice_create_swapchain(device, &wined3d_desc, FALSE, &wined3d_swapchain)))
863 WARN("Failed to create swapchain, hr %#x.\n", hr);
864 return hr;
867 wined3d_mutex_lock();
868 *swapchain = wined3d_swapchain_get_parent(wined3d_swapchain);
869 wined3d_mutex_unlock();
871 return S_OK;
874 #ifdef SONAME_LIBVKD3D
876 static PFN_vkd3d_acquire_vk_queue vkd3d_acquire_vk_queue;
877 static PFN_vkd3d_create_image_resource vkd3d_create_image_resource;
878 static PFN_vkd3d_get_vk_device vkd3d_get_vk_device;
879 static PFN_vkd3d_get_vk_format vkd3d_get_vk_format;
880 static PFN_vkd3d_get_vk_physical_device vkd3d_get_vk_physical_device;
881 static PFN_vkd3d_get_vk_queue_family_index vkd3d_get_vk_queue_family_index;
882 static PFN_vkd3d_instance_from_device vkd3d_instance_from_device;
883 static PFN_vkd3d_instance_get_vk_instance vkd3d_instance_get_vk_instance;
884 static PFN_vkd3d_release_vk_queue vkd3d_release_vk_queue;
885 static PFN_vkd3d_resource_decref vkd3d_resource_decref;
886 static PFN_vkd3d_resource_incref vkd3d_resource_incref;
888 struct dxgi_vk_funcs
890 PFN_vkAcquireNextImageKHR p_vkAcquireNextImageKHR;
891 PFN_vkAllocateCommandBuffers p_vkAllocateCommandBuffers;
892 PFN_vkAllocateMemory p_vkAllocateMemory;
893 PFN_vkBeginCommandBuffer p_vkBeginCommandBuffer;
894 PFN_vkBindImageMemory p_vkBindImageMemory;
895 PFN_vkCmdBlitImage p_vkCmdBlitImage;
896 PFN_vkCmdPipelineBarrier p_vkCmdPipelineBarrier;
897 PFN_vkCreateCommandPool p_vkCreateCommandPool;
898 PFN_vkCreateFence p_vkCreateFence;
899 PFN_vkCreateImage p_vkCreateImage;
900 PFN_vkCreateSemaphore p_vkCreateSemaphore;
901 PFN_vkCreateSwapchainKHR p_vkCreateSwapchainKHR;
902 PFN_vkCreateWin32SurfaceKHR p_vkCreateWin32SurfaceKHR;
903 PFN_vkDestroyCommandPool p_vkDestroyCommandPool;
904 PFN_vkDestroyFence p_vkDestroyFence;
905 PFN_vkDestroyImage p_vkDestroyImage;
906 PFN_vkDestroySemaphore p_vkDestroySemaphore;
907 PFN_vkDestroySurfaceKHR p_vkDestroySurfaceKHR;
908 PFN_vkDestroySwapchainKHR p_vkDestroySwapchainKHR;
909 PFN_vkEndCommandBuffer p_vkEndCommandBuffer;
910 PFN_vkFreeMemory p_vkFreeMemory;
911 PFN_vkGetImageMemoryRequirements p_vkGetImageMemoryRequirements;
912 PFN_vkGetInstanceProcAddr p_vkGetInstanceProcAddr;
913 PFN_vkGetPhysicalDeviceMemoryProperties p_vkGetPhysicalDeviceMemoryProperties;
914 PFN_vkGetPhysicalDeviceSurfaceCapabilitiesKHR p_vkGetPhysicalDeviceSurfaceCapabilitiesKHR;
915 PFN_vkGetPhysicalDeviceSurfaceFormatsKHR p_vkGetPhysicalDeviceSurfaceFormatsKHR;
916 PFN_vkGetPhysicalDeviceSurfacePresentModesKHR p_vkGetPhysicalDeviceSurfacePresentModesKHR;
917 PFN_vkGetPhysicalDeviceSurfaceSupportKHR p_vkGetPhysicalDeviceSurfaceSupportKHR;
918 PFN_vkGetPhysicalDeviceWin32PresentationSupportKHR p_vkGetPhysicalDeviceWin32PresentationSupportKHR;
919 PFN_vkGetSwapchainImagesKHR p_vkGetSwapchainImagesKHR;
920 PFN_vkQueuePresentKHR p_vkQueuePresentKHR;
921 PFN_vkQueueSubmit p_vkQueueSubmit;
922 PFN_vkQueueWaitIdle p_vkQueueWaitIdle;
923 PFN_vkResetFences p_vkResetFences;
924 PFN_vkWaitForFences p_vkWaitForFences;
927 static HRESULT hresult_from_vk_result(VkResult vr)
929 switch (vr)
931 case VK_SUCCESS:
932 return S_OK;
933 case VK_ERROR_OUT_OF_HOST_MEMORY:
934 case VK_ERROR_OUT_OF_DEVICE_MEMORY:
935 return E_OUTOFMEMORY;
936 default:
937 FIXME("Unhandled VkResult %d.\n", vr);
938 return E_FAIL;
942 struct d3d12_swapchain
944 IDXGISwapChain3 IDXGISwapChain3_iface;
945 LONG refcount;
946 struct wined3d_private_store private_store;
948 VkSwapchainKHR vk_swapchain;
949 VkSurfaceKHR vk_surface;
950 VkFence vk_fence;
951 VkInstance vk_instance;
952 VkDevice vk_device;
953 VkPhysicalDevice vk_physical_device;
954 VkDeviceMemory vk_memory;
955 VkCommandPool vk_cmd_pool;
956 VkImage vk_images[DXGI_MAX_SWAP_CHAIN_BUFFERS];
957 VkCommandBuffer vk_cmd_buffers[DXGI_MAX_SWAP_CHAIN_BUFFERS];
958 VkSemaphore vk_semaphores[DXGI_MAX_SWAP_CHAIN_BUFFERS];
959 ID3D12Resource *buffers[DXGI_MAX_SWAP_CHAIN_BUFFERS];
960 unsigned int buffer_count;
962 uint32_t current_buffer_index;
963 struct dxgi_vk_funcs vk_funcs;
965 ID3D12CommandQueue *command_queue;
966 ID3D12Device *device;
967 IWineDXGIFactory *factory;
969 HWND window;
970 DXGI_SWAP_CHAIN_DESC1 desc;
971 DXGI_SWAP_CHAIN_FULLSCREEN_DESC fullscreen_desc;
974 static DXGI_FORMAT dxgi_format_from_vk_format(VkFormat vk_format)
976 switch (vk_format)
978 case VK_FORMAT_B8G8R8A8_UNORM: return DXGI_FORMAT_B8G8R8A8_UNORM;
979 case VK_FORMAT_R8G8B8A8_UNORM: return DXGI_FORMAT_R8G8B8A8_UNORM;
980 case VK_FORMAT_A2B10G10R10_UNORM_PACK32: return DXGI_FORMAT_R10G10B10A2_UNORM;
981 case VK_FORMAT_R16G16B16A16_SFLOAT: return DXGI_FORMAT_R16G16B16A16_FLOAT;
982 default:
983 WARN("Unhandled format %#x.\n", vk_format);
984 return DXGI_FORMAT_UNKNOWN;
988 static VkFormat get_swapchain_fallback_format(VkFormat vk_format)
990 switch (vk_format)
992 case VK_FORMAT_R8G8B8A8_UNORM:
993 case VK_FORMAT_A2B10G10R10_UNORM_PACK32:
994 case VK_FORMAT_R16G16B16A16_SFLOAT:
995 return VK_FORMAT_B8G8R8A8_UNORM;
996 default:
997 WARN("Unhandled format %#x.\n", vk_format);
998 return VK_FORMAT_UNDEFINED;
1002 static HRESULT select_vk_format(const struct dxgi_vk_funcs *vk_funcs,
1003 VkPhysicalDevice vk_physical_device, VkSurfaceKHR vk_surface,
1004 const DXGI_SWAP_CHAIN_DESC1 *swapchain_desc, VkFormat *vk_format)
1006 VkSurfaceFormatKHR *formats;
1007 uint32_t format_count;
1008 VkFormat format;
1009 unsigned int i;
1010 VkResult vr;
1012 *vk_format = VK_FORMAT_UNDEFINED;
1014 format = vkd3d_get_vk_format(swapchain_desc->Format);
1016 vr = vk_funcs->p_vkGetPhysicalDeviceSurfaceFormatsKHR(vk_physical_device, vk_surface, &format_count, NULL);
1017 if (vr < 0 || !format_count)
1019 WARN("Failed to get supported surface formats, vr %d.\n", vr);
1020 return DXGI_ERROR_INVALID_CALL;
1023 if (!(formats = heap_calloc(format_count, sizeof(*formats))))
1024 return E_OUTOFMEMORY;
1026 if ((vr = vk_funcs->p_vkGetPhysicalDeviceSurfaceFormatsKHR(vk_physical_device,
1027 vk_surface, &format_count, formats)) < 0)
1029 WARN("Failed to enumerate supported surface formats, vr %d.\n", vr);
1030 heap_free(formats);
1031 return hresult_from_vk_result(vr);
1034 for (i = 0; i < format_count; ++i)
1036 if (formats[i].format == format && formats[i].colorSpace == VK_COLOR_SPACE_SRGB_NONLINEAR_KHR)
1037 break;
1039 if (i == format_count)
1041 /* Try to create a swapchain with format conversion. */
1042 format = get_swapchain_fallback_format(format);
1043 WARN("Failed to find Vulkan swapchain format for %s.\n", debug_dxgi_format(swapchain_desc->Format));
1044 for (i = 0; i < format_count; ++i)
1046 if (formats[i].format == format && formats[i].colorSpace == VK_COLOR_SPACE_SRGB_NONLINEAR_KHR)
1048 format = formats[i].format;
1049 break;
1053 heap_free(formats);
1054 if (i == format_count)
1056 FIXME("Failed to find Vulkan swapchain format for %s.\n", debug_dxgi_format(swapchain_desc->Format));
1057 return DXGI_ERROR_UNSUPPORTED;
1060 TRACE("Using Vulkan swapchain format %#x.\n", format);
1062 *vk_format = format;
1063 return S_OK;
1066 static HRESULT vk_select_memory_type(const struct dxgi_vk_funcs *vk_funcs,
1067 VkPhysicalDevice vk_physical_device, uint32_t memory_type_mask,
1068 VkMemoryPropertyFlags flags, uint32_t *memory_type_index)
1070 VkPhysicalDeviceMemoryProperties memory_properties;
1071 unsigned int i;
1073 vk_funcs->p_vkGetPhysicalDeviceMemoryProperties(vk_physical_device, &memory_properties);
1074 for (i = 0; i < memory_properties.memoryTypeCount; ++i)
1076 if (!(memory_type_mask & (1u << i)))
1077 continue;
1079 if ((memory_properties.memoryTypes[i].propertyFlags & flags) == flags)
1081 *memory_type_index = i;
1082 return S_OK;
1086 FIXME("Failed to find memory type (allowed types %#x).\n", memory_type_mask);
1087 return E_FAIL;
1090 static HRESULT d3d12_swapchain_create_user_buffers(struct d3d12_swapchain *swapchain, VkFormat vk_format)
1092 const struct dxgi_vk_funcs *vk_funcs = &swapchain->vk_funcs;
1093 VkDeviceSize image_offset[DXGI_MAX_SWAP_CHAIN_BUFFERS];
1094 VkDevice vk_device = swapchain->vk_device;
1095 VkMemoryAllocateInfo allocate_info;
1096 VkMemoryRequirements requirements;
1097 VkImageCreateInfo image_info;
1098 uint32_t memory_type_mask;
1099 VkDeviceSize memory_size;
1100 unsigned int i;
1101 VkResult vr;
1102 HRESULT hr;
1104 memset(&image_info, 0, sizeof(image_info));
1105 image_info.sType = VK_STRUCTURE_TYPE_IMAGE_CREATE_INFO;
1106 image_info.flags = VK_IMAGE_CREATE_MUTABLE_FORMAT_BIT;
1107 image_info.imageType = VK_IMAGE_TYPE_2D;
1108 image_info.format = vk_format;
1109 image_info.extent.width = swapchain->desc.Width;
1110 image_info.extent.height = swapchain->desc.Height;
1111 image_info.extent.depth = 1;
1112 image_info.mipLevels = 1;
1113 image_info.arrayLayers = 1;
1114 image_info.samples = VK_SAMPLE_COUNT_1_BIT;
1115 image_info.tiling = VK_IMAGE_TILING_OPTIMAL;
1116 image_info.usage = VK_IMAGE_USAGE_TRANSFER_SRC_BIT
1117 | VK_IMAGE_USAGE_TRANSFER_DST_BIT
1118 | VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT;
1119 image_info.sharingMode = VK_SHARING_MODE_EXCLUSIVE;
1120 image_info.queueFamilyIndexCount = 0;
1121 image_info.pQueueFamilyIndices = NULL;
1122 image_info.initialLayout = VK_IMAGE_LAYOUT_UNDEFINED;
1124 for (i = 0; i < swapchain->buffer_count; ++i)
1126 if ((vr = vk_funcs->p_vkCreateImage(vk_device, &image_info, NULL, &swapchain->vk_images[i])) < 0)
1128 WARN("Failed to create Vulkan image, vr %d.\n", vr);
1129 swapchain->vk_images[i] = VK_NULL_HANDLE;
1130 return hresult_from_vk_result(vr);
1134 memory_size = 0;
1135 memory_type_mask = ~0u;
1136 for (i = 0; i < swapchain->buffer_count; ++i)
1138 vk_funcs->p_vkGetImageMemoryRequirements(vk_device, swapchain->vk_images[i], &requirements);
1140 TRACE("Size %s, alignment %s, memory types %#x.\n",
1141 wine_dbgstr_longlong(requirements.size), wine_dbgstr_longlong(requirements.alignment),
1142 requirements.memoryTypeBits);
1144 image_offset[i] = (memory_size + (requirements.alignment - 1)) & ~(requirements.alignment - 1);
1145 memory_size = image_offset[i] + requirements.size;
1147 memory_type_mask &= requirements.memoryTypeBits;
1150 TRACE("Allocating %s bytes for user images.\n", wine_dbgstr_longlong(memory_size));
1152 allocate_info.sType = VK_STRUCTURE_TYPE_MEMORY_ALLOCATE_INFO;
1153 allocate_info.pNext = NULL;
1154 allocate_info.allocationSize = memory_size;
1156 if (FAILED(hr = vk_select_memory_type(vk_funcs, swapchain->vk_physical_device,
1157 memory_type_mask, VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT, &allocate_info.memoryTypeIndex)))
1158 return hr;
1160 if ((vr = vk_funcs->p_vkAllocateMemory(vk_device, &allocate_info, NULL, &swapchain->vk_memory)) < 0)
1162 WARN("Failed to allocate device memory, vr %d.\n", vr);
1163 swapchain->vk_memory = VK_NULL_HANDLE;
1164 return hresult_from_vk_result(vr);
1167 for (i = 0; i < swapchain->buffer_count; ++i)
1169 if ((vr = vk_funcs->p_vkBindImageMemory(vk_device, swapchain->vk_images[i],
1170 swapchain->vk_memory, image_offset[i])) < 0)
1172 WARN("Failed to bind image memory, vr %d.\n", vr);
1173 return hresult_from_vk_result(vr);
1177 return S_OK;
1180 static void vk_cmd_image_barrier(const struct dxgi_vk_funcs *vk_funcs, VkCommandBuffer cmd_buffer,
1181 VkPipelineStageFlags src_stage_mask, VkPipelineStageFlags dst_stage_mask,
1182 VkAccessFlags src_access_mask, VkAccessFlags dst_access_mask,
1183 VkImageLayout old_layout, VkImageLayout new_layout, VkImage image)
1185 VkImageMemoryBarrier barrier;
1187 barrier.sType = VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER;
1188 barrier.pNext = NULL;
1189 barrier.srcAccessMask = src_access_mask;
1190 barrier.dstAccessMask = dst_access_mask;
1191 barrier.oldLayout = old_layout;
1192 barrier.newLayout = new_layout;
1193 barrier.srcQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED;
1194 barrier.dstQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED;
1195 barrier.image = image;
1196 barrier.subresourceRange.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT;
1197 barrier.subresourceRange.baseMipLevel = 0;
1198 barrier.subresourceRange.levelCount = VK_REMAINING_MIP_LEVELS;
1199 barrier.subresourceRange.baseArrayLayer = 0;
1200 barrier.subresourceRange.layerCount = VK_REMAINING_ARRAY_LAYERS;
1202 vk_funcs->p_vkCmdPipelineBarrier(cmd_buffer,
1203 src_stage_mask, dst_stage_mask, 0, 0, NULL, 0, NULL, 1, &barrier);
1206 static HRESULT d3d12_swapchain_prepare_command_buffers(struct d3d12_swapchain *swapchain,
1207 uint32_t queue_family_index, VkImage vk_swapchain_images[DXGI_MAX_SWAP_CHAIN_BUFFERS])
1209 const struct dxgi_vk_funcs *vk_funcs = &swapchain->vk_funcs;
1210 VkDevice vk_device = swapchain->vk_device;
1211 VkCommandBufferAllocateInfo allocate_info;
1212 VkSemaphoreCreateInfo semaphore_info;
1213 VkCommandBufferBeginInfo begin_info;
1214 VkCommandPoolCreateInfo pool_info;
1215 VkImageBlit blit;
1216 unsigned int i;
1217 VkResult vr;
1219 pool_info.sType = VK_STRUCTURE_TYPE_COMMAND_POOL_CREATE_INFO;
1220 pool_info.pNext = NULL;
1221 pool_info.flags = 0;
1222 pool_info.queueFamilyIndex = queue_family_index;
1224 if ((vr = vk_funcs->p_vkCreateCommandPool(vk_device, &pool_info,
1225 NULL, &swapchain->vk_cmd_pool)) < 0)
1227 WARN("Failed to create command pool, vr %d.\n", vr);
1228 swapchain->vk_cmd_pool = VK_NULL_HANDLE;
1229 return hresult_from_vk_result(vr);
1232 allocate_info.sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_ALLOCATE_INFO;
1233 allocate_info.pNext = NULL;
1234 allocate_info.commandPool = swapchain->vk_cmd_pool;
1235 allocate_info.level = VK_COMMAND_BUFFER_LEVEL_PRIMARY;
1236 allocate_info.commandBufferCount = swapchain->buffer_count;
1238 if ((vr = vk_funcs->p_vkAllocateCommandBuffers(vk_device, &allocate_info,
1239 swapchain->vk_cmd_buffers)) < 0)
1241 WARN("Failed to allocate command buffers, vr %d.\n", vr);
1242 return hresult_from_vk_result(vr);
1245 for (i = 0; i < swapchain->buffer_count; ++i)
1247 VkCommandBuffer vk_cmd_buffer = swapchain->vk_cmd_buffers[i];
1249 begin_info.sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_BEGIN_INFO;
1250 begin_info.pNext = NULL;
1251 begin_info.flags = 0;
1252 begin_info.pInheritanceInfo = NULL;
1254 if ((vr = vk_funcs->p_vkBeginCommandBuffer(vk_cmd_buffer, &begin_info)) < 0)
1256 WARN("Failed to begin command buffer, vr %d.\n", vr);
1257 return hresult_from_vk_result(vr);
1260 vk_cmd_image_barrier(vk_funcs, vk_cmd_buffer,
1261 VK_PIPELINE_STAGE_TOP_OF_PIPE_BIT, VK_PIPELINE_STAGE_TRANSFER_BIT,
1262 0, VK_ACCESS_TRANSFER_WRITE_BIT,
1263 VK_IMAGE_LAYOUT_UNDEFINED, VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL,
1264 vk_swapchain_images[i]);
1266 blit.srcSubresource.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT;
1267 blit.srcSubresource.mipLevel = 0;
1268 blit.srcSubresource.baseArrayLayer = 0;
1269 blit.srcSubresource.layerCount = 1;
1270 blit.srcOffsets[0].x = 0;
1271 blit.srcOffsets[0].y = 0;
1272 blit.srcOffsets[0].z = 0;
1273 blit.srcOffsets[1].x = swapchain->desc.Width;
1274 blit.srcOffsets[1].y = swapchain->desc.Height;
1275 blit.srcOffsets[1].z = 1;
1276 blit.dstSubresource = blit.srcSubresource;
1277 blit.dstOffsets[0] = blit.srcOffsets[0];
1278 blit.dstOffsets[1] = blit.srcOffsets[1];
1280 vk_funcs->p_vkCmdBlitImage(vk_cmd_buffer,
1281 swapchain->vk_images[i], VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL,
1282 vk_swapchain_images[i], VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL,
1283 1, &blit, VK_FILTER_NEAREST);
1285 vk_cmd_image_barrier(vk_funcs, vk_cmd_buffer,
1286 VK_PIPELINE_STAGE_TRANSFER_BIT, VK_PIPELINE_STAGE_BOTTOM_OF_PIPE_BIT,
1287 VK_ACCESS_TRANSFER_WRITE_BIT, 0,
1288 VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, VK_IMAGE_LAYOUT_PRESENT_SRC_KHR,
1289 vk_swapchain_images[i]);
1291 if ((vr = vk_funcs->p_vkEndCommandBuffer(vk_cmd_buffer)) < 0)
1293 WARN("Failed to end command buffer, vr %d.\n", vr);
1294 return hresult_from_vk_result(vr);
1298 for (i = 0; i < swapchain->buffer_count; ++i)
1300 semaphore_info.sType = VK_STRUCTURE_TYPE_SEMAPHORE_CREATE_INFO;
1301 semaphore_info.pNext = NULL;
1302 semaphore_info.flags = 0;
1304 if ((vr = vk_funcs->p_vkCreateSemaphore(vk_device, &semaphore_info,
1305 NULL, &swapchain->vk_semaphores[i])) < 0)
1307 WARN("Failed to create semaphore, vr %d.\n", vr);
1308 swapchain->vk_semaphores[i] = VK_NULL_HANDLE;
1309 return hresult_from_vk_result(vr);
1313 return S_OK;
1316 static HRESULT d3d12_swapchain_create_buffers(struct d3d12_swapchain *swapchain,
1317 VkFormat vk_swapchain_format, VkFormat vk_format)
1319 const struct dxgi_vk_funcs *vk_funcs = &swapchain->vk_funcs;
1320 VkImage vk_swapchain_images[DXGI_MAX_SWAP_CHAIN_BUFFERS];
1321 struct vkd3d_image_resource_create_info resource_info;
1322 VkSwapchainKHR vk_swapchain = swapchain->vk_swapchain;
1323 ID3D12CommandQueue *queue = swapchain->command_queue;
1324 VkDevice vk_device = swapchain->vk_device;
1325 ID3D12Device *device = swapchain->device;
1326 uint32_t image_count, queue_family_index;
1327 D3D12_COMMAND_QUEUE_DESC queue_desc;
1328 unsigned int i;
1329 VkResult vr;
1330 HRESULT hr;
1332 if ((vr = vk_funcs->p_vkGetSwapchainImagesKHR(vk_device, vk_swapchain, &image_count, NULL)) < 0)
1334 WARN("Failed to get Vulkan swapchain images, vr %d.\n", vr);
1335 return hresult_from_vk_result(vr);
1337 if (image_count != swapchain->desc.BufferCount)
1338 FIXME("Got %u swapchain images, expected %u.\n", image_count, swapchain->desc.BufferCount);
1339 if (image_count > ARRAY_SIZE(vk_swapchain_images))
1340 return E_FAIL;
1341 swapchain->buffer_count = image_count;
1342 if ((vr = vk_funcs->p_vkGetSwapchainImagesKHR(vk_device, vk_swapchain,
1343 &image_count, vk_swapchain_images)) < 0)
1345 WARN("Failed to get Vulkan swapchain images, vr %d.\n", vr);
1346 return hresult_from_vk_result(vr);
1349 resource_info.type = VKD3D_STRUCTURE_TYPE_IMAGE_RESOURCE_CREATE_INFO;
1350 resource_info.next = NULL;
1351 resource_info.desc.Dimension = D3D12_RESOURCE_DIMENSION_TEXTURE2D;
1352 resource_info.desc.Alignment = 0;
1353 resource_info.desc.Width = swapchain->desc.Width;
1354 resource_info.desc.Height = swapchain->desc.Height;
1355 resource_info.desc.DepthOrArraySize = 1;
1356 resource_info.desc.MipLevels = 1;
1357 resource_info.desc.Format = dxgi_format_from_vk_format(vk_format);
1358 resource_info.desc.SampleDesc.Count = 1;
1359 resource_info.desc.SampleDesc.Quality = 0;
1360 resource_info.desc.Layout = D3D12_TEXTURE_LAYOUT_UNKNOWN;
1361 resource_info.desc.Flags = D3D12_RESOURCE_FLAG_ALLOW_RENDER_TARGET;
1362 resource_info.flags = VKD3D_RESOURCE_INITIAL_STATE_TRANSITION | VKD3D_RESOURCE_PRESENT_STATE_TRANSITION;
1364 if (vk_swapchain_format != vk_format)
1366 queue_desc = ID3D12CommandQueue_GetDesc(queue);
1367 if (queue_desc.Type != D3D12_COMMAND_LIST_TYPE_DIRECT)
1369 /* vkCmdBlitImage() is only supported for Graphics queues. */
1370 FIXME("Format conversion not implemented for command queue type %#x.\n", queue_desc.Type);
1371 return E_NOTIMPL;
1373 queue_family_index = vkd3d_get_vk_queue_family_index(queue);
1375 TRACE("Creating user swapchain buffers for format conversion.\n");
1377 if (FAILED(hr = d3d12_swapchain_create_user_buffers(swapchain, vk_format)))
1378 return hr;
1380 if (FAILED(hr = d3d12_swapchain_prepare_command_buffers(swapchain,
1381 queue_family_index, vk_swapchain_images)))
1382 return hr;
1385 for (i = 0; i < swapchain->buffer_count; ++i)
1387 if (swapchain->vk_images[i])
1389 resource_info.vk_image = swapchain->vk_images[i];
1390 resource_info.present_state = D3D12_RESOURCE_STATE_COPY_SOURCE;
1392 else
1394 resource_info.vk_image = vk_swapchain_images[i];
1395 resource_info.present_state = D3D12_RESOURCE_STATE_PRESENT;
1398 if (FAILED(hr = vkd3d_create_image_resource(device, &resource_info, &swapchain->buffers[i])))
1400 WARN("Failed to create vkd3d resource for Vulkan image %u, hr %#x.\n", i, hr);
1401 return hr;
1404 vkd3d_resource_incref(swapchain->buffers[i]);
1405 ID3D12Resource_Release(swapchain->buffers[i]);
1408 return S_OK;
1411 static HRESULT d3d12_swapchain_acquire_next_image(struct d3d12_swapchain *swapchain)
1413 const struct dxgi_vk_funcs *vk_funcs = &swapchain->vk_funcs;
1414 VkDevice vk_device = swapchain->vk_device;
1415 VkFence vk_fence = swapchain->vk_fence;
1416 VkResult vr;
1418 if ((vr = vk_funcs->p_vkAcquireNextImageKHR(vk_device, swapchain->vk_swapchain, UINT64_MAX,
1419 VK_NULL_HANDLE, vk_fence, &swapchain->current_buffer_index)) < 0)
1421 ERR("Failed to acquire next Vulkan image, vr %d.\n", vr);
1422 return hresult_from_vk_result(vr);
1425 if ((vr = vk_funcs->p_vkWaitForFences(vk_device, 1, &vk_fence, VK_TRUE, UINT64_MAX)) != VK_SUCCESS)
1427 ERR("Failed to wait for fence, vr %d.\n", vr);
1428 return hresult_from_vk_result(vr);
1430 if ((vr = vk_funcs->p_vkResetFences(vk_device, 1, &vk_fence)) < 0)
1432 ERR("Failed to reset fence, vr %d.\n", vr);
1433 return hresult_from_vk_result(vr);
1436 return S_OK;
1439 static void d3d12_swapchain_destroy_buffers(struct d3d12_swapchain *swapchain)
1441 const struct dxgi_vk_funcs *vk_funcs = &swapchain->vk_funcs;
1442 VkQueue vk_queue;
1443 unsigned int i;
1445 if (swapchain->command_queue)
1447 if ((vk_queue = vkd3d_acquire_vk_queue(swapchain->command_queue)))
1449 vk_funcs->p_vkQueueWaitIdle(vk_queue);
1451 vkd3d_release_vk_queue(swapchain->command_queue);
1453 else
1455 WARN("Failed to acquire Vulkan queue.\n");
1459 for (i = 0; i < swapchain->buffer_count; ++i)
1461 if (swapchain->buffers[i])
1463 vkd3d_resource_decref(swapchain->buffers[i]);
1464 swapchain->buffers[i] = NULL;
1467 if (swapchain->vk_device)
1469 vk_funcs->p_vkDestroyImage(swapchain->vk_device, swapchain->vk_images[i], NULL);
1470 swapchain->vk_images[i] = VK_NULL_HANDLE;
1471 vk_funcs->p_vkDestroySemaphore(swapchain->vk_device, swapchain->vk_semaphores[i], NULL);
1472 swapchain->vk_semaphores[i] = VK_NULL_HANDLE;
1476 if (swapchain->vk_device)
1478 vk_funcs->p_vkFreeMemory(swapchain->vk_device, swapchain->vk_memory, NULL);
1479 swapchain->vk_memory = VK_NULL_HANDLE;
1480 vk_funcs->p_vkDestroyCommandPool(swapchain->vk_device, swapchain->vk_cmd_pool, NULL);
1481 swapchain->vk_cmd_pool = VK_NULL_HANDLE;
1485 static HRESULT d3d12_swapchain_create_vulkan_swapchain(struct d3d12_swapchain *swapchain)
1487 VkPhysicalDevice vk_physical_device = swapchain->vk_physical_device;
1488 const struct dxgi_vk_funcs *vk_funcs = &swapchain->vk_funcs;
1489 VkSwapchainCreateInfoKHR vk_swapchain_desc;
1490 VkDevice vk_device = swapchain->vk_device;
1491 VkFormat vk_format, vk_swapchain_format;
1492 VkSurfaceCapabilitiesKHR surface_caps;
1493 VkSwapchainKHR vk_swapchain;
1494 VkImageUsageFlags usage;
1495 VkResult vr;
1496 HRESULT hr;
1498 if (!(vk_format = vkd3d_get_vk_format(swapchain->desc.Format)))
1500 WARN("Invalid format %#x.\n", swapchain->desc.Format);
1501 return DXGI_ERROR_INVALID_CALL;
1504 if (FAILED(hr = select_vk_format(vk_funcs, vk_physical_device,
1505 swapchain->vk_surface, &swapchain->desc, &vk_swapchain_format)))
1506 return hr;
1508 if ((vr = vk_funcs->p_vkGetPhysicalDeviceSurfaceCapabilitiesKHR(vk_physical_device,
1509 swapchain->vk_surface, &surface_caps)) < 0)
1511 WARN("Failed to get surface capabilities, vr %d.\n", vr);
1512 return hresult_from_vk_result(vr);
1515 if (surface_caps.maxImageCount && (swapchain->desc.BufferCount > surface_caps.maxImageCount
1516 || swapchain->desc.BufferCount < surface_caps.minImageCount))
1518 WARN("Buffer count %u is not supported (%u-%u).\n", swapchain->desc.BufferCount,
1519 surface_caps.minImageCount, surface_caps.maxImageCount);
1520 return DXGI_ERROR_UNSUPPORTED;
1523 if (swapchain->desc.Width > surface_caps.maxImageExtent.width
1524 || swapchain->desc.Width < surface_caps.minImageExtent.width
1525 || swapchain->desc.Height > surface_caps.maxImageExtent.height
1526 || swapchain->desc.Height < surface_caps.minImageExtent.height)
1528 FIXME("Swapchain dimensions %ux%u are not supported (%u-%u x %u-%u).\n",
1529 swapchain->desc.Width, swapchain->desc.Height,
1530 surface_caps.minImageExtent.width, surface_caps.maxImageExtent.width,
1531 surface_caps.minImageExtent.height, surface_caps.maxImageExtent.height);
1534 if (!(surface_caps.supportedCompositeAlpha & VK_COMPOSITE_ALPHA_OPAQUE_BIT_KHR))
1536 FIXME("Unsupported alpha mode.\n");
1537 return DXGI_ERROR_UNSUPPORTED;
1540 usage = VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT;
1541 usage |= surface_caps.supportedUsageFlags & VK_IMAGE_USAGE_TRANSFER_SRC_BIT;
1542 usage |= surface_caps.supportedUsageFlags & VK_IMAGE_USAGE_TRANSFER_DST_BIT;
1543 if (!(usage & VK_IMAGE_USAGE_TRANSFER_SRC_BIT) || !(usage & VK_IMAGE_USAGE_TRANSFER_DST_BIT))
1544 WARN("Transfer not supported for swapchain images.\n");
1546 vk_swapchain_desc.sType = VK_STRUCTURE_TYPE_SWAPCHAIN_CREATE_INFO_KHR;
1547 vk_swapchain_desc.pNext = NULL;
1548 vk_swapchain_desc.flags = 0;
1549 vk_swapchain_desc.surface = swapchain->vk_surface;
1550 vk_swapchain_desc.minImageCount = swapchain->desc.BufferCount;
1551 vk_swapchain_desc.imageFormat = vk_swapchain_format;
1552 vk_swapchain_desc.imageColorSpace = VK_COLOR_SPACE_SRGB_NONLINEAR_KHR;
1553 vk_swapchain_desc.imageExtent.width = swapchain->desc.Width;
1554 vk_swapchain_desc.imageExtent.height = swapchain->desc.Height;
1555 vk_swapchain_desc.imageArrayLayers = 1;
1556 vk_swapchain_desc.imageUsage = usage;
1557 vk_swapchain_desc.imageSharingMode = VK_SHARING_MODE_EXCLUSIVE;
1558 vk_swapchain_desc.queueFamilyIndexCount = 0;
1559 vk_swapchain_desc.pQueueFamilyIndices = NULL;
1560 vk_swapchain_desc.preTransform = surface_caps.currentTransform;
1561 vk_swapchain_desc.compositeAlpha = VK_COMPOSITE_ALPHA_OPAQUE_BIT_KHR;
1562 vk_swapchain_desc.presentMode = VK_PRESENT_MODE_FIFO_KHR;
1563 vk_swapchain_desc.clipped = VK_TRUE;
1564 vk_swapchain_desc.oldSwapchain = swapchain->vk_swapchain;
1565 if ((vr = vk_funcs->p_vkCreateSwapchainKHR(vk_device, &vk_swapchain_desc, NULL, &vk_swapchain)) < 0)
1567 WARN("Failed to create Vulkan swapchain, vr %d.\n", vr);
1568 return hresult_from_vk_result(vr);
1571 if (swapchain->vk_swapchain)
1572 vk_funcs->p_vkDestroySwapchainKHR(swapchain->vk_device, swapchain->vk_swapchain, NULL);
1574 swapchain->vk_swapchain = vk_swapchain;
1576 if (FAILED(hr = d3d12_swapchain_create_buffers(swapchain, vk_swapchain_format, vk_format)))
1577 return hr;
1579 return S_OK;
1582 static inline struct d3d12_swapchain *d3d12_swapchain_from_IDXGISwapChain3(IDXGISwapChain3 *iface)
1584 return CONTAINING_RECORD(iface, struct d3d12_swapchain, IDXGISwapChain3_iface);
1587 /* IUnknown methods */
1589 static HRESULT STDMETHODCALLTYPE d3d12_swapchain_QueryInterface(IDXGISwapChain3 *iface, REFIID iid, void **object)
1591 TRACE("iface %p, iid %s, object %p.\n", iface, debugstr_guid(iid), object);
1593 if (IsEqualGUID(iid, &IID_IUnknown)
1594 || IsEqualGUID(iid, &IID_IDXGIObject)
1595 || IsEqualGUID(iid, &IID_IDXGIDeviceSubObject)
1596 || IsEqualGUID(iid, &IID_IDXGISwapChain)
1597 || IsEqualGUID(iid, &IID_IDXGISwapChain1)
1598 || IsEqualGUID(iid, &IID_IDXGISwapChain2)
1599 || IsEqualGUID(iid, &IID_IDXGISwapChain3))
1601 IUnknown_AddRef(iface);
1602 *object = iface;
1603 return S_OK;
1606 WARN("%s not implemented, returning E_NOINTERFACE.\n", debugstr_guid(iid));
1608 *object = NULL;
1609 return E_NOINTERFACE;
1612 static ULONG STDMETHODCALLTYPE d3d12_swapchain_AddRef(IDXGISwapChain3 *iface)
1614 struct d3d12_swapchain *swapchain = d3d12_swapchain_from_IDXGISwapChain3(iface);
1615 ULONG refcount = InterlockedIncrement(&swapchain->refcount);
1617 TRACE("%p increasing refcount to %u.\n", swapchain, refcount);
1619 return refcount;
1622 static void d3d12_swapchain_destroy(struct d3d12_swapchain *swapchain)
1624 const struct dxgi_vk_funcs *vk_funcs = &swapchain->vk_funcs;
1626 d3d12_swapchain_destroy_buffers(swapchain);
1628 if (swapchain->command_queue)
1629 ID3D12CommandQueue_Release(swapchain->command_queue);
1631 wined3d_private_store_cleanup(&swapchain->private_store);
1633 if (swapchain->vk_device)
1635 vk_funcs->p_vkDestroyFence(swapchain->vk_device, swapchain->vk_fence, NULL);
1636 vk_funcs->p_vkDestroySwapchainKHR(swapchain->vk_device, swapchain->vk_swapchain, NULL);
1639 if (swapchain->vk_instance)
1640 vk_funcs->p_vkDestroySurfaceKHR(swapchain->vk_instance, swapchain->vk_surface, NULL);
1642 if (swapchain->device)
1643 ID3D12Device_Release(swapchain->device);
1645 if (swapchain->factory)
1646 IWineDXGIFactory_Release(swapchain->factory);
1649 static ULONG STDMETHODCALLTYPE d3d12_swapchain_Release(IDXGISwapChain3 *iface)
1651 struct d3d12_swapchain *swapchain = d3d12_swapchain_from_IDXGISwapChain3(iface);
1652 ULONG refcount = InterlockedDecrement(&swapchain->refcount);
1654 TRACE("%p decreasing refcount to %u.\n", swapchain, refcount);
1656 if (!refcount)
1658 d3d12_swapchain_destroy(swapchain);
1659 heap_free(swapchain);
1662 return refcount;
1665 /* IDXGIObject methods */
1667 static HRESULT STDMETHODCALLTYPE d3d12_swapchain_SetPrivateData(IDXGISwapChain3 *iface,
1668 REFGUID guid, UINT data_size, const void *data)
1670 struct d3d12_swapchain *swapchain = d3d12_swapchain_from_IDXGISwapChain3(iface);
1672 TRACE("iface %p, guid %s, data_size %u, data %p.\n", iface, debugstr_guid(guid), data_size, data);
1674 return dxgi_set_private_data(&swapchain->private_store, guid, data_size, data);
1677 static HRESULT STDMETHODCALLTYPE d3d12_swapchain_SetPrivateDataInterface(IDXGISwapChain3 *iface,
1678 REFGUID guid, const IUnknown *object)
1680 struct d3d12_swapchain *swapchain = d3d12_swapchain_from_IDXGISwapChain3(iface);
1682 TRACE("iface %p, guid %s, object %p.\n", iface, debugstr_guid(guid), object);
1684 return dxgi_set_private_data_interface(&swapchain->private_store, guid, object);
1687 static HRESULT STDMETHODCALLTYPE d3d12_swapchain_GetPrivateData(IDXGISwapChain3 *iface,
1688 REFGUID guid, UINT *data_size, void *data)
1690 struct d3d12_swapchain *swapchain = d3d12_swapchain_from_IDXGISwapChain3(iface);
1692 TRACE("iface %p, guid %s, data_size %p, data %p.\n", iface, debugstr_guid(guid), data_size, data);
1694 return dxgi_get_private_data(&swapchain->private_store, guid, data_size, data);
1697 static HRESULT STDMETHODCALLTYPE d3d12_swapchain_GetParent(IDXGISwapChain3 *iface, REFIID iid, void **parent)
1699 struct d3d12_swapchain *swapchain = d3d12_swapchain_from_IDXGISwapChain3(iface);
1701 TRACE("iface %p, iid %s, parent %p.\n", iface, debugstr_guid(iid), parent);
1703 return IWineDXGIFactory_QueryInterface(swapchain->factory, iid, parent);
1706 /* IDXGIDeviceSubObject methods */
1708 static HRESULT STDMETHODCALLTYPE d3d12_swapchain_GetDevice(IDXGISwapChain3 *iface, REFIID iid, void **device)
1710 struct d3d12_swapchain *swapchain = d3d12_swapchain_from_IDXGISwapChain3(iface);
1712 TRACE("iface %p, iid %s, device %p.\n", iface, debugstr_guid(iid), device);
1714 return ID3D12Device_QueryInterface(swapchain->device, iid, device);
1717 /* IDXGISwapChain methods */
1719 static HRESULT STDMETHODCALLTYPE d3d12_swapchain_Present(IDXGISwapChain3 *iface, UINT sync_interval, UINT flags)
1721 struct d3d12_swapchain *swapchain = d3d12_swapchain_from_IDXGISwapChain3(iface);
1723 TRACE("iface %p, sync_interval %u, flags %#x.\n", iface, sync_interval, flags);
1725 return IDXGISwapChain3_Present1(&swapchain->IDXGISwapChain3_iface, sync_interval, flags, NULL);
1728 static HRESULT STDMETHODCALLTYPE d3d12_swapchain_GetBuffer(IDXGISwapChain3 *iface,
1729 UINT buffer_idx, REFIID iid, void **surface)
1731 struct d3d12_swapchain *swapchain = d3d12_swapchain_from_IDXGISwapChain3(iface);
1733 TRACE("iface %p, buffer_idx %u, iid %s, surface %p.\n",
1734 iface, buffer_idx, debugstr_guid(iid), surface);
1736 if (buffer_idx >= swapchain->buffer_count)
1738 WARN("Invalid buffer index %u.\n", buffer_idx);
1739 return DXGI_ERROR_INVALID_CALL;
1742 return ID3D12Resource_QueryInterface(swapchain->buffers[buffer_idx], iid, surface);
1745 static HRESULT STDMETHODCALLTYPE DECLSPEC_HOTPATCH d3d12_swapchain_SetFullscreenState(IDXGISwapChain3 *iface,
1746 BOOL fullscreen, IDXGIOutput *target)
1748 FIXME("iface %p, fullscreen %#x, target %p stub!\n", iface, fullscreen, target);
1750 return E_NOTIMPL;
1753 static HRESULT STDMETHODCALLTYPE d3d12_swapchain_GetFullscreenState(IDXGISwapChain3 *iface,
1754 BOOL *fullscreen, IDXGIOutput **target)
1756 FIXME("iface %p, fullscreen %p, target %p stub!\n", iface, fullscreen, target);
1758 return E_NOTIMPL;
1761 static HRESULT STDMETHODCALLTYPE d3d12_swapchain_GetDesc(IDXGISwapChain3 *iface, DXGI_SWAP_CHAIN_DESC *desc)
1763 struct d3d12_swapchain *swapchain = d3d12_swapchain_from_IDXGISwapChain3(iface);
1764 const DXGI_SWAP_CHAIN_FULLSCREEN_DESC *fullscreen_desc = &swapchain->fullscreen_desc;
1765 const DXGI_SWAP_CHAIN_DESC1 *swapchain_desc = &swapchain->desc;
1767 TRACE("iface %p, desc %p.\n", iface, desc);
1769 if (!desc)
1771 WARN("Invalid pointer.\n");
1772 return E_INVALIDARG;
1775 desc->BufferDesc.Width = swapchain_desc->Width;
1776 desc->BufferDesc.Height = swapchain_desc->Height;
1777 desc->BufferDesc.RefreshRate = fullscreen_desc->RefreshRate;
1778 desc->BufferDesc.Format = swapchain_desc->Format;
1779 desc->BufferDesc.ScanlineOrdering = fullscreen_desc->ScanlineOrdering;
1780 desc->BufferDesc.Scaling = fullscreen_desc->Scaling;
1781 desc->SampleDesc = swapchain_desc->SampleDesc;
1782 desc->BufferUsage = swapchain_desc->BufferUsage;
1783 desc->BufferCount = swapchain_desc->BufferCount;
1784 desc->OutputWindow = swapchain->window;
1785 desc->Windowed = fullscreen_desc->Windowed;
1786 desc->SwapEffect = swapchain_desc->SwapEffect;
1787 desc->Flags = swapchain_desc->Flags;
1789 return S_OK;
1792 static HRESULT STDMETHODCALLTYPE d3d12_swapchain_ResizeBuffers(IDXGISwapChain3 *iface,
1793 UINT buffer_count, UINT width, UINT height, DXGI_FORMAT format, UINT flags)
1795 struct d3d12_swapchain *swapchain = d3d12_swapchain_from_IDXGISwapChain3(iface);
1796 DXGI_SWAP_CHAIN_DESC1 *desc, new_desc;
1797 unsigned int i;
1798 ULONG refcount;
1799 HRESULT hr;
1801 TRACE("iface %p, buffer_count %u, width %u, height %u, format %s, flags %#x.\n",
1802 iface, buffer_count, width, height, debug_dxgi_format(format), flags);
1804 if (flags)
1805 FIXME("Ignoring flags %#x.\n", flags);
1807 for (i = 0; i < swapchain->buffer_count; ++i)
1809 ID3D12Resource_AddRef(swapchain->buffers[i]);
1810 if ((refcount = ID3D12Resource_Release(swapchain->buffers[i])))
1812 WARN("Buffer %p has %u references left.\n", swapchain->buffers[i], refcount);
1813 return DXGI_ERROR_INVALID_CALL;
1817 desc = &swapchain->desc;
1818 new_desc = swapchain->desc;
1820 if (buffer_count)
1821 new_desc.BufferCount = buffer_count;
1822 if (!width || !height)
1824 RECT client_rect;
1826 if (!GetClientRect(swapchain->window, &client_rect))
1828 WARN("Failed to get client rect, last error %#x.\n", GetLastError());
1829 return DXGI_ERROR_INVALID_CALL;
1832 if (!width)
1833 width = client_rect.right;
1834 if (!height)
1835 height = client_rect.bottom;
1837 new_desc.Width = width;
1838 new_desc.Height = height;
1840 if (format)
1841 new_desc.Format = format;
1843 if (!dxgi_validate_swapchain_desc(&new_desc))
1844 return DXGI_ERROR_INVALID_CALL;
1846 if (desc->Width == new_desc.Width && desc->Height == new_desc.Height
1847 && desc->Format == new_desc.Format && desc->BufferCount == new_desc.BufferCount)
1848 return S_OK;
1850 d3d12_swapchain_destroy_buffers(swapchain);
1851 swapchain->desc = new_desc;
1852 if (FAILED(hr = d3d12_swapchain_create_vulkan_swapchain(swapchain)))
1854 ERR("Failed to recreate Vulkan swapchain, hr %#x.\n", hr);
1855 return hr;
1858 return d3d12_swapchain_acquire_next_image(swapchain);
1861 static HRESULT STDMETHODCALLTYPE d3d12_swapchain_ResizeTarget(IDXGISwapChain3 *iface,
1862 const DXGI_MODE_DESC *target_mode_desc)
1864 FIXME("iface %p, target_mode_desc %p stub!\n", iface, target_mode_desc);
1866 return E_NOTIMPL;
1869 static HRESULT STDMETHODCALLTYPE d3d12_swapchain_GetContainingOutput(IDXGISwapChain3 *iface,
1870 IDXGIOutput **output)
1872 FIXME("iface %p, output %p stub!\n", iface, output);
1874 return E_NOTIMPL;
1877 static HRESULT STDMETHODCALLTYPE d3d12_swapchain_GetFrameStatistics(IDXGISwapChain3 *iface,
1878 DXGI_FRAME_STATISTICS *stats)
1880 FIXME("iface %p, stats %p stub!\n", iface, stats);
1882 return E_NOTIMPL;
1885 static HRESULT STDMETHODCALLTYPE d3d12_swapchain_GetLastPresentCount(IDXGISwapChain3 *iface,
1886 UINT *last_present_count)
1888 FIXME("iface %p, last_present_count %p stub!\n", iface, last_present_count);
1890 return E_NOTIMPL;
1893 /* IDXGISwapChain1 methods */
1895 static HRESULT STDMETHODCALLTYPE d3d12_swapchain_GetDesc1(IDXGISwapChain3 *iface, DXGI_SWAP_CHAIN_DESC1 *desc)
1897 struct d3d12_swapchain *swapchain = d3d12_swapchain_from_IDXGISwapChain3(iface);
1899 TRACE("iface %p, desc %p.\n", iface, desc);
1901 if (!desc)
1903 WARN("Invalid pointer.\n");
1904 return E_INVALIDARG;
1907 *desc = swapchain->desc;
1908 return S_OK;
1911 static HRESULT STDMETHODCALLTYPE d3d12_swapchain_GetFullscreenDesc(IDXGISwapChain3 *iface,
1912 DXGI_SWAP_CHAIN_FULLSCREEN_DESC *desc)
1914 struct d3d12_swapchain *swapchain = d3d12_swapchain_from_IDXGISwapChain3(iface);
1916 TRACE("iface %p, desc %p.\n", iface, desc);
1918 if (!desc)
1920 WARN("Invalid pointer.\n");
1921 return E_INVALIDARG;
1924 *desc = swapchain->fullscreen_desc;
1925 return S_OK;
1928 static HRESULT STDMETHODCALLTYPE d3d12_swapchain_GetHwnd(IDXGISwapChain3 *iface, HWND *hwnd)
1930 struct d3d12_swapchain *swapchain = d3d12_swapchain_from_IDXGISwapChain3(iface);
1932 TRACE("iface %p, hwnd %p.\n", iface, hwnd);
1934 if (!hwnd)
1936 WARN("Invalid pointer.\n");
1937 return DXGI_ERROR_INVALID_CALL;
1940 *hwnd = swapchain->window;
1941 return S_OK;
1944 static HRESULT STDMETHODCALLTYPE d3d12_swapchain_GetCoreWindow(IDXGISwapChain3 *iface,
1945 REFIID iid, void **core_window)
1947 FIXME("iface %p, iid %s, core_window %p stub!\n", iface, debugstr_guid(iid), core_window);
1949 if (core_window)
1950 *core_window = NULL;
1952 return DXGI_ERROR_INVALID_CALL;
1955 static HRESULT d3d12_swapchain_blit_buffer(struct d3d12_swapchain *swapchain, VkQueue vk_queue)
1957 const struct dxgi_vk_funcs *vk_funcs = &swapchain->vk_funcs;
1958 VkSubmitInfo submit_info;
1959 VkResult vr;
1961 submit_info.sType = VK_STRUCTURE_TYPE_SUBMIT_INFO;
1962 submit_info.pNext = NULL;
1963 submit_info.waitSemaphoreCount = 0;
1964 submit_info.pWaitSemaphores = NULL;
1965 submit_info.pWaitDstStageMask = NULL;
1966 submit_info.commandBufferCount = 1;
1967 submit_info.pCommandBuffers = &swapchain->vk_cmd_buffers[swapchain->current_buffer_index];
1968 submit_info.signalSemaphoreCount = 1;
1969 submit_info.pSignalSemaphores = &swapchain->vk_semaphores[swapchain->current_buffer_index];
1971 if ((vr = vk_funcs->p_vkQueueSubmit(vk_queue, 1, &submit_info, VK_NULL_HANDLE)) < 0)
1972 ERR("Failed to blit swapchain buffer, vr %d.\n", vr);
1973 return hresult_from_vk_result(vr);
1976 static HRESULT d3d12_swapchain_queue_present(struct d3d12_swapchain *swapchain, VkQueue vk_queue)
1978 const struct dxgi_vk_funcs *vk_funcs = &swapchain->vk_funcs;
1979 VkPresentInfoKHR present_info;
1980 VkResult vr;
1982 present_info.sType = VK_STRUCTURE_TYPE_PRESENT_INFO_KHR;
1983 present_info.pNext = NULL;
1984 present_info.waitSemaphoreCount = 0;
1985 present_info.pWaitSemaphores = NULL;
1986 present_info.swapchainCount = 1;
1987 present_info.pSwapchains = &swapchain->vk_swapchain;
1988 present_info.pImageIndices = &swapchain->current_buffer_index;
1989 present_info.pResults = NULL;
1991 if (swapchain->vk_semaphores[swapchain->current_buffer_index])
1993 present_info.waitSemaphoreCount = 1;
1994 present_info.pWaitSemaphores = &swapchain->vk_semaphores[swapchain->current_buffer_index];
1997 if ((vr = vk_funcs->p_vkQueuePresentKHR(vk_queue, &present_info)) < 0)
1998 ERR("Failed to queue present, vr %d.\n", vr);
1999 return hresult_from_vk_result(vr);
2002 static HRESULT STDMETHODCALLTYPE d3d12_swapchain_Present1(IDXGISwapChain3 *iface,
2003 UINT sync_interval, UINT flags, const DXGI_PRESENT_PARAMETERS *present_parameters)
2005 struct d3d12_swapchain *swapchain = d3d12_swapchain_from_IDXGISwapChain3(iface);
2006 VkQueue vk_queue;
2007 HRESULT hr;
2009 TRACE("iface %p, sync_interval %u, flags %#x, present_parameters %p.\n",
2010 iface, sync_interval, flags, present_parameters);
2012 if (sync_interval > 4)
2014 WARN("Invalid sync interval %u.\n", sync_interval);
2015 return DXGI_ERROR_INVALID_CALL;
2017 if (sync_interval != 1)
2018 FIXME("Ignoring sync interval %u.\n", sync_interval);
2020 if (flags & ~DXGI_PRESENT_TEST)
2021 FIXME("Unimplemented flags %#x.\n", flags);
2022 if (flags & DXGI_PRESENT_TEST)
2024 WARN("Returning S_OK for DXGI_PRESENT_TEST.\n");
2025 return S_OK;
2028 if (present_parameters)
2029 FIXME("Ignored present parameters %p.\n", present_parameters);
2031 if (!(vk_queue = vkd3d_acquire_vk_queue(swapchain->command_queue)))
2033 ERR("Failed to acquire Vulkan queue.\n");
2034 return E_FAIL;
2037 if (swapchain->vk_images[swapchain->current_buffer_index])
2039 if (FAILED(hr = d3d12_swapchain_blit_buffer(swapchain, vk_queue)))
2041 vkd3d_release_vk_queue(swapchain->command_queue);
2042 return hr;
2046 if (FAILED(hr = d3d12_swapchain_queue_present(swapchain, vk_queue)))
2048 vkd3d_release_vk_queue(swapchain->command_queue);
2049 return hr;
2052 vkd3d_release_vk_queue(swapchain->command_queue);
2054 return d3d12_swapchain_acquire_next_image(swapchain);
2057 static BOOL STDMETHODCALLTYPE d3d12_swapchain_IsTemporaryMonoSupported(IDXGISwapChain3 *iface)
2059 FIXME("iface %p stub!\n", iface);
2061 return FALSE;
2064 static HRESULT STDMETHODCALLTYPE d3d12_swapchain_GetRestrictToOutput(IDXGISwapChain3 *iface, IDXGIOutput **output)
2066 FIXME("iface %p, output %p stub!\n", iface, output);
2068 if (!output)
2070 WARN("Invalid pointer.\n");
2071 return E_INVALIDARG;
2074 *output = NULL;
2075 return E_NOTIMPL;
2078 static HRESULT STDMETHODCALLTYPE d3d12_swapchain_SetBackgroundColor(IDXGISwapChain3 *iface, const DXGI_RGBA *color)
2080 FIXME("iface %p, color %p stub!\n", iface, color);
2082 return E_NOTIMPL;
2085 static HRESULT STDMETHODCALLTYPE d3d12_swapchain_GetBackgroundColor(IDXGISwapChain3 *iface, DXGI_RGBA *color)
2087 FIXME("iface %p, color %p stub!\n", iface, color);
2089 return E_NOTIMPL;
2092 static HRESULT STDMETHODCALLTYPE d3d12_swapchain_SetRotation(IDXGISwapChain3 *iface, DXGI_MODE_ROTATION rotation)
2094 FIXME("iface %p, rotation %#x stub!\n", iface, rotation);
2096 return E_NOTIMPL;
2099 static HRESULT STDMETHODCALLTYPE d3d12_swapchain_GetRotation(IDXGISwapChain3 *iface, DXGI_MODE_ROTATION *rotation)
2101 FIXME("iface %p, rotation %p stub!\n", iface, rotation);
2103 return E_NOTIMPL;
2106 /* IDXGISwapChain2 methods */
2108 static HRESULT STDMETHODCALLTYPE d3d12_swapchain_SetSourceSize(IDXGISwapChain3 *iface, UINT width, UINT height)
2110 FIXME("iface %p, width %u, height %u stub!\n", iface, width, height);
2112 return E_NOTIMPL;
2115 static HRESULT STDMETHODCALLTYPE d3d12_swapchain_GetSourceSize(IDXGISwapChain3 *iface, UINT *width, UINT *height)
2117 FIXME("iface %p, width %p, height %p stub!\n", iface, width, height);
2119 return E_NOTIMPL;
2122 static HRESULT STDMETHODCALLTYPE d3d12_swapchain_SetMaximumFrameLatency(IDXGISwapChain3 *iface, UINT max_latency)
2124 FIXME("iface %p, max_latency %u stub!\n", iface, max_latency);
2126 return E_NOTIMPL;
2129 static HRESULT STDMETHODCALLTYPE d3d12_swapchain_GetMaximumFrameLatency(IDXGISwapChain3 *iface, UINT *max_latency)
2131 FIXME("iface %p, max_latency %p stub!\n", iface, max_latency);
2133 return E_NOTIMPL;
2136 static HANDLE STDMETHODCALLTYPE d3d12_swapchain_GetFrameLatencyWaitableObject(IDXGISwapChain3 *iface)
2138 FIXME("iface %p stub!\n", iface);
2140 return NULL;
2143 static HRESULT STDMETHODCALLTYPE d3d12_swapchain_SetMatrixTransform(IDXGISwapChain3 *iface,
2144 const DXGI_MATRIX_3X2_F *matrix)
2146 FIXME("iface %p, matrix %p stub!\n", iface, matrix);
2148 return E_NOTIMPL;
2151 static HRESULT STDMETHODCALLTYPE d3d12_swapchain_GetMatrixTransform(IDXGISwapChain3 *iface,
2152 DXGI_MATRIX_3X2_F *matrix)
2154 FIXME("iface %p, matrix %p stub!\n", iface, matrix);
2156 return E_NOTIMPL;
2159 /* IDXGISwapChain3 methods */
2161 static UINT STDMETHODCALLTYPE d3d12_swapchain_GetCurrentBackBufferIndex(IDXGISwapChain3 *iface)
2163 struct d3d12_swapchain *swapchain = d3d12_swapchain_from_IDXGISwapChain3(iface);
2165 TRACE("iface %p.\n", iface);
2167 return swapchain->current_buffer_index;
2170 static HRESULT STDMETHODCALLTYPE d3d12_swapchain_CheckColorSpaceSupport(IDXGISwapChain3 *iface,
2171 DXGI_COLOR_SPACE_TYPE colour_space, UINT *colour_space_support)
2173 FIXME("iface %p, colour_space %#x, colour_space_support %p stub!\n",
2174 iface, colour_space, colour_space_support);
2176 return E_NOTIMPL;
2179 static HRESULT STDMETHODCALLTYPE d3d12_swapchain_SetColorSpace1(IDXGISwapChain3 *iface,
2180 DXGI_COLOR_SPACE_TYPE colour_space)
2182 FIXME("iface %p, colour_space %#x stub!\n", iface, colour_space);
2184 return E_NOTIMPL;
2187 static HRESULT STDMETHODCALLTYPE d3d12_swapchain_ResizeBuffers1(IDXGISwapChain3 *iface,
2188 UINT buffer_count, UINT width, UINT height, DXGI_FORMAT format, UINT flags,
2189 const UINT *node_mask, IUnknown * const *present_queue)
2191 FIXME("iface %p, buffer_count %u, width %u, height %u, format %s, flags %#x, "
2192 "node_mask %p, present_queue %p stub!\n",
2193 iface, buffer_count, width, height, debug_dxgi_format(format), flags, node_mask, present_queue);
2195 return E_NOTIMPL;
2198 static const struct IDXGISwapChain3Vtbl d3d12_swapchain_vtbl =
2200 /* IUnknown methods */
2201 d3d12_swapchain_QueryInterface,
2202 d3d12_swapchain_AddRef,
2203 d3d12_swapchain_Release,
2204 /* IDXGIObject methods */
2205 d3d12_swapchain_SetPrivateData,
2206 d3d12_swapchain_SetPrivateDataInterface,
2207 d3d12_swapchain_GetPrivateData,
2208 d3d12_swapchain_GetParent,
2209 /* IDXGIDeviceSubObject methods */
2210 d3d12_swapchain_GetDevice,
2211 /* IDXGISwapChain methods */
2212 d3d12_swapchain_Present,
2213 d3d12_swapchain_GetBuffer,
2214 d3d12_swapchain_SetFullscreenState,
2215 d3d12_swapchain_GetFullscreenState,
2216 d3d12_swapchain_GetDesc,
2217 d3d12_swapchain_ResizeBuffers,
2218 d3d12_swapchain_ResizeTarget,
2219 d3d12_swapchain_GetContainingOutput,
2220 d3d12_swapchain_GetFrameStatistics,
2221 d3d12_swapchain_GetLastPresentCount,
2222 /* IDXGISwapChain1 methods */
2223 d3d12_swapchain_GetDesc1,
2224 d3d12_swapchain_GetFullscreenDesc,
2225 d3d12_swapchain_GetHwnd,
2226 d3d12_swapchain_GetCoreWindow,
2227 d3d12_swapchain_Present1,
2228 d3d12_swapchain_IsTemporaryMonoSupported,
2229 d3d12_swapchain_GetRestrictToOutput,
2230 d3d12_swapchain_SetBackgroundColor,
2231 d3d12_swapchain_GetBackgroundColor,
2232 d3d12_swapchain_SetRotation,
2233 d3d12_swapchain_GetRotation,
2234 /* IDXGISwapChain2 methods */
2235 d3d12_swapchain_SetSourceSize,
2236 d3d12_swapchain_GetSourceSize,
2237 d3d12_swapchain_SetMaximumFrameLatency,
2238 d3d12_swapchain_GetMaximumFrameLatency,
2239 d3d12_swapchain_GetFrameLatencyWaitableObject,
2240 d3d12_swapchain_SetMatrixTransform,
2241 d3d12_swapchain_GetMatrixTransform,
2242 /* IDXGISwapChain3 methods */
2243 d3d12_swapchain_GetCurrentBackBufferIndex,
2244 d3d12_swapchain_CheckColorSpaceSupport,
2245 d3d12_swapchain_SetColorSpace1,
2246 d3d12_swapchain_ResizeBuffers1,
2249 static const struct vulkan_funcs *get_vk_funcs(void)
2251 const struct vulkan_funcs *vk_funcs;
2252 HDC hdc;
2254 hdc = GetDC(0);
2255 vk_funcs = __wine_get_vulkan_driver(hdc, WINE_VULKAN_DRIVER_VERSION);
2256 ReleaseDC(0, hdc);
2257 return vk_funcs;
2260 static BOOL load_vkd3d_functions(void *vkd3d_handle)
2262 #define LOAD_FUNCPTR(f) if (!(f = wine_dlsym(vkd3d_handle, #f, NULL, 0))) return FALSE;
2263 LOAD_FUNCPTR(vkd3d_acquire_vk_queue)
2264 LOAD_FUNCPTR(vkd3d_create_image_resource)
2265 LOAD_FUNCPTR(vkd3d_get_vk_device)
2266 LOAD_FUNCPTR(vkd3d_get_vk_format)
2267 LOAD_FUNCPTR(vkd3d_get_vk_physical_device)
2268 LOAD_FUNCPTR(vkd3d_get_vk_queue_family_index)
2269 LOAD_FUNCPTR(vkd3d_instance_from_device)
2270 LOAD_FUNCPTR(vkd3d_instance_get_vk_instance)
2271 LOAD_FUNCPTR(vkd3d_release_vk_queue)
2272 LOAD_FUNCPTR(vkd3d_resource_decref)
2273 LOAD_FUNCPTR(vkd3d_resource_incref)
2274 #undef LOAD_FUNCPTR
2276 return TRUE;
2279 static void *vkd3d_handle;
2281 static BOOL WINAPI init_vkd3d_once(INIT_ONCE *once, void *param, void **context)
2283 TRACE("Loading vkd3d %s.\n", SONAME_LIBVKD3D);
2285 if (!(vkd3d_handle = wine_dlopen(SONAME_LIBVKD3D, RTLD_NOW, NULL, 0)))
2286 return FALSE;
2288 if (!load_vkd3d_functions(vkd3d_handle))
2290 ERR("Failed to load vkd3d functions.\n");
2291 wine_dlclose(vkd3d_handle, NULL, 0);
2292 vkd3d_handle = NULL;
2293 return FALSE;
2296 return TRUE;
2299 static BOOL init_vkd3d(void)
2301 static INIT_ONCE init_once = INIT_ONCE_STATIC_INIT;
2302 InitOnceExecuteOnce(&init_once, init_vkd3d_once, NULL, NULL);
2303 return !!vkd3d_handle;
2306 static BOOL init_vk_funcs(struct dxgi_vk_funcs *dxgi, VkInstance vk_instance, VkDevice vk_device)
2308 const struct vulkan_funcs *vk;
2310 if (!(vk = get_vk_funcs()))
2312 ERR_(winediag)("Failed to load Wine Vulkan driver.\n");
2313 return FALSE;
2316 dxgi->p_vkGetInstanceProcAddr = (PFN_vkGetInstanceProcAddr)vk->p_vkGetInstanceProcAddr;
2318 #define LOAD_INSTANCE_PFN(name) \
2319 if (!(dxgi->p_##name = vk->p_vkGetInstanceProcAddr(vk_instance, #name))) \
2321 ERR("Failed to get instance proc "#name".\n"); \
2322 return FALSE; \
2324 LOAD_INSTANCE_PFN(vkCreateWin32SurfaceKHR)
2325 LOAD_INSTANCE_PFN(vkDestroySurfaceKHR)
2326 LOAD_INSTANCE_PFN(vkGetPhysicalDeviceMemoryProperties)
2327 LOAD_INSTANCE_PFN(vkGetPhysicalDeviceSurfaceCapabilitiesKHR)
2328 LOAD_INSTANCE_PFN(vkGetPhysicalDeviceSurfaceFormatsKHR)
2329 LOAD_INSTANCE_PFN(vkGetPhysicalDeviceSurfacePresentModesKHR)
2330 LOAD_INSTANCE_PFN(vkGetPhysicalDeviceSurfaceSupportKHR)
2331 LOAD_INSTANCE_PFN(vkGetPhysicalDeviceWin32PresentationSupportKHR)
2332 #undef LOAD_INSTANCE_PFN
2334 #define LOAD_DEVICE_PFN(name) \
2335 if (!(dxgi->p_##name = vk->p_vkGetDeviceProcAddr(vk_device, #name))) \
2337 ERR("Failed to get device proc "#name".\n"); \
2338 return FALSE; \
2340 LOAD_DEVICE_PFN(vkAcquireNextImageKHR)
2341 LOAD_DEVICE_PFN(vkAllocateCommandBuffers)
2342 LOAD_DEVICE_PFN(vkAllocateMemory)
2343 LOAD_DEVICE_PFN(vkBeginCommandBuffer)
2344 LOAD_DEVICE_PFN(vkBindImageMemory)
2345 LOAD_DEVICE_PFN(vkCmdBlitImage)
2346 LOAD_DEVICE_PFN(vkCmdPipelineBarrier)
2347 LOAD_DEVICE_PFN(vkCreateCommandPool)
2348 LOAD_DEVICE_PFN(vkCreateFence)
2349 LOAD_DEVICE_PFN(vkCreateImage)
2350 LOAD_DEVICE_PFN(vkCreateSemaphore)
2351 LOAD_DEVICE_PFN(vkCreateSwapchainKHR)
2352 LOAD_DEVICE_PFN(vkDestroyCommandPool)
2353 LOAD_DEVICE_PFN(vkDestroyFence)
2354 LOAD_DEVICE_PFN(vkDestroyImage)
2355 LOAD_DEVICE_PFN(vkDestroySemaphore)
2356 LOAD_DEVICE_PFN(vkDestroySwapchainKHR)
2357 LOAD_DEVICE_PFN(vkEndCommandBuffer)
2358 LOAD_DEVICE_PFN(vkFreeMemory)
2359 LOAD_DEVICE_PFN(vkGetImageMemoryRequirements)
2360 LOAD_DEVICE_PFN(vkGetSwapchainImagesKHR)
2361 LOAD_DEVICE_PFN(vkQueuePresentKHR)
2362 LOAD_DEVICE_PFN(vkQueueSubmit)
2363 LOAD_DEVICE_PFN(vkQueueWaitIdle)
2364 LOAD_DEVICE_PFN(vkResetFences)
2365 LOAD_DEVICE_PFN(vkWaitForFences)
2366 #undef LOAD_DEVICE_PFN
2368 return TRUE;
2371 static HRESULT d3d12_swapchain_init(struct d3d12_swapchain *swapchain, IWineDXGIFactory *factory,
2372 ID3D12Device *device, ID3D12CommandQueue *queue, HWND window,
2373 const DXGI_SWAP_CHAIN_DESC1 *swapchain_desc, const DXGI_SWAP_CHAIN_FULLSCREEN_DESC *fullscreen_desc)
2375 const struct dxgi_vk_funcs *vk_funcs = &swapchain->vk_funcs;
2376 VkWin32SurfaceCreateInfoKHR surface_desc;
2377 VkPhysicalDevice vk_physical_device;
2378 VkFenceCreateInfo fence_desc;
2379 uint32_t queue_family_index;
2380 VkSurfaceKHR vk_surface;
2381 VkInstance vk_instance;
2382 VkBool32 supported;
2383 VkDevice vk_device;
2384 VkFence vk_fence;
2385 VkResult vr;
2386 HRESULT hr;
2388 swapchain->IDXGISwapChain3_iface.lpVtbl = &d3d12_swapchain_vtbl;
2389 swapchain->refcount = 1;
2391 swapchain->window = window;
2392 swapchain->desc = *swapchain_desc;
2393 swapchain->fullscreen_desc = *fullscreen_desc;
2395 switch (swapchain_desc->SwapEffect)
2397 case DXGI_SWAP_EFFECT_FLIP_SEQUENTIAL:
2398 case DXGI_SWAP_EFFECT_FLIP_DISCARD:
2399 FIXME("Ignoring swap effect %#x.\n", swapchain_desc->SwapEffect);
2400 break;
2401 default:
2402 WARN("Invalid swap effect %#x.\n", swapchain_desc->SwapEffect);
2403 return DXGI_ERROR_INVALID_CALL;
2406 if (!init_vkd3d())
2408 ERR_(winediag)("libvkd3d could not be loaded.\n");
2409 return DXGI_ERROR_UNSUPPORTED;
2412 if (swapchain_desc->BufferUsage && swapchain_desc->BufferUsage != DXGI_USAGE_RENDER_TARGET_OUTPUT)
2413 FIXME("Ignoring buffer usage %#x.\n", swapchain_desc->BufferUsage);
2414 if (swapchain_desc->Scaling != DXGI_SCALING_STRETCH)
2415 FIXME("Ignoring scaling %#x.\n", swapchain_desc->Scaling);
2416 if (swapchain_desc->AlphaMode && swapchain_desc->AlphaMode != DXGI_ALPHA_MODE_IGNORE)
2417 FIXME("Ignoring alpha mode %#x.\n", swapchain_desc->AlphaMode);
2418 if (swapchain_desc->Flags)
2419 FIXME("Ignoring swapchain flags %#x.\n", swapchain_desc->Flags);
2421 FIXME("Ignoring refresh rate.\n");
2422 if (fullscreen_desc->ScanlineOrdering)
2423 FIXME("Unhandled scanline ordering %#x.\n", fullscreen_desc->ScanlineOrdering);
2424 if (fullscreen_desc->Scaling)
2425 FIXME("Unhandled mode scaling %#x.\n", fullscreen_desc->Scaling);
2426 if (!fullscreen_desc->Windowed)
2427 FIXME("Fullscreen not supported yet.\n");
2429 vk_instance = vkd3d_instance_get_vk_instance(vkd3d_instance_from_device(device));
2430 vk_physical_device = vkd3d_get_vk_physical_device(device);
2431 vk_device = vkd3d_get_vk_device(device);
2433 swapchain->vk_instance = vk_instance;
2434 swapchain->vk_device = vk_device;
2435 swapchain->vk_physical_device = vk_physical_device;
2437 if (!init_vk_funcs(&swapchain->vk_funcs, vk_instance, vk_device))
2438 return E_FAIL;
2440 wined3d_private_store_init(&swapchain->private_store);
2442 surface_desc.sType = VK_STRUCTURE_TYPE_WIN32_SURFACE_CREATE_INFO_KHR;
2443 surface_desc.pNext = NULL;
2444 surface_desc.flags = 0;
2445 surface_desc.hinstance = GetModuleHandleA("dxgi.dll");
2446 surface_desc.hwnd = window;
2447 if ((vr = vk_funcs->p_vkCreateWin32SurfaceKHR(vk_instance, &surface_desc, NULL, &vk_surface)) < 0)
2449 WARN("Failed to create Vulkan surface, vr %d.\n", vr);
2450 d3d12_swapchain_destroy(swapchain);
2451 return hresult_from_vk_result(vr);
2453 swapchain->vk_surface = vk_surface;
2455 queue_family_index = vkd3d_get_vk_queue_family_index(queue);
2456 if ((vr = vk_funcs->p_vkGetPhysicalDeviceSurfaceSupportKHR(vk_physical_device,
2457 queue_family_index, vk_surface, &supported)) < 0 || !supported)
2459 FIXME("Queue family does not support presentation, vr %d.\n", vr);
2460 d3d12_swapchain_destroy(swapchain);
2461 return DXGI_ERROR_UNSUPPORTED;
2464 ID3D12CommandQueue_AddRef(swapchain->command_queue = queue);
2465 ID3D12Device_AddRef(swapchain->device = device);
2467 if (FAILED(hr = d3d12_swapchain_create_vulkan_swapchain(swapchain)))
2469 d3d12_swapchain_destroy(swapchain);
2470 return hr;
2473 fence_desc.sType = VK_STRUCTURE_TYPE_FENCE_CREATE_INFO;
2474 fence_desc.pNext = NULL;
2475 fence_desc.flags = 0;
2476 if ((vr = vk_funcs->p_vkCreateFence(vk_device, &fence_desc, NULL, &vk_fence)) < 0)
2478 WARN("Failed to create Vulkan fence, vr %d.\n", vr);
2479 d3d12_swapchain_destroy(swapchain);
2480 return hresult_from_vk_result(vr);
2482 swapchain->vk_fence = vk_fence;
2484 if (FAILED(hr = d3d12_swapchain_acquire_next_image(swapchain)))
2486 WARN("Failed to acquire Vulkan image, hr %#x.\n", hr);
2487 d3d12_swapchain_destroy(swapchain);
2488 return hr;
2491 IWineDXGIFactory_AddRef(swapchain->factory = factory);
2493 return S_OK;
2496 HRESULT d3d12_swapchain_create(IWineDXGIFactory *factory, ID3D12CommandQueue *queue, HWND window,
2497 const DXGI_SWAP_CHAIN_DESC1 *swapchain_desc, const DXGI_SWAP_CHAIN_FULLSCREEN_DESC *fullscreen_desc,
2498 IDXGISwapChain1 **swapchain)
2500 DXGI_SWAP_CHAIN_FULLSCREEN_DESC default_fullscreen_desc;
2501 struct d3d12_swapchain *object;
2502 ID3D12Device *device;
2503 HRESULT hr;
2505 if (!fullscreen_desc)
2507 memset(&default_fullscreen_desc, 0, sizeof(default_fullscreen_desc));
2508 default_fullscreen_desc.Windowed = TRUE;
2509 fullscreen_desc = &default_fullscreen_desc;
2512 if (!(object = heap_alloc_zero(sizeof(*object))))
2513 return E_OUTOFMEMORY;
2515 if (FAILED(hr = ID3D12CommandQueue_GetDevice(queue, &IID_ID3D12Device, (void **)&device)))
2517 ERR("Failed to get D3D12 device, hr %#x.\n", hr);
2518 heap_free(object);
2519 return hr;
2522 hr = d3d12_swapchain_init(object, factory, device, queue, window, swapchain_desc, fullscreen_desc);
2523 ID3D12Device_Release(device);
2524 if (FAILED(hr))
2526 heap_free(object);
2527 return hr;
2530 TRACE("Created swapchain %p.\n", object);
2532 *swapchain = (IDXGISwapChain1 *)&object->IDXGISwapChain3_iface;
2534 return S_OK;
2537 #else
2539 HRESULT d3d12_swapchain_create(IWineDXGIFactory *factory, ID3D12CommandQueue *queue, HWND window,
2540 const DXGI_SWAP_CHAIN_DESC1 *swapchain_desc, const DXGI_SWAP_CHAIN_FULLSCREEN_DESC *fullscreen_desc,
2541 IDXGISwapChain1 **swapchain)
2543 ERR_(winediag)("Wine was built without Direct3D 12 support.\n");
2544 return DXGI_ERROR_UNSUPPORTED;
2547 #endif /* SONAME_LIBVKD3D */