GrManagerImpl.cpp 47 KB

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