GrManagerImpl.cpp 47 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269127012711272127312741275127612771278127912801281128212831284128512861287128812891290129112921293129412951296129712981299130013011302130313041305130613071308130913101311131213131314131513161317131813191320132113221323132413251326132713281329133013311332133313341335133613371338133913401341134213431344134513461347134813491350135113521353135413551356135713581359136013611362136313641365136613671368136913701371137213731374137513761377137813791380138113821383138413851386138713881389139013911392139313941395139613971398139914001401140214031404140514061407140814091410141114121413141414151416141714181419142014211422142314241425142614271428142914301431143214331434143514361437143814391440144114421443144414451446144714481449145014511452145314541455145614571458145914601461146214631464146514661467146814691470147114721473147414751476147714781479148014811482148314841485148614871488148914901491
  1. // Copyright (C) 2009-2021, Panagiotis Christopoulos Charitos and contributors.
  2. // All rights reserved.
  3. // Code licensed under the BSD License.
  4. // http://www.anki3d.org/LICENSE
  5. #include <AnKi/Gr/Vulkan/GrManagerImpl.h>
  6. #include <AnKi/Gr/GrManager.h>
  7. #include <AnKi/Gr/Vulkan/CommandBufferImpl.h>
  8. #include <AnKi/Gr/CommandBuffer.h>
  9. #include <AnKi/Gr/Fence.h>
  10. #include <AnKi/Gr/Vulkan/FenceImpl.h>
  11. #include <AnKi/Util/Functions.h>
  12. #include <AnKi/Util/StringList.h>
  13. #include <AnKi/Core/ConfigSet.h>
  14. #include <glslang/Public/ShaderLang.h>
  15. namespace anki
  16. {
  17. GrManagerImpl::~GrManagerImpl()
  18. {
  19. // 1st THING: wait for the present fences because I don't know if waiting on queue will cover this
  20. for(PerFrame& frame : m_perFrame)
  21. {
  22. if(frame.m_presentFence.isCreated())
  23. {
  24. frame.m_presentFence->wait();
  25. }
  26. }
  27. // 2nd THING: wait for the GPU
  28. for(VkQueue& queue : m_queues)
  29. {
  30. LockGuard<Mutex> lock(m_globalMtx);
  31. if(queue)
  32. {
  33. vkQueueWaitIdle(queue);
  34. queue = VK_NULL_HANDLE;
  35. }
  36. }
  37. m_cmdbFactory.destroy();
  38. // 3rd THING: The destroy everything that has a reference to GrObjects.
  39. for(PerFrame& frame : m_perFrame)
  40. {
  41. frame.m_presentFence.reset(nullptr);
  42. frame.m_acquireSemaphore.reset(nullptr);
  43. frame.m_renderSemaphore.reset(nullptr);
  44. }
  45. m_crntSwapchain.reset(nullptr);
  46. // 4th THING: Continue with the rest
  47. m_gpuMemManager.destroy();
  48. m_barrierFactory.destroy(); // Destroy before fences
  49. m_semaphoreFactory.destroy(); // Destroy before fences
  50. m_swapchainFactory.destroy(); // Destroy before fences
  51. m_pplineLayoutFactory.destroy();
  52. m_descrFactory.destroy();
  53. m_pplineCache.destroy(m_device, m_physicalDevice, getAllocator());
  54. m_fenceFactory.destroy();
  55. m_samplerFactory.destroy();
  56. if(m_device)
  57. {
  58. vkDestroyDevice(m_device, nullptr);
  59. }
  60. if(m_surface)
  61. {
  62. vkDestroySurfaceKHR(m_instance, m_surface, nullptr);
  63. }
  64. if(m_debugCallback)
  65. {
  66. vkDestroyDebugReportCallbackEXT(m_instance, m_debugCallback, nullptr);
  67. }
  68. if(m_instance)
  69. {
  70. #if ANKI_GR_MANAGER_DEBUG_MEMMORY
  71. VkAllocationCallbacks* pallocCbs = &m_debugAllocCbs;
  72. #else
  73. VkAllocationCallbacks* pallocCbs = nullptr;
  74. #endif
  75. vkDestroyInstance(m_instance, pallocCbs);
  76. }
  77. m_vkHandleToName.destroy(getAllocator());
  78. }
  79. Error GrManagerImpl::init(const GrManagerInitInfo& init)
  80. {
  81. const Error err = initInternal(init);
  82. if(err)
  83. {
  84. ANKI_VK_LOGE("Vulkan initialization failed");
  85. return Error::FUNCTION_FAILED;
  86. }
  87. return Error::NONE;
  88. }
  89. Error GrManagerImpl::initInternal(const GrManagerInitInfo& init)
  90. {
  91. ANKI_VK_LOGI("Initializing Vulkan backend");
  92. ANKI_CHECK(initInstance(init));
  93. ANKI_CHECK(initSurface(init));
  94. ANKI_CHECK(initDevice(init));
  95. for(VulkanQueueType qtype : EnumIterable<VulkanQueueType>())
  96. {
  97. if(m_queueFamilyIndices[qtype] != MAX_U32)
  98. {
  99. vkGetDeviceQueue(m_device, m_queueFamilyIndices[qtype], 0, &m_queues[qtype]);
  100. }
  101. else
  102. {
  103. m_queues[qtype] = VK_NULL_HANDLE;
  104. }
  105. }
  106. m_swapchainFactory.init(this, init.m_config->getBool("gr_vsync"));
  107. m_crntSwapchain = m_swapchainFactory.newInstance();
  108. ANKI_CHECK(m_pplineCache.init(m_device, m_physicalDevice, init.m_cacheDirectory, *init.m_config, getAllocator()));
  109. ANKI_CHECK(initMemory(*init.m_config));
  110. ANKI_CHECK(m_cmdbFactory.init(getAllocator(), m_device, m_queueFamilyIndices));
  111. for(PerFrame& f : m_perFrame)
  112. {
  113. resetFrame(f);
  114. }
  115. glslang::InitializeProcess();
  116. m_fenceFactory.init(getAllocator(), m_device);
  117. m_semaphoreFactory.init(getAllocator(), m_device);
  118. m_samplerFactory.init(this);
  119. m_barrierFactory.init(getAllocator(), m_device);
  120. m_occlusionQueryFactory.init(getAllocator(), m_device, VK_QUERY_TYPE_OCCLUSION);
  121. m_timestampQueryFactory.init(getAllocator(), m_device, VK_QUERY_TYPE_TIMESTAMP);
  122. // Set m_r8g8b8ImagesSupported
  123. {
  124. VkImageFormatProperties props = {};
  125. const VkResult res = vkGetPhysicalDeviceImageFormatProperties(
  126. m_physicalDevice, VK_FORMAT_R8G8B8_UNORM, VK_IMAGE_TYPE_2D, VK_IMAGE_TILING_OPTIMAL,
  127. VK_IMAGE_USAGE_SAMPLED_BIT | VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT, 0, &props);
  128. if(res == VK_ERROR_FORMAT_NOT_SUPPORTED)
  129. {
  130. ANKI_VK_LOGI("R8G8B8 Images are not supported. Will workaround this");
  131. m_r8g8b8ImagesSupported = false;
  132. }
  133. else
  134. {
  135. ANKI_ASSERT(res == VK_SUCCESS);
  136. ANKI_VK_LOGI("R8G8B8 Images are supported");
  137. m_r8g8b8ImagesSupported = true;
  138. }
  139. }
  140. // Set m_s8ImagesSupported
  141. {
  142. VkImageFormatProperties props = {};
  143. const VkResult res = vkGetPhysicalDeviceImageFormatProperties(
  144. m_physicalDevice, VK_FORMAT_S8_UINT, VK_IMAGE_TYPE_2D, VK_IMAGE_TILING_OPTIMAL,
  145. VK_IMAGE_USAGE_SAMPLED_BIT | VK_IMAGE_USAGE_DEPTH_STENCIL_ATTACHMENT_BIT, 0, &props);
  146. if(res == VK_ERROR_FORMAT_NOT_SUPPORTED)
  147. {
  148. ANKI_VK_LOGI("S8 Images are not supported. Will workaround this");
  149. m_s8ImagesSupported = false;
  150. }
  151. else
  152. {
  153. ANKI_ASSERT(res == VK_SUCCESS);
  154. ANKI_VK_LOGI("S8 Images are supported");
  155. m_s8ImagesSupported = true;
  156. }
  157. }
  158. // Set m_d24S8ImagesSupported
  159. {
  160. VkImageFormatProperties props = {};
  161. VkResult res = vkGetPhysicalDeviceImageFormatProperties(
  162. m_physicalDevice, VK_FORMAT_D24_UNORM_S8_UINT, VK_IMAGE_TYPE_2D, VK_IMAGE_TILING_OPTIMAL,
  163. VK_IMAGE_USAGE_SAMPLED_BIT | VK_IMAGE_USAGE_DEPTH_STENCIL_ATTACHMENT_BIT, 0, &props);
  164. if(res == VK_ERROR_FORMAT_NOT_SUPPORTED)
  165. {
  166. ANKI_VK_LOGI("D24S8 Images are not supported. Will workaround this");
  167. m_d24S8ImagesSupported = false;
  168. }
  169. else
  170. {
  171. ANKI_ASSERT(res == VK_SUCCESS);
  172. ANKI_VK_LOGI("D24S8 Images are supported");
  173. m_d24S8ImagesSupported = true;
  174. }
  175. }
  176. m_bindlessLimits.m_bindlessTextureCount = init.m_config->getNumberU32("gr_maxBindlessTextures");
  177. m_bindlessLimits.m_bindlessImageCount = init.m_config->getNumberU32("gr_maxBindlessImages");
  178. ANKI_CHECK(m_descrFactory.init(getAllocator(), m_device, m_bindlessLimits));
  179. m_pplineLayoutFactory.init(getAllocator(), m_device);
  180. return Error::NONE;
  181. }
  182. Error GrManagerImpl::initInstance(const GrManagerInitInfo& init)
  183. {
  184. // Init VOLK
  185. //
  186. ANKI_VK_CHECK(volkInitialize());
  187. // Create the instance
  188. //
  189. const U8 vulkanMinor = init.m_config->getNumberU8("gr_vkminor");
  190. const U8 vulkanMajor = init.m_config->getNumberU8("gr_vkmajor");
  191. VkApplicationInfo app = {};
  192. app.sType = VK_STRUCTURE_TYPE_APPLICATION_INFO;
  193. app.pApplicationName = "unamed";
  194. app.applicationVersion = 1;
  195. app.pEngineName = "AnKi 3D Engine";
  196. app.engineVersion = (ANKI_VERSION_MAJOR << 16) | ANKI_VERSION_MINOR;
  197. app.apiVersion = VK_MAKE_VERSION(vulkanMajor, vulkanMinor, 0);
  198. VkInstanceCreateInfo ci = {};
  199. ci.sType = VK_STRUCTURE_TYPE_INSTANCE_CREATE_INFO;
  200. ci.pApplicationInfo = &app;
  201. // Validation layers
  202. static Array<const char*, 1> LAYERS = {"VK_LAYER_KHRONOS_validation"};
  203. Array<const char*, LAYERS.getSize()> layersToEnable; // Keep it alive in the stack
  204. if(init.m_config->getBool("gr_validation") || init.m_config->getBool("gr_debugPrintf"))
  205. {
  206. uint32_t count;
  207. vkEnumerateInstanceLayerProperties(&count, nullptr);
  208. if(count)
  209. {
  210. DynamicArrayAuto<VkLayerProperties> layerProps(getAllocator());
  211. layerProps.create(count);
  212. vkEnumerateInstanceLayerProperties(&count, &layerProps[0]);
  213. U32 layersToEnableCount = 0;
  214. for(const char* c : LAYERS)
  215. {
  216. for(U32 i = 0; i < count; ++i)
  217. {
  218. if(CString(c) == layerProps[i].layerName)
  219. {
  220. layersToEnable[layersToEnableCount++] = c;
  221. break;
  222. }
  223. }
  224. }
  225. if(layersToEnableCount)
  226. {
  227. ANKI_VK_LOGI("Will enable the following layers:");
  228. for(U32 i = 0; i < layersToEnableCount; ++i)
  229. {
  230. ANKI_VK_LOGI("\t%s", layersToEnable[i]);
  231. }
  232. ci.enabledLayerCount = layersToEnableCount;
  233. ci.ppEnabledLayerNames = &layersToEnable[0];
  234. }
  235. }
  236. }
  237. // Validation features
  238. DynamicArrayAuto<VkValidationFeatureEnableEXT> enabledValidationFeatures(getAllocator());
  239. DynamicArrayAuto<VkValidationFeatureDisableEXT> disabledValidationFeatures(getAllocator());
  240. if(init.m_config->getBool("gr_debugPrintf"))
  241. {
  242. enabledValidationFeatures.emplaceBack(VK_VALIDATION_FEATURE_ENABLE_DEBUG_PRINTF_EXT);
  243. }
  244. if(!init.m_config->getBool("gr_validation"))
  245. {
  246. disabledValidationFeatures.emplaceBack(VK_VALIDATION_FEATURE_DISABLE_ALL_EXT);
  247. }
  248. VkValidationFeaturesEXT validationFeatures = {};
  249. if(enabledValidationFeatures.getSize() || disabledValidationFeatures.getSize())
  250. {
  251. validationFeatures.sType = VK_STRUCTURE_TYPE_VALIDATION_FEATURES_EXT;
  252. validationFeatures.disabledValidationFeatureCount = disabledValidationFeatures.getSize();
  253. validationFeatures.enabledValidationFeatureCount = enabledValidationFeatures.getSize();
  254. validationFeatures.pDisabledValidationFeatures = disabledValidationFeatures.getBegin();
  255. validationFeatures.pEnabledValidationFeatures = enabledValidationFeatures.getBegin();
  256. validationFeatures.pNext = ci.pNext;
  257. ci.pNext = &validationFeatures;
  258. }
  259. // Extensions
  260. DynamicArrayAuto<const char*> instExtensions(getAllocator());
  261. DynamicArrayAuto<VkExtensionProperties> instExtensionInf(getAllocator());
  262. U32 extCount = 0;
  263. vkEnumerateInstanceExtensionProperties(nullptr, &extCount, nullptr);
  264. if(extCount)
  265. {
  266. instExtensions.create(extCount);
  267. instExtensionInf.create(extCount);
  268. vkEnumerateInstanceExtensionProperties(nullptr, &extCount, &instExtensionInf[0]);
  269. ANKI_VK_LOGI("Found the following instance extensions:");
  270. for(U32 i = 0; i < extCount; ++i)
  271. {
  272. ANKI_VK_LOGI("\t%s", instExtensionInf[i].extensionName);
  273. }
  274. U32 instExtensionCount = 0;
  275. for(U32 i = 0; i < extCount; ++i)
  276. {
  277. #if ANKI_OS_LINUX
  278. if(CString(instExtensionInf[i].extensionName) == VK_KHR_XCB_SURFACE_EXTENSION_NAME)
  279. {
  280. m_extensions |= VulkanExtensions::KHR_XCB_SURFACE;
  281. instExtensions[instExtensionCount++] = VK_KHR_XCB_SURFACE_EXTENSION_NAME;
  282. }
  283. else if(CString(instExtensionInf[i].extensionName) == VK_KHR_XLIB_SURFACE_EXTENSION_NAME)
  284. {
  285. m_extensions |= VulkanExtensions::KHR_XLIB_SURFACE;
  286. instExtensions[instExtensionCount++] = VK_KHR_XLIB_SURFACE_EXTENSION_NAME;
  287. }
  288. #elif ANKI_OS_WINDOWS
  289. if(CString(instExtensionInf[i].extensionName) == VK_KHR_WIN32_SURFACE_EXTENSION_NAME)
  290. {
  291. m_extensions |= VulkanExtensions::KHR_WIN32_SURFACE;
  292. instExtensions[instExtensionCount++] = VK_KHR_WIN32_SURFACE_EXTENSION_NAME;
  293. }
  294. #elif ANKI_OS_ANDROID
  295. if(CString(instExtensionInf[i].extensionName) == VK_KHR_ANDROID_SURFACE_EXTENSION_NAME)
  296. {
  297. m_extensions |= VulkanExtensions::KHR_ANDROID_SURFACE;
  298. instExtensions[instExtensionCount++] = VK_KHR_ANDROID_SURFACE_EXTENSION_NAME;
  299. }
  300. #else
  301. # error Not implemented
  302. #endif
  303. else if(CString(instExtensionInf[i].extensionName) == VK_KHR_SURFACE_EXTENSION_NAME)
  304. {
  305. m_extensions |= VulkanExtensions::KHR_SURFACE;
  306. instExtensions[instExtensionCount++] = VK_KHR_SURFACE_EXTENSION_NAME;
  307. }
  308. else if(CString(instExtensionInf[i].extensionName) == VK_EXT_DEBUG_REPORT_EXTENSION_NAME
  309. && (init.m_config->getBool("gr_validation") || init.m_config->getBool("gr_debugPrintf")))
  310. {
  311. m_extensions |= VulkanExtensions::EXT_DEBUG_REPORT;
  312. instExtensions[instExtensionCount++] = VK_EXT_DEBUG_REPORT_EXTENSION_NAME;
  313. }
  314. }
  315. if(instExtensionCount)
  316. {
  317. ANKI_VK_LOGI("Will enable the following instance extensions:");
  318. for(U32 i = 0; i < instExtensionCount; ++i)
  319. {
  320. ANKI_VK_LOGI("\t%s", instExtensions[i]);
  321. }
  322. ci.enabledExtensionCount = instExtensionCount;
  323. ci.ppEnabledExtensionNames = &instExtensions[0];
  324. }
  325. }
  326. #if ANKI_GR_MANAGER_DEBUG_MEMMORY
  327. m_debugAllocCbs = {};
  328. m_debugAllocCbs.pUserData = this;
  329. m_debugAllocCbs.pfnAllocation = allocateCallback;
  330. m_debugAllocCbs.pfnReallocation = reallocateCallback;
  331. m_debugAllocCbs.pfnFree = freeCallback;
  332. VkAllocationCallbacks* pallocCbs = &m_debugAllocCbs;
  333. #else
  334. VkAllocationCallbacks* pallocCbs = nullptr;
  335. #endif
  336. ANKI_VK_CHECK(vkCreateInstance(&ci, pallocCbs, &m_instance));
  337. // Get symbolx
  338. //
  339. volkLoadInstance(m_instance);
  340. // Set debug callbacks
  341. //
  342. if(!!(m_extensions & VulkanExtensions::EXT_DEBUG_REPORT))
  343. {
  344. VkDebugReportCallbackCreateInfoEXT ci = {};
  345. ci.sType = VK_STRUCTURE_TYPE_DEBUG_REPORT_CALLBACK_CREATE_INFO_EXT;
  346. ci.pfnCallback = debugReportCallbackEXT;
  347. ci.flags = VK_DEBUG_REPORT_ERROR_BIT_EXT | VK_DEBUG_REPORT_WARNING_BIT_EXT
  348. | VK_DEBUG_REPORT_PERFORMANCE_WARNING_BIT_EXT;
  349. if(init.m_config->getBool("gr_debugPrintf"))
  350. {
  351. ci.flags |= VK_DEBUG_REPORT_INFORMATION_BIT_EXT;
  352. }
  353. ci.pUserData = this;
  354. vkCreateDebugReportCallbackEXT(m_instance, &ci, nullptr, &m_debugCallback);
  355. }
  356. // Create the physical device
  357. //
  358. uint32_t count = 0;
  359. ANKI_VK_CHECK(vkEnumeratePhysicalDevices(m_instance, &count, nullptr));
  360. ANKI_VK_LOGI("Number of physical devices: %u", count);
  361. if(count < 1)
  362. {
  363. ANKI_VK_LOGE("Wrong number of physical devices");
  364. return Error::FUNCTION_FAILED;
  365. }
  366. count = 1;
  367. ANKI_VK_CHECK(vkEnumeratePhysicalDevices(m_instance, &count, &m_physicalDevice));
  368. m_rtPipelineProps.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_RAY_TRACING_PIPELINE_PROPERTIES_KHR;
  369. m_accelerationStructureProps.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_ACCELERATION_STRUCTURE_PROPERTIES_KHR;
  370. m_devProps.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_PROPERTIES_2;
  371. m_devProps.pNext = &m_rtPipelineProps;
  372. m_rtPipelineProps.pNext = &m_accelerationStructureProps;
  373. vkGetPhysicalDeviceProperties2(m_physicalDevice, &m_devProps);
  374. // Find vendor
  375. switch(m_devProps.properties.vendorID)
  376. {
  377. case 0x13B5:
  378. m_capabilities.m_gpuVendor = GpuVendor::ARM;
  379. break;
  380. case 0x10DE:
  381. m_capabilities.m_gpuVendor = GpuVendor::NVIDIA;
  382. break;
  383. case 0x1002:
  384. case 0x1022:
  385. m_capabilities.m_gpuVendor = GpuVendor::AMD;
  386. break;
  387. case 0x8086:
  388. m_capabilities.m_gpuVendor = GpuVendor::INTEL;
  389. break;
  390. default:
  391. m_capabilities.m_gpuVendor = GpuVendor::UNKNOWN;
  392. }
  393. ANKI_VK_LOGI("GPU is %s. Vendor identified as %s", m_devProps.properties.deviceName,
  394. &GPU_VENDOR_STR[m_capabilities.m_gpuVendor][0]);
  395. // Set limits
  396. m_capabilities.m_uniformBufferBindOffsetAlignment =
  397. max<U32>(ANKI_SAFE_ALIGNMENT, U32(m_devProps.properties.limits.minUniformBufferOffsetAlignment));
  398. m_capabilities.m_uniformBufferMaxRange = m_devProps.properties.limits.maxUniformBufferRange;
  399. m_capabilities.m_storageBufferBindOffsetAlignment =
  400. max<U32>(ANKI_SAFE_ALIGNMENT, U32(m_devProps.properties.limits.minStorageBufferOffsetAlignment));
  401. m_capabilities.m_storageBufferMaxRange = m_devProps.properties.limits.maxStorageBufferRange;
  402. m_capabilities.m_textureBufferBindOffsetAlignment =
  403. max<U32>(ANKI_SAFE_ALIGNMENT, U32(m_devProps.properties.limits.minTexelBufferOffsetAlignment));
  404. m_capabilities.m_textureBufferMaxRange = MAX_U32;
  405. m_capabilities.m_majorApiVersion = vulkanMajor;
  406. m_capabilities.m_minorApiVersion = vulkanMinor;
  407. m_capabilities.m_shaderGroupHandleSize = m_rtPipelineProps.shaderGroupHandleSize;
  408. m_capabilities.m_sbtRecordAlignment = m_rtPipelineProps.shaderGroupBaseAlignment;
  409. return Error::NONE;
  410. }
  411. Error GrManagerImpl::initDevice(const GrManagerInitInfo& init)
  412. {
  413. uint32_t count = 0;
  414. vkGetPhysicalDeviceQueueFamilyProperties(m_physicalDevice, &count, nullptr);
  415. ANKI_VK_LOGI("Number of queue families: %u", count);
  416. DynamicArrayAuto<VkQueueFamilyProperties> queueInfos(getAllocator());
  417. queueInfos.create(count);
  418. vkGetPhysicalDeviceQueueFamilyProperties(m_physicalDevice, &count, &queueInfos[0]);
  419. const VkQueueFlags GENERAL_QUEUE_FLAGS = VK_QUEUE_GRAPHICS_BIT | VK_QUEUE_COMPUTE_BIT | VK_QUEUE_TRANSFER_BIT;
  420. for(U32 i = 0; i < count; ++i)
  421. {
  422. VkBool32 supportsPresent = false;
  423. ANKI_VK_CHECK(vkGetPhysicalDeviceSurfaceSupportKHR(m_physicalDevice, i, m_surface, &supportsPresent));
  424. if(supportsPresent)
  425. {
  426. if((queueInfos[i].queueFlags & GENERAL_QUEUE_FLAGS) == GENERAL_QUEUE_FLAGS)
  427. {
  428. m_queueFamilyIndices[VulkanQueueType::GENERAL] = i;
  429. }
  430. else if((queueInfos[i].queueFlags & VK_QUEUE_COMPUTE_BIT)
  431. && !(queueInfos[i].queueFlags & VK_QUEUE_GRAPHICS_BIT))
  432. {
  433. // This must be the async compute
  434. m_queueFamilyIndices[VulkanQueueType::COMPUTE] = i;
  435. }
  436. }
  437. }
  438. if(m_queueFamilyIndices[VulkanQueueType::GENERAL] == MAX_U32)
  439. {
  440. ANKI_VK_LOGE("Couldn't find a queue family with graphics+compute+transfer+present. "
  441. "Something is wrong");
  442. return Error::FUNCTION_FAILED;
  443. }
  444. if(!init.m_config->getBool("gr_asyncCompute"))
  445. {
  446. m_queueFamilyIndices[VulkanQueueType::COMPUTE] = MAX_U32;
  447. }
  448. if(m_queueFamilyIndices[VulkanQueueType::COMPUTE] == MAX_U32)
  449. {
  450. ANKI_VK_LOGW("Couldn't find an async compute queue. Will try to use the general queue instead");
  451. }
  452. else
  453. {
  454. ANKI_VK_LOGI("Async compute is enabled");
  455. }
  456. const F32 priority = 1.0f;
  457. Array<VkDeviceQueueCreateInfo, U32(VulkanQueueType::COUNT)> q = {};
  458. VkDeviceCreateInfo ci = {};
  459. ci.sType = VK_STRUCTURE_TYPE_DEVICE_CREATE_INFO;
  460. ci.pQueueCreateInfos = &q[0];
  461. for(VulkanQueueType qtype : EnumIterable<VulkanQueueType>())
  462. {
  463. if(m_queueFamilyIndices[qtype] != MAX_U32)
  464. {
  465. q[qtype].sType = VK_STRUCTURE_TYPE_DEVICE_QUEUE_CREATE_INFO;
  466. q[qtype].queueFamilyIndex = m_queueFamilyIndices[qtype];
  467. q[qtype].queueCount = 1;
  468. q[qtype].pQueuePriorities = &priority;
  469. ++ci.queueCreateInfoCount;
  470. }
  471. }
  472. // Extensions
  473. U32 extCount = 0;
  474. vkEnumerateDeviceExtensionProperties(m_physicalDevice, nullptr, &extCount, nullptr);
  475. DynamicArrayAuto<VkExtensionProperties> extensionInfos(getAllocator()); // Keep it alive in the stack
  476. DynamicArrayAuto<const char*> extensionsToEnable(getAllocator());
  477. if(extCount)
  478. {
  479. extensionInfos.create(extCount);
  480. extensionsToEnable.create(extCount);
  481. U32 extensionsToEnableCount = 0;
  482. vkEnumerateDeviceExtensionProperties(m_physicalDevice, nullptr, &extCount, &extensionInfos[0]);
  483. ANKI_VK_LOGI("Found the following device extensions:");
  484. for(U32 i = 0; i < extCount; ++i)
  485. {
  486. ANKI_VK_LOGI("\t%s", extensionInfos[i].extensionName);
  487. }
  488. while(extCount-- != 0)
  489. {
  490. const CString extensionName(&extensionInfos[extCount].extensionName[0]);
  491. if(extensionName == VK_KHR_SWAPCHAIN_EXTENSION_NAME)
  492. {
  493. m_extensions |= VulkanExtensions::KHR_SWAPCHAIN;
  494. extensionsToEnable[extensionsToEnableCount++] = extensionName.cstr();
  495. }
  496. else if(extensionName == VK_EXT_DEBUG_MARKER_EXTENSION_NAME && init.m_config->getBool("gr_debugMarkers"))
  497. {
  498. m_extensions |= VulkanExtensions::EXT_DEBUG_MARKER;
  499. extensionsToEnable[extensionsToEnableCount++] = extensionName.cstr();
  500. }
  501. else if(extensionName == VK_AMD_SHADER_INFO_EXTENSION_NAME && init.m_config->getBool("core_displayStats"))
  502. {
  503. m_extensions |= VulkanExtensions::AMD_SHADER_INFO;
  504. extensionsToEnable[extensionsToEnableCount++] = extensionName.cstr();
  505. }
  506. else if(extensionName == VK_AMD_RASTERIZATION_ORDER_EXTENSION_NAME)
  507. {
  508. m_extensions |= VulkanExtensions::AMD_RASTERIZATION_ORDER;
  509. extensionsToEnable[extensionsToEnableCount++] = extensionName.cstr();
  510. }
  511. else if(extensionName == VK_KHR_RAY_TRACING_PIPELINE_EXTENSION_NAME
  512. && init.m_config->getBool("gr_rayTracing"))
  513. {
  514. m_extensions |= VulkanExtensions::KHR_RAY_TRACING;
  515. extensionsToEnable[extensionsToEnableCount++] = extensionName.cstr();
  516. m_capabilities.m_rayTracingEnabled = true;
  517. }
  518. else if(extensionName == VK_KHR_RAY_QUERY_EXTENSION_NAME && init.m_config->getBool("gr_rayTracing"))
  519. {
  520. extensionsToEnable[extensionsToEnableCount++] = extensionName.cstr();
  521. }
  522. else if(extensionName == VK_KHR_ACCELERATION_STRUCTURE_EXTENSION_NAME
  523. && init.m_config->getBool("gr_rayTracing"))
  524. {
  525. extensionsToEnable[extensionsToEnableCount++] = extensionName.cstr();
  526. }
  527. else if(extensionName == VK_KHR_DEFERRED_HOST_OPERATIONS_EXTENSION_NAME
  528. && init.m_config->getBool("gr_rayTracing"))
  529. {
  530. extensionsToEnable[extensionsToEnableCount++] = extensionName.cstr();
  531. }
  532. else if(extensionName == VK_KHR_PIPELINE_LIBRARY_EXTENSION_NAME && init.m_config->getBool("gr_rayTracing"))
  533. {
  534. extensionsToEnable[extensionsToEnableCount++] = extensionName.cstr();
  535. }
  536. else if(extensionName == VK_KHR_PIPELINE_EXECUTABLE_PROPERTIES_EXTENSION_NAME
  537. && init.m_config->getBool("core_displayStats"))
  538. {
  539. m_extensions |= VulkanExtensions::KHR_PIPELINE_EXECUTABLE_PROPERTIES;
  540. extensionsToEnable[extensionsToEnableCount++] = extensionName.cstr();
  541. }
  542. else if(extensionName == VK_KHR_SHADER_NON_SEMANTIC_INFO_EXTENSION_NAME
  543. && init.m_config->getBool("gr_debugPrintf"))
  544. {
  545. extensionsToEnable[extensionsToEnableCount++] = extensionName.cstr();
  546. }
  547. else if(extensionName == VK_EXT_DESCRIPTOR_INDEXING_EXTENSION_NAME)
  548. {
  549. m_extensions |= VulkanExtensions::EXT_DESCRIPTOR_INDEXING;
  550. extensionsToEnable[extensionsToEnableCount++] = extensionName.cstr();
  551. }
  552. else if(extensionName == VK_KHR_BUFFER_DEVICE_ADDRESS_EXTENSION_NAME)
  553. {
  554. m_extensions |= VulkanExtensions::KHR_BUFFER_DEVICE_ADDRESS;
  555. extensionsToEnable[extensionsToEnableCount++] = extensionName.cstr();
  556. }
  557. else if(extensionName == VK_EXT_SCALAR_BLOCK_LAYOUT_EXTENSION_NAME)
  558. {
  559. m_extensions |= VulkanExtensions::EXT_SCALAR_BLOCK_LAYOUT;
  560. extensionsToEnable[extensionsToEnableCount++] = extensionName.cstr();
  561. }
  562. else if(extensionName == VK_KHR_TIMELINE_SEMAPHORE_EXTENSION_NAME)
  563. {
  564. m_extensions |= VulkanExtensions::KHR_TIMELINE_SEMAPHORE;
  565. extensionsToEnable[extensionsToEnableCount++] = extensionName.cstr();
  566. }
  567. else if(extensionName == VK_KHR_SHADER_FLOAT16_INT8_EXTENSION_NAME)
  568. {
  569. m_extensions |= VulkanExtensions::KHR_SHADER_FLOAT16_INT8;
  570. extensionsToEnable[extensionsToEnableCount++] = extensionName.cstr();
  571. }
  572. else if(extensionName == VK_KHR_SHADER_ATOMIC_INT64_EXTENSION_NAME
  573. && init.m_config->getBool("gr_64bitAtomics"))
  574. {
  575. m_extensions |= VulkanExtensions::KHR_SHADER_ATOMIC_INT64;
  576. extensionsToEnable[extensionsToEnableCount++] = extensionName.cstr();
  577. }
  578. else if(extensionName == VK_KHR_SPIRV_1_4_EXTENSION_NAME)
  579. {
  580. m_extensions |= VulkanExtensions::KHR_SPIRV_1_4;
  581. extensionsToEnable[extensionsToEnableCount++] = extensionName.cstr();
  582. }
  583. else if(extensionName == VK_KHR_SHADER_FLOAT_CONTROLS_EXTENSION_NAME)
  584. {
  585. m_extensions |= VulkanExtensions::KHR_SHADER_FLOAT_CONTROLS;
  586. extensionsToEnable[extensionsToEnableCount++] = extensionName.cstr();
  587. }
  588. else if(extensionName == VK_EXT_SAMPLER_FILTER_MINMAX_EXTENSION_NAME
  589. && init.m_config->getBool("gr_samplerFilterMinMax"))
  590. {
  591. m_extensions |= VulkanExtensions::EXT_SAMPLER_FILTER_MIN_MAX;
  592. extensionsToEnable[extensionsToEnableCount++] = extensionName.cstr();
  593. }
  594. }
  595. ANKI_VK_LOGI("Will enable the following device extensions:");
  596. for(U32 i = 0; i < extensionsToEnableCount; ++i)
  597. {
  598. ANKI_VK_LOGI("\t%s", extensionsToEnable[i]);
  599. }
  600. ci.enabledExtensionCount = extensionsToEnableCount;
  601. ci.ppEnabledExtensionNames = &extensionsToEnable[0];
  602. }
  603. // Enable/disable generic features
  604. {
  605. VkPhysicalDeviceFeatures2 devFeatures = {};
  606. devFeatures.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_FEATURES_2;
  607. vkGetPhysicalDeviceFeatures2(m_physicalDevice, &devFeatures);
  608. m_devFeatures = devFeatures.features;
  609. m_devFeatures.robustBufferAccess =
  610. (init.m_config->getBool("gr_validation") && m_devFeatures.robustBufferAccess) ? true : false;
  611. ANKI_VK_LOGI("Robust buffer access is %s", (m_devFeatures.robustBufferAccess) ? "enabled" : "disabled");
  612. ci.pEnabledFeatures = &m_devFeatures;
  613. }
  614. if(!!(m_extensions & VulkanExtensions::EXT_SAMPLER_FILTER_MIN_MAX))
  615. {
  616. m_capabilities.m_samplingFilterMinMax = true;
  617. }
  618. else
  619. {
  620. m_capabilities.m_samplingFilterMinMax = false;
  621. ANKI_VK_LOGI(VK_EXT_SAMPLER_FILTER_MINMAX_EXTENSION_NAME " is not supported or disabled");
  622. }
  623. // Descriptor indexing
  624. if(!(m_extensions & VulkanExtensions::EXT_DESCRIPTOR_INDEXING))
  625. {
  626. ANKI_VK_LOGE(VK_EXT_DESCRIPTOR_INDEXING_EXTENSION_NAME " is not supported");
  627. return Error::FUNCTION_FAILED;
  628. }
  629. else
  630. {
  631. m_descriptorIndexingFeatures.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_DESCRIPTOR_INDEXING_FEATURES_EXT;
  632. VkPhysicalDeviceFeatures2 features = {};
  633. features.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_FEATURES_2;
  634. features.pNext = &m_descriptorIndexingFeatures;
  635. vkGetPhysicalDeviceFeatures2(m_physicalDevice, &features);
  636. if(!m_descriptorIndexingFeatures.shaderSampledImageArrayNonUniformIndexing
  637. || !m_descriptorIndexingFeatures.shaderStorageImageArrayNonUniformIndexing)
  638. {
  639. ANKI_VK_LOGE("Non uniform indexing is not supported by the device");
  640. return Error::FUNCTION_FAILED;
  641. }
  642. if(!m_descriptorIndexingFeatures.descriptorBindingSampledImageUpdateAfterBind
  643. || !m_descriptorIndexingFeatures.descriptorBindingStorageImageUpdateAfterBind)
  644. {
  645. ANKI_VK_LOGE("Update descriptors after bind is not supported by the device");
  646. return Error::FUNCTION_FAILED;
  647. }
  648. if(!m_descriptorIndexingFeatures.descriptorBindingUpdateUnusedWhilePending)
  649. {
  650. ANKI_VK_LOGE("Update descriptors while cmd buffer is pending is not supported by the device");
  651. return Error::FUNCTION_FAILED;
  652. }
  653. m_descriptorIndexingFeatures.pNext = const_cast<void*>(ci.pNext);
  654. ci.pNext = &m_descriptorIndexingFeatures;
  655. }
  656. // Buffer address
  657. if(!(m_extensions & VulkanExtensions::KHR_BUFFER_DEVICE_ADDRESS))
  658. {
  659. ANKI_VK_LOGW(VK_KHR_BUFFER_DEVICE_ADDRESS_EXTENSION_NAME " is not supported");
  660. }
  661. else
  662. {
  663. m_deviceBufferFeatures.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_BUFFER_DEVICE_ADDRESS_FEATURES_KHR;
  664. VkPhysicalDeviceFeatures2 features = {};
  665. features.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_FEATURES_2;
  666. features.pNext = &m_deviceBufferFeatures;
  667. vkGetPhysicalDeviceFeatures2(m_physicalDevice, &features);
  668. m_deviceBufferFeatures.bufferDeviceAddressCaptureReplay =
  669. m_deviceBufferFeatures.bufferDeviceAddressCaptureReplay && init.m_config->getBool("gr_debugMarkers");
  670. m_deviceBufferFeatures.bufferDeviceAddressMultiDevice = false;
  671. m_deviceBufferFeatures.pNext = const_cast<void*>(ci.pNext);
  672. ci.pNext = &m_deviceBufferFeatures;
  673. }
  674. // Scalar block layout
  675. if(!(m_extensions & VulkanExtensions::EXT_SCALAR_BLOCK_LAYOUT))
  676. {
  677. ANKI_VK_LOGE(VK_EXT_SCALAR_BLOCK_LAYOUT_EXTENSION_NAME " is not supported");
  678. return Error::FUNCTION_FAILED;
  679. }
  680. else
  681. {
  682. m_scalarBlockLayout.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_SCALAR_BLOCK_LAYOUT_FEATURES_EXT;
  683. VkPhysicalDeviceFeatures2 features = {};
  684. features.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_FEATURES_2;
  685. features.pNext = &m_scalarBlockLayout;
  686. vkGetPhysicalDeviceFeatures2(m_physicalDevice, &features);
  687. if(!m_scalarBlockLayout.scalarBlockLayout)
  688. {
  689. ANKI_VK_LOGE("Scalar block layout is not supported by the device");
  690. return Error::FUNCTION_FAILED;
  691. }
  692. m_scalarBlockLayout.pNext = const_cast<void*>(ci.pNext);
  693. ci.pNext = &m_scalarBlockLayout;
  694. }
  695. // Timeline semaphore
  696. if(!(m_extensions & VulkanExtensions::KHR_TIMELINE_SEMAPHORE))
  697. {
  698. ANKI_VK_LOGE(VK_KHR_TIMELINE_SEMAPHORE_EXTENSION_NAME " is not supported");
  699. return Error::FUNCTION_FAILED;
  700. }
  701. else
  702. {
  703. m_timelineSemaphoreFeatures.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_TIMELINE_SEMAPHORE_FEATURES_KHR;
  704. VkPhysicalDeviceFeatures2 features = {};
  705. features.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_FEATURES_2;
  706. features.pNext = &m_timelineSemaphoreFeatures;
  707. vkGetPhysicalDeviceFeatures2(m_physicalDevice, &features);
  708. if(!m_timelineSemaphoreFeatures.timelineSemaphore)
  709. {
  710. ANKI_VK_LOGE("Timeline semaphores are not supported by the device");
  711. return Error::FUNCTION_FAILED;
  712. }
  713. m_timelineSemaphoreFeatures.pNext = const_cast<void*>(ci.pNext);
  714. ci.pNext = &m_timelineSemaphoreFeatures;
  715. }
  716. // Set RT features
  717. if(!!(m_extensions & VulkanExtensions::KHR_RAY_TRACING))
  718. {
  719. m_rtPipelineFeatures.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_RAY_TRACING_PIPELINE_FEATURES_KHR;
  720. m_rayQueryFeatures.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_RAY_QUERY_FEATURES_KHR;
  721. m_accelerationStructureFeatures.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_ACCELERATION_STRUCTURE_FEATURES_KHR;
  722. VkPhysicalDeviceFeatures2 features = {};
  723. features.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_FEATURES_2;
  724. features.pNext = &m_rtPipelineFeatures;
  725. m_rtPipelineFeatures.pNext = &m_rayQueryFeatures;
  726. m_rayQueryFeatures.pNext = &m_accelerationStructureFeatures;
  727. vkGetPhysicalDeviceFeatures2(m_physicalDevice, &features);
  728. if(!m_rtPipelineFeatures.rayTracingPipeline || !m_rayQueryFeatures.rayQuery
  729. || !m_accelerationStructureFeatures.accelerationStructure)
  730. {
  731. ANKI_VK_LOGE("Ray tracing and ray query are both required");
  732. return Error::FUNCTION_FAILED;
  733. }
  734. // Only enable what's necessary
  735. m_rtPipelineFeatures.rayTracingPipelineShaderGroupHandleCaptureReplay = false;
  736. m_rtPipelineFeatures.rayTracingPipelineShaderGroupHandleCaptureReplayMixed = false;
  737. m_rtPipelineFeatures.rayTraversalPrimitiveCulling = false;
  738. m_accelerationStructureFeatures.accelerationStructureCaptureReplay = false;
  739. m_accelerationStructureFeatures.accelerationStructureHostCommands = false;
  740. m_accelerationStructureFeatures.descriptorBindingAccelerationStructureUpdateAfterBind = false;
  741. ANKI_ASSERT(m_accelerationStructureFeatures.pNext == nullptr);
  742. m_accelerationStructureFeatures.pNext = const_cast<void*>(ci.pNext);
  743. ci.pNext = &m_rtPipelineFeatures;
  744. }
  745. // Pipeline features
  746. if(!!(m_extensions & VulkanExtensions::KHR_PIPELINE_EXECUTABLE_PROPERTIES))
  747. {
  748. m_pplineExecutablePropertiesFeatures.sType =
  749. VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_PIPELINE_EXECUTABLE_PROPERTIES_FEATURES_KHR;
  750. m_pplineExecutablePropertiesFeatures.pipelineExecutableInfo = true;
  751. m_pplineExecutablePropertiesFeatures.pNext = const_cast<void*>(ci.pNext);
  752. ci.pNext = &m_pplineExecutablePropertiesFeatures;
  753. }
  754. // F16 I8
  755. if(!(m_extensions & VulkanExtensions::KHR_SHADER_FLOAT16_INT8))
  756. {
  757. ANKI_VK_LOGE(VK_KHR_SHADER_FLOAT16_INT8_EXTENSION_NAME " is not supported");
  758. return Error::FUNCTION_FAILED;
  759. }
  760. else
  761. {
  762. m_float16Int8Features.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_FLOAT16_INT8_FEATURES_KHR;
  763. VkPhysicalDeviceFeatures2 features = {};
  764. features.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_FEATURES_2;
  765. features.pNext = &m_float16Int8Features;
  766. vkGetPhysicalDeviceFeatures2(m_physicalDevice, &features);
  767. m_float16Int8Features.pNext = const_cast<void*>(ci.pNext);
  768. ci.pNext = &m_float16Int8Features;
  769. }
  770. // 64bit atomics
  771. if(!(m_extensions & VulkanExtensions::KHR_SHADER_ATOMIC_INT64))
  772. {
  773. ANKI_VK_LOGW(VK_KHR_SHADER_ATOMIC_INT64_EXTENSION_NAME " is not supported or disabled");
  774. m_capabilities.m_64bitAtomics = false;
  775. }
  776. else
  777. {
  778. m_capabilities.m_64bitAtomics = true;
  779. m_atomicInt64Features.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_SHADER_ATOMIC_INT64_FEATURES_KHR;
  780. VkPhysicalDeviceFeatures2 features = {};
  781. features.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_FEATURES_2;
  782. features.pNext = &m_atomicInt64Features;
  783. vkGetPhysicalDeviceFeatures2(m_physicalDevice, &features);
  784. m_atomicInt64Features.pNext = const_cast<void*>(ci.pNext);
  785. ci.pNext = &m_atomicInt64Features;
  786. }
  787. ANKI_VK_CHECK(vkCreateDevice(m_physicalDevice, &ci, nullptr, &m_device));
  788. // Get debug marker
  789. if(!!(m_extensions & VulkanExtensions::EXT_DEBUG_MARKER))
  790. {
  791. m_pfnDebugMarkerSetObjectNameEXT = reinterpret_cast<PFN_vkDebugMarkerSetObjectNameEXT>(
  792. vkGetDeviceProcAddr(m_device, "vkDebugMarkerSetObjectNameEXT"));
  793. if(!m_pfnDebugMarkerSetObjectNameEXT)
  794. {
  795. ANKI_VK_LOGW("VK_EXT_debug_marker is present but vkDebugMarkerSetObjectNameEXT is not there");
  796. }
  797. m_pfnCmdDebugMarkerBeginEXT =
  798. reinterpret_cast<PFN_vkCmdDebugMarkerBeginEXT>(vkGetDeviceProcAddr(m_device, "vkCmdDebugMarkerBeginEXT"));
  799. if(!m_pfnCmdDebugMarkerBeginEXT)
  800. {
  801. ANKI_VK_LOGW("VK_EXT_debug_marker is present but vkCmdDebugMarkerBeginEXT is not there");
  802. }
  803. m_pfnCmdDebugMarkerEndEXT =
  804. reinterpret_cast<PFN_vkCmdDebugMarkerEndEXT>(vkGetDeviceProcAddr(m_device, "vkCmdDebugMarkerEndEXT"));
  805. if(!m_pfnCmdDebugMarkerEndEXT)
  806. {
  807. ANKI_VK_LOGW("VK_EXT_debug_marker is present but vkCmdDebugMarkerEndEXT is not there");
  808. }
  809. }
  810. // Get VK_AMD_shader_info entry points
  811. if(!!(m_extensions & VulkanExtensions::AMD_SHADER_INFO))
  812. {
  813. m_pfnGetShaderInfoAMD =
  814. reinterpret_cast<PFN_vkGetShaderInfoAMD>(vkGetDeviceProcAddr(m_device, "vkGetShaderInfoAMD"));
  815. if(!m_pfnGetShaderInfoAMD)
  816. {
  817. ANKI_VK_LOGW("VK_AMD_shader_info is present but vkGetShaderInfoAMD is not there");
  818. }
  819. }
  820. if(!(m_extensions & VulkanExtensions::KHR_SPIRV_1_4))
  821. {
  822. ANKI_VK_LOGE(VK_KHR_SPIRV_1_4_EXTENSION_NAME " is not supported");
  823. return Error::FUNCTION_FAILED;
  824. }
  825. if(!(m_extensions & VulkanExtensions::KHR_SHADER_FLOAT_CONTROLS))
  826. {
  827. ANKI_VK_LOGE(VK_KHR_SHADER_FLOAT_CONTROLS_EXTENSION_NAME " is not supported");
  828. return Error::FUNCTION_FAILED;
  829. }
  830. return Error::NONE;
  831. }
  832. Error GrManagerImpl::initMemory(const ConfigSet& cfg)
  833. {
  834. vkGetPhysicalDeviceMemoryProperties(m_physicalDevice, &m_memoryProperties);
  835. // Print some info
  836. ANKI_VK_LOGI("Vulkan memory info:");
  837. for(U32 i = 0; i < m_memoryProperties.memoryHeapCount; ++i)
  838. {
  839. ANKI_VK_LOGI("\tHeap %u size %zu", i, m_memoryProperties.memoryHeaps[i].size);
  840. }
  841. for(U32 i = 0; i < m_memoryProperties.memoryTypeCount; ++i)
  842. {
  843. ANKI_VK_LOGI("\tMem type %u points to heap %u, flags %" ANKI_PRIb32, i,
  844. m_memoryProperties.memoryTypes[i].heapIndex,
  845. ANKI_FORMAT_U32(m_memoryProperties.memoryTypes[i].propertyFlags));
  846. }
  847. m_gpuMemManager.init(m_physicalDevice, m_device, getAllocator(),
  848. !!(m_extensions & VulkanExtensions::KHR_BUFFER_DEVICE_ADDRESS));
  849. return Error::NONE;
  850. }
  851. #if ANKI_GR_MANAGER_DEBUG_MEMMORY
  852. void* GrManagerImpl::allocateCallback(void* userData, size_t size, size_t alignment,
  853. VkSystemAllocationScope allocationScope)
  854. {
  855. if(ANKI_UNLIKELY(size == 0))
  856. {
  857. return nullptr;
  858. }
  859. ANKI_ASSERT(userData);
  860. ANKI_ASSERT(size);
  861. ANKI_ASSERT(isPowerOfTwo(alignment));
  862. ANKI_ASSERT(alignment <= MAX_ALLOC_ALIGNMENT);
  863. auto alloc = static_cast<GrManagerImpl*>(userData)->getAllocator();
  864. PtrSize newSize = size + sizeof(AllocHeader);
  865. AllocHeader* header = static_cast<AllocHeader*>(alloc.getMemoryPool().allocate(newSize, MAX_ALLOC_ALIGNMENT));
  866. header->m_sig = ALLOC_SIG;
  867. header->m_size = size;
  868. ++header;
  869. return static_cast<AllocHeader*>(header);
  870. }
  871. void* GrManagerImpl::reallocateCallback(void* userData, void* original, size_t size, size_t alignment,
  872. VkSystemAllocationScope allocationScope)
  873. {
  874. if(original && size == 0)
  875. {
  876. freeCallback(userData, original);
  877. return nullptr;
  878. }
  879. void* mem = allocateCallback(userData, size, alignment, allocationScope);
  880. if(original)
  881. {
  882. // Move the data
  883. AllocHeader* header = static_cast<AllocHeader*>(original);
  884. --header;
  885. ANKI_ASSERT(header->m_sig == ALLOC_SIG);
  886. memcpy(mem, original, header->m_size);
  887. }
  888. return mem;
  889. }
  890. void GrManagerImpl::freeCallback(void* userData, void* ptr)
  891. {
  892. if(ptr)
  893. {
  894. ANKI_ASSERT(userData);
  895. auto alloc = static_cast<GrManagerImpl*>(userData)->getAllocator();
  896. AllocHeader* header = static_cast<AllocHeader*>(ptr);
  897. --header;
  898. ANKI_ASSERT(header->m_sig == ALLOC_SIG);
  899. alloc.getMemoryPool().free(header);
  900. }
  901. }
  902. #endif
  903. TexturePtr GrManagerImpl::acquireNextPresentableTexture()
  904. {
  905. ANKI_TRACE_SCOPED_EVENT(VK_ACQUIRE_IMAGE);
  906. LockGuard<Mutex> lock(m_globalMtx);
  907. PerFrame& frame = m_perFrame[m_frame % MAX_FRAMES_IN_FLIGHT];
  908. // Create sync objects
  909. MicroFencePtr fence = m_fenceFactory.newInstance();
  910. frame.m_acquireSemaphore = m_semaphoreFactory.newInstance(fence, false);
  911. // Get new image
  912. uint32_t imageIdx;
  913. VkResult res = vkAcquireNextImageKHR(m_device, m_crntSwapchain->m_swapchain, UINT64_MAX,
  914. frame.m_acquireSemaphore->getHandle(), fence->getHandle(), &imageIdx);
  915. if(res == VK_ERROR_OUT_OF_DATE_KHR)
  916. {
  917. ANKI_VK_LOGW("Swapchain is out of date. Will wait for the queue and create a new one");
  918. for(VkQueue queue : m_queues)
  919. {
  920. if(queue)
  921. {
  922. vkQueueWaitIdle(queue);
  923. }
  924. }
  925. m_crntSwapchain.reset(nullptr);
  926. m_crntSwapchain = m_swapchainFactory.newInstance();
  927. // Can't fail a second time
  928. ANKI_VK_CHECKF(vkAcquireNextImageKHR(m_device, m_crntSwapchain->m_swapchain, UINT64_MAX,
  929. frame.m_acquireSemaphore->getHandle(), fence->getHandle(), &imageIdx));
  930. }
  931. else
  932. {
  933. ANKI_VK_CHECKF(res);
  934. }
  935. m_acquiredImageIdx = U8(imageIdx);
  936. return m_crntSwapchain->m_textures[imageIdx];
  937. }
  938. void GrManagerImpl::endFrame()
  939. {
  940. ANKI_TRACE_SCOPED_EVENT(VK_PRESENT);
  941. LockGuard<Mutex> lock(m_globalMtx);
  942. PerFrame& frame = m_perFrame[m_frame % MAX_FRAMES_IN_FLIGHT];
  943. // Wait for the fence of N-2 frame
  944. const U waitFrameIdx = (m_frame + 1) % MAX_FRAMES_IN_FLIGHT;
  945. PerFrame& waitFrame = m_perFrame[waitFrameIdx];
  946. if(waitFrame.m_presentFence)
  947. {
  948. waitFrame.m_presentFence->wait();
  949. }
  950. resetFrame(waitFrame);
  951. if(!frame.m_renderSemaphore)
  952. {
  953. ANKI_VK_LOGW("Nobody draw to the default framebuffer");
  954. }
  955. // Present
  956. VkResult res;
  957. VkPresentInfoKHR present = {};
  958. present.sType = VK_STRUCTURE_TYPE_PRESENT_INFO_KHR;
  959. present.waitSemaphoreCount = (frame.m_renderSemaphore) ? 1 : 0;
  960. present.pWaitSemaphores = (frame.m_renderSemaphore) ? &frame.m_renderSemaphore->getHandle() : nullptr;
  961. present.swapchainCount = 1;
  962. present.pSwapchains = &m_crntSwapchain->m_swapchain;
  963. const U32 idx = m_acquiredImageIdx;
  964. present.pImageIndices = &idx;
  965. present.pResults = &res;
  966. const VkResult res1 = vkQueuePresentKHR(m_queues[frame.m_queueWroteToSwapchainImage], &present);
  967. if(res1 == VK_ERROR_OUT_OF_DATE_KHR)
  968. {
  969. ANKI_VK_LOGW("Swapchain is out of date. Will wait for the queues and create a new one");
  970. for(VkQueue queue : m_queues)
  971. {
  972. if(queue)
  973. {
  974. vkQueueWaitIdle(queue);
  975. }
  976. }
  977. vkDeviceWaitIdle(m_device);
  978. m_crntSwapchain.reset(nullptr);
  979. m_crntSwapchain = m_swapchainFactory.newInstance();
  980. }
  981. else
  982. {
  983. ANKI_VK_CHECKF(res1);
  984. ANKI_VK_CHECKF(res);
  985. }
  986. m_descrFactory.endFrame();
  987. // Finalize
  988. ++m_frame;
  989. }
  990. void GrManagerImpl::resetFrame(PerFrame& frame)
  991. {
  992. frame.m_presentFence.reset(nullptr);
  993. frame.m_acquireSemaphore.reset(nullptr);
  994. frame.m_renderSemaphore.reset(nullptr);
  995. }
  996. void GrManagerImpl::flushCommandBuffer(MicroCommandBufferPtr cmdb, Bool cmdbRenderedToSwapchain,
  997. WeakArray<MicroSemaphorePtr> userWaitSemaphores,
  998. MicroSemaphorePtr* userSignalSemaphore, Bool wait)
  999. {
  1000. constexpr U32 maxSemaphores = 8;
  1001. VkSubmitInfo submit = {};
  1002. submit.sType = VK_STRUCTURE_TYPE_SUBMIT_INFO;
  1003. Array<VkSemaphore, maxSemaphores> waitSemaphores;
  1004. submit.pWaitSemaphores = &waitSemaphores[0];
  1005. Array<VkSemaphore, maxSemaphores> signalSemaphores;
  1006. submit.pSignalSemaphores = &signalSemaphores[0];
  1007. Array<VkPipelineStageFlags, maxSemaphores> waitStages;
  1008. submit.pWaitDstStageMask = &waitStages[0];
  1009. // First thing, create a fence
  1010. MicroFencePtr fence = m_fenceFactory.newInstance();
  1011. // Command buffer
  1012. const VkCommandBuffer handle = cmdb->getHandle();
  1013. cmdb->setFence(fence);
  1014. submit.commandBufferCount = 1;
  1015. submit.pCommandBuffers = &handle;
  1016. // Handle user semaphores
  1017. Array<U64, maxSemaphores> waitTimelineValues;
  1018. Array<U64, maxSemaphores> signalTimelineValues;
  1019. VkTimelineSemaphoreSubmitInfo timelineInfo = {};
  1020. timelineInfo.sType = VK_STRUCTURE_TYPE_TIMELINE_SEMAPHORE_SUBMIT_INFO;
  1021. timelineInfo.waitSemaphoreValueCount = userWaitSemaphores.getSize();
  1022. timelineInfo.pWaitSemaphoreValues = &waitTimelineValues[0];
  1023. timelineInfo.signalSemaphoreValueCount = (userSignalSemaphore != nullptr);
  1024. timelineInfo.pSignalSemaphoreValues = &signalTimelineValues[0];
  1025. submit.pNext = &timelineInfo;
  1026. for(MicroSemaphorePtr& userWaitSemaphore : userWaitSemaphores)
  1027. {
  1028. ANKI_ASSERT(userWaitSemaphore.isCreated());
  1029. ANKI_ASSERT(userWaitSemaphore->isTimeline());
  1030. waitSemaphores[submit.waitSemaphoreCount] = userWaitSemaphore->getHandle();
  1031. waitTimelineValues[submit.waitSemaphoreCount] = userWaitSemaphore->getSemaphoreValue();
  1032. // Be a bit conservative
  1033. waitStages[submit.waitSemaphoreCount] = VK_PIPELINE_STAGE_ALL_COMMANDS_BIT;
  1034. ++submit.waitSemaphoreCount;
  1035. // Refresh the fence because the semaphore can't be recycled until the current submission is done
  1036. userWaitSemaphore->setFence(fence);
  1037. }
  1038. if(userSignalSemaphore)
  1039. {
  1040. *userSignalSemaphore = m_semaphoreFactory.newInstance(fence, true);
  1041. signalSemaphores[submit.signalSemaphoreCount] = (*userSignalSemaphore)->getHandle();
  1042. signalTimelineValues[submit.signalSemaphoreCount] = (*userSignalSemaphore)->getNextSemaphoreValue();
  1043. ++submit.signalSemaphoreCount;
  1044. }
  1045. // Protect the class, the queue and other stuff
  1046. LockGuard<Mutex> lock(m_globalMtx);
  1047. // Do some special stuff for the last command buffer
  1048. PerFrame& frame = m_perFrame[m_frame % MAX_FRAMES_IN_FLIGHT];
  1049. if(cmdbRenderedToSwapchain)
  1050. {
  1051. // Wait semaphore
  1052. waitSemaphores[submit.waitSemaphoreCount] = frame.m_acquireSemaphore->getHandle();
  1053. // That depends on how we use the swapchain img. Be a bit conservative
  1054. waitStages[submit.waitSemaphoreCount] =
  1055. VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT | VK_PIPELINE_STAGE_COMPUTE_SHADER_BIT;
  1056. ++submit.waitSemaphoreCount;
  1057. // Refresh the fence because the semaphore can't be recycled until the current submission is done
  1058. frame.m_acquireSemaphore->setFence(fence);
  1059. // Create the semaphore to signal
  1060. ANKI_ASSERT(!frame.m_renderSemaphore && "Only one begin/end render pass is allowed with the default fb");
  1061. frame.m_renderSemaphore = m_semaphoreFactory.newInstance(fence, false);
  1062. signalSemaphores[submit.signalSemaphoreCount++] = frame.m_renderSemaphore->getHandle();
  1063. // Update the frame fence
  1064. frame.m_presentFence = fence;
  1065. // Update the swapchain's fence
  1066. m_crntSwapchain->setFence(fence);
  1067. frame.m_queueWroteToSwapchainImage = cmdb->getVulkanQueueType();
  1068. }
  1069. // Submit
  1070. {
  1071. ANKI_TRACE_SCOPED_EVENT(VK_QUEUE_SUBMIT);
  1072. ANKI_VK_CHECKF(vkQueueSubmit(m_queues[cmdb->getVulkanQueueType()], 1, &submit, fence->getHandle()));
  1073. }
  1074. if(wait)
  1075. {
  1076. vkQueueWaitIdle(m_queues[cmdb->getVulkanQueueType()]);
  1077. }
  1078. }
  1079. void GrManagerImpl::finish()
  1080. {
  1081. LockGuard<Mutex> lock(m_globalMtx);
  1082. for(VkQueue queue : m_queues)
  1083. {
  1084. if(queue)
  1085. {
  1086. vkQueueWaitIdle(queue);
  1087. }
  1088. }
  1089. }
  1090. void GrManagerImpl::trySetVulkanHandleName(CString name, VkDebugReportObjectTypeEXT type, U64 handle) const
  1091. {
  1092. if(name && name.getLength())
  1093. {
  1094. if(m_pfnDebugMarkerSetObjectNameEXT)
  1095. {
  1096. VkDebugMarkerObjectNameInfoEXT inf = {};
  1097. inf.sType = VK_STRUCTURE_TYPE_DEBUG_MARKER_OBJECT_NAME_INFO_EXT;
  1098. inf.objectType = type;
  1099. inf.pObjectName = name.cstr();
  1100. inf.object = handle;
  1101. m_pfnDebugMarkerSetObjectNameEXT(m_device, &inf);
  1102. }
  1103. LockGuard<SpinLock> lock(m_vkHandleToNameLock);
  1104. StringAuto newName(getAllocator());
  1105. newName.create(name);
  1106. m_vkHandleToName.emplace(getAllocator(), computeHash(&handle, sizeof(handle)), std::move(newName));
  1107. }
  1108. }
  1109. StringAuto GrManagerImpl::tryGetVulkanHandleName(U64 handle) const
  1110. {
  1111. StringAuto out(getAllocator());
  1112. LockGuard<SpinLock> lock(m_vkHandleToNameLock);
  1113. auto it = m_vkHandleToName.find(computeHash(&handle, sizeof(handle)));
  1114. CString objName;
  1115. if(it != m_vkHandleToName.getEnd())
  1116. {
  1117. objName = it->toCString();
  1118. }
  1119. else
  1120. {
  1121. objName = "Unnamed";
  1122. }
  1123. out.create(objName);
  1124. return out;
  1125. }
  1126. VkBool32 GrManagerImpl::debugReportCallbackEXT(VkDebugReportFlagsEXT flags, VkDebugReportObjectTypeEXT objectType,
  1127. uint64_t object, size_t location, int32_t messageCode,
  1128. const char* pLayerPrefix, const char* pMessage, void* pUserData)
  1129. {
  1130. // Get the object name
  1131. GrManagerImpl* self = static_cast<GrManagerImpl*>(pUserData);
  1132. StringAuto name = self->tryGetVulkanHandleName(object);
  1133. if(flags & VK_DEBUG_REPORT_ERROR_BIT_EXT)
  1134. {
  1135. ANKI_VK_LOGE("%s (handle: %s)", pMessage, name.cstr());
  1136. }
  1137. else if(flags & (VK_DEBUG_REPORT_WARNING_BIT_EXT | VK_DEBUG_REPORT_PERFORMANCE_WARNING_BIT_EXT))
  1138. {
  1139. ANKI_VK_LOGW("%s (handle: %s)", pMessage, name.cstr());
  1140. }
  1141. else
  1142. {
  1143. ANKI_VK_LOGI("%s (handle: %s)", pMessage, name.cstr());
  1144. }
  1145. return false;
  1146. }
  1147. void GrManagerImpl::printPipelineShaderInfo(VkPipeline ppline, CString name, ShaderTypeBit stages, U64 hash) const
  1148. {
  1149. if(printPipelineShaderInfoInternal(ppline, name, stages, hash))
  1150. {
  1151. ANKI_VK_LOGE("Ignoring previous errors");
  1152. }
  1153. }
  1154. Error GrManagerImpl::printPipelineShaderInfoInternal(VkPipeline ppline, CString name, ShaderTypeBit stages,
  1155. U64 hash) const
  1156. {
  1157. if(m_pfnGetShaderInfoAMD)
  1158. {
  1159. VkShaderStatisticsInfoAMD stats = {};
  1160. LockGuard<SpinLock> lock(m_shaderStatsFileMtx);
  1161. // Open the file
  1162. if(!m_shaderStatsFile.isOpen())
  1163. {
  1164. ANKI_CHECK(m_shaderStatsFile.open(
  1165. StringAuto(getAllocator()).sprintf("%s/../ppline_stats.csv", m_cacheDir.cstr()).toCString(),
  1166. FileOpenFlag::WRITE));
  1167. ANKI_CHECK(m_shaderStatsFile.writeText("ppline name,hash,"
  1168. "stage 0 VGPR,stage 0 SGPR,"
  1169. "stage 1 VGPR,stage 1 SGPR,"
  1170. "stage 2 VGPR,stage 2 SGPR,"
  1171. "stage 3 VGPR,stage 3 SGPR,"
  1172. "stage 4 VGPR,stage 4 SGPR,"
  1173. "stage 5 VGPR,stage 5 SGPR\n"));
  1174. }
  1175. ANKI_CHECK(m_shaderStatsFile.writeText("%s,0x%" PRIx64 ",", name.cstr(), hash));
  1176. StringAuto str(getAllocator());
  1177. for(ShaderType type = ShaderType::FIRST; type < ShaderType::COUNT; ++type)
  1178. {
  1179. ShaderTypeBit stage = stages & ShaderTypeBit(1 << type);
  1180. if(!stage)
  1181. {
  1182. ANKI_CHECK(m_shaderStatsFile.writeText((type != ShaderType::LAST) ? "0,0," : "0,0\n"));
  1183. continue;
  1184. }
  1185. size_t size = sizeof(stats);
  1186. ANKI_VK_CHECK(m_pfnGetShaderInfoAMD(m_device, ppline, VkShaderStageFlagBits(convertShaderTypeBit(stage)),
  1187. VK_SHADER_INFO_TYPE_STATISTICS_AMD, &size, &stats));
  1188. str.append(StringAuto(getAllocator())
  1189. .sprintf("Stage %u: VGRPS %02u, SGRPS %02u ", U32(type), stats.resourceUsage.numUsedVgprs,
  1190. stats.resourceUsage.numUsedSgprs));
  1191. ANKI_CHECK(m_shaderStatsFile.writeText((type != ShaderType::LAST) ? "%u,%u," : "%u,%u\n",
  1192. stats.resourceUsage.numUsedVgprs, stats.resourceUsage.numUsedSgprs));
  1193. }
  1194. ANKI_VK_LOGI("Pipeline \"%s\" (0x%016" PRIx64 ") stats: %s", name.cstr(), hash, str.cstr());
  1195. // Flush the file just in case
  1196. ANKI_CHECK(m_shaderStatsFile.flush());
  1197. }
  1198. if(!!(m_extensions & VulkanExtensions::KHR_PIPELINE_EXECUTABLE_PROPERTIES))
  1199. {
  1200. StringListAuto log(m_alloc);
  1201. VkPipelineInfoKHR pplineInf = {};
  1202. pplineInf.sType = VK_STRUCTURE_TYPE_PIPELINE_INFO_KHR;
  1203. pplineInf.pipeline = ppline;
  1204. U32 executableCount = 0;
  1205. ANKI_VK_CHECK(vkGetPipelineExecutablePropertiesKHR(m_device, &pplineInf, &executableCount, nullptr));
  1206. DynamicArrayAuto<VkPipelineExecutablePropertiesKHR> executableProps(m_alloc, executableCount);
  1207. ANKI_VK_CHECK(
  1208. vkGetPipelineExecutablePropertiesKHR(m_device, &pplineInf, &executableCount, &executableProps[0]));
  1209. log.pushBackSprintf("Pipeline info \"%s\" (0x%016" PRIx64 "): ", name.cstr(), hash);
  1210. for(U32 i = 0; i < executableCount; ++i)
  1211. {
  1212. const VkPipelineExecutablePropertiesKHR& p = executableProps[i];
  1213. log.pushBackSprintf("%s: ", p.description);
  1214. // Get stats
  1215. VkPipelineExecutableInfoKHR exeInf = {};
  1216. exeInf.sType = VK_STRUCTURE_TYPE_PIPELINE_EXECUTABLE_INFO_KHR;
  1217. exeInf.executableIndex = i;
  1218. exeInf.pipeline = ppline;
  1219. U32 statCount = 0;
  1220. vkGetPipelineExecutableStatisticsKHR(m_device, &exeInf, &statCount, nullptr);
  1221. DynamicArrayAuto<VkPipelineExecutableStatisticKHR> stats(m_alloc, statCount);
  1222. vkGetPipelineExecutableStatisticsKHR(m_device, &exeInf, &statCount, &stats[0]);
  1223. for(U32 s = 0; s < statCount; ++s)
  1224. {
  1225. const VkPipelineExecutableStatisticKHR& ss = stats[s];
  1226. switch(ss.format)
  1227. {
  1228. case VK_PIPELINE_EXECUTABLE_STATISTIC_FORMAT_BOOL32_KHR:
  1229. log.pushBackSprintf("%s: %u, ", ss.name, ss.value.b32);
  1230. break;
  1231. case VK_PIPELINE_EXECUTABLE_STATISTIC_FORMAT_INT64_KHR:
  1232. log.pushBackSprintf("%s: %" PRId64 ", ", ss.name, ss.value.i64);
  1233. break;
  1234. case VK_PIPELINE_EXECUTABLE_STATISTIC_FORMAT_UINT64_KHR:
  1235. log.pushBackSprintf("%s: %" PRIu64 ", ", ss.name, ss.value.u64);
  1236. break;
  1237. case VK_PIPELINE_EXECUTABLE_STATISTIC_FORMAT_FLOAT64_KHR:
  1238. log.pushBackSprintf("%s: %f, ", ss.name, ss.value.f64);
  1239. break;
  1240. default:
  1241. ANKI_ASSERT(0);
  1242. }
  1243. }
  1244. log.pushBackSprintf("Subgroup size: %u", p.subgroupSize);
  1245. if(i < executableCount - 1)
  1246. {
  1247. log.pushBack(", ");
  1248. }
  1249. }
  1250. StringAuto finalLog(m_alloc);
  1251. log.join("", finalLog);
  1252. ANKI_VK_LOGI("%s", finalLog.cstr());
  1253. }
  1254. return Error::NONE;
  1255. }
  1256. } // end namespace anki