2 * Copyright 2018 Józef Kucia for CodeWeavers
4 * This library is free software; you can redistribute it and/or
5 * modify it under the terms of the GNU Lesser General Public
6 * License as published by the Free Software Foundation; either
7 * version 2.1 of the License, or (at your option) any later version.
9 * This library is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
12 * Lesser General Public License for more details.
14 * You should have received a copy of the GNU Lesser General Public
15 * License along with this library; if not, write to the Free Software
16 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
21 #include "wine/port.h"
24 #define VK_NO_PROTOTYPES
25 #define VKD3D_NO_VULKAN_H
26 #define VKD3D_NO_WIN32_TYPES
27 #ifndef USE_WIN32_VULKAN
31 #include "wine/debug.h"
32 #include "wine/heap.h"
33 #include "wine/vulkan.h"
34 #include "wine/vulkan_driver.h"
42 #include "wine/wined3d.h"
43 #include "wine/winedxgi.h"
45 WINE_DEFAULT_DEBUG_CHANNEL(d3d12
);
46 WINE_DECLARE_DEBUG_CHANNEL(winediag
);
48 #ifdef USE_WIN32_VULKAN
50 static HMODULE vulkan_module
;
52 /* FIXME: We should unload vulkan-1.dll. */
53 static BOOL WINAPI
load_vulkan_dll_once(INIT_ONCE
*once
, void *param
, void **context
)
55 vulkan_module
= LoadLibraryA("vulkan-1.dll");
59 static PFN_vkGetInstanceProcAddr
load_vulkan(void)
61 static INIT_ONCE init_once
= INIT_ONCE_STATIC_INIT
;
63 InitOnceExecuteOnce(&init_once
, load_vulkan_dll_once
, NULL
, NULL
);
66 return (void *)GetProcAddress(vulkan_module
, "vkGetInstanceProcAddr");
73 static PFN_vkGetInstanceProcAddr
load_vulkan(void)
75 const struct vulkan_funcs
*vk_funcs
;
79 vk_funcs
= __wine_get_vulkan_driver(hdc
, WINE_VULKAN_DRIVER_VERSION
);
83 return (PFN_vkGetInstanceProcAddr
)vk_funcs
->p_vkGetInstanceProcAddr
;
88 #endif /* USE_WIN32_VULKAN */
90 HRESULT WINAPI
D3D12GetDebugInterface(REFIID iid
, void **debug
)
92 TRACE("iid %s, debug %p.\n", debugstr_guid(iid
), debug
);
94 WARN("Returning DXGI_ERROR_SDK_COMPONENT_MISSING.\n");
95 return DXGI_ERROR_SDK_COMPONENT_MISSING
;
98 HRESULT WINAPI
D3D12EnableExperimentalFeatures(UINT feature_count
,
99 const IID
*iids
, void *configurations
, UINT
*configurations_sizes
)
101 FIXME("feature_count %u, iids %p, configurations %p, configurations_sizes %p stub!\n",
102 feature_count
, iids
, configurations
, configurations_sizes
);
104 return E_NOINTERFACE
;
107 static HRESULT
d3d12_signal_event(HANDLE event
)
109 return SetEvent(event
) ? S_OK
: E_FAIL
;
112 struct d3d12_thread_data
114 PFN_vkd3d_thread main_pfn
;
118 static DWORD WINAPI
d3d12_thread_main(void *data
)
120 struct d3d12_thread_data
*thread_data
= data
;
122 thread_data
->main_pfn(thread_data
->data
);
123 heap_free(thread_data
);
127 static void *d3d12_create_thread(PFN_vkd3d_thread main_pfn
, void *data
)
129 struct d3d12_thread_data
*thread_data
;
132 if (!(thread_data
= heap_alloc(sizeof(*thread_data
))))
134 ERR("Failed to allocate thread data.\n");
138 thread_data
->main_pfn
= main_pfn
;
139 thread_data
->data
= data
;
141 if (!(thread
= CreateThread(NULL
, 0, d3d12_thread_main
, thread_data
, 0, NULL
)))
142 heap_free(thread_data
);
147 static HRESULT
d3d12_join_thread(void *handle
)
149 HANDLE thread
= handle
;
152 if ((ret
= WaitForSingleObject(thread
, INFINITE
)) != WAIT_OBJECT_0
)
153 ERR("Failed to wait for thread, ret %#x.\n", ret
);
155 return ret
== WAIT_OBJECT_0
? S_OK
: E_FAIL
;
158 static HRESULT
d3d12_get_adapter(IWineDXGIAdapter
**wine_adapter
, IUnknown
*adapter
)
160 IDXGIAdapter
*dxgi_adapter
= NULL
;
161 IDXGIFactory4
*factory
= NULL
;
166 if (FAILED(hr
= CreateDXGIFactory2(0, &IID_IDXGIFactory4
, (void **)&factory
)))
168 WARN("Failed to create DXGI factory, hr %#x.\n", hr
);
172 if (FAILED(hr
= IDXGIFactory4_EnumAdapters(factory
, 0, &dxgi_adapter
)))
174 WARN("Failed to enumerate primary adapter, hr %#x.\n", hr
);
178 adapter
= (IUnknown
*)dxgi_adapter
;
181 if (FAILED(hr
= IUnknown_QueryInterface(adapter
, &IID_IWineDXGIAdapter
, (void **)wine_adapter
)))
182 WARN("Invalid adapter %p, hr %#x.\n", adapter
, hr
);
186 IDXGIAdapter_Release(dxgi_adapter
);
188 IDXGIFactory4_Release(factory
);
193 static BOOL
check_vk_instance_extension(VkInstance vk_instance
,
194 PFN_vkGetInstanceProcAddr pfn_vkGetInstanceProcAddr
, const char *name
)
196 PFN_vkEnumerateInstanceExtensionProperties pfn_vkEnumerateInstanceExtensionProperties
;
197 VkExtensionProperties
*properties
;
202 pfn_vkEnumerateInstanceExtensionProperties
203 = (void *)pfn_vkGetInstanceProcAddr(vk_instance
, "vkEnumerateInstanceExtensionProperties");
205 if (pfn_vkEnumerateInstanceExtensionProperties(NULL
, &count
, NULL
) < 0)
208 if (!(properties
= heap_calloc(count
, sizeof(*properties
))))
211 if (pfn_vkEnumerateInstanceExtensionProperties(NULL
, &count
, properties
) >= 0)
213 for (i
= 0; i
< count
; ++i
)
215 if (!strcmp(properties
[i
].extensionName
, name
))
223 heap_free(properties
);
227 static VkPhysicalDevice
d3d12_get_vk_physical_device(struct vkd3d_instance
*instance
,
228 PFN_vkGetInstanceProcAddr pfn_vkGetInstanceProcAddr
, const struct wine_dxgi_adapter_info
*adapter_info
)
230 PFN_vkGetPhysicalDeviceProperties2 pfn_vkGetPhysicalDeviceProperties2
= NULL
;
231 PFN_vkGetPhysicalDeviceProperties pfn_vkGetPhysicalDeviceProperties
;
232 PFN_vkEnumeratePhysicalDevices pfn_vkEnumeratePhysicalDevices
;
233 VkPhysicalDevice vk_physical_device
= VK_NULL_HANDLE
;
234 VkPhysicalDeviceIDProperties id_properties
;
235 VkPhysicalDeviceProperties2 properties2
;
236 VkPhysicalDeviceProperties properties
;
237 VkPhysicalDevice
*vk_physical_devices
;
238 VkInstance vk_instance
;
243 vk_instance
= vkd3d_instance_get_vk_instance(instance
);
245 pfn_vkEnumeratePhysicalDevices
= (void *)pfn_vkGetInstanceProcAddr(vk_instance
, "vkEnumeratePhysicalDevices");
247 pfn_vkGetPhysicalDeviceProperties
= (void *)pfn_vkGetInstanceProcAddr(vk_instance
, "vkGetPhysicalDeviceProperties");
248 if (check_vk_instance_extension(vk_instance
, pfn_vkGetInstanceProcAddr
, VK_KHR_GET_PHYSICAL_DEVICE_PROPERTIES_2_EXTENSION_NAME
))
249 pfn_vkGetPhysicalDeviceProperties2
= (void *)pfn_vkGetInstanceProcAddr(vk_instance
, "vkGetPhysicalDeviceProperties2KHR");
251 if ((vr
= pfn_vkEnumeratePhysicalDevices(vk_instance
, &count
, NULL
)) < 0)
253 WARN("Failed to get device count, vr %d.\n", vr
);
254 return VK_NULL_HANDLE
;
258 WARN("No physical device available.\n");
259 return VK_NULL_HANDLE
;
262 if (!(vk_physical_devices
= heap_calloc(count
, sizeof(*vk_physical_devices
))))
263 return VK_NULL_HANDLE
;
265 if ((vr
= pfn_vkEnumeratePhysicalDevices(vk_instance
, &count
, vk_physical_devices
)) < 0)
268 if (!IsEqualGUID(&adapter_info
->driver_uuid
, &GUID_NULL
) && pfn_vkGetPhysicalDeviceProperties2
269 && check_vk_instance_extension(vk_instance
, pfn_vkGetInstanceProcAddr
,
270 VK_KHR_EXTERNAL_MEMORY_CAPABILITIES_EXTENSION_NAME
))
272 TRACE("Matching adapters by UUIDs.\n");
274 for (i
= 0; i
< count
; ++i
)
276 memset(&id_properties
, 0, sizeof(id_properties
));
277 id_properties
.sType
= VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_ID_PROPERTIES
;
279 properties2
.sType
= VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_PROPERTIES_2
;
280 properties2
.pNext
= &id_properties
;
282 pfn_vkGetPhysicalDeviceProperties2(vk_physical_devices
[i
], &properties2
);
284 if (!memcmp(id_properties
.driverUUID
, &adapter_info
->driver_uuid
, VK_UUID_SIZE
)
285 && !memcmp(id_properties
.deviceUUID
, &adapter_info
->device_uuid
, VK_UUID_SIZE
))
287 vk_physical_device
= vk_physical_devices
[i
];
293 if (!vk_physical_device
)
295 WARN("Matching adapters by PCI IDs.\n");
297 for (i
= 0; i
< count
; ++i
)
299 pfn_vkGetPhysicalDeviceProperties(vk_physical_devices
[i
], &properties
);
301 if (properties
.vendorID
== adapter_info
->vendor_id
&& properties
.deviceID
== adapter_info
->device_id
)
303 vk_physical_device
= vk_physical_devices
[i
];
309 if (!vk_physical_device
)
310 FIXME("Could not find Vulkan physical device for DXGI adapter.\n");
313 heap_free(vk_physical_devices
);
314 return vk_physical_device
;
317 HRESULT WINAPI
D3D12CreateDevice(IUnknown
*adapter
, D3D_FEATURE_LEVEL minimum_feature_level
,
318 REFIID iid
, void **device
)
320 struct vkd3d_optional_instance_extensions_info optional_extensions_info
;
321 struct vkd3d_instance_create_info instance_create_info
;
322 PFN_vkGetInstanceProcAddr pfn_vkGetInstanceProcAddr
;
323 struct vkd3d_device_create_info device_create_info
;
324 struct wine_dxgi_adapter_info adapter_info
;
325 struct vkd3d_instance
*instance
;
326 IWineDXGIAdapter
*wine_adapter
;
329 static const char * const instance_extensions
[] =
331 VK_KHR_SURFACE_EXTENSION_NAME
,
332 VK_KHR_WIN32_SURFACE_EXTENSION_NAME
,
334 static const char * const optional_instance_extensions
[] =
336 VK_KHR_EXTERNAL_MEMORY_CAPABILITIES_EXTENSION_NAME
,
337 VK_KHR_GET_PHYSICAL_DEVICE_PROPERTIES_2_EXTENSION_NAME
,
339 static const char * const device_extensions
[] =
341 VK_KHR_SWAPCHAIN_EXTENSION_NAME
,
343 static const struct vkd3d_application_info application_info
=
345 .type
= VKD3D_STRUCTURE_TYPE_APPLICATION_INFO
,
346 .api_version
= VKD3D_API_VERSION_1_2
,
349 TRACE("adapter %p, minimum_feature_level %#x, iid %s, device %p.\n",
350 adapter
, minimum_feature_level
, debugstr_guid(iid
), device
);
352 if (!(pfn_vkGetInstanceProcAddr
= load_vulkan()))
354 ERR_(winediag
)("Failed to load Vulkan library.\n");
358 if (FAILED(hr
= d3d12_get_adapter(&wine_adapter
, adapter
)))
361 if (FAILED(hr
= IWineDXGIAdapter_get_adapter_info(wine_adapter
, &adapter_info
)))
363 WARN("Failed to get adapter info, hr %#x.\n", hr
);
367 optional_extensions_info
.type
= VKD3D_STRUCTURE_TYPE_OPTIONAL_INSTANCE_EXTENSIONS_INFO
;
368 optional_extensions_info
.next
= &application_info
;
369 optional_extensions_info
.extensions
= optional_instance_extensions
;
370 optional_extensions_info
.extension_count
= ARRAY_SIZE(optional_instance_extensions
);
372 instance_create_info
.type
= VKD3D_STRUCTURE_TYPE_INSTANCE_CREATE_INFO
;
373 instance_create_info
.next
= &optional_extensions_info
;
374 instance_create_info
.pfn_signal_event
= d3d12_signal_event
;
375 instance_create_info
.pfn_create_thread
= d3d12_create_thread
;
376 instance_create_info
.pfn_join_thread
= d3d12_join_thread
;
377 instance_create_info
.wchar_size
= sizeof(WCHAR
);
378 instance_create_info
.pfn_vkGetInstanceProcAddr
= pfn_vkGetInstanceProcAddr
;
379 instance_create_info
.instance_extensions
= instance_extensions
;
380 instance_create_info
.instance_extension_count
= ARRAY_SIZE(instance_extensions
);
382 if (FAILED(hr
= vkd3d_create_instance(&instance_create_info
, &instance
)))
384 WARN("Failed to create vkd3d instance, hr %#x.\n", hr
);
388 device_create_info
.type
= VKD3D_STRUCTURE_TYPE_DEVICE_CREATE_INFO
;
389 device_create_info
.next
= NULL
;
390 device_create_info
.minimum_feature_level
= minimum_feature_level
;
391 device_create_info
.instance
= instance
;
392 device_create_info
.instance_create_info
= NULL
;
393 device_create_info
.vk_physical_device
= d3d12_get_vk_physical_device(instance
, pfn_vkGetInstanceProcAddr
, &adapter_info
);
394 device_create_info
.device_extensions
= device_extensions
;
395 device_create_info
.device_extension_count
= ARRAY_SIZE(device_extensions
);
396 device_create_info
.parent
= (IUnknown
*)wine_adapter
;
397 device_create_info
.adapter_luid
= adapter_info
.luid
;
399 hr
= vkd3d_create_device(&device_create_info
, iid
, device
);
401 vkd3d_instance_decref(instance
);
404 IWineDXGIAdapter_Release(wine_adapter
);
408 HRESULT WINAPI
D3D12CreateRootSignatureDeserializer(const void *data
, SIZE_T data_size
,
409 REFIID iid
, void **deserializer
)
411 TRACE("data %p, data_size %lu, iid %s, deserializer %p.\n",
412 data
, data_size
, debugstr_guid(iid
), deserializer
);
414 return vkd3d_create_root_signature_deserializer(data
, data_size
, iid
, deserializer
);
417 HRESULT WINAPI
D3D12CreateVersionedRootSignatureDeserializer(const void *data
, SIZE_T data_size
,
418 REFIID iid
, void **deserializer
)
420 TRACE("data %p, data_size %lu, iid %s, deserializer %p.\n",
421 data
, data_size
, debugstr_guid(iid
), deserializer
);
423 return vkd3d_create_versioned_root_signature_deserializer(data
, data_size
, iid
, deserializer
);
426 HRESULT WINAPI
D3D12SerializeRootSignature(const D3D12_ROOT_SIGNATURE_DESC
*root_signature_desc
,
427 D3D_ROOT_SIGNATURE_VERSION version
, ID3DBlob
**blob
, ID3DBlob
**error_blob
)
429 TRACE("root_signature_desc %p, version %#x, blob %p, error_blob %p.\n",
430 root_signature_desc
, version
, blob
, error_blob
);
432 return vkd3d_serialize_root_signature(root_signature_desc
, version
, blob
, error_blob
);
435 HRESULT WINAPI
D3D12SerializeVersionedRootSignature(const D3D12_VERSIONED_ROOT_SIGNATURE_DESC
*desc
,
436 ID3DBlob
**blob
, ID3DBlob
**error_blob
)
438 TRACE("desc %p, blob %p, error_blob %p.\n", desc
, blob
, error_blob
);
440 return vkd3d_serialize_versioned_root_signature(desc
, blob
, error_blob
);