VulkanBase.cpp 9.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309
  1. #include "core/VulkanBase.hpp"
  2. #include <cstring>
  3. #include "GLFW.hpp"
  4. import Core.List;
  5. import Core.Logger;
  6. import Core.Types;
  7. import Core.Array;
  8. using Core::Vulkan::Base;
  9. #define GET_FUNCTION(name) (reinterpret_cast<PFN_##name>(getFunction(#name)))
  10. Base::Base() :
  11. instance(VK_NULL_HANDLE),
  12. #ifdef DEBUG_VULKAN
  13. debugMessenger(VK_NULL_HANDLE), debugReportCallback(VK_NULL_HANDLE),
  14. #endif
  15. surface(VK_NULL_HANDLE), physicalDevice(VK_NULL_HANDLE),
  16. device(VK_NULL_HANDLE) {
  17. }
  18. Base::~Base() {
  19. destroy();
  20. }
  21. bool Base::initInstance() {
  22. u32 baseCount = 0;
  23. const char** baseExtensions = glfwGetRequiredInstanceExtensions(&baseCount);
  24. if(baseExtensions == nullptr) {
  25. VK_REPORT_ERROR("Could not get required extensions from GLFW");
  26. return true;
  27. }
  28. Core::List<const char*> extensions;
  29. for(u32 i = 0; i < baseCount; i++) {
  30. extensions.add(baseExtensions[i]);
  31. }
  32. Core::List<const char*> layers;
  33. #ifdef DEBUG_VULKAN
  34. extensions.add(VK_EXT_DEBUG_UTILS_EXTENSION_NAME);
  35. extensions.add(VK_EXT_DEBUG_REPORT_EXTENSION_NAME);
  36. layers.add("VK_LAYER_KHRONOS_validation");
  37. #endif
  38. VkApplicationInfo appInfo = {
  39. .sType = VK_STRUCTURE_TYPE_APPLICATION_INFO,
  40. .pApplicationName = "Vulkan",
  41. .applicationVersion = VK_MAKE_VERSION(1, 0, 0),
  42. .pEngineName = "Kajetan",
  43. .engineVersion = VK_MAKE_VERSION(0, 0, 1),
  44. .apiVersion = VK_API_VERSION_1_1};
  45. VkInstanceCreateInfo info = {
  46. .sType = VK_STRUCTURE_TYPE_INSTANCE_CREATE_INFO,
  47. .pApplicationInfo = &appInfo,
  48. .enabledLayerCount = static_cast<u32>(layers.getLength()),
  49. .ppEnabledLayerNames = &layers[0],
  50. .enabledExtensionCount = static_cast<u32>(extensions.getLength()),
  51. .ppEnabledExtensionNames = &extensions[0]};
  52. VK_CHECK_TRUE(vkCreateInstance(&info, nullptr, &instance));
  53. return false;
  54. }
  55. #ifdef DEBUG_VULKAN
  56. static VKAPI_ATTR VkBool32 onVulkanDebugMessenger VKAPI_CALL(
  57. VkDebugUtilsMessageSeverityFlagBitsEXT, VkDebugUtilsMessageTypeFlagsEXT,
  58. const VkDebugUtilsMessengerCallbackDataEXT* data, void*) {
  59. VK_REPORT_WARNING("Vulkan validation layer message: {}", data->pMessage);
  60. return false;
  61. }
  62. bool Base::initDebugMessenger() {
  63. VkDebugUtilsMessengerCreateInfoEXT info = {
  64. .sType = VK_STRUCTURE_TYPE_DEBUG_UTILS_MESSENGER_CREATE_INFO_EXT,
  65. .messageSeverity = VK_DEBUG_UTILS_MESSAGE_SEVERITY_WARNING_BIT_EXT |
  66. VK_DEBUG_UTILS_MESSAGE_SEVERITY_ERROR_BIT_EXT,
  67. .messageType = VK_DEBUG_UTILS_MESSAGE_TYPE_GENERAL_BIT_EXT |
  68. VK_DEBUG_UTILS_MESSAGE_TYPE_VALIDATION_BIT_EXT |
  69. VK_DEBUG_UTILS_MESSAGE_TYPE_PERFORMANCE_BIT_EXT,
  70. .pfnUserCallback = onVulkanDebugMessenger};
  71. auto f = GET_FUNCTION(vkCreateDebugUtilsMessengerEXT);
  72. if(f == nullptr) {
  73. VK_REPORT_WARNING("Could not find debug util messenger function");
  74. return false;
  75. }
  76. VK_CHECK_TRUE(f(instance, &info, nullptr, &debugMessenger));
  77. return false;
  78. }
  79. static VKAPI_ATTR VkBool32 onVulkanDebugReport VKAPI_CALL(
  80. VkDebugReportFlagsEXT, VkDebugReportObjectTypeEXT, uint64_t, size_t,
  81. int32_t, const char* pLayerPrefix, const char* pMessage, void*) {
  82. VK_REPORT_WARNING("Vulkan debug message '{}': {}", pLayerPrefix, pMessage);
  83. return false;
  84. }
  85. bool Base::initDebugReportCallback() {
  86. VkDebugReportCallbackCreateInfoEXT info = {
  87. .sType = VK_STRUCTURE_TYPE_DEBUG_REPORT_CREATE_INFO_EXT,
  88. .flags = VK_DEBUG_REPORT_WARNING_BIT_EXT |
  89. VK_DEBUG_REPORT_PERFORMANCE_WARNING_BIT_EXT |
  90. VK_DEBUG_REPORT_ERROR_BIT_EXT,
  91. .pfnCallback = onVulkanDebugReport};
  92. auto f = GET_FUNCTION(vkCreateDebugReportCallbackEXT);
  93. if(f == nullptr) {
  94. VK_REPORT_WARNING("Could not find debug report function");
  95. return false;
  96. }
  97. VK_CHECK_TRUE(f(instance, &info, nullptr, &debugReportCallback));
  98. return false;
  99. }
  100. void Base::destroyDebugMessenger() {
  101. if(debugMessenger == VK_NULL_HANDLE) {
  102. return;
  103. }
  104. auto f = GET_FUNCTION(vkDestroyDebugUtilsMessengerEXT);
  105. if(f == nullptr) {
  106. VK_REPORT_WARNING(
  107. "Could not find debug util messenger destroy function");
  108. return;
  109. }
  110. f(instance, debugMessenger, nullptr);
  111. debugMessenger = VK_NULL_HANDLE;
  112. }
  113. void Base::destroyDebugReportCallback() {
  114. if(debugReportCallback == VK_NULL_HANDLE) {
  115. return;
  116. }
  117. auto f = GET_FUNCTION(vkDestroyDebugReportCallbackEXT);
  118. if(f == nullptr) {
  119. VK_REPORT_WARNING("Could not find debug report destroy function");
  120. return;
  121. }
  122. f(instance, debugReportCallback, nullptr);
  123. debugReportCallback = VK_NULL_HANDLE;
  124. }
  125. #endif
  126. bool Base::initSurface() {
  127. GLFWwindow* w = Window::get();
  128. if(w == nullptr) {
  129. VK_REPORT_ERROR("Init a window before Vulkan");
  130. return true;
  131. }
  132. VK_CHECK_TRUE(glfwCreateWindowSurface(instance, w, nullptr, &surface));
  133. return false;
  134. }
  135. bool Base::init() {
  136. if(initInstance()) {
  137. return true;
  138. }
  139. #ifdef DEBUG_VULKAN
  140. if(initDebugMessenger() || initDebugReportCallback()) {
  141. return true;
  142. }
  143. #endif
  144. return initSurface();
  145. }
  146. void Base::destroy() {
  147. #ifdef DEBUG_VULKAN
  148. destroyDebugMessenger();
  149. destroyDebugReportCallback();
  150. #endif
  151. if(instance != VK_NULL_HANDLE) {
  152. vkDestroySurfaceKHR(instance, surface, nullptr);
  153. surface = VK_NULL_HANDLE;
  154. vkDestroyDevice(device, nullptr);
  155. device = VK_NULL_HANDLE;
  156. }
  157. vkDestroyInstance(instance, nullptr);
  158. instance = VK_NULL_HANDLE;
  159. }
  160. PFN_vkVoidFunction Base::getFunction(const char* name) {
  161. return vkGetInstanceProcAddr(instance, name);
  162. }
  163. void Base::getPhysicalDeviceProperties(VkPhysicalDeviceProperties& p) {
  164. vkGetPhysicalDeviceProperties(physicalDevice, &p);
  165. }
  166. u32 Base::findQueueFamily(VkQueueFlags flags) {
  167. Core::Array<VkQueueFamilyProperties, 32> p;
  168. u32 c = p.getLength();
  169. vkGetPhysicalDeviceQueueFamilyProperties(physicalDevice, &c, p.begin());
  170. for(u32 i = 0; i < c; i++) {
  171. if((p[i].queueFlags & flags) == flags) {
  172. return i;
  173. }
  174. }
  175. return INVALID_QUEUE_FAMILY;
  176. }
  177. static bool hasPresentationSupport(
  178. VkPhysicalDevice pd, VkSurfaceKHR s, u32 index) {
  179. VkBool32 b = false;
  180. VK_CHECK(false, vkGetPhysicalDeviceSurfaceSupportKHR(pd, index, s, &b));
  181. return b;
  182. }
  183. u32 Base::findSurfaceQueueFamily() {
  184. u32 c = 0;
  185. vkGetPhysicalDeviceQueueFamilyProperties(physicalDevice, &c, nullptr);
  186. for(u32 i = 0; i < c; i++) {
  187. if(hasPresentationSupport(physicalDevice, surface, i)) {
  188. return i;
  189. }
  190. }
  191. return INVALID_QUEUE_FAMILY;
  192. }
  193. bool Base::hasExtension(const char* extension) {
  194. Core::Array<VkExtensionProperties, 1024> e;
  195. u32 c = e.getLength();
  196. VK_CHECK(
  197. false, vkEnumerateDeviceExtensionProperties(
  198. physicalDevice, nullptr, &c, &e[0]));
  199. for(u32 i = 0; i < c; i++) {
  200. if(strcmp(e[i].extensionName, extension) == 0) {
  201. return true;
  202. }
  203. }
  204. return false;
  205. }
  206. bool Base::getSurfaceCapabilities(VkSurfaceCapabilitiesKHR& c) {
  207. VK_CHECK_TRUE(
  208. vkGetPhysicalDeviceSurfaceCapabilitiesKHR(physicalDevice, surface, &c));
  209. return false;
  210. }
  211. bool Base::findSurfaceFormat(
  212. VkSurfaceFormatKHR& sf, SurfaceFormatSelector sfs) {
  213. Core::Array<VkSurfaceFormatKHR, 128> formats;
  214. u32 c = formats.getLength();
  215. VK_CHECK_TRUE(vkGetPhysicalDeviceSurfaceFormatsKHR(
  216. physicalDevice, surface, &c, formats.begin()));
  217. int bestPoints = 0;
  218. for(u32 i = 0; i < c; i++) {
  219. int points = sfs(formats[i]);
  220. if(points > bestPoints) {
  221. bestPoints = points;
  222. sf = formats[i];
  223. }
  224. }
  225. return bestPoints == 0;
  226. }
  227. bool Base::findSurfacePresentMode(
  228. VkPresentModeKHR& m, SurfacePresentModeSelector spms) {
  229. Core::Array<VkPresentModeKHR, 64> modes;
  230. u32 c = modes.getLength();
  231. VK_CHECK_TRUE(vkGetPhysicalDeviceSurfacePresentModesKHR(
  232. physicalDevice, surface, &c, modes.begin()));
  233. int bestPoints = 0;
  234. for(u32 i = 0; i < c; i++) {
  235. int points = spms(modes[i]);
  236. if(points > bestPoints) {
  237. bestPoints = points;
  238. m = modes[i];
  239. }
  240. }
  241. return bestPoints == 0;
  242. }
  243. bool Base::initDevice(
  244. const List<DeviceQueueData> data, const List<const char*>& extensions) {
  245. Core::List<VkDeviceQueueCreateInfo> qInfo;
  246. for(const DeviceQueueData& d : data) {
  247. VkDeviceQueueCreateInfo& i = qInfo.put();
  248. i.sType = VK_STRUCTURE_TYPE_DEVICE_QUEUE_CREATE_INFO;
  249. i.queueFamilyIndex = d.queueFamilyIndex;
  250. i.queueCount = 1;
  251. i.pQueuePriorities = &d.priority;
  252. }
  253. VkPhysicalDeviceFeatures deviceFeatures = {};
  254. vkGetPhysicalDeviceFeatures(physicalDevice, &deviceFeatures);
  255. VkDeviceCreateInfo info = {
  256. .sType = VK_STRUCTURE_TYPE_DEVICE_CREATE_INFO,
  257. .queueCreateInfoCount = static_cast<u32>(qInfo.getLength()),
  258. .pQueueCreateInfos = &qInfo[0],
  259. .enabledExtensionCount = static_cast<u32>(extensions.getLength()),
  260. .ppEnabledExtensionNames = &extensions[0],
  261. .pEnabledFeatures = &deviceFeatures};
  262. VK_CHECK_TRUE(vkCreateDevice(physicalDevice, &info, nullptr, &device));
  263. return false;
  264. }
  265. void Base::waitForIdle() {
  266. if(device != VK_NULL_HANDLE) {
  267. vkDeviceWaitIdle(device);
  268. }
  269. }
  270. u32 Base::findMemoryType(u32 typeFilter, VkMemoryPropertyFlags flags) {
  271. VkPhysicalDeviceMemoryProperties m;
  272. vkGetPhysicalDeviceMemoryProperties(physicalDevice, &m);
  273. for(u32 i = 0; i < m.memoryTypeCount; i++) {
  274. if(typeFilter & (1u << i) &&
  275. (m.memoryTypes[i].propertyFlags & flags) == flags) {
  276. return i;
  277. }
  278. }
  279. return INVALID_MEMORY_TYPE;
  280. }