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