vulkan_instance.cc 16 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468
  1. // Copyright (c) 2018 The Chromium Authors. All rights reserved.
  2. // Use of this source code is governed by a BSD-style license that can be
  3. // found in the LICENSE file.
  4. #include "gpu/vulkan/vulkan_instance.h"
  5. #include <vector>
  6. #include "base/containers/flat_set.h"
  7. #include "base/logging.h"
  8. #include "base/numerics/safe_conversions.h"
  9. #include "build/build_config.h"
  10. #include "gpu/vulkan/vulkan_crash_keys.h"
  11. #include "gpu/vulkan/vulkan_device_queue.h"
  12. #include "gpu/vulkan/vulkan_function_pointers.h"
  13. #include "gpu/vulkan/vulkan_util.h"
  14. #include "ui/gl/gl_angle_util_vulkan.h"
  15. #include "ui/gl/gl_switches.h"
  16. namespace gpu {
  17. namespace {
  18. #if DCHECK_IS_ON()
  19. const char* kSkippedErrors[] = {
  20. // http://anglebug.com/4583
  21. "VUID-VkGraphicsPipelineCreateInfo-blendEnable-02023",
  22. };
  23. VKAPI_ATTR VkBool32 VKAPI_CALL
  24. VulkanErrorCallback(VkDebugReportFlagsEXT flags,
  25. VkDebugReportObjectTypeEXT object_type,
  26. uint64_t object,
  27. size_t location,
  28. int32_t message_code,
  29. const char* layer_prefix,
  30. const char* message,
  31. void* user_data) {
  32. static base::flat_set<const char*> hitted_errors;
  33. for (const char* error : kSkippedErrors) {
  34. if (strstr(message, error) != nullptr) {
  35. if (hitted_errors.find(error) != hitted_errors.end())
  36. return VK_FALSE;
  37. hitted_errors.insert(error);
  38. }
  39. }
  40. LOG(ERROR) << message;
  41. return VK_FALSE;
  42. }
  43. VKAPI_ATTR VkBool32 VKAPI_CALL
  44. VulkanWarningCallback(VkDebugReportFlagsEXT flags,
  45. VkDebugReportObjectTypeEXT object_type,
  46. uint64_t object,
  47. size_t location,
  48. int32_t message_code,
  49. const char* layer_prefix,
  50. const char* message,
  51. void* user_data) {
  52. LOG(WARNING) << message;
  53. return VK_FALSE;
  54. }
  55. #endif // DCHECK_IS_ON()
  56. } // namespace
  57. VulkanInstance::VulkanInstance()
  58. : is_from_angle_(base::FeatureList::IsEnabled(features::kVulkanFromANGLE)) {
  59. }
  60. VulkanInstance::~VulkanInstance() {
  61. Destroy();
  62. }
  63. bool VulkanInstance::Initialize(
  64. const base::FilePath& vulkan_loader_library_path,
  65. const std::vector<const char*>& required_extensions,
  66. const std::vector<const char*>& required_layers) {
  67. if (!BindUnassignedFunctionPointers(vulkan_loader_library_path))
  68. return false;
  69. return InitializeInstace(required_extensions, required_layers);
  70. }
  71. bool VulkanInstance::BindUnassignedFunctionPointers(
  72. const base::FilePath& vulkan_loader_library_path) {
  73. VulkanFunctionPointers* vulkan_function_pointers =
  74. gpu::GetVulkanFunctionPointers();
  75. if (is_from_angle_) {
  76. PFN_vkGetInstanceProcAddr proc = gl::QueryVkGetInstanceProcAddrFromANGLE();
  77. if (!proc) {
  78. LOG(ERROR) << "Failed to get vkGetInstanceProcAddr pointer from ANGLE.";
  79. return false;
  80. }
  81. if (!vulkan_function_pointers
  82. ->BindUnassociatedFunctionPointersFromGetProcAddr(proc)) {
  83. return false;
  84. }
  85. } else {
  86. base::NativeLibraryLoadError error;
  87. loader_library_ =
  88. base::LoadNativeLibrary(vulkan_loader_library_path, &error);
  89. if (!loader_library_) {
  90. LOG(ERROR) << "Failed to load '" << vulkan_loader_library_path
  91. << "': " << error.ToString();
  92. return false;
  93. }
  94. if (!vulkan_function_pointers
  95. ->BindUnassociatedFunctionPointersFromLoaderLib(loader_library_)) {
  96. return false;
  97. }
  98. }
  99. return true;
  100. }
  101. bool VulkanInstance::InitializeInstace(
  102. const std::vector<const char*>& required_extensions,
  103. const std::vector<const char*>& required_layers) {
  104. if (is_from_angle_)
  105. return InitializeFromANGLE(required_extensions, required_layers);
  106. return CreateInstance(required_extensions, required_layers);
  107. }
  108. bool VulkanInstance::CreateInstance(
  109. const std::vector<const char*>& required_extensions,
  110. const std::vector<const char*>& required_layers) {
  111. DCHECK(!vk_instance_);
  112. if (!CollectBasicInfo(required_layers))
  113. return false;
  114. vulkan_info_.used_api_version = kVulkanRequiredApiVersion;
  115. VkApplicationInfo app_info = {};
  116. app_info.sType = VK_STRUCTURE_TYPE_APPLICATION_INFO;
  117. app_info.pApplicationName = "Chromium";
  118. app_info.apiVersion = vulkan_info_.used_api_version;
  119. vulkan_info_.enabled_instance_extensions = required_extensions;
  120. for (const VkExtensionProperties& ext_property :
  121. vulkan_info_.instance_extensions) {
  122. if (strcmp(ext_property.extensionName,
  123. VK_EXT_DEBUG_REPORT_EXTENSION_NAME) == 0) {
  124. debug_report_enabled_ = true;
  125. vulkan_info_.enabled_instance_extensions.push_back(
  126. VK_EXT_DEBUG_REPORT_EXTENSION_NAME);
  127. }
  128. }
  129. #if DCHECK_IS_ON()
  130. for (const char* enabled_extension :
  131. vulkan_info_.enabled_instance_extensions) {
  132. bool found = false;
  133. for (const VkExtensionProperties& ext_property :
  134. vulkan_info_.instance_extensions) {
  135. if (strcmp(ext_property.extensionName, enabled_extension) == 0) {
  136. found = true;
  137. break;
  138. }
  139. }
  140. if (!found) {
  141. DLOG(ERROR) << "Required extension " << enabled_extension
  142. << " missing from enumerated Vulkan extensions. "
  143. "vkCreateInstance will likely fail.";
  144. }
  145. }
  146. #endif
  147. VkInstanceCreateInfo instance_create_info = {
  148. VK_STRUCTURE_TYPE_INSTANCE_CREATE_INFO, // sType
  149. nullptr, // pNext
  150. 0, // flags
  151. &app_info, // pApplicationInfo
  152. base::checked_cast<uint32_t>(required_layers.size()),
  153. // enableLayerCount
  154. required_layers.data(), // ppEnabledLayerNames
  155. base::checked_cast<uint32_t>(
  156. vulkan_info_.enabled_instance_extensions.size()),
  157. // enabledExtensionCount
  158. vulkan_info_.enabled_instance_extensions.data(),
  159. // ppEnabledExtensionNames
  160. };
  161. VkResult result =
  162. vkCreateInstance(&instance_create_info, nullptr, &owned_vk_instance_);
  163. if (VK_SUCCESS != result) {
  164. DLOG(ERROR) << "vkCreateInstance() failed: " << result;
  165. return false;
  166. }
  167. vk_instance_ = owned_vk_instance_;
  168. gfx::ExtensionSet enabled_extensions(
  169. std::begin(vulkan_info_.enabled_instance_extensions),
  170. std::end(vulkan_info_.enabled_instance_extensions));
  171. VulkanFunctionPointers* vulkan_function_pointers =
  172. gpu::GetVulkanFunctionPointers();
  173. if (!vulkan_function_pointers->BindInstanceFunctionPointers(
  174. vk_instance_, vulkan_info_.used_api_version, enabled_extensions)) {
  175. return false;
  176. }
  177. #if DCHECK_IS_ON()
  178. // Register our error logging function.
  179. if (debug_report_enabled_) {
  180. VkDebugReportCallbackCreateInfoEXT cb_create_info = {};
  181. cb_create_info.sType = VK_STRUCTURE_TYPE_DEBUG_REPORT_CREATE_INFO_EXT;
  182. cb_create_info.flags = VK_DEBUG_REPORT_ERROR_BIT_EXT;
  183. cb_create_info.pfnCallback = &VulkanErrorCallback;
  184. result = vkCreateDebugReportCallbackEXT(vk_instance_, &cb_create_info,
  185. nullptr, &error_callback_);
  186. if (VK_SUCCESS != result) {
  187. error_callback_ = VK_NULL_HANDLE;
  188. DLOG(ERROR) << "vkCreateDebugReportCallbackEXT(ERROR) failed: " << result;
  189. return false;
  190. }
  191. cb_create_info.flags = VK_DEBUG_REPORT_WARNING_BIT_EXT |
  192. VK_DEBUG_REPORT_PERFORMANCE_WARNING_BIT_EXT;
  193. cb_create_info.pfnCallback = &VulkanWarningCallback;
  194. result = vkCreateDebugReportCallbackEXT(vk_instance_, &cb_create_info,
  195. nullptr, &warning_callback_);
  196. if (VK_SUCCESS != result) {
  197. warning_callback_ = VK_NULL_HANDLE;
  198. DLOG(ERROR) << "vkCreateDebugReportCallbackEXT(WARN) failed: " << result;
  199. return false;
  200. }
  201. }
  202. #endif
  203. if (!CollectDeviceInfo())
  204. return false;
  205. return true;
  206. }
  207. bool VulkanInstance::InitializeFromANGLE(
  208. const std::vector<const char*>& required_extensions,
  209. const std::vector<const char*>& required_layers) {
  210. vk_instance_ = gl::QueryVkInstanceFromANGLE();
  211. if (vk_instance_ == VK_NULL_HANDLE)
  212. return false;
  213. uint32_t api_version = gl::QueryVkVersionFromANGLE();
  214. if (api_version < kVulkanRequiredApiVersion)
  215. return false;
  216. if (!CollectBasicInfo({}))
  217. return false;
  218. vulkan_info_.used_api_version = api_version;
  219. auto extensions = gl::QueryVkInstanceExtensionsFromANGLE();
  220. DCHECK(!extensions.empty());
  221. for (const auto& extension : extensions)
  222. vulkan_info_.enabled_instance_extensions.push_back(extension.data());
  223. VulkanFunctionPointers* vulkan_function_pointers =
  224. gpu::GetVulkanFunctionPointers();
  225. if (!vulkan_function_pointers->BindInstanceFunctionPointers(
  226. vk_instance_, vulkan_info_.used_api_version, extensions)) {
  227. return false;
  228. }
  229. VkPhysicalDevice physical_device = gl::QueryVkPhysicalDeviceFromANGLE();
  230. if (physical_device == VK_NULL_HANDLE)
  231. return false;
  232. if (!CollectDeviceInfo(physical_device))
  233. return false;
  234. return true;
  235. }
  236. bool VulkanInstance::CollectBasicInfo(
  237. const std::vector<const char*>& required_layers) {
  238. VkResult result = vkEnumerateInstanceVersion(&vulkan_info_.api_version);
  239. if (result != VK_SUCCESS) {
  240. DLOG(ERROR) << "vkEnumerateInstanceVersion() failed: " << result;
  241. return false;
  242. }
  243. if (vulkan_info_.api_version < kVulkanRequiredApiVersion)
  244. return false;
  245. gpu::crash_keys::vulkan_api_version.Set(
  246. VkVersionToString(vulkan_info_.api_version));
  247. // Query the extensions from all layers, including ones that are implicitly
  248. // available (identified by passing a null ptr as the layer name).
  249. std::vector<const char*> all_required_layers = required_layers;
  250. // Include the extension properties provided by the Vulkan implementation as
  251. // part of the enumeration.
  252. all_required_layers.push_back(nullptr);
  253. for (const char* layer_name : all_required_layers) {
  254. uint32_t num_instance_exts = 0;
  255. result = vkEnumerateInstanceExtensionProperties(
  256. layer_name, &num_instance_exts, nullptr);
  257. if (VK_SUCCESS != result) {
  258. DLOG(ERROR) << "vkEnumerateInstanceExtensionProperties(" << layer_name
  259. << ") failed: " << result;
  260. return false;
  261. }
  262. const size_t previous_extension_count =
  263. vulkan_info_.instance_extensions.size();
  264. vulkan_info_.instance_extensions.resize(previous_extension_count +
  265. num_instance_exts);
  266. result = vkEnumerateInstanceExtensionProperties(
  267. layer_name, &num_instance_exts,
  268. &vulkan_info_.instance_extensions.data()[previous_extension_count]);
  269. if (VK_SUCCESS != result) {
  270. DLOG(ERROR) << "vkEnumerateInstanceExtensionProperties(" << layer_name
  271. << ") failed: " << result;
  272. return false;
  273. }
  274. }
  275. for (const VkExtensionProperties& ext_property :
  276. vulkan_info_.instance_extensions) {
  277. if (strcmp(ext_property.extensionName,
  278. VK_EXT_DEBUG_REPORT_EXTENSION_NAME) == 0) {
  279. debug_report_enabled_ = true;
  280. vulkan_info_.enabled_instance_extensions.push_back(
  281. VK_EXT_DEBUG_REPORT_EXTENSION_NAME);
  282. }
  283. }
  284. uint32_t num_instance_layers = 0;
  285. result = vkEnumerateInstanceLayerProperties(&num_instance_layers, nullptr);
  286. if (VK_SUCCESS != result) {
  287. DLOG(ERROR) << "vkEnumerateInstanceLayerProperties(NULL) failed: "
  288. << result;
  289. return false;
  290. }
  291. vulkan_info_.instance_layers.resize(num_instance_layers);
  292. result = vkEnumerateInstanceLayerProperties(
  293. &num_instance_layers, vulkan_info_.instance_layers.data());
  294. if (VK_SUCCESS != result) {
  295. DLOG(ERROR) << "vkEnumerateInstanceLayerProperties() failed: " << result;
  296. return false;
  297. }
  298. return true;
  299. }
  300. bool VulkanInstance::CollectDeviceInfo(VkPhysicalDevice physical_device) {
  301. std::vector<VkPhysicalDevice> physical_devices;
  302. if (physical_device == VK_NULL_HANDLE) {
  303. uint32_t count = 0;
  304. VkResult result = vkEnumeratePhysicalDevices(vk_instance_, &count, nullptr);
  305. if (result != VK_SUCCESS) {
  306. DLOG(ERROR) << "vkEnumeratePhysicalDevices failed: " << result;
  307. return false;
  308. }
  309. if (!count) {
  310. DLOG(ERROR) << "vkEnumeratePhysicalDevices returns zero device.";
  311. return false;
  312. }
  313. physical_devices.resize(count);
  314. result = vkEnumeratePhysicalDevices(vk_instance_, &count,
  315. physical_devices.data());
  316. if (VK_SUCCESS != result) {
  317. DLOG(ERROR) << "vkEnumeratePhysicalDevices() failed: " << result;
  318. return false;
  319. }
  320. } else {
  321. physical_devices.push_back(physical_device);
  322. }
  323. vulkan_info_.physical_devices.reserve(physical_devices.size());
  324. for (VkPhysicalDevice device : physical_devices) {
  325. vulkan_info_.physical_devices.emplace_back();
  326. auto& info = vulkan_info_.physical_devices.back();
  327. info.device = device;
  328. vkGetPhysicalDeviceProperties(device, &info.properties);
  329. uint32_t count = 0;
  330. VkResult result = vkEnumerateDeviceExtensionProperties(
  331. device, nullptr /* pLayerName */, &count, nullptr);
  332. DLOG_IF(ERROR, result != VK_SUCCESS)
  333. << "vkEnumerateDeviceExtensionProperties failed: " << result;
  334. info.extensions.resize(count);
  335. result = vkEnumerateDeviceExtensionProperties(
  336. device, nullptr /* pLayerName */, &count, info.extensions.data());
  337. DLOG_IF(ERROR, result != VK_SUCCESS)
  338. << "vkEnumerateDeviceExtensionProperties failed: " << result;
  339. // The API version of the VkInstance might be different than the supported
  340. // API version of the VkPhysicalDevice, so we need to check the GPU's
  341. // API version instead of just testing to see if
  342. // vkGetPhysicalDeviceProperties2 and vkGetPhysicalDeviceFeatures2 are
  343. // non-null.
  344. static_assert(kVulkanRequiredApiVersion >= VK_API_VERSION_1_1, "");
  345. if (info.properties.apiVersion >= kVulkanRequiredApiVersion) {
  346. info.driver_properties = VkPhysicalDeviceDriverProperties{
  347. .sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_DRIVER_PROPERTIES,
  348. };
  349. VkPhysicalDeviceProperties2 properties2 = {
  350. .sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_PROPERTIES_2,
  351. .pNext = &info.driver_properties,
  352. };
  353. vkGetPhysicalDeviceProperties2(device, &properties2);
  354. VkPhysicalDeviceSamplerYcbcrConversionFeatures ycbcr_conversion_features =
  355. {VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_SAMPLER_YCBCR_CONVERSION_FEATURES};
  356. VkPhysicalDeviceProtectedMemoryFeatures protected_memory_feature = {
  357. VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_PROTECTED_MEMORY_FEATURES};
  358. VkPhysicalDeviceFeatures2 features_2 = {
  359. VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_FEATURES_2};
  360. features_2.pNext = &ycbcr_conversion_features;
  361. ycbcr_conversion_features.pNext = &protected_memory_feature;
  362. vkGetPhysicalDeviceFeatures2(device, &features_2);
  363. info.features = features_2.features;
  364. info.feature_sampler_ycbcr_conversion =
  365. ycbcr_conversion_features.samplerYcbcrConversion;
  366. info.feature_protected_memory = protected_memory_feature.protectedMemory;
  367. }
  368. count = 0;
  369. vkGetPhysicalDeviceQueueFamilyProperties(device, &count, nullptr);
  370. if (count) {
  371. info.queue_families.resize(count);
  372. vkGetPhysicalDeviceQueueFamilyProperties(device, &count,
  373. info.queue_families.data());
  374. }
  375. }
  376. return true;
  377. }
  378. void VulkanInstance::Destroy() {
  379. #if DCHECK_IS_ON()
  380. if (debug_report_enabled_ && (error_callback_ != VK_NULL_HANDLE ||
  381. warning_callback_ != VK_NULL_HANDLE)) {
  382. if (error_callback_ != VK_NULL_HANDLE) {
  383. vkDestroyDebugReportCallbackEXT(vk_instance_, error_callback_, nullptr);
  384. error_callback_ = VK_NULL_HANDLE;
  385. }
  386. if (warning_callback_ != VK_NULL_HANDLE) {
  387. vkDestroyDebugReportCallbackEXT(vk_instance_, warning_callback_, nullptr);
  388. warning_callback_ = VK_NULL_HANDLE;
  389. }
  390. }
  391. #endif
  392. if (owned_vk_instance_ != VK_NULL_HANDLE) {
  393. vkDestroyInstance(owned_vk_instance_, nullptr);
  394. owned_vk_instance_ = VK_NULL_HANDLE;
  395. }
  396. vk_instance_ = VK_NULL_HANDLE;
  397. if (loader_library_) {
  398. base::UnloadNativeLibrary(loader_library_);
  399. loader_library_ = nullptr;
  400. }
  401. }
  402. } // namespace gpu