4#include <SDL3/SDL_vulkan.h>
15#include "SDL3/SDL_error.h"
17 #include "vulkan/vulkan_wayland.h"
18#elif defined(PLATFORM_WIN)
19 #include <vulkan/vulkan_win32.h>
26bool VulkanRenderer::InitVulkan() {
28 instance = VK_NULL_HANDLE;
30 std::vector<const char*> requiredExtensions = {
31 VK_KHR_SURFACE_EXTENSION_NAME,
32 VK_EXT_DEBUG_UTILS_EXTENSION_NAME
39 uint32_t surfExtCount = 0;
40 vkEnumerateInstanceExtensionProperties(
nullptr, &surfExtCount,
nullptr);
41 std::vector<VkExtensionProperties> surfExts(surfExtCount);
42 vkEnumerateInstanceExtensionProperties(
nullptr, &surfExtCount, surfExts.data());
43 auto hasSurfExt = [&](
const char* name) {
44 for (
auto& e : surfExts)
45 if (strcmp(e.extensionName, name) == 0)
return true;
48 if (hasSurfExt(
"VK_KHR_wayland_surface"))
49 requiredExtensions.push_back(
"VK_KHR_wayland_surface");
50 if (hasSurfExt(
"VK_KHR_xlib_surface"))
51 requiredExtensions.push_back(
"VK_KHR_xlib_surface");
53 #elif defined(PLATFORM_WIN)
54 requiredExtensions.push_back(
55 VK_KHR_WIN32_SURFACE_EXTENSION_NAME);
56 #elif defined(TARGET_OS_MAC) || defined(TARGET_OS_IOS)
57 requiredExtensions.push_back(VK_MVK_MOLTENVK_EXTENSION_NAME);
64 std::vector<const char*> enabledLayers;
66 uint32_t layerCount = 0;
67 vkEnumerateInstanceLayerProperties(&layerCount,
nullptr);
68 std::vector<VkLayerProperties> availableLayers(layerCount);
69 vkEnumerateInstanceLayerProperties(&layerCount,
70 availableLayers.data());
72 const char* desiredLayer =
"VK_LAYER_KHRONOS_validation";
73 for (
const auto& layer : availableLayers) {
74 if (strcmp(layer.layerName, desiredLayer) == 0) {
75 enabledLayers.push_back(desiredLayer);
80 if (enabledLayers.empty()) {
81 SLEAK_WARN(
"VK_LAYER_KHRONOS_validation not available — GPU errors will not be reported");
84 if (enabledLayers.empty()) {
85 auto it = std::find_if(
86 requiredExtensions.begin(), requiredExtensions.end(),
89 VK_EXT_DEBUG_UTILS_EXTENSION_NAME) == 0;
91 if (it != requiredExtensions.end()) {
92 requiredExtensions.erase(it);
97 uint32_t extensionCount = 0;
98 vkEnumerateInstanceExtensionProperties(
nullptr, &extensionCount,
100 std::vector<VkExtensionProperties> extensions(extensionCount);
101 vkEnumerateInstanceExtensionProperties(
nullptr, &extensionCount,
104 VkApplicationInfo appInfo{};
105 appInfo.sType = VK_STRUCTURE_TYPE_APPLICATION_INFO;
106 appInfo.pApplicationName =
"SleakEngine";
107 appInfo.applicationVersion = VK_MAKE_VERSION(1, 0, 0);
108 appInfo.pEngineName =
"Sleak Engine";
109 appInfo.engineVersion = VK_MAKE_VERSION(1, 0, 0);
110 appInfo.apiVersion = VK_API_VERSION_1_1;
112 VkInstanceCreateInfo createInfo{};
113 createInfo.sType = VK_STRUCTURE_TYPE_INSTANCE_CREATE_INFO;
114 createInfo.pApplicationInfo = &appInfo;
115 createInfo.enabledExtensionCount =
116 static_cast<uint32_t
>(requiredExtensions.size());
117 createInfo.ppEnabledExtensionNames = requiredExtensions.data();
118 createInfo.enabledLayerCount =
119 static_cast<uint32_t
>(enabledLayers.size());
120 createInfo.ppEnabledLayerNames = enabledLayers.data();
122 VkDebugUtilsMessengerCreateInfoEXT debugCreateInfo{};
123 if (!enabledLayers.empty()) {
124 PopulateDebugMessengerCreateInfo(debugCreateInfo);
125 createInfo.pNext = &debugCreateInfo;
129 vkCreateInstance(&createInfo,
nullptr, &instance);
130 if (result != VK_SUCCESS) {
135 SLEAK_INFO(
"Vulkan instance created successfully.");
138 }
catch (
const std::exception& e) {
139 SLEAK_ERROR(
"Exception in InitVulkan: {}", e.what());
145bool VulkanRenderer::CreateDevice() {
147 uint32_t deviceCount = 0;
148 VkResult result = vkEnumeratePhysicalDevices(instance, &deviceCount,
150 if (result != VK_SUCCESS || deviceCount == 0)
153 GPUs.resize(deviceCount);
154 vkEnumeratePhysicalDevices(instance, &deviceCount, GPUs.data());
156 SLEAK_INFO(
"Found totally {} devices in computer", deviceCount);
159 physicalDevice = GPUs[0];
160 for (auto& dev : GPUs) {
161 VkPhysicalDeviceProperties props;
162 VkPhysicalDeviceMemoryProperties memprops;
163 vkGetPhysicalDeviceProperties(dev, &props);
164 vkGetPhysicalDeviceMemoryProperties(dev, &memprops);
167 switch (props.deviceType) {
168 case VK_PHYSICAL_DEVICE_TYPE_INTEGRATED_GPU:
169 type =
"Integrated GPU";
break;
170 case VK_PHYSICAL_DEVICE_TYPE_DISCRETE_GPU:
171 type =
"Discrete GPU";
break;
172 case VK_PHYSICAL_DEVICE_TYPE_VIRTUAL_GPU:
173 type =
"Virtual GPU";
break;
174 case VK_PHYSICAL_DEVICE_TYPE_CPU:
180 VkDeviceSize totalDedicatedMemory = 0;
181 for (uint32_t i = 0; i < memprops.memoryHeapCount; i++) {
182 if (memprops.memoryHeaps[i].flags &
183 VK_MEMORY_HEAP_DEVICE_LOCAL_BIT) {
184 totalDedicatedMemory += memprops.memoryHeaps[i].size;
187 float totalDedicatedMemoryGB =
188 static_cast<float>(totalDedicatedMemory) /
189 (1024.0f * 1024.0f * 1024.0f);
192 props.deviceName, type, totalDedicatedMemoryGB);
194 if (props.deviceType == VK_PHYSICAL_DEVICE_TYPE_DISCRETE_GPU)
195 physicalDevice = dev;
202 uint32_t familyCount = 0;
203 vkGetPhysicalDeviceQueueFamilyProperties(physicalDevice, &familyCount,
205 std::vector<VkQueueFamilyProperties> queueFamilies(familyCount);
206 vkGetPhysicalDeviceQueueFamilyProperties(physicalDevice, &familyCount,
207 queueFamilies.data());
209 QueueIDs.GraphicsIndex = UINT32_MAX;
210 QueueIDs.ComputeIndex = UINT32_MAX;
211 QueueIDs.TransferIndex = UINT32_MAX;
212 QueueIDs.PresentIndex = UINT32_MAX;
214 for (uint32_t i = 0; i < familyCount; i++) {
215 if (queueFamilies[i].queueFlags & VK_QUEUE_GRAPHICS_BIT &&
216 QueueIDs.GraphicsIndex == UINT32_MAX) {
217 QueueIDs.GraphicsIndex = i;
219 if (queueFamilies[i].queueFlags & VK_QUEUE_COMPUTE_BIT &&
220 QueueIDs.ComputeIndex == UINT32_MAX) {
221 QueueIDs.ComputeIndex = i;
223 if (queueFamilies[i].queueFlags & VK_QUEUE_TRANSFER_BIT &&
224 QueueIDs.TransferIndex == UINT32_MAX) {
225 QueueIDs.TransferIndex = i;
228 if (QueueIDs.PresentIndex == UINT32_MAX) {
229 VkBool32 presentSupport = VK_FALSE;
230 vkGetPhysicalDeviceSurfaceSupportKHR(physicalDevice, i,
233 if (presentSupport) {
234 QueueIDs.PresentIndex = i;
239 if (QueueIDs.GraphicsIndex == UINT32_MAX ||
240 QueueIDs.PresentIndex == UINT32_MAX)
244 if (QueueIDs.ComputeIndex == UINT32_MAX)
245 QueueIDs.ComputeIndex = QueueIDs.GraphicsIndex;
246 if (QueueIDs.TransferIndex == UINT32_MAX)
247 QueueIDs.TransferIndex = QueueIDs.GraphicsIndex;
251 "Graphics: {0} Compute: {1} Transfer: {2} Present: {3}",
252 QueueIDs.GraphicsIndex, QueueIDs.ComputeIndex,
253 QueueIDs.TransferIndex, QueueIDs.PresentIndex);
257 auto queueCreateInfos = GetUniqueQueueCreateInfos();
260 VkPhysicalDeviceFeatures features{};
261 vkGetPhysicalDeviceFeatures(physicalDevice, &features);
264 VkPhysicalDeviceProperties deviceProperties;
265 vkGetPhysicalDeviceProperties(physicalDevice, &deviceProperties);
266 VkSampleCountFlags counts = deviceProperties.limits.framebufferColorSampleCounts
267 & deviceProperties.limits.framebufferDepthSampleCounts;
274 std::vector<const char*> requiredExtensions = {
275 VK_KHR_SWAPCHAIN_EXTENSION_NAME};
278 VkDeviceCreateInfo deviceInfo{};
279 deviceInfo.sType = VK_STRUCTURE_TYPE_DEVICE_CREATE_INFO;
280 deviceInfo.pQueueCreateInfos = queueCreateInfos.data();
281 deviceInfo.queueCreateInfoCount =
282 static_cast<uint32_t
>(queueCreateInfos.size());
283 deviceInfo.ppEnabledExtensionNames = requiredExtensions.data();
284 deviceInfo.enabledExtensionCount =
285 static_cast<uint32_t
>(requiredExtensions.size());
286 deviceInfo.pEnabledFeatures = &features;
287 deviceInfo.enabledLayerCount = 0;
289 result = vkCreateDevice(physicalDevice, &deviceInfo,
nullptr, &device);
291 if (result != VK_SUCCESS)
295 vkGetDeviceQueue(device, QueueIDs.GraphicsIndex, 0, &graphicsQueue);
296 vkGetDeviceQueue(device, QueueIDs.ComputeIndex, 0, &computeQueue);
297 vkGetDeviceQueue(device, QueueIDs.TransferIndex, 0, &transferQueue);
298 vkGetDeviceQueue(device, QueueIDs.PresentIndex, 0, &presentQueue);
301 VulkanBuffer::InitAllocator(instance, physicalDevice, device);
308std::vector<VkDeviceQueueCreateInfo>
310 std::set<uint32_t> uniqueFamilies = {
311 QueueIDs.GraphicsIndex, QueueIDs.ComputeIndex,
312 QueueIDs.TransferIndex, QueueIDs.PresentIndex};
314 std::vector<VkDeviceQueueCreateInfo> result;
316 for (uint32_t family : uniqueFamilies) {
317 VkDeviceQueueCreateInfo info{};
318 info.sType = VK_STRUCTURE_TYPE_DEVICE_QUEUE_CREATE_INFO;
319 info.queueFamilyIndex = family;
321 info.pQueuePriorities = &QueueIDs.GraphicsPriority;
322 result.push_back(info);
329bool VulkanRenderer::SetupDebugMessenger() {
330 VkDebugUtilsMessengerCreateInfoEXT createInfo{};
331 PopulateDebugMessengerCreateInfo(createInfo);
333 auto func = (PFN_vkCreateDebugUtilsMessengerEXT)vkGetInstanceProcAddr(
334 instance,
"vkCreateDebugUtilsMessengerEXT");
338 func(instance, &createInfo,
nullptr, &debugMessenger);
339 if (result != VK_SUCCESS)
342 vkDestroyDebugUtilsMessengerEXT =
343 (PFN_vkDestroyDebugUtilsMessengerEXT)vkGetInstanceProcAddr(
344 instance,
"vkDestroyDebugUtilsMessengerEXT");
345 if (!vkDestroyDebugUtilsMessengerEXT)
347 "Failed to setup Debug Messenger Destroy Function!")
350 "vkCreateDebugUtilsMessengerEXT could not found!")
357bool VulkanRenderer::CreateSurface() {
358 SDL_Vulkan_LoadLibrary(NULL);
359 bool result = SDL_Vulkan_CreateSurface(sdlWindow->GetSDLWindow(),
360 instance,
nullptr, &surface);
362 if (!result || surface == VK_NULL_HANDLE) {
363 const char* error = SDL_GetError();
372void VulkanRenderer::PopulateDebugMessengerCreateInfo(
373 VkDebugUtilsMessengerCreateInfoEXT& createInfo) {
376 VK_STRUCTURE_TYPE_DEBUG_UTILS_MESSENGER_CREATE_INFO_EXT;
377 createInfo.messageSeverity =
378 VK_DEBUG_UTILS_MESSAGE_SEVERITY_VERBOSE_BIT_EXT |
379 VK_DEBUG_UTILS_MESSAGE_SEVERITY_WARNING_BIT_EXT |
380 VK_DEBUG_UTILS_MESSAGE_SEVERITY_ERROR_BIT_EXT;
381 createInfo.messageType =
382 VK_DEBUG_UTILS_MESSAGE_TYPE_GENERAL_BIT_EXT |
383 VK_DEBUG_UTILS_MESSAGE_TYPE_VALIDATION_BIT_EXT |
384 VK_DEBUG_UTILS_MESSAGE_TYPE_PERFORMANCE_BIT_EXT;
385 createInfo.pfnUserCallback = &VulkanRenderer::Validation;
389VkBool32 VulkanRenderer::Validation(
390 VkDebugUtilsMessageSeverityFlagBitsEXT messageSeverity,
391 VkDebugUtilsMessageTypeFlagsEXT messageTypes,
392 const VkDebugUtilsMessengerCallbackDataEXT* pCallbackData,
394 std::string out = std::format(
"Vulkan: {} \n Type: {}",
395 pCallbackData->pMessage, messageTypes);
397 switch (messageSeverity) {
398 case VK_DEBUG_UTILS_MESSAGE_SEVERITY_WARNING_BIT_EXT:
401 case VK_DEBUG_UTILS_MESSAGE_SEVERITY_ERROR_BIT_EXT:
#define SLEAK_RETURN_ERR(...)
uint32_t m_maxMsaaSampleCount
static void SetPhysicalDevice(VkPhysicalDevice device)
VulkanRenderer(Window *window)
Backend-facing rendering layer shared by the four graphics backends.
Root namespace for everything the engine exposes.