1 // Copyright 2016 Dolphin Emulator Project
2 // Licensed under GPLv2+
3 // Refer to the license.txt file included.
4
5 #include <algorithm>
6 #include <array>
7 #include <cstring>
8
9 #include "Common/Assert.h"
10 #include "Common/CommonFuncs.h"
11 #include "Common/Logging/Log.h"
12 #include "Common/MsgHandler.h"
13 #include "Common/StringUtil.h"
14
15 #include "VideoBackends/Vulkan/VulkanContext.h"
16 #include "VideoCommon/DriverDetails.h"
17 #include "VideoCommon/VideoCommon.h"
18
19 namespace Vulkan
20 {
21 std::unique_ptr<VulkanContext> g_vulkan_context;
22
VulkanContext(VkInstance instance,VkPhysicalDevice physical_device)23 VulkanContext::VulkanContext(VkInstance instance, VkPhysicalDevice physical_device)
24 : m_instance(instance), m_physical_device(physical_device)
25 {
26 // Read device physical memory properties, we need it for allocating buffers
27 vkGetPhysicalDeviceProperties(physical_device, &m_device_properties);
28 vkGetPhysicalDeviceMemoryProperties(physical_device, &m_device_memory_properties);
29
30 // Would any drivers be this silly? I hope not...
31 m_device_properties.limits.minUniformBufferOffsetAlignment = std::max(
32 m_device_properties.limits.minUniformBufferOffsetAlignment, static_cast<VkDeviceSize>(1));
33 m_device_properties.limits.minTexelBufferOffsetAlignment = std::max(
34 m_device_properties.limits.minTexelBufferOffsetAlignment, static_cast<VkDeviceSize>(1));
35 m_device_properties.limits.optimalBufferCopyOffsetAlignment = std::max(
36 m_device_properties.limits.optimalBufferCopyOffsetAlignment, static_cast<VkDeviceSize>(1));
37 m_device_properties.limits.optimalBufferCopyRowPitchAlignment = std::max(
38 m_device_properties.limits.optimalBufferCopyRowPitchAlignment, static_cast<VkDeviceSize>(1));
39 }
40
~VulkanContext()41 VulkanContext::~VulkanContext()
42 {
43 if (m_device != VK_NULL_HANDLE)
44 vkDestroyDevice(m_device, nullptr);
45
46 if (m_debug_report_callback != VK_NULL_HANDLE)
47 DisableDebugReports();
48
49 vkDestroyInstance(m_instance, nullptr);
50 }
51
CheckValidationLayerAvailablility()52 bool VulkanContext::CheckValidationLayerAvailablility()
53 {
54 u32 extension_count = 0;
55 VkResult res = vkEnumerateInstanceExtensionProperties(nullptr, &extension_count, nullptr);
56 if (res != VK_SUCCESS)
57 {
58 LOG_VULKAN_ERROR(res, "vkEnumerateInstanceExtensionProperties failed: ");
59 return false;
60 }
61
62 std::vector<VkExtensionProperties> extension_list(extension_count);
63 res = vkEnumerateInstanceExtensionProperties(nullptr, &extension_count, extension_list.data());
64 ASSERT(res == VK_SUCCESS);
65
66 u32 layer_count = 0;
67 res = vkEnumerateInstanceLayerProperties(&layer_count, nullptr);
68 if (res != VK_SUCCESS)
69 {
70 LOG_VULKAN_ERROR(res, "vkEnumerateInstanceExtensionProperties failed: ");
71 return false;
72 }
73
74 std::vector<VkLayerProperties> layer_list(layer_count);
75 res = vkEnumerateInstanceLayerProperties(&layer_count, layer_list.data());
76 ASSERT(res == VK_SUCCESS);
77
78 // Check for both VK_EXT_debug_report and VK_LAYER_LUNARG_standard_validation
79 return (std::find_if(extension_list.begin(), extension_list.end(),
80 [](const auto& it) {
81 return strcmp(it.extensionName, VK_EXT_DEBUG_REPORT_EXTENSION_NAME) == 0;
82 }) != extension_list.end() &&
83 std::find_if(layer_list.begin(), layer_list.end(), [](const auto& it) {
84 return strcmp(it.layerName, "VK_LAYER_LUNARG_standard_validation") == 0;
85 }) != layer_list.end());
86 }
87
CreateVulkanInstance(WindowSystemType wstype,bool enable_debug_report,bool enable_validation_layer)88 VkInstance VulkanContext::CreateVulkanInstance(WindowSystemType wstype, bool enable_debug_report,
89 bool enable_validation_layer)
90 {
91 std::vector<const char*> enabled_extensions;
92 if (!SelectInstanceExtensions(&enabled_extensions, wstype, enable_debug_report))
93 return VK_NULL_HANDLE;
94
95 VkApplicationInfo app_info = {};
96 app_info.sType = VK_STRUCTURE_TYPE_APPLICATION_INFO;
97 app_info.pNext = nullptr;
98 app_info.pApplicationName = "Dolphin Emulator";
99 app_info.applicationVersion = VK_MAKE_VERSION(5, 0, 0);
100 app_info.pEngineName = "Dolphin Emulator";
101 app_info.engineVersion = VK_MAKE_VERSION(5, 0, 0);
102 app_info.apiVersion = VK_MAKE_VERSION(1, 0, 0);
103
104 // Try for Vulkan 1.1 if the loader supports it.
105 if (vkEnumerateInstanceVersion)
106 {
107 u32 supported_api_version = 0;
108 VkResult res = vkEnumerateInstanceVersion(&supported_api_version);
109 if (res == VK_SUCCESS && (VK_VERSION_MAJOR(supported_api_version) > 1 ||
110 VK_VERSION_MINOR(supported_api_version) >= 1))
111 {
112 // The device itself may not support 1.1, so we check that before using any 1.1 functionality.
113 app_info.apiVersion = VK_MAKE_VERSION(1, 1, 0);
114 }
115 }
116
117 VkInstanceCreateInfo instance_create_info = {};
118 instance_create_info.sType = VK_STRUCTURE_TYPE_INSTANCE_CREATE_INFO;
119 instance_create_info.pNext = nullptr;
120 instance_create_info.flags = 0;
121 instance_create_info.pApplicationInfo = &app_info;
122 instance_create_info.enabledExtensionCount = static_cast<uint32_t>(enabled_extensions.size());
123 instance_create_info.ppEnabledExtensionNames = enabled_extensions.data();
124 instance_create_info.enabledLayerCount = 0;
125 instance_create_info.ppEnabledLayerNames = nullptr;
126
127 // Enable debug layer on debug builds
128 if (enable_validation_layer)
129 {
130 static const char* layer_names[] = {"VK_LAYER_LUNARG_standard_validation"};
131 instance_create_info.enabledLayerCount = 1;
132 instance_create_info.ppEnabledLayerNames = layer_names;
133 }
134
135 VkInstance instance;
136 VkResult res = vkCreateInstance(&instance_create_info, nullptr, &instance);
137 if (res != VK_SUCCESS)
138 {
139 LOG_VULKAN_ERROR(res, "vkCreateInstance failed: ");
140 return nullptr;
141 }
142
143 return instance;
144 }
145
SelectInstanceExtensions(std::vector<const char * > * extension_list,WindowSystemType wstype,bool enable_debug_report)146 bool VulkanContext::SelectInstanceExtensions(std::vector<const char*>* extension_list,
147 WindowSystemType wstype, bool enable_debug_report)
148 {
149 u32 extension_count = 0;
150 VkResult res = vkEnumerateInstanceExtensionProperties(nullptr, &extension_count, nullptr);
151 if (res != VK_SUCCESS)
152 {
153 LOG_VULKAN_ERROR(res, "vkEnumerateInstanceExtensionProperties failed: ");
154 return false;
155 }
156
157 if (extension_count == 0)
158 {
159 ERROR_LOG(VIDEO, "Vulkan: No extensions supported by instance.");
160 return false;
161 }
162
163 std::vector<VkExtensionProperties> available_extension_list(extension_count);
164 res = vkEnumerateInstanceExtensionProperties(nullptr, &extension_count,
165 available_extension_list.data());
166 ASSERT(res == VK_SUCCESS);
167
168 for (const auto& extension_properties : available_extension_list)
169 INFO_LOG(VIDEO, "Available extension: %s", extension_properties.extensionName);
170
171 auto AddExtension = [&](const char* name, bool required) {
172 if (std::find_if(available_extension_list.begin(), available_extension_list.end(),
173 [&](const VkExtensionProperties& properties) {
174 return !strcmp(name, properties.extensionName);
175 }) != available_extension_list.end())
176 {
177 INFO_LOG(VIDEO, "Enabling extension: %s", name);
178 extension_list->push_back(name);
179 return true;
180 }
181
182 if (required)
183 ERROR_LOG(VIDEO, "Vulkan: Missing required extension %s.", name);
184
185 return false;
186 };
187
188 // Common extensions
189 if (wstype != WindowSystemType::Headless && !AddExtension(VK_KHR_SURFACE_EXTENSION_NAME, true))
190 {
191 return false;
192 }
193
194 #if defined(VK_USE_PLATFORM_WIN32_KHR)
195 if (wstype == WindowSystemType::Windows &&
196 !AddExtension(VK_KHR_WIN32_SURFACE_EXTENSION_NAME, true))
197 {
198 return false;
199 }
200 #endif
201 #if defined(VK_USE_PLATFORM_XLIB_KHR)
202 if (wstype == WindowSystemType::X11 && !AddExtension(VK_KHR_XLIB_SURFACE_EXTENSION_NAME, true))
203 {
204 return false;
205 }
206 #endif
207 #if defined(VK_USE_PLATFORM_ANDROID_KHR)
208 if (wstype == WindowSystemType::Android &&
209 !AddExtension(VK_KHR_ANDROID_SURFACE_EXTENSION_NAME, true))
210 {
211 return false;
212 }
213 #endif
214 #if defined(VK_USE_PLATFORM_METAL_EXT)
215 if (wstype == WindowSystemType::MacOS && !AddExtension(VK_EXT_METAL_SURFACE_EXTENSION_NAME, true))
216 {
217 return false;
218 }
219 #endif
220
221 // VK_EXT_debug_report
222 if (enable_debug_report && !AddExtension(VK_EXT_DEBUG_REPORT_EXTENSION_NAME, false))
223 WARN_LOG(VIDEO, "Vulkan: Debug report requested, but extension is not available.");
224
225 AddExtension(VK_KHR_GET_PHYSICAL_DEVICE_PROPERTIES_2_EXTENSION_NAME, false);
226 AddExtension(VK_KHR_GET_SURFACE_CAPABILITIES_2_EXTENSION_NAME, false);
227
228 return true;
229 }
230
EnumerateGPUs(VkInstance instance)231 VulkanContext::GPUList VulkanContext::EnumerateGPUs(VkInstance instance)
232 {
233 u32 gpu_count = 0;
234 VkResult res = vkEnumeratePhysicalDevices(instance, &gpu_count, nullptr);
235 if (res != VK_SUCCESS)
236 {
237 LOG_VULKAN_ERROR(res, "vkEnumeratePhysicalDevices failed: ");
238 return {};
239 }
240
241 GPUList gpus;
242 gpus.resize(gpu_count);
243
244 res = vkEnumeratePhysicalDevices(instance, &gpu_count, gpus.data());
245 if (res != VK_SUCCESS)
246 {
247 LOG_VULKAN_ERROR(res, "vkEnumeratePhysicalDevices failed: ");
248 return {};
249 }
250
251 return gpus;
252 }
253
PopulateBackendInfo(VideoConfig * config)254 void VulkanContext::PopulateBackendInfo(VideoConfig* config)
255 {
256 config->backend_info.api_type = APIType::Vulkan;
257 config->backend_info.bSupports3DVision = false; // D3D-exclusive.
258 config->backend_info.bSupportsOversizedViewports = true; // Assumed support.
259 config->backend_info.bSupportsEarlyZ = true; // Assumed support.
260 config->backend_info.bSupportsPrimitiveRestart = true; // Assumed support.
261 config->backend_info.bSupportsBindingLayout = false; // Assumed support.
262 config->backend_info.bSupportsPaletteConversion = true; // Assumed support.
263 config->backend_info.bSupportsClipControl = true; // Assumed support.
264 config->backend_info.bSupportsMultithreading = true; // Assumed support.
265 config->backend_info.bSupportsComputeShaders = true; // Assumed support.
266 config->backend_info.bSupportsGPUTextureDecoding = true; // Assumed support.
267 config->backend_info.bSupportsBitfield = true; // Assumed support.
268 config->backend_info.bSupportsPartialDepthCopies = true; // Assumed support.
269 config->backend_info.bSupportsShaderBinaries = true; // Assumed support.
270 config->backend_info.bSupportsPipelineCacheData = false; // Handled via pipeline caches.
271 config->backend_info.bSupportsDynamicSamplerIndexing = true; // Assumed support.
272 config->backend_info.bSupportsPostProcessing = true; // Assumed support.
273 config->backend_info.bSupportsBackgroundCompiling = true; // Assumed support.
274 config->backend_info.bSupportsCopyToVram = true; // Assumed support.
275 config->backend_info.bSupportsReversedDepthRange = true; // Assumed support.
276 config->backend_info.bSupportsExclusiveFullscreen = false; // Dependent on OS and features.
277 config->backend_info.bSupportsDualSourceBlend = false; // Dependent on features.
278 config->backend_info.bSupportsGeometryShaders = false; // Dependent on features.
279 config->backend_info.bSupportsGSInstancing = false; // Dependent on features.
280 config->backend_info.bSupportsBBox = false; // Dependent on features.
281 config->backend_info.bSupportsFragmentStoresAndAtomics = false; // Dependent on features.
282 config->backend_info.bSupportsSSAA = false; // Dependent on features.
283 config->backend_info.bSupportsDepthClamp = false; // Dependent on features.
284 config->backend_info.bSupportsST3CTextures = false; // Dependent on features.
285 config->backend_info.bSupportsBPTCTextures = false; // Dependent on features.
286 config->backend_info.bSupportsLogicOp = false; // Dependent on features.
287 config->backend_info.bSupportsLargePoints = false; // Dependent on features.
288 config->backend_info.bSupportsFramebufferFetch = false; // No support.
289 }
290
PopulateBackendInfoAdapters(VideoConfig * config,const GPUList & gpu_list)291 void VulkanContext::PopulateBackendInfoAdapters(VideoConfig* config, const GPUList& gpu_list)
292 {
293 config->backend_info.Adapters.clear();
294 for (VkPhysicalDevice physical_device : gpu_list)
295 {
296 VkPhysicalDeviceProperties properties;
297 vkGetPhysicalDeviceProperties(physical_device, &properties);
298 config->backend_info.Adapters.push_back(properties.deviceName);
299 }
300 }
301
PopulateBackendInfoFeatures(VideoConfig * config,VkPhysicalDevice gpu,const VkPhysicalDeviceProperties & properties,const VkPhysicalDeviceFeatures & features)302 void VulkanContext::PopulateBackendInfoFeatures(VideoConfig* config, VkPhysicalDevice gpu,
303 const VkPhysicalDeviceProperties& properties,
304 const VkPhysicalDeviceFeatures& features)
305 {
306 config->backend_info.MaxTextureSize = properties.limits.maxImageDimension2D;
307 config->backend_info.bUsesLowerLeftOrigin = false;
308 config->backend_info.bSupportsDualSourceBlend = (features.dualSrcBlend == VK_TRUE);
309 config->backend_info.bSupportsGeometryShaders = (features.geometryShader == VK_TRUE);
310 config->backend_info.bSupportsGSInstancing = (features.geometryShader == VK_TRUE);
311 config->backend_info.bSupportsBBox = config->backend_info.bSupportsFragmentStoresAndAtomics =
312 (features.fragmentStoresAndAtomics == VK_TRUE);
313 config->backend_info.bSupportsSSAA = (features.sampleRateShading == VK_TRUE);
314 config->backend_info.bSupportsLogicOp = (features.logicOp == VK_TRUE);
315
316 // Disable geometry shader when shaderTessellationAndGeometryPointSize is not supported.
317 // Seems this is needed for gl_Layer.
318 if (!features.shaderTessellationAndGeometryPointSize)
319 {
320 config->backend_info.bSupportsGeometryShaders = VK_FALSE;
321 config->backend_info.bSupportsGSInstancing = VK_FALSE;
322 }
323
324 // Depth clamping implies shaderClipDistance and depthClamp
325 config->backend_info.bSupportsDepthClamp =
326 (features.depthClamp == VK_TRUE && features.shaderClipDistance == VK_TRUE);
327
328 // textureCompressionBC implies BC1 through BC7, which is a superset of DXT1/3/5, which we need.
329 const bool supports_bc = features.textureCompressionBC == VK_TRUE;
330 config->backend_info.bSupportsST3CTextures = supports_bc;
331 config->backend_info.bSupportsBPTCTextures = supports_bc;
332
333 // Some devices don't support point sizes >1 (e.g. Adreno).
334 // If we can't use a point size above our maximum IR, use triangles instead for EFB pokes.
335 // This means a 6x increase in the size of the vertices, though.
336 config->backend_info.bSupportsLargePoints = features.largePoints &&
337 properties.limits.pointSizeRange[0] <= 1.0f &&
338 properties.limits.pointSizeRange[1] >= 16;
339
340 // Our usage of primitive restart appears to be broken on AMD's binary drivers.
341 // Seems to be fine on GCN Gen 1-2, unconfirmed on GCN Gen 3, causes driver resets on GCN Gen 4.
342 if (DriverDetails::HasBug(DriverDetails::BUG_PRIMITIVE_RESTART))
343 config->backend_info.bSupportsPrimitiveRestart = false;
344
345 // Reversed depth range is broken on some drivers, or is broken when used in combination
346 // with depth clamping. Fall back to inverted depth range for these.
347 if (DriverDetails::HasBug(DriverDetails::BUG_BROKEN_REVERSED_DEPTH_RANGE))
348 config->backend_info.bSupportsReversedDepthRange = false;
349
350 // GPU Texture Decoding is broken under MoltenVK.
351 if (DriverDetails::HasBug(DriverDetails::BUG_BROKEN_GPU_TEXTURE_DECODING))
352 config->backend_info.bSupportsGPUTextureDecoding = false;
353 }
354
PopulateBackendInfoMultisampleModes(VideoConfig * config,VkPhysicalDevice gpu,const VkPhysicalDeviceProperties & properties)355 void VulkanContext::PopulateBackendInfoMultisampleModes(
356 VideoConfig* config, VkPhysicalDevice gpu, const VkPhysicalDeviceProperties& properties)
357 {
358 // Query image support for the EFB texture formats.
359 VkImageFormatProperties efb_color_properties = {};
360 vkGetPhysicalDeviceImageFormatProperties(
361 gpu, VK_FORMAT_R8G8B8A8_UNORM, VK_IMAGE_TYPE_2D, VK_IMAGE_TILING_OPTIMAL,
362 VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT, 0, &efb_color_properties);
363 VkImageFormatProperties efb_depth_properties = {};
364 vkGetPhysicalDeviceImageFormatProperties(
365 gpu, VK_FORMAT_D32_SFLOAT, VK_IMAGE_TYPE_2D, VK_IMAGE_TILING_OPTIMAL,
366 VK_IMAGE_USAGE_DEPTH_STENCIL_ATTACHMENT_BIT, 0, &efb_depth_properties);
367
368 // We can only support MSAA if it's supported on our render target formats.
369 VkSampleCountFlags supported_sample_counts = properties.limits.framebufferColorSampleCounts &
370 properties.limits.framebufferDepthSampleCounts &
371 efb_color_properties.sampleCounts &
372 efb_depth_properties.sampleCounts;
373
374 // No AA
375 config->backend_info.AAModes.clear();
376 config->backend_info.AAModes.emplace_back(1);
377
378 // 2xMSAA/SSAA
379 if (supported_sample_counts & VK_SAMPLE_COUNT_2_BIT)
380 config->backend_info.AAModes.emplace_back(2);
381
382 // 4xMSAA/SSAA
383 if (supported_sample_counts & VK_SAMPLE_COUNT_4_BIT)
384 config->backend_info.AAModes.emplace_back(4);
385
386 // 8xMSAA/SSAA
387 if (supported_sample_counts & VK_SAMPLE_COUNT_8_BIT)
388 config->backend_info.AAModes.emplace_back(8);
389
390 // 16xMSAA/SSAA
391 if (supported_sample_counts & VK_SAMPLE_COUNT_16_BIT)
392 config->backend_info.AAModes.emplace_back(16);
393
394 // 32xMSAA/SSAA
395 if (supported_sample_counts & VK_SAMPLE_COUNT_32_BIT)
396 config->backend_info.AAModes.emplace_back(32);
397
398 // 64xMSAA/SSAA
399 if (supported_sample_counts & VK_SAMPLE_COUNT_64_BIT)
400 config->backend_info.AAModes.emplace_back(64);
401 }
402
Create(VkInstance instance,VkPhysicalDevice gpu,VkSurfaceKHR surface,bool enable_debug_reports,bool enable_validation_layer)403 std::unique_ptr<VulkanContext> VulkanContext::Create(VkInstance instance, VkPhysicalDevice gpu,
404 VkSurfaceKHR surface,
405 bool enable_debug_reports,
406 bool enable_validation_layer)
407 {
408 std::unique_ptr<VulkanContext> context = std::make_unique<VulkanContext>(instance, gpu);
409
410 // Initialize DriverDetails so that we can check for bugs to disable features if needed.
411 context->InitDriverDetails();
412 context->PopulateShaderSubgroupSupport();
413
414 // Enable debug reports if the "Host GPU" log category is enabled.
415 if (enable_debug_reports)
416 context->EnableDebugReports();
417
418 // Attempt to create the device.
419 if (!context->CreateDevice(surface, enable_validation_layer))
420 {
421 // Since we are destroying the instance, we're also responsible for destroying the surface.
422 if (surface != VK_NULL_HANDLE)
423 vkDestroySurfaceKHR(instance, surface, nullptr);
424
425 return nullptr;
426 }
427
428 return context;
429 }
430
SelectDeviceExtensions(bool enable_surface)431 bool VulkanContext::SelectDeviceExtensions(bool enable_surface)
432 {
433 u32 extension_count = 0;
434 VkResult res =
435 vkEnumerateDeviceExtensionProperties(m_physical_device, nullptr, &extension_count, nullptr);
436 if (res != VK_SUCCESS)
437 {
438 LOG_VULKAN_ERROR(res, "vkEnumerateDeviceExtensionProperties failed: ");
439 return false;
440 }
441
442 if (extension_count == 0)
443 {
444 ERROR_LOG(VIDEO, "Vulkan: No extensions supported by device.");
445 return false;
446 }
447
448 std::vector<VkExtensionProperties> available_extension_list(extension_count);
449 res = vkEnumerateDeviceExtensionProperties(m_physical_device, nullptr, &extension_count,
450 available_extension_list.data());
451 ASSERT(res == VK_SUCCESS);
452
453 for (const auto& extension_properties : available_extension_list)
454 INFO_LOG(VIDEO, "Available extension: %s", extension_properties.extensionName);
455
456 auto AddExtension = [&](const char* name, bool required) {
457 if (std::find_if(available_extension_list.begin(), available_extension_list.end(),
458 [&](const VkExtensionProperties& properties) {
459 return !strcmp(name, properties.extensionName);
460 }) != available_extension_list.end())
461 {
462 INFO_LOG(VIDEO, "Enabling extension: %s", name);
463 m_device_extensions.push_back(name);
464 return true;
465 }
466
467 if (required)
468 ERROR_LOG(VIDEO, "Vulkan: Missing required extension %s.", name);
469
470 return false;
471 };
472
473 if (enable_surface && !AddExtension(VK_KHR_SWAPCHAIN_EXTENSION_NAME, true))
474 return false;
475
476 #ifdef SUPPORTS_VULKAN_EXCLUSIVE_FULLSCREEN
477 // VK_EXT_full_screen_exclusive
478 if (AddExtension(VK_EXT_FULL_SCREEN_EXCLUSIVE_EXTENSION_NAME, true))
479 INFO_LOG(VIDEO, "Using VK_EXT_full_screen_exclusive for exclusive fullscreen.");
480 #endif
481
482 return true;
483 }
484
SelectDeviceFeatures()485 bool VulkanContext::SelectDeviceFeatures()
486 {
487 VkPhysicalDeviceProperties properties;
488 vkGetPhysicalDeviceProperties(m_physical_device, &properties);
489
490 VkPhysicalDeviceFeatures available_features;
491 vkGetPhysicalDeviceFeatures(m_physical_device, &available_features);
492
493 // Not having geometry shaders or wide lines will cause issues with rendering.
494 if (!available_features.geometryShader && !available_features.wideLines)
495 WARN_LOG(VIDEO, "Vulkan: Missing both geometryShader and wideLines features.");
496 if (!available_features.largePoints)
497 WARN_LOG(VIDEO, "Vulkan: Missing large points feature. CPU EFB writes will be slower.");
498 if (!available_features.occlusionQueryPrecise)
499 WARN_LOG(VIDEO, "Vulkan: Missing precise occlusion queries. Perf queries will be inaccurate.");
500
501 // Enable the features we use.
502 m_device_features.dualSrcBlend = available_features.dualSrcBlend;
503 m_device_features.geometryShader = available_features.geometryShader;
504 m_device_features.samplerAnisotropy = available_features.samplerAnisotropy;
505 m_device_features.logicOp = available_features.logicOp;
506 m_device_features.fragmentStoresAndAtomics = available_features.fragmentStoresAndAtomics;
507 m_device_features.sampleRateShading = available_features.sampleRateShading;
508 m_device_features.largePoints = available_features.largePoints;
509 m_device_features.shaderStorageImageMultisample =
510 available_features.shaderStorageImageMultisample;
511 m_device_features.shaderTessellationAndGeometryPointSize =
512 available_features.shaderTessellationAndGeometryPointSize;
513 m_device_features.occlusionQueryPrecise = available_features.occlusionQueryPrecise;
514 m_device_features.shaderClipDistance = available_features.shaderClipDistance;
515 m_device_features.depthClamp = available_features.depthClamp;
516 m_device_features.textureCompressionBC = available_features.textureCompressionBC;
517 return true;
518 }
519
CreateDevice(VkSurfaceKHR surface,bool enable_validation_layer)520 bool VulkanContext::CreateDevice(VkSurfaceKHR surface, bool enable_validation_layer)
521 {
522 u32 queue_family_count;
523 vkGetPhysicalDeviceQueueFamilyProperties(m_physical_device, &queue_family_count, nullptr);
524 if (queue_family_count == 0)
525 {
526 ERROR_LOG(VIDEO, "No queue families found on specified vulkan physical device.");
527 return false;
528 }
529
530 std::vector<VkQueueFamilyProperties> queue_family_properties(queue_family_count);
531 vkGetPhysicalDeviceQueueFamilyProperties(m_physical_device, &queue_family_count,
532 queue_family_properties.data());
533 INFO_LOG(VIDEO, "%u vulkan queue families", queue_family_count);
534
535 // Find graphics and present queues.
536 m_graphics_queue_family_index = queue_family_count;
537 m_present_queue_family_index = queue_family_count;
538 for (uint32_t i = 0; i < queue_family_count; i++)
539 {
540 VkBool32 graphics_supported = queue_family_properties[i].queueFlags & VK_QUEUE_GRAPHICS_BIT;
541 if (graphics_supported)
542 {
543 m_graphics_queue_family_index = i;
544 // Quit now, no need for a present queue.
545 if (!surface)
546 {
547 break;
548 }
549 }
550
551 if (surface)
552 {
553 VkBool32 present_supported;
554 VkResult res =
555 vkGetPhysicalDeviceSurfaceSupportKHR(m_physical_device, i, surface, &present_supported);
556 if (res != VK_SUCCESS)
557 {
558 LOG_VULKAN_ERROR(res, "vkGetPhysicalDeviceSurfaceSupportKHR failed: ");
559 return false;
560 }
561
562 if (present_supported)
563 {
564 m_present_queue_family_index = i;
565 }
566
567 // Prefer one queue family index that does both graphics and present.
568 if (graphics_supported && present_supported)
569 {
570 break;
571 }
572 }
573 }
574 if (m_graphics_queue_family_index == queue_family_count)
575 {
576 ERROR_LOG(VIDEO, "Vulkan: Failed to find an acceptable graphics queue.");
577 return false;
578 }
579 if (surface && m_present_queue_family_index == queue_family_count)
580 {
581 ERROR_LOG(VIDEO, "Vulkan: Failed to find an acceptable present queue.");
582 return false;
583 }
584
585 VkDeviceCreateInfo device_info = {};
586 device_info.sType = VK_STRUCTURE_TYPE_DEVICE_CREATE_INFO;
587 device_info.pNext = nullptr;
588 device_info.flags = 0;
589
590 static constexpr float queue_priorities[] = {1.0f};
591 VkDeviceQueueCreateInfo graphics_queue_info = {};
592 graphics_queue_info.sType = VK_STRUCTURE_TYPE_DEVICE_QUEUE_CREATE_INFO;
593 graphics_queue_info.pNext = nullptr;
594 graphics_queue_info.flags = 0;
595 graphics_queue_info.queueFamilyIndex = m_graphics_queue_family_index;
596 graphics_queue_info.queueCount = 1;
597 graphics_queue_info.pQueuePriorities = queue_priorities;
598
599 VkDeviceQueueCreateInfo present_queue_info = {};
600 present_queue_info.sType = VK_STRUCTURE_TYPE_DEVICE_QUEUE_CREATE_INFO;
601 present_queue_info.pNext = nullptr;
602 present_queue_info.flags = 0;
603 present_queue_info.queueFamilyIndex = m_present_queue_family_index;
604 present_queue_info.queueCount = 1;
605 present_queue_info.pQueuePriorities = queue_priorities;
606
607 std::array<VkDeviceQueueCreateInfo, 2> queue_infos = {{
608 graphics_queue_info,
609 present_queue_info,
610 }};
611
612 device_info.queueCreateInfoCount = 1;
613 if (m_graphics_queue_family_index != m_present_queue_family_index)
614 {
615 device_info.queueCreateInfoCount = 2;
616 }
617 device_info.pQueueCreateInfos = queue_infos.data();
618
619 if (!SelectDeviceExtensions(surface != VK_NULL_HANDLE))
620 return false;
621
622 // convert std::string list to a char pointer list which we can feed in
623 std::vector<const char*> extension_name_pointers;
624 for (const std::string& name : m_device_extensions)
625 extension_name_pointers.push_back(name.c_str());
626
627 device_info.enabledLayerCount = 0;
628 device_info.ppEnabledLayerNames = nullptr;
629 device_info.enabledExtensionCount = static_cast<uint32_t>(extension_name_pointers.size());
630 device_info.ppEnabledExtensionNames = extension_name_pointers.data();
631
632 // Check for required features before creating.
633 if (!SelectDeviceFeatures())
634 return false;
635
636 device_info.pEnabledFeatures = &m_device_features;
637
638 // Enable debug layer on debug builds
639 if (enable_validation_layer)
640 {
641 static const char* layer_names[] = {"VK_LAYER_LUNARG_standard_validation"};
642 device_info.enabledLayerCount = 1;
643 device_info.ppEnabledLayerNames = layer_names;
644 }
645
646 VkResult res = vkCreateDevice(m_physical_device, &device_info, nullptr, &m_device);
647 if (res != VK_SUCCESS)
648 {
649 LOG_VULKAN_ERROR(res, "vkCreateDevice failed: ");
650 return false;
651 }
652
653 // With the device created, we can fill the remaining entry points.
654 if (!LoadVulkanDeviceFunctions(m_device))
655 return false;
656
657 // Grab the graphics and present queues.
658 vkGetDeviceQueue(m_device, m_graphics_queue_family_index, 0, &m_graphics_queue);
659 if (surface)
660 {
661 vkGetDeviceQueue(m_device, m_present_queue_family_index, 0, &m_present_queue);
662 }
663 return true;
664 }
665
DebugReportCallback(VkDebugReportFlagsEXT flags,VkDebugReportObjectTypeEXT objectType,uint64_t object,size_t location,int32_t messageCode,const char * pLayerPrefix,const char * pMessage,void * pUserData)666 static VKAPI_ATTR VkBool32 VKAPI_CALL DebugReportCallback(VkDebugReportFlagsEXT flags,
667 VkDebugReportObjectTypeEXT objectType,
668 uint64_t object, size_t location,
669 int32_t messageCode,
670 const char* pLayerPrefix,
671 const char* pMessage, void* pUserData)
672 {
673 std::string log_message =
674 StringFromFormat("Vulkan debug report: (%s) %s", pLayerPrefix ? pLayerPrefix : "", pMessage);
675 if (flags & VK_DEBUG_REPORT_ERROR_BIT_EXT)
676 GENERIC_LOG(Common::Log::HOST_GPU, Common::Log::LERROR, "%s", log_message.c_str());
677 else if (flags & (VK_DEBUG_REPORT_WARNING_BIT_EXT | VK_DEBUG_REPORT_PERFORMANCE_WARNING_BIT_EXT))
678 GENERIC_LOG(Common::Log::HOST_GPU, Common::Log::LWARNING, "%s", log_message.c_str());
679 else if (flags & VK_DEBUG_REPORT_INFORMATION_BIT_EXT)
680 GENERIC_LOG(Common::Log::HOST_GPU, Common::Log::LINFO, "%s", log_message.c_str());
681 else
682 GENERIC_LOG(Common::Log::HOST_GPU, Common::Log::LDEBUG, "%s", log_message.c_str());
683
684 return VK_FALSE;
685 }
686
EnableDebugReports()687 bool VulkanContext::EnableDebugReports()
688 {
689 // Already enabled?
690 if (m_debug_report_callback != VK_NULL_HANDLE)
691 return true;
692
693 // Check for presence of the functions before calling
694 if (!vkCreateDebugReportCallbackEXT || !vkDestroyDebugReportCallbackEXT ||
695 !vkDebugReportMessageEXT)
696 {
697 return false;
698 }
699
700 VkDebugReportCallbackCreateInfoEXT callback_info = {
701 VK_STRUCTURE_TYPE_DEBUG_REPORT_CALLBACK_CREATE_INFO_EXT, nullptr,
702 VK_DEBUG_REPORT_ERROR_BIT_EXT | VK_DEBUG_REPORT_WARNING_BIT_EXT |
703 VK_DEBUG_REPORT_PERFORMANCE_WARNING_BIT_EXT | VK_DEBUG_REPORT_INFORMATION_BIT_EXT |
704 VK_DEBUG_REPORT_DEBUG_BIT_EXT,
705 DebugReportCallback, nullptr};
706
707 VkResult res =
708 vkCreateDebugReportCallbackEXT(m_instance, &callback_info, nullptr, &m_debug_report_callback);
709 if (res != VK_SUCCESS)
710 {
711 LOG_VULKAN_ERROR(res, "vkCreateDebugReportCallbackEXT failed: ");
712 return false;
713 }
714
715 return true;
716 }
717
DisableDebugReports()718 void VulkanContext::DisableDebugReports()
719 {
720 if (m_debug_report_callback != VK_NULL_HANDLE)
721 {
722 vkDestroyDebugReportCallbackEXT(m_instance, m_debug_report_callback, nullptr);
723 m_debug_report_callback = VK_NULL_HANDLE;
724 }
725 }
726
GetMemoryType(u32 bits,VkMemoryPropertyFlags properties,bool strict,bool * is_coherent)727 std::optional<u32> VulkanContext::GetMemoryType(u32 bits, VkMemoryPropertyFlags properties,
728 bool strict, bool* is_coherent)
729 {
730 static constexpr u32 ALL_MEMORY_PROPERTY_FLAGS = VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT |
731 VK_MEMORY_PROPERTY_HOST_COHERENT_BIT |
732 VK_MEMORY_PROPERTY_HOST_CACHED_BIT;
733
734 const u32 mask = strict ? ALL_MEMORY_PROPERTY_FLAGS : properties;
735
736 for (u32 i = 0; i < VK_MAX_MEMORY_TYPES; i++)
737 {
738 if ((bits & (1 << i)) != 0)
739 {
740 const VkMemoryPropertyFlags type_flags =
741 m_device_memory_properties.memoryTypes[i].propertyFlags;
742 const VkMemoryPropertyFlags supported = type_flags & mask;
743 if (supported == properties)
744 {
745 if (is_coherent)
746 *is_coherent = (type_flags & VK_MEMORY_PROPERTY_HOST_COHERENT_BIT) != 0;
747 return i;
748 }
749 }
750 }
751
752 return std::nullopt;
753 }
754
GetUploadMemoryType(u32 bits,bool * is_coherent)755 u32 VulkanContext::GetUploadMemoryType(u32 bits, bool* is_coherent)
756 {
757 static constexpr VkMemoryPropertyFlags COHERENT_FLAGS =
758 VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT | VK_MEMORY_PROPERTY_HOST_COHERENT_BIT;
759
760 // Try for coherent memory. Some drivers (looking at you, Adreno) have the cached type before the
761 // uncached type, so use a strict check first.
762 std::optional<u32> type_index = GetMemoryType(bits, COHERENT_FLAGS, true, is_coherent);
763 if (type_index)
764 return type_index.value();
765
766 // Try for coherent memory, with any other bits set.
767 type_index = GetMemoryType(bits, COHERENT_FLAGS, false, is_coherent);
768 if (type_index)
769 {
770 WARN_LOG(VIDEO,
771 "Strict check for upload memory properties failed, this may affect performance");
772 return type_index.value();
773 }
774
775 // Fall back to non-coherent memory.
776 WARN_LOG(
777 VIDEO,
778 "Vulkan: Failed to find a coherent memory type for uploads, this will affect performance.");
779 type_index = GetMemoryType(bits, VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT, false, is_coherent);
780 if (type_index)
781 return type_index.value();
782
783 // Shouldn't happen, there should be at least one host-visible heap.
784 PanicAlert("Unable to get memory type for upload.");
785 return 0;
786 }
787
GetReadbackMemoryType(u32 bits,bool * is_coherent)788 u32 VulkanContext::GetReadbackMemoryType(u32 bits, bool* is_coherent)
789 {
790 std::optional<u32> type_index;
791
792 // Mali driver appears to be significantly slower for readbacks when using cached memory.
793 if (DriverDetails::HasBug(DriverDetails::BUG_SLOW_CACHED_READBACK_MEMORY))
794 {
795 type_index = GetMemoryType(
796 bits, VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT | VK_MEMORY_PROPERTY_HOST_COHERENT_BIT, true,
797 is_coherent);
798 if (type_index)
799 return type_index.value();
800 }
801
802 // Optimal config uses cached+coherent.
803 type_index =
804 GetMemoryType(bits,
805 VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT | VK_MEMORY_PROPERTY_HOST_CACHED_BIT |
806 VK_MEMORY_PROPERTY_HOST_COHERENT_BIT,
807 true, is_coherent);
808 if (type_index)
809 return type_index.value();
810
811 // Otherwise, prefer cached over coherent if we must choose one.
812 type_index =
813 GetMemoryType(bits, VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT | VK_MEMORY_PROPERTY_HOST_CACHED_BIT,
814 false, is_coherent);
815 if (type_index)
816 return type_index.value();
817
818 WARN_LOG(VIDEO, "Vulkan: Failed to find a cached memory type for readbacks, this will affect "
819 "performance.");
820 type_index = GetMemoryType(bits, VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT, false, is_coherent);
821 *is_coherent = false;
822 if (type_index)
823 return type_index.value();
824
825 // We should have at least one host visible memory type...
826 PanicAlert("Unable to get memory type for upload.");
827 return 0;
828 }
829
SupportsDeviceExtension(const char * name) const830 bool VulkanContext::SupportsDeviceExtension(const char* name) const
831 {
832 return std::any_of(m_device_extensions.begin(), m_device_extensions.end(),
833 [name](const std::string& extension) { return extension == name; });
834 }
835
InitDriverDetails()836 void VulkanContext::InitDriverDetails()
837 {
838 DriverDetails::Vendor vendor;
839 DriverDetails::Driver driver;
840
841 // String comparisons aren't ideal, but there doesn't seem to be any other way to tell
842 // which vendor a driver is for. These names are based on the reports submitted to
843 // vulkan.gpuinfo.org, as of 19/09/2017.
844 std::string device_name = m_device_properties.deviceName;
845 u32 vendor_id = m_device_properties.vendorID;
846 if (vendor_id == 0x10DE)
847 {
848 // Currently, there is only the official NV binary driver.
849 // "NVIDIA" does not appear in the device name.
850 vendor = DriverDetails::VENDOR_NVIDIA;
851 driver = DriverDetails::DRIVER_NVIDIA;
852 }
853 else if (vendor_id == 0x1002 || vendor_id == 0x1022 ||
854 device_name.find("AMD") != std::string::npos)
855 {
856 // RADV always advertises its name in the device string.
857 // If not RADV, assume the AMD binary driver.
858 if (device_name.find("RADV") != std::string::npos)
859 {
860 vendor = DriverDetails::VENDOR_MESA;
861 driver = DriverDetails::DRIVER_R600;
862 }
863 else
864 {
865 vendor = DriverDetails::VENDOR_ATI;
866 driver = DriverDetails::DRIVER_ATI;
867 }
868 }
869 else if (vendor_id == 0x8086 || vendor_id == 0x8087 ||
870 device_name.find("Intel") != std::string::npos)
871 {
872 // Apart from the driver version, Intel does not appear to provide a way to
873 // differentiate between anv and the binary driver (Skylake+). Assume to be
874 // using anv if we not running on Windows.
875 #ifdef WIN32
876 vendor = DriverDetails::VENDOR_INTEL;
877 driver = DriverDetails::DRIVER_INTEL;
878 #else
879 vendor = DriverDetails::VENDOR_MESA;
880 driver = DriverDetails::DRIVER_I965;
881 #endif
882 }
883 else if (vendor_id == 0x5143 || device_name.find("Adreno") != std::string::npos)
884 {
885 // Currently only the Qualcomm binary driver exists for Adreno.
886 vendor = DriverDetails::VENDOR_QUALCOMM;
887 driver = DriverDetails::DRIVER_QUALCOMM;
888 }
889 else if (vendor_id == 0x13B6 || device_name.find("Mali") != std::string::npos)
890 {
891 // Currently only the ARM binary driver exists for Mali.
892 vendor = DriverDetails::VENDOR_ARM;
893 driver = DriverDetails::DRIVER_ARM;
894 }
895 else if (vendor_id == 0x1010 || device_name.find("PowerVR") != std::string::npos)
896 {
897 // Currently only the binary driver exists for PowerVR.
898 vendor = DriverDetails::VENDOR_IMGTEC;
899 driver = DriverDetails::DRIVER_IMGTEC;
900 }
901 else
902 {
903 WARN_LOG(VIDEO, "Unknown Vulkan driver vendor, please report it to us.");
904 WARN_LOG(VIDEO, "Vendor ID: 0x%X, Device Name: %s", vendor_id, device_name.c_str());
905 vendor = DriverDetails::VENDOR_UNKNOWN;
906 driver = DriverDetails::DRIVER_UNKNOWN;
907 }
908
909 #ifdef __APPLE__
910 // Vulkan on macOS goes through Metal, and is not susceptible to the same bugs
911 // as the vendor's native Vulkan drivers. We use a different driver fields to
912 // differentiate MoltenVK.
913 driver = DriverDetails::DRIVER_PORTABILITY;
914 #endif
915
916 DriverDetails::Init(DriverDetails::API_VULKAN, vendor, driver,
917 static_cast<double>(m_device_properties.driverVersion),
918 DriverDetails::Family::UNKNOWN);
919 }
920
PopulateShaderSubgroupSupport()921 void VulkanContext::PopulateShaderSubgroupSupport()
922 {
923 // Vulkan 1.1 support is required for vkGetPhysicalDeviceProperties2(), but we can't rely on the
924 // function pointer alone.
925 if (!vkGetPhysicalDeviceProperties2 || (VK_VERSION_MAJOR(m_device_properties.apiVersion) == 1 &&
926 VK_VERSION_MINOR(m_device_properties.apiVersion) < 1))
927 {
928 return;
929 }
930
931 VkPhysicalDeviceProperties2 device_properties_2 = {};
932 device_properties_2.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_PROPERTIES_2;
933
934 VkPhysicalDeviceSubgroupProperties subgroup_properties = {};
935 subgroup_properties.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_SUBGROUP_PROPERTIES;
936 device_properties_2.pNext = &subgroup_properties;
937
938 vkGetPhysicalDeviceProperties2(m_physical_device, &device_properties_2);
939
940 m_shader_subgroup_size = subgroup_properties.subgroupSize;
941
942 // We require basic ops (for gl_SubgroupInvocationID), ballot (for subgroupBallot,
943 // subgroupBallotFindLSB), and arithmetic (for subgroupMin/subgroupMax).
944 constexpr VkSubgroupFeatureFlags required_operations = VK_SUBGROUP_FEATURE_BASIC_BIT |
945 VK_SUBGROUP_FEATURE_ARITHMETIC_BIT |
946 VK_SUBGROUP_FEATURE_BALLOT_BIT;
947 m_supports_shader_subgroup_operations =
948 (subgroup_properties.supportedOperations & required_operations) == required_operations &&
949 subgroup_properties.supportedStages & VK_SHADER_STAGE_FRAGMENT_BIT;
950 }
951
SupportsExclusiveFullscreen(const WindowSystemInfo & wsi,VkSurfaceKHR surface)952 bool VulkanContext::SupportsExclusiveFullscreen(const WindowSystemInfo& wsi, VkSurfaceKHR surface)
953 {
954 #ifdef SUPPORTS_VULKAN_EXCLUSIVE_FULLSCREEN
955 if (!surface || !vkGetPhysicalDeviceSurfaceCapabilities2KHR ||
956 !SupportsDeviceExtension(VK_EXT_FULL_SCREEN_EXCLUSIVE_EXTENSION_NAME))
957 {
958 return false;
959 }
960
961 VkPhysicalDeviceSurfaceInfo2KHR si = {};
962 si.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_SURFACE_INFO_2_KHR;
963 si.surface = surface;
964
965 auto platform_info = GetPlatformExclusiveFullscreenInfo(wsi);
966 si.pNext = &platform_info;
967
968 VkSurfaceCapabilities2KHR caps = {};
969 caps.sType = VK_STRUCTURE_TYPE_SURFACE_CAPABILITIES_2_KHR;
970
971 VkSurfaceCapabilitiesFullScreenExclusiveEXT fullscreen_caps = {};
972 fullscreen_caps.sType = VK_STRUCTURE_TYPE_SURFACE_CAPABILITIES_FULL_SCREEN_EXCLUSIVE_EXT;
973 fullscreen_caps.fullScreenExclusiveSupported = VK_TRUE;
974 caps.pNext = &fullscreen_caps;
975
976 VkResult res = vkGetPhysicalDeviceSurfaceCapabilities2KHR(m_physical_device, &si, &caps);
977 if (res != VK_SUCCESS)
978 {
979 LOG_VULKAN_ERROR(res, "vkGetPhysicalDeviceSurfaceCapabilities2KHR failed:");
980 return false;
981 }
982
983 return fullscreen_caps.fullScreenExclusiveSupported;
984 #else
985 return false;
986 #endif
987 }
988
989 #ifdef WIN32
990 VkSurfaceFullScreenExclusiveWin32InfoEXT
GetPlatformExclusiveFullscreenInfo(const WindowSystemInfo & wsi)991 VulkanContext::GetPlatformExclusiveFullscreenInfo(const WindowSystemInfo& wsi)
992 {
993 VkSurfaceFullScreenExclusiveWin32InfoEXT info = {};
994 info.sType = VK_STRUCTURE_TYPE_SURFACE_FULL_SCREEN_EXCLUSIVE_WIN32_INFO_EXT;
995 info.hmonitor =
996 MonitorFromWindow(static_cast<HWND>(wsi.render_surface), MONITOR_DEFAULTTOPRIMARY);
997 return info;
998 }
999 #endif
1000
1001 } // namespace Vulkan
1002