15constexpr const char *kValidationLayerName =
"VK_LAYER_KHRONOS_validation";
17const std::vector<const char *> kRequiredDeviceExtensions = {
18 VK_KHR_SWAPCHAIN_EXTENSION_NAME,
21void Check(VkResult result,
const char *what)
23 if (result != VK_SUCCESS)
25 throw std::runtime_error(std::string(
"vk: ") + what +
" failed (VkResult=" +
26 std::to_string(
static_cast<int>(result)) +
")");
30bool ValidationLayerAvailable()
33 vkEnumerateInstanceLayerProperties(&count,
nullptr);
34 std::vector<VkLayerProperties> layers(count);
35 vkEnumerateInstanceLayerProperties(&count, layers.data());
36 for (
const auto &layer : layers)
38 if (std::strcmp(layer.layerName, kValidationLayerName) == 0)
46VKAPI_ATTR VkBool32 VKAPI_CALL DebugCallback(VkDebugUtilsMessageSeverityFlagBitsEXT severity,
47 VkDebugUtilsMessageTypeFlagsEXT ,
48 const VkDebugUtilsMessengerCallbackDataEXT *data,
52 if (severity >= VK_DEBUG_UTILS_MESSAGE_SEVERITY_WARNING_BIT_EXT)
54 fprintf(stderr,
"[vk] %s\n", data->pMessage);
59QueueFamilies FindQueueFamilies(VkPhysicalDevice device, VkSurfaceKHR surface)
63 vkGetPhysicalDeviceQueueFamilyProperties(device, &count,
nullptr);
64 std::vector<VkQueueFamilyProperties> families(count);
65 vkGetPhysicalDeviceQueueFamilyProperties(device, &count, families.data());
67 for (uint32_t i = 0; i < count; ++i)
69 if (families[i].queueFlags & VK_QUEUE_GRAPHICS_BIT)
73 VkBool32 presentSupport = VK_FALSE;
74 vkGetPhysicalDeviceSurfaceSupportKHR(device, i, surface, &presentSupport);
87bool DeviceHasRequiredExtensions(VkPhysicalDevice device)
90 vkEnumerateDeviceExtensionProperties(device,
nullptr, &count,
nullptr);
91 std::vector<VkExtensionProperties> extensions(count);
92 vkEnumerateDeviceExtensionProperties(device,
nullptr, &count, extensions.data());
94 for (
const char *required : kRequiredDeviceExtensions)
97 for (
const auto &ext : extensions)
99 if (std::strcmp(ext.extensionName, required) == 0)
113bool DeviceHasUsableSwapchain(VkPhysicalDevice device, VkSurfaceKHR surface)
115 uint32_t formatCount = 0;
116 vkGetPhysicalDeviceSurfaceFormatsKHR(device, surface, &formatCount,
nullptr);
117 uint32_t presentModeCount = 0;
118 vkGetPhysicalDeviceSurfacePresentModesKHR(device, surface, &presentModeCount,
nullptr);
119 return formatCount > 0 && presentModeCount > 0;
124 : m_enableValidation(enableValidation && ValidationLayerAvailable())
127 if (m_enableValidation)
129 CreateDebugMessenger();
131 CreateSurface(window);
132 PickPhysicalDevice();
133 CreateLogicalDevice();
140 vkDestroyDevice(m_device,
nullptr);
142 if (m_debugMessenger)
144 auto destroyFn =
reinterpret_cast<PFN_vkDestroyDebugUtilsMessengerEXT
>(
145 vkGetInstanceProcAddr(m_instance,
"vkDestroyDebugUtilsMessengerEXT"));
148 destroyFn(m_instance, m_debugMessenger,
nullptr);
153 vkDestroySurfaceKHR(m_instance, m_surface,
nullptr);
157 vkDestroyInstance(m_instance,
nullptr);
161void Context::CreateInstance()
163 VkApplicationInfo app{};
164 app.sType = VK_STRUCTURE_TYPE_APPLICATION_INFO;
165 app.pApplicationName =
"monad-engine vulkan preview";
166 app.applicationVersion = VK_MAKE_VERSION(0, 1, 0);
167 app.pEngineName =
"monad-engine";
168 app.engineVersion = VK_MAKE_VERSION(0, 1, 0);
169 app.apiVersion = VK_API_VERSION_1_2;
171 uint32_t glfwExtCount = 0;
172 const char **glfwExt = glfwGetRequiredInstanceExtensions(&glfwExtCount);
174 std::vector<const char *> extensions(glfwExt, glfwExt + glfwExtCount);
175 if (m_enableValidation)
177 extensions.push_back(VK_EXT_DEBUG_UTILS_EXTENSION_NAME);
180 VkInstanceCreateInfo info{};
181 info.sType = VK_STRUCTURE_TYPE_INSTANCE_CREATE_INFO;
182 info.pApplicationInfo = &app;
183 info.enabledExtensionCount =
static_cast<uint32_t
>(extensions.size());
184 info.ppEnabledExtensionNames = extensions.data();
186 const char *layers[] = { kValidationLayerName };
187 if (m_enableValidation)
189 info.enabledLayerCount = 1;
190 info.ppEnabledLayerNames = layers;
193 Check(vkCreateInstance(&info,
nullptr, &m_instance),
"vkCreateInstance");
196void Context::CreateDebugMessenger()
198 VkDebugUtilsMessengerCreateInfoEXT info{};
199 info.sType = VK_STRUCTURE_TYPE_DEBUG_UTILS_MESSENGER_CREATE_INFO_EXT;
200 info.messageSeverity = VK_DEBUG_UTILS_MESSAGE_SEVERITY_WARNING_BIT_EXT |
201 VK_DEBUG_UTILS_MESSAGE_SEVERITY_ERROR_BIT_EXT;
202 info.messageType = VK_DEBUG_UTILS_MESSAGE_TYPE_GENERAL_BIT_EXT |
203 VK_DEBUG_UTILS_MESSAGE_TYPE_VALIDATION_BIT_EXT |
204 VK_DEBUG_UTILS_MESSAGE_TYPE_PERFORMANCE_BIT_EXT;
205 info.pfnUserCallback = DebugCallback;
207 auto createFn =
reinterpret_cast<PFN_vkCreateDebugUtilsMessengerEXT
>(
208 vkGetInstanceProcAddr(m_instance,
"vkCreateDebugUtilsMessengerEXT"));
213 Check(createFn(m_instance, &info,
nullptr, &m_debugMessenger),
214 "vkCreateDebugUtilsMessengerEXT");
217void Context::CreateSurface(GLFWwindow *window)
219 Check(glfwCreateWindowSurface(m_instance, window,
nullptr, &m_surface),
220 "glfwCreateWindowSurface");
223void Context::PickPhysicalDevice()
226 vkEnumeratePhysicalDevices(m_instance, &count,
nullptr);
229 throw std::runtime_error(
"vk: no physical devices found");
231 std::vector<VkPhysicalDevice> devices(count);
232 vkEnumeratePhysicalDevices(m_instance, &count, devices.data());
236 VkPhysicalDevice bestDevice = VK_NULL_HANDLE;
237 QueueFamilies bestFamilies;
239 for (
auto device : devices)
241 if (!DeviceHasRequiredExtensions(device))
continue;
242 if (!DeviceHasUsableSwapchain(device, m_surface))
continue;
244 QueueFamilies fam = FindQueueFamilies(device, m_surface);
245 if (!fam.IsComplete())
continue;
247 VkPhysicalDeviceProperties props;
248 vkGetPhysicalDeviceProperties(device, &props);
250 if (props.deviceType == VK_PHYSICAL_DEVICE_TYPE_DISCRETE_GPU) score = 1000;
251 if (props.deviceType == VK_PHYSICAL_DEVICE_TYPE_INTEGRATED_GPU) score = 500;
252 if (score > bestScore)
260 if (bestDevice == VK_NULL_HANDLE)
262 throw std::runtime_error(
"vk: no suitable physical device");
264 m_physicalDevice = bestDevice;
265 m_queueFamilies = bestFamilies;
268void Context::CreateLogicalDevice()
270 std::set<uint32_t> uniqueFamilies = { m_queueFamilies.
graphics, m_queueFamilies.
present };
271 std::vector<VkDeviceQueueCreateInfo> queueInfos;
272 queueInfos.reserve(uniqueFamilies.size());
273 float priority = 1.0f;
274 for (uint32_t family : uniqueFamilies)
276 VkDeviceQueueCreateInfo qci{};
277 qci.sType = VK_STRUCTURE_TYPE_DEVICE_QUEUE_CREATE_INFO;
278 qci.queueFamilyIndex = family;
280 qci.pQueuePriorities = &priority;
281 queueInfos.push_back(qci);
284 VkPhysicalDeviceFeatures features{};
286 VkDeviceCreateInfo info{};
287 info.sType = VK_STRUCTURE_TYPE_DEVICE_CREATE_INFO;
288 info.queueCreateInfoCount =
static_cast<uint32_t
>(queueInfos.size());
289 info.pQueueCreateInfos = queueInfos.data();
290 info.pEnabledFeatures = &features;
291 info.enabledExtensionCount =
static_cast<uint32_t
>(kRequiredDeviceExtensions.size());
292 info.ppEnabledExtensionNames = kRequiredDeviceExtensions.data();
294 Check(vkCreateDevice(m_physicalDevice, &info,
nullptr, &m_device),
"vkCreateDevice");
296 vkGetDeviceQueue(m_device, m_queueFamilies.
graphics, 0, &m_graphicsQueue);
297 vkGetDeviceQueue(m_device, m_queueFamilies.
present, 0, &m_presentQueue);