scop
a small 3D object loader
Loading...
Searching...
No Matches
VulkanInit.cpp
Go to the documentation of this file.
1/* ************************************************************************** */
2/* */
3/* ::: :::::::: */
4/* VulkanInit.cpp :+: :+: :+: */
5/* +:+ +:+ +:+ */
6/* By: rbourgea <rbourgea@student.42.fr> +#+ +:+ +#+ */
7/* +#+#+#+#+#+ +#+ */
8/* Created: 2024/01/11 06:50:01 by rbourgea #+# #+# */
9/* Updated: 2024/04/11 10:59:47 by rbourgea ### ########.fr */
10/* */
11/* ************************************************************************** */
12
13#include "VulkanApp.hpp"
14
15void VulkanApp::run(const std::string& objFile) {
16 parseObjFile(objFile);
17 initWindow();
18 initVulkan();
19 mainLoop();
20 cleanup();
21}
22
24 glfwInit();
25
26 glfwWindowHint(GLFW_CLIENT_API, GLFW_NO_API);
27
28 window = glfwCreateWindow(WIDTH, HEIGHT, TITLE, nullptr, nullptr);
29 glfwSetWindowUserPointer(window, this);
30 glfwSetFramebufferSizeCallback(window, framebufferResizeCallback);
31 glfwSetKeyCallback(window, keyCallback);
32 glfwSetMouseButtonCallback(window, VulkanApp::mouseButtonCallback);
33 glfwSetCursorPosCallback(window, cursorPosCallback);
34}
35
37 uint32_t fps = 0;
38 double last_time_print = glfwGetTime();
39
40 while (!glfwWindowShouldClose(window)) {
41 glfwPollEvents();
42 if (!transition_over)
44 drawFrame();
45
46 fps++;
47 if (glfwGetTime() - last_time_print > 1.0 + std::numeric_limits<double>::epsilon()) {
48 std::ostringstream oss;
49 oss << TITLE << " - " << fps << " fps";
50
51 glfwSetWindowTitle(window, oss.str().c_str());
52 fps = 0;
53 last_time_print = glfwGetTime();
54 }
55 }
56
57 vkDeviceWaitIdle(device);
58}
59
86
88 if (!debugMode) return true;
89
90 uint32_t layerCount;
91 vkEnumerateInstanceLayerProperties(&layerCount, nullptr);
92
93 std::vector<VkLayerProperties> availableLayers(layerCount);
94 vkEnumerateInstanceLayerProperties(&layerCount, availableLayers.data());
95
96 std::cout << "Available Validation Layers:" << std::endl;
97 for (const auto& layerProperties : availableLayers) {
98 std::cout << " " << layerProperties.layerName << std::endl;
99 }
100 std::cout << "-----------------------------" << std::endl;
101
102 for (const char* layerName : validationLayers) {
103 bool layerFound = false;
104
105 for (const auto& layerProperties : availableLayers) {
106 if (strcmp(layerName, layerProperties.layerName) == 0) {
107 layerFound = true;
108 break;
109 }
110 }
111
112 if (!layerFound) {
113 return false;
114 }
115 }
116 return true;
117}
118
119std::vector<const char*> VulkanApp::getRequiredExtensions() {
120 uint32_t glfwExtensionCount = 0;
121 const char** glfwExtensions;
122 glfwExtensions = glfwGetRequiredInstanceExtensions(&glfwExtensionCount);
123
124 std::vector<const char*> extensions(glfwExtensions, glfwExtensions + glfwExtensionCount);
125
126 if (debugMode) {
127 extensions.push_back(VK_EXT_DEBUG_UTILS_EXTENSION_NAME);
128 }
129
130 return extensions;
131}
132
135 throw std::runtime_error("Validation layers requested, but not available !");
136 }
137
138 VkApplicationInfo appInfo{};
139 appInfo.sType = VK_STRUCTURE_TYPE_APPLICATION_INFO;
140 appInfo.pApplicationName = TITLE;
141 appInfo.applicationVersion = VK_MAKE_VERSION(1, 0, 0);
142 appInfo.pEngineName = "No Engine";
143 appInfo.engineVersion = VK_MAKE_VERSION(1, 0, 0);
144 appInfo.apiVersion = VK_API_VERSION_1_0;
145
146 VkInstanceCreateInfo createInfo{};
147 createInfo.sType = VK_STRUCTURE_TYPE_INSTANCE_CREATE_INFO;
148 createInfo.pApplicationInfo = &appInfo;
149
150 auto extensions = getRequiredExtensions();
151#ifdef __APPLE__
152 extensions.push_back(VK_KHR_PORTABILITY_ENUMERATION_EXTENSION_NAME);
153#endif
154 createInfo.enabledExtensionCount = static_cast<uint32_t>(extensions.size());
155 createInfo.ppEnabledExtensionNames = extensions.data();
156
157 VkDebugUtilsMessengerCreateInfoEXT debugCreateInfo{};
158 if (debugMode) {
159 createInfo.enabledLayerCount = static_cast<uint32_t>(validationLayers.size());
160 createInfo.ppEnabledLayerNames = validationLayers.data();
161
162 populateDebugMessengerCreateInfo(debugCreateInfo);
163 createInfo.pNext = (VkDebugUtilsMessengerCreateInfoEXT*) &debugCreateInfo;
164 } else {
165 createInfo.enabledLayerCount = 0;
166
167 createInfo.pNext = nullptr;
168 }
169
170#ifdef __APPLE__
171 createInfo.flags |= VK_INSTANCE_CREATE_ENUMERATE_PORTABILITY_BIT_KHR;
172#endif
173
174 if (vkCreateInstance(&createInfo, nullptr, &instance) != VK_SUCCESS) {
175 throw std::runtime_error("Failed to create instance !");
176 }
177}
178
180 if (glfwCreateWindowSurface(instance, window, nullptr, &surface) != VK_SUCCESS) {
181 throw std::runtime_error("Failed to create window surface !");
182 }
183}
184
185bool VulkanApp::checkDeviceExtensionSupport(VkPhysicalDevice device) {
186 uint32_t extensionCount;
187 vkEnumerateDeviceExtensionProperties(device, nullptr, &extensionCount, nullptr);
188
189 std::vector<VkExtensionProperties> availableExtensions(extensionCount);
190 vkEnumerateDeviceExtensionProperties(device, nullptr, &extensionCount, availableExtensions.data());
191
192 std::set<std::string> requiredExtensions(deviceExtensions.begin(), deviceExtensions.end());
193
194 for (const auto& extension : availableExtensions) {
195 requiredExtensions.erase(extension.extensionName);
196 }
197
198 return requiredExtensions.empty();
199}
200
201bool VulkanApp::isDeviceSuitable(VkPhysicalDevice device) {
203
204 bool extensionsSupported = checkDeviceExtensionSupport(device);
205
206 bool swapChainAdequate = false;
207 if (extensionsSupported) {
209 swapChainAdequate = !swapChainSupport.formats.empty() && !swapChainSupport.presentModes.empty();
210 }
211
212 VkPhysicalDeviceFeatures supportedFeatures;
213 vkGetPhysicalDeviceFeatures(device, &supportedFeatures);
214
215 return indices.isComplete() && extensionsSupported && swapChainAdequate && supportedFeatures.samplerAnisotropy;
216}
217
219 uint32_t deviceCount = 0;
220 vkEnumeratePhysicalDevices(instance, &deviceCount, nullptr);
221
222 if (deviceCount == 0) {
223 throw std::runtime_error("Failed to find GPUs with Vulkan support !");
224 }
225
226 std::vector<VkPhysicalDevice> devices(deviceCount);
227 vkEnumeratePhysicalDevices(instance, &deviceCount, devices.data());
228
229 for (const auto& device : devices) {
233 break;
234 }
235 }
236
237 if (physicalDevice == VK_NULL_HANDLE) {
238 throw std::runtime_error("Failed to find a suitable GPU !");
239 }
240}
241
244
245 std::vector<VkDeviceQueueCreateInfo> queueCreateInfos;
246 std::set<uint32_t> uniqueQueueFamilies = {indices.graphicsFamily.value(), indices.presentFamily.value()};
247
248 float queuePriority = 1.0f;
249 for (uint32_t queueFamily : uniqueQueueFamilies) {
250 VkDeviceQueueCreateInfo queueCreateInfo{};
251 queueCreateInfo.sType = VK_STRUCTURE_TYPE_DEVICE_QUEUE_CREATE_INFO;
252 queueCreateInfo.queueFamilyIndex = queueFamily;
253 queueCreateInfo.queueCount = 1;
254 queueCreateInfo.pQueuePriorities = &queuePriority;
255 queueCreateInfos.push_back(queueCreateInfo);
256 }
257
258 VkPhysicalDeviceFeatures deviceFeatures{};
259 deviceFeatures.samplerAnisotropy = VK_TRUE;
260 deviceFeatures.sampleRateShading = VK_TRUE;
261
262 VkDeviceCreateInfo createInfo{};
263 createInfo.sType = VK_STRUCTURE_TYPE_DEVICE_CREATE_INFO;
264
265 createInfo.queueCreateInfoCount = static_cast<uint32_t>(queueCreateInfos.size());
266 createInfo.pQueueCreateInfos = queueCreateInfos.data();
267
268 createInfo.pEnabledFeatures = &deviceFeatures;
269
270 createInfo.enabledExtensionCount = static_cast<uint32_t>(deviceExtensions.size());
271 createInfo.ppEnabledExtensionNames = deviceExtensions.data();
272
273 if (debugMode) {
274 createInfo.enabledLayerCount = static_cast<uint32_t>(validationLayers.size());
275 createInfo.ppEnabledLayerNames = validationLayers.data();
276 } else {
277 createInfo.enabledLayerCount = 0;
278 }
279
280 if (vkCreateDevice(physicalDevice, &createInfo, nullptr, &device) != VK_SUCCESS) {
281 throw std::runtime_error("Failed to create logical device !");
282 }
283
284 vkGetDeviceQueue(device, indices.graphicsFamily.value(), 0, &graphicsQueue);
285 vkGetDeviceQueue(device, indices.presentFamily.value(), 0, &presentQueue);
286}
287
288VkSurfaceFormatKHR chooseSwapSurfaceFormat(const std::vector<VkSurfaceFormatKHR>& availableFormats) {
289 for (const auto& availableFormat : availableFormats) {
290 if (availableFormat.format == VK_FORMAT_B8G8R8A8_SRGB && availableFormat.colorSpace == VK_COLOR_SPACE_SRGB_NONLINEAR_KHR) {
291 return availableFormat;
292 }
293 }
294
295 return availableFormats[0];
296}
297
298VkPresentModeKHR VulkanApp::chooseSwapPresentMode(const std::vector<VkPresentModeKHR>& availablePresentModes) {
299 for (const auto& availablePresentMode : availablePresentModes) {
300 if (availablePresentMode == VK_PRESENT_MODE_MAILBOX_KHR) {
301 return availablePresentMode;
302 }
303 }
304
305 return VK_PRESENT_MODE_FIFO_KHR;
306}
307
308VkExtent2D VulkanApp::chooseSwapExtent(const VkSurfaceCapabilitiesKHR& capabilities) {
309 if (capabilities.currentExtent.width != std::numeric_limits<uint32_t>::max()) {
310 return capabilities.currentExtent;
311 } else {
312 int width, height;
313 glfwGetFramebufferSize(window, &width, &height);
314
315 VkExtent2D actualExtent = {
316 static_cast<uint32_t>(width),
317 static_cast<uint32_t>(height)
318 };
319
320 actualExtent.width = std::clamp(actualExtent.width, capabilities.minImageExtent.width, capabilities.maxImageExtent.width);
321 actualExtent.height = std::clamp(actualExtent.height, capabilities.minImageExtent.height, capabilities.maxImageExtent.height);
322
323 return actualExtent;
324 }
325}
326
329
330 vkGetPhysicalDeviceSurfaceCapabilitiesKHR(device, surface, &details.capabilities);
331
332 uint32_t formatCount;
333 vkGetPhysicalDeviceSurfaceFormatsKHR(device, surface, &formatCount, nullptr);
334
335 if (formatCount != 0) {
336 details.formats.resize(formatCount);
337 vkGetPhysicalDeviceSurfaceFormatsKHR(device, surface, &formatCount, details.formats.data());
338 }
339
340 uint32_t presentModeCount;
341 vkGetPhysicalDeviceSurfacePresentModesKHR(device, surface, &presentModeCount, nullptr);
342
343 if (presentModeCount != 0) {
344 details.presentModes.resize(presentModeCount);
345 vkGetPhysicalDeviceSurfacePresentModesKHR(device, surface, &presentModeCount, details.presentModes.data());
346 }
347
348 return details;
349}
350
353
354 VkSurfaceFormatKHR surfaceFormat = chooseSwapSurfaceFormat(swapChainSupport.formats);
355 VkPresentModeKHR presentMode = chooseSwapPresentMode(swapChainSupport.presentModes);
356 VkExtent2D extent = chooseSwapExtent(swapChainSupport.capabilities);
357
358 uint32_t imageCount = swapChainSupport.capabilities.minImageCount + 1;
359 if (swapChainSupport.capabilities.maxImageCount > 0 && imageCount > swapChainSupport.capabilities.maxImageCount) {
360 imageCount = swapChainSupport.capabilities.maxImageCount;
361 }
362
363 VkSwapchainCreateInfoKHR createInfo{};
364 createInfo.sType = VK_STRUCTURE_TYPE_SWAPCHAIN_CREATE_INFO_KHR;
365 createInfo.surface = surface;
366
367 createInfo.minImageCount = imageCount;
368 createInfo.imageFormat = surfaceFormat.format;
369 createInfo.imageColorSpace = surfaceFormat.colorSpace;
370 createInfo.imageExtent = extent;
371 createInfo.imageArrayLayers = 1;
372 createInfo.imageUsage = VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT;
373
375 uint32_t queueFamilyIndices[] = {indices.graphicsFamily.value(), indices.presentFamily.value()};
376
377 if (indices.graphicsFamily != indices.presentFamily) {
378 createInfo.imageSharingMode = VK_SHARING_MODE_CONCURRENT;
379 createInfo.queueFamilyIndexCount = 2;
380 createInfo.pQueueFamilyIndices = queueFamilyIndices;
381 } else {
382 createInfo.imageSharingMode = VK_SHARING_MODE_EXCLUSIVE;
383 }
384
385 createInfo.preTransform = swapChainSupport.capabilities.currentTransform;
386 createInfo.compositeAlpha = VK_COMPOSITE_ALPHA_OPAQUE_BIT_KHR;
387 createInfo.presentMode = presentMode;
388 createInfo.clipped = VK_TRUE;
389
390 createInfo.oldSwapchain = VK_NULL_HANDLE;
391
392 if (vkCreateSwapchainKHR(device, &createInfo, nullptr, &swapChain) != VK_SUCCESS) {
393 throw std::runtime_error("Failed to create swap chain !");
394 }
395
396 vkGetSwapchainImagesKHR(device, swapChain, &imageCount, nullptr);
397 swapChainImages.resize(imageCount);
398 vkGetSwapchainImagesKHR(device, swapChain, &imageCount, swapChainImages.data());
399
400 swapChainImageFormat = surfaceFormat.format;
401 swapChainExtent = extent;
402}
403
405 int width = 0, height = 0;
406 glfwGetFramebufferSize(window, &width, &height);
407 while (width == 0 || height == 0) {
408 glfwGetFramebufferSize(window, &width, &height);
409 glfwWaitEvents();
410 }
411
412 vkDeviceWaitIdle(device);
413
415
421}
const uint32_t WIDTH
Definition VulkanApp.hpp:42
const std::vector< const char * > validationLayers
Definition VulkanApp.hpp:47
constexpr bool debugMode
Definition VulkanApp.hpp:61
const std::vector< const char * > deviceExtensions
Definition VulkanApp.hpp:54
const uint32_t HEIGHT
Definition VulkanApp.hpp:43
const char * TITLE
Definition VulkanApp.hpp:41
VkSurfaceFormatKHR chooseSwapSurfaceFormat(const std::vector< VkSurfaceFormatKHR > &availableFormats)
void createCommandPool()
void createDescriptorSets()
std::vector< uint32_t > indices
void createDepthResources()
GLFWwindow * window
VkSampleCountFlagBits msaaSamples
VkDevice device
void createVertexBuffer()
void createGraphicsPipeline()
static void keyCallback(GLFWwindow *window, int key, int scancode, int action, int mods)
QueueFamilyIndices findQueueFamilies(VkPhysicalDevice device)
VkPhysicalDevice physicalDevice
void createColorResources()
VkQueue presentQueue
void createSwapChain()
void drawFrame()
void recreateSwapChain()
void createTextureImageView()
void cleanupSwapChain()
static void cursorPosCallback(GLFWwindow *window, double xpos, double ypos)
VkSurfaceKHR surface
bool checkValidationLayerSupport()
VkQueue graphicsQueue
std::vector< VkImage > swapChainImages
VkPresentModeKHR chooseSwapPresentMode(const std::vector< VkPresentModeKHR > &availablePresentModes)
void run(const std::string &objFile1)
void pickPhysicalDevice()
void createDescriptorSetLayout()
void transitionTextures()
VkExtent2D swapChainExtent
static void framebufferResizeCallback(GLFWwindow *window, int width, int height)
void createInstance()
void createTextureImage()
void setupDebugMessenger()
VkInstance instance
std::vector< const char * > getRequiredExtensions()
void createIndexBuffer()
void parseObjFile(const std::string &filename)
Definition Parsing.cpp:15
bool checkDeviceExtensionSupport(VkPhysicalDevice device)
void createImageViews()
bool isDeviceSuitable(VkPhysicalDevice device)
void initWindow()
void createCommandBuffers()
void initVulkan()
void cleanup()
void createUniformBuffers()
void createSyncObjects()
void createLogicalDevice()
void createFramebuffers()
void createTextureSampler()
SwapChainSupportDetails querySwapChainSupport(VkPhysicalDevice device)
void mainLoop()
void createDescriptorPool()
VkExtent2D chooseSwapExtent(const VkSurfaceCapabilitiesKHR &capabilities)
void createRenderPass()
void populateDebugMessengerCreateInfo(VkDebugUtilsMessengerCreateInfoEXT &createInfo)
VkSwapchainKHR swapChain
static void mouseButtonCallback(GLFWwindow *window, int button, int action, int mods)
bool transition_over
VkFormat swapChainImageFormat
void createSurface()
VkSampleCountFlagBits getMaxUsableSampleCount()
std::vector< VkSurfaceFormatKHR > formats
Definition VulkanApp.hpp:78
VkSurfaceCapabilitiesKHR capabilities
Definition VulkanApp.hpp:77
std::vector< VkPresentModeKHR > presentModes
Definition VulkanApp.hpp:79