source: opengl-game/vulkan-game.cpp@ 621664a

feature/imgui-sdl points-test
Last change on this file since 621664a was 621664a, checked in by Dmitry Portnoy <dmp1488@…>, 5 years ago

Reformat vulkan-game.cpp and fix a seg fault

  • Property mode set to 100644
File size: 59.0 KB
RevLine 
[cae7a2c]1/*
2DESIGN GUIDE
3
[de32fda]4-I should store multiple buffers (e.g. vertex and index buffers) in the same VkBuffer and use offsets into it
5-For specifying a separate transform for each model, I can specify a descriptorCount > ` in the ubo layout binding
6-Name class instance variables that are pointers (and possibly other pointer variables as well) like pVarName
[cae7a2c]7*/
8
[0e6ecf3]9#include "game-gui-glfw.hpp"
[03f4c64]10
[0e6ecf3]11#include "game-gui-sdl.hpp"
[826df16]12
13//#define _USE_MATH_DEFINES // Will be needed when/if I need to # include <cmath>
[03f4c64]14
15#define GLM_FORCE_RADIANS
[80edd70]16#include <glm/glm.hpp>
[de32fda]17#include <glm/gtc/matrix_transform.hpp>
[03f4c64]18
[eea05dd]19#define STB_IMAGE_IMPLEMENTATION
20#include "stb_image.h"
21
[03f4c64]22#include <iostream>
[80edd70]23#include <fstream>
24#include <algorithm>
25#include <vector>
26#include <array>
[0e6ecf3]27#include <set>
[80edd70]28#include <optional>
[de32fda]29#include <chrono>
[03f4c64]30
31using namespace std;
32
[826df16]33const int SCREEN_WIDTH = 800;
34const int SCREEN_HEIGHT = 600;
35
[47bff4c]36const int MAX_FRAMES_IN_FLIGHT = 2;
37
[826df16]38#ifdef NDEBUG
39 const bool enableValidationLayers = false;
40#else
41 const bool enableValidationLayers = true;
42#endif
43
[bfd620e]44const vector<const char*> validationLayers = {
45 "VK_LAYER_KHRONOS_validation"
46};
47
48const vector<const char*> deviceExtensions = {
49 VK_KHR_SWAPCHAIN_EXTENSION_NAME
50};
51
[909b51a]52struct QueueFamilyIndices {
53 optional<uint32_t> graphicsFamily;
[b3671b5]54 optional<uint32_t> presentFamily;
[909b51a]55
56 bool isComplete() {
[b3671b5]57 return graphicsFamily.has_value() && presentFamily.has_value();
[909b51a]58 }
59};
60
[bfd620e]61struct SwapChainSupportDetails {
62 VkSurfaceCapabilitiesKHR capabilities;
63 vector<VkSurfaceFormatKHR> formats;
64 vector<VkPresentModeKHR> presentModes;
65};
66
[80edd70]67struct Vertex {
68 glm::vec2 pos;
69 glm::vec3 color;
70
71 static VkVertexInputBindingDescription getBindingDescription() {
72 VkVertexInputBindingDescription bindingDescription = {};
73
74 bindingDescription.binding = 0;
75 bindingDescription.stride = sizeof(Vertex);
76 bindingDescription.inputRate = VK_VERTEX_INPUT_RATE_VERTEX;
77
78 return bindingDescription;
79 }
80
81 static array<VkVertexInputAttributeDescription, 2> getAttributeDescriptions() {
82 array<VkVertexInputAttributeDescription, 2> attributeDescriptions = {};
83
84 attributeDescriptions[0].binding = 0;
85 attributeDescriptions[0].location = 0;
86 attributeDescriptions[0].format = VK_FORMAT_R32G32_SFLOAT;
87 attributeDescriptions[0].offset = offsetof(Vertex, pos);
88
89 attributeDescriptions[1].binding = 0;
90 attributeDescriptions[1].location = 1;
91 attributeDescriptions[1].format = VK_FORMAT_R32G32B32_SFLOAT;
92 attributeDescriptions[1].offset = offsetof(Vertex, color);
93
94 return attributeDescriptions;
95 }
96};
97
[de32fda]98struct UniformBufferObject {
[621664a]99 alignas(16) glm::mat4 model;
100 alignas(16) glm::mat4 view;
101 alignas(16) glm::mat4 proj;
[de32fda]102};
103
[80edd70]104const vector<Vertex> vertices = {
[cae7a2c]105 {{-0.5f, -0.5f}, {1.0f, 0.0f, 0.0f}},
106 {{ 0.5f, -0.5f}, {0.0f, 1.0f, 0.0f}},
107 {{ 0.5f, 0.5f}, {0.0f, 0.0f, 1.0f}},
108 {{-0.5f, 0.5f}, {1.0f, 1.0f, 1.0f}}
109};
110
111const vector<uint16_t> indices = {
[621664a]112 0, 1, 2, 2, 3, 0
[80edd70]113};
114
[b6127d2]115VkResult CreateDebugUtilsMessengerEXT(VkInstance instance,
116 const VkDebugUtilsMessengerCreateInfoEXT* pCreateInfo,
117 const VkAllocationCallbacks* pAllocator,
118 VkDebugUtilsMessengerEXT* pDebugMessenger) {
[621664a]119 auto func = (PFN_vkCreateDebugUtilsMessengerEXT) vkGetInstanceProcAddr(instance, "vkCreateDebugUtilsMessengerEXT");
[b6127d2]120
121 if (func != nullptr) {
122 return func(instance, pCreateInfo, pAllocator, pDebugMessenger);
123 } else {
124 return VK_ERROR_EXTENSION_NOT_PRESENT;
125 }
126}
127
[80de39d]128void DestroyDebugUtilsMessengerEXT(VkInstance instance,
129 VkDebugUtilsMessengerEXT debugMessenger,
130 const VkAllocationCallbacks* pAllocator) {
[621664a]131 auto func = (PFN_vkDestroyDebugUtilsMessengerEXT) vkGetInstanceProcAddr(instance, "vkDestroyDebugUtilsMessengerEXT");
[80de39d]132
133 if (func != nullptr) {
134 func(instance, debugMessenger, pAllocator);
135 }
136}
137
[826df16]138class VulkanGame {
139 public:
140 void run() {
141 if (initWindow() == RTWO_ERROR) {
142 return;
143 }
144 initVulkan();
145 mainLoop();
146 cleanup();
147 }
[621664a]148
[826df16]149 private:
[98f3232]150 GameGui* gui = new GameGui_SDL();
[80de39d]151 SDL_Window* window = nullptr;
[826df16]152
153 VkInstance instance;
[b6127d2]154 VkDebugUtilsMessengerEXT debugMessenger;
[b3671b5]155 VkSurfaceKHR surface;
[321272c]156 SDL_Surface* sdlSurface = nullptr;
[b3671b5]157
[909b51a]158 VkPhysicalDevice physicalDevice = VK_NULL_HANDLE;
159 VkDevice device;
[b3671b5]160
[909b51a]161 VkQueue graphicsQueue;
[b3671b5]162 VkQueue presentQueue;
[826df16]163
[bfd620e]164 VkSwapchainKHR swapChain;
165 vector<VkImage> swapChainImages;
166 VkFormat swapChainImageFormat;
167 VkExtent2D swapChainExtent;
168 vector<VkImageView> swapChainImageViews;
[621664a]169 vector<VkFramebuffer> swapChainFramebuffers;
170
[be34c9a]171 VkRenderPass renderPass;
[de32fda]172 VkDescriptorSetLayout descriptorSetLayout;
[84216c7]173 VkPipelineLayout pipelineLayout;
[fd70015]174 VkPipeline graphicsPipeline;
[c7fb883]175 VkDescriptorPool descriptorPool;
176 vector<VkDescriptorSet> descriptorSets;
[bfd620e]177
[f5d5686]178 VkCommandPool commandPool;
179
180 VkImage textureImage;
181 VkDeviceMemory textureImageMemory;
182
[80edd70]183 VkBuffer vertexBuffer;
184 VkDeviceMemory vertexBufferMemory;
[de32fda]185
[cae7a2c]186 VkBuffer indexBuffer;
187 VkDeviceMemory indexBufferMemory;
[80edd70]188
[de32fda]189 vector<VkBuffer> uniformBuffers;
190 vector<VkDeviceMemory> uniformBuffersMemory;
191
[47bff4c]192 vector<VkCommandBuffer> commandBuffers;
193
194 vector<VkSemaphore> imageAvailableSemaphores;
195 vector<VkSemaphore> renderFinishedSemaphores;
196 vector<VkFence> inFlightFences;
197
198 size_t currentFrame = 0;
[ebeb3aa]199
[75108ef]200 bool framebufferResized = false;
201
[826df16]202 bool initWindow() {
[98f3232]203 if (gui->Init() == RTWO_ERROR) {
[826df16]204 cout << "UI library could not be initialized!" << endl;
205 return RTWO_ERROR;
206 } else {
[0e6ecf3]207 window = (SDL_Window*) gui->CreateWindow("Vulkan Game", SCREEN_WIDTH, SCREEN_HEIGHT);
[826df16]208
[80de39d]209 if (window == nullptr) {
[826df16]210 cout << "Window could not be created!" << endl;
211 return RTWO_ERROR;
212 } else {
213 return RTWO_SUCCESS;
214 }
215 }
216 }
217
218 void initVulkan() {
219 createInstance();
[7dcd925]220 setupDebugMessenger();
[b3671b5]221 createSurface();
[909b51a]222 pickPhysicalDevice();
223 createLogicalDevice();
[bfd620e]224 createSwapChain();
225 createImageViews();
[be34c9a]226 createRenderPass();
[de32fda]227 createDescriptorSetLayout();
[4befb76]228 createGraphicsPipeline();
[ebeb3aa]229 createFramebuffers();
[47bff4c]230 createCommandPool();
[eea05dd]231 createTextureImage();
[80edd70]232 createVertexBuffer();
[cae7a2c]233 createIndexBuffer();
[de32fda]234 createUniformBuffers();
[c7fb883]235 createDescriptorPool();
236 createDescriptorSets();
[47bff4c]237 createCommandBuffers();
238 createSyncObjects();
[826df16]239 }
240
241 void createInstance() {
[b6127d2]242 if (enableValidationLayers && !checkValidationLayerSupport()) {
243 throw runtime_error("validation layers requested, but not available!");
244 }
245
[826df16]246 VkApplicationInfo appInfo = {};
247 appInfo.sType = VK_STRUCTURE_TYPE_APPLICATION_INFO;
248 appInfo.pApplicationName = "Vulkan Game";
249 appInfo.applicationVersion = VK_MAKE_VERSION(1, 0, 0);
250 appInfo.pEngineName = "No Engine";
251 appInfo.engineVersion = VK_MAKE_VERSION(1, 0, 0);
252 appInfo.apiVersion = VK_API_VERSION_1_0;
253
254 VkInstanceCreateInfo createInfo = {};
255 createInfo.sType = VK_STRUCTURE_TYPE_INSTANCE_CREATE_INFO;
256 createInfo.pApplicationInfo = &appInfo;
257
[a8f0577]258 vector<const char*> extensions = getRequiredExtensions();
[b6127d2]259 createInfo.enabledExtensionCount = static_cast<uint32_t>(extensions.size());
260 createInfo.ppEnabledExtensionNames = extensions.data();
[826df16]261
[8667f76]262 cout << endl << "Extensions:" << endl;
[b3671b5]263 for (const char* extensionName : extensions) {
264 cout << extensionName << endl;
265 }
266 cout << endl;
267
[80de39d]268 VkDebugUtilsMessengerCreateInfoEXT debugCreateInfo;
[b6127d2]269 if (enableValidationLayers) {
270 createInfo.enabledLayerCount = static_cast<uint32_t>(validationLayers.size());
271 createInfo.ppEnabledLayerNames = validationLayers.data();
[80de39d]272
273 populateDebugMessengerCreateInfo(debugCreateInfo);
274 createInfo.pNext = &debugCreateInfo;
[b6127d2]275 } else {
276 createInfo.enabledLayerCount = 0;
[80de39d]277
278 createInfo.pNext = nullptr;
[b6127d2]279 }
[826df16]280
281 if (vkCreateInstance(&createInfo, nullptr, &instance) != VK_SUCCESS) {
282 throw runtime_error("failed to create instance!");
283 }
284 }
285
[621664a]286 bool checkValidationLayerSupport() {
287 uint32_t layerCount;
288 vkEnumerateInstanceLayerProperties(&layerCount, nullptr);
289
290 vector<VkLayerProperties> availableLayers(layerCount);
291 vkEnumerateInstanceLayerProperties(&layerCount, availableLayers.data());
292
293 for (const char* layerName : validationLayers) {
294 bool layerFound = false;
295
296 for (const auto& layerProperties : availableLayers) {
297 if (strcmp(layerName, layerProperties.layerName) == 0) {
298 layerFound = true;
299 break;
300 }
301 }
302
303 if (!layerFound) {
304 return false;
305 }
306 }
307
308 return true;
309 }
310
311 vector<const char*> getRequiredExtensions() {
312 vector<const char*> extensions = gui->GetRequiredExtensions();
313
314 if (enableValidationLayers) {
315 extensions.push_back(VK_EXT_DEBUG_UTILS_EXTENSION_NAME);
316 }
317
318 return extensions;
319 }
320
[80de39d]321 void setupDebugMessenger() {
322 if (!enableValidationLayers) return;
323
324 VkDebugUtilsMessengerCreateInfoEXT createInfo;
325 populateDebugMessengerCreateInfo(createInfo);
[b6127d2]326
327 if (CreateDebugUtilsMessengerEXT(instance, &createInfo, nullptr, &debugMessenger) != VK_SUCCESS) {
[621664a]328 throw runtime_error("failed to set up debug messenger!");
[b6127d2]329 }
330 }
331
[621664a]332 void populateDebugMessengerCreateInfo(VkDebugUtilsMessengerCreateInfoEXT& createInfo) {
333 createInfo = {};
334 createInfo.sType = VK_STRUCTURE_TYPE_DEBUG_UTILS_MESSENGER_CREATE_INFO_EXT;
335 createInfo.messageSeverity = VK_DEBUG_UTILS_MESSAGE_SEVERITY_VERBOSE_BIT_EXT | VK_DEBUG_UTILS_MESSAGE_SEVERITY_WARNING_BIT_EXT | VK_DEBUG_UTILS_MESSAGE_SEVERITY_ERROR_BIT_EXT;
336 createInfo.messageType = VK_DEBUG_UTILS_MESSAGE_TYPE_GENERAL_BIT_EXT | VK_DEBUG_UTILS_MESSAGE_TYPE_VALIDATION_BIT_EXT | VK_DEBUG_UTILS_MESSAGE_TYPE_PERFORMANCE_BIT_EXT;
337 createInfo.pfnUserCallback = debugCallback;
338 }
339
[b3671b5]340 void createSurface() {
[321272c]341 sdlSurface = SDL_GetWindowSurface(window);
342
343 if (sdlSurface == nullptr) {
[621664a]344 cout << "Could not get SDL Surface! =(" << endl;
[321272c]345 }
[b3671b5]346
[0e6ecf3]347 if (gui->CreateVulkanSurface(instance, &surface) == RTWO_ERROR) {
[b3671b5]348 throw runtime_error("failed to create window surface!");
349 }
350 }
351
[909b51a]352 void pickPhysicalDevice() {
353 uint32_t deviceCount = 0;
354 vkEnumeratePhysicalDevices(instance, &deviceCount, nullptr);
355
356 if (deviceCount == 0) {
357 throw runtime_error("failed to find GPUs with Vulkan support!");
358 }
359
360 vector<VkPhysicalDevice> devices(deviceCount);
361 vkEnumeratePhysicalDevices(instance, &deviceCount, devices.data());
362
363 cout << endl << "Graphics cards:" << endl;
364 for (const VkPhysicalDevice& device : devices) {
365 if (isDeviceSuitable(device)) {
366 physicalDevice = device;
367 break;
368 }
369 }
370 cout << endl;
371
372 if (physicalDevice == VK_NULL_HANDLE) {
373 throw runtime_error("failed to find a suitable GPU!");
374 }
375 }
376
377 bool isDeviceSuitable(VkPhysicalDevice device) {
378 VkPhysicalDeviceProperties deviceProperties;
379 VkPhysicalDeviceFeatures deviceFeatures;
380
381 vkGetPhysicalDeviceProperties(device, &deviceProperties);
382 vkGetPhysicalDeviceFeatures(device, &deviceFeatures);
383
384 cout << "Device: " << deviceProperties.deviceName << endl;
385
386 QueueFamilyIndices indices = findQueueFamilies(device);
[bfd620e]387 bool extensionsSupported = checkDeviceExtensionSupport(device);
388 bool swapChainAdequate = false;
389
390 if (extensionsSupported) {
391 SwapChainSupportDetails swapChainSupport = querySwapChainSupport(device);
392 swapChainAdequate = !swapChainSupport.formats.empty() && !swapChainSupport.presentModes.empty();
393 }
394
395 return indices.isComplete() && extensionsSupported && swapChainAdequate;
396 }
397
398 bool checkDeviceExtensionSupport(VkPhysicalDevice device) {
399 uint32_t extensionCount;
400 vkEnumerateDeviceExtensionProperties(device, nullptr, &extensionCount, nullptr);
401
402 vector<VkExtensionProperties> availableExtensions(extensionCount);
403 vkEnumerateDeviceExtensionProperties(device, nullptr, &extensionCount, availableExtensions.data());
404
405 set<string> requiredExtensions(deviceExtensions.begin(), deviceExtensions.end());
406
407 for (const auto& extension : availableExtensions) {
408 requiredExtensions.erase(extension.extensionName);
409 }
410
411 return requiredExtensions.empty();
[909b51a]412 }
413
414 void createLogicalDevice() {
415 QueueFamilyIndices indices = findQueueFamilies(physicalDevice);
416
[b3671b5]417 vector<VkDeviceQueueCreateInfo> queueCreateInfos;
418 set<uint32_t> uniqueQueueFamilies = {indices.graphicsFamily.value(), indices.presentFamily.value()};
[909b51a]419
420 float queuePriority = 1.0f;
[b3671b5]421 for (uint32_t queueFamily : uniqueQueueFamilies) {
422 VkDeviceQueueCreateInfo queueCreateInfo = {};
423 queueCreateInfo.sType = VK_STRUCTURE_TYPE_DEVICE_QUEUE_CREATE_INFO;
424 queueCreateInfo.queueFamilyIndex = queueFamily;
425 queueCreateInfo.queueCount = 1;
426 queueCreateInfo.pQueuePriorities = &queuePriority;
427
428 queueCreateInfos.push_back(queueCreateInfo);
429 }
[909b51a]430
431 VkPhysicalDeviceFeatures deviceFeatures = {};
432
433 VkDeviceCreateInfo createInfo = {};
434 createInfo.sType = VK_STRUCTURE_TYPE_DEVICE_CREATE_INFO;
[621664a]435 createInfo.queueCreateInfoCount = static_cast<uint32_t>(queueCreateInfos.size());
[b3671b5]436 createInfo.pQueueCreateInfos = queueCreateInfos.data();
[909b51a]437
438 createInfo.pEnabledFeatures = &deviceFeatures;
439
[bfd620e]440 createInfo.enabledExtensionCount = static_cast<uint32_t>(deviceExtensions.size());
441 createInfo.ppEnabledExtensionNames = deviceExtensions.data();
[909b51a]442
443 // These fields are ignored by up-to-date Vulkan implementations,
444 // but it's a good idea to set them for backwards compatibility
445 if (enableValidationLayers) {
446 createInfo.enabledLayerCount = static_cast<uint32_t>(validationLayers.size());
447 createInfo.ppEnabledLayerNames = validationLayers.data();
448 } else {
449 createInfo.enabledLayerCount = 0;
450 }
451
452 if (vkCreateDevice(physicalDevice, &createInfo, nullptr, &device) != VK_SUCCESS) {
453 throw runtime_error("failed to create logical device!");
454 }
455
456 vkGetDeviceQueue(device, indices.graphicsFamily.value(), 0, &graphicsQueue);
[b3671b5]457 vkGetDeviceQueue(device, indices.presentFamily.value(), 0, &presentQueue);
[909b51a]458 }
459
[621664a]460 void createSwapChain() {
461 SwapChainSupportDetails swapChainSupport = querySwapChainSupport(physicalDevice);
[a8f0577]462
[621664a]463 VkSurfaceFormatKHR surfaceFormat = chooseSwapSurfaceFormat(swapChainSupport.formats);
464 VkPresentModeKHR presentMode = chooseSwapPresentMode(swapChainSupport.presentModes);
465 VkExtent2D extent = chooseSwapExtent(swapChainSupport.capabilities);
[a8f0577]466
[621664a]467 uint32_t imageCount = swapChainSupport.capabilities.minImageCount + 1;
468 if (swapChainSupport.capabilities.maxImageCount > 0 && imageCount > swapChainSupport.capabilities.maxImageCount) {
469 imageCount = swapChainSupport.capabilities.maxImageCount;
[a8f0577]470 }
471
[621664a]472 VkSwapchainCreateInfoKHR createInfo = {};
473 createInfo.sType = VK_STRUCTURE_TYPE_SWAPCHAIN_CREATE_INFO_KHR;
474 createInfo.surface = surface;
475 createInfo.minImageCount = imageCount;
476 createInfo.imageFormat = surfaceFormat.format;
477 createInfo.imageColorSpace = surfaceFormat.colorSpace;
478 createInfo.imageExtent = extent;
479 createInfo.imageArrayLayers = 1;
480 createInfo.imageUsage = VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT;
[909b51a]481
[621664a]482 QueueFamilyIndices indices = findQueueFamilies(physicalDevice);
483 uint32_t queueFamilyIndices[] = {indices.graphicsFamily.value(), indices.presentFamily.value()};
[b3671b5]484
[621664a]485 if (indices.graphicsFamily != indices.presentFamily) {
486 createInfo.imageSharingMode = VK_SHARING_MODE_CONCURRENT;
487 createInfo.queueFamilyIndexCount = 2;
488 createInfo.pQueueFamilyIndices = queueFamilyIndices;
489 } else {
490 createInfo.imageSharingMode = VK_SHARING_MODE_EXCLUSIVE;
491 createInfo.queueFamilyIndexCount = 0;
492 createInfo.pQueueFamilyIndices = nullptr;
493 }
[b3671b5]494
[621664a]495 createInfo.preTransform = swapChainSupport.capabilities.currentTransform;
496 createInfo.compositeAlpha = VK_COMPOSITE_ALPHA_OPAQUE_BIT_KHR;
497 createInfo.presentMode = presentMode;
498 createInfo.clipped = VK_TRUE;
499 createInfo.oldSwapchain = VK_NULL_HANDLE;
[909b51a]500
[621664a]501 if (vkCreateSwapchainKHR(device, &createInfo, nullptr, &swapChain) != VK_SUCCESS) {
502 throw runtime_error("failed to create swap chain!");
[909b51a]503 }
504
[621664a]505 vkGetSwapchainImagesKHR(device, swapChain, &imageCount, nullptr);
506 swapChainImages.resize(imageCount);
507 vkGetSwapchainImagesKHR(device, swapChain, &imageCount, swapChainImages.data());
508
509 swapChainImageFormat = surfaceFormat.format;
510 swapChainExtent = extent;
[909b51a]511 }
512
[bfd620e]513 SwapChainSupportDetails querySwapChainSupport(VkPhysicalDevice device) {
514 SwapChainSupportDetails details;
515
516 vkGetPhysicalDeviceSurfaceCapabilitiesKHR(device, surface, &details.capabilities);
517
518 uint32_t formatCount;
519 vkGetPhysicalDeviceSurfaceFormatsKHR(device, surface, &formatCount, nullptr);
520
521 if (formatCount != 0) {
522 details.formats.resize(formatCount);
523 vkGetPhysicalDeviceSurfaceFormatsKHR(device, surface, &formatCount, details.formats.data());
524 }
525
526 uint32_t presentModeCount;
527 vkGetPhysicalDeviceSurfacePresentModesKHR(device, surface, &presentModeCount, nullptr);
528
529 if (presentModeCount != 0) {
530 details.presentModes.resize(presentModeCount);
531 vkGetPhysicalDeviceSurfacePresentModesKHR(device, surface, &presentModeCount, details.presentModes.data());
532 }
533
534 return details;
535 }
536
537 VkSurfaceFormatKHR chooseSwapSurfaceFormat(const vector<VkSurfaceFormatKHR>& availableFormats) {
538 for (const auto& availableFormat : availableFormats) {
539 if (availableFormat.format == VK_FORMAT_B8G8R8A8_UNORM && availableFormat.colorSpace == VK_COLOR_SPACE_SRGB_NONLINEAR_KHR) {
540 return availableFormat;
541 }
542 }
543
544 return availableFormats[0];
545 }
546
547 VkPresentModeKHR chooseSwapPresentMode(const vector<VkPresentModeKHR>& availablePresentModes) {
548 VkPresentModeKHR bestMode = VK_PRESENT_MODE_FIFO_KHR;
549
550 for (const auto& availablePresentMode : availablePresentModes) {
551 if (availablePresentMode == VK_PRESENT_MODE_MAILBOX_KHR) {
552 return availablePresentMode;
[621664a]553 }
554 else if (availablePresentMode == VK_PRESENT_MODE_IMMEDIATE_KHR) {
[bfd620e]555 bestMode = availablePresentMode;
556 }
557 }
558
559 return bestMode;
560 }
561
562 VkExtent2D chooseSwapExtent(const VkSurfaceCapabilitiesKHR& capabilities) {
563 if (capabilities.currentExtent.width != numeric_limits<uint32_t>::max()) {
564 return capabilities.currentExtent;
[621664a]565 }
566 else {
[75108ef]567 int width, height;
[8667f76]568 gui->GetWindowSize(&width, &height);
[75108ef]569
570 VkExtent2D actualExtent = {
571 static_cast<uint32_t>(width),
572 static_cast<uint32_t>(height)
573 };
[bfd620e]574
575 actualExtent.width = max(capabilities.minImageExtent.width, min(capabilities.maxImageExtent.width, actualExtent.width));
576 actualExtent.height = max(capabilities.minImageExtent.height, min(capabilities.maxImageExtent.height, actualExtent.height));
577
578 return actualExtent;
579 }
580 }
581
582 void createImageViews() {
583 swapChainImageViews.resize(swapChainImages.size());
584
[621664a]585 for (size_t i = 0; i < swapChainImages.size(); i++) {
[bfd620e]586 VkImageViewCreateInfo createInfo = {};
587 createInfo.sType = VK_STRUCTURE_TYPE_IMAGE_VIEW_CREATE_INFO;
588 createInfo.image = swapChainImages[i];
589 createInfo.viewType = VK_IMAGE_VIEW_TYPE_2D;
590 createInfo.format = swapChainImageFormat;
591
592 createInfo.components.r = VK_COMPONENT_SWIZZLE_IDENTITY;
593 createInfo.components.g = VK_COMPONENT_SWIZZLE_IDENTITY;
594 createInfo.components.b = VK_COMPONENT_SWIZZLE_IDENTITY;
595 createInfo.components.a = VK_COMPONENT_SWIZZLE_IDENTITY;
596
597 createInfo.subresourceRange.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT;
598 createInfo.subresourceRange.baseMipLevel = 0;
599 createInfo.subresourceRange.levelCount = 1;
600 createInfo.subresourceRange.baseArrayLayer = 0;
601 createInfo.subresourceRange.layerCount = 1;
602
603 if (vkCreateImageView(device, &createInfo, nullptr, &swapChainImageViews[i]) != VK_SUCCESS) {
604 throw runtime_error("failed to create image views!");
605 }
606 }
607 }
608
[be34c9a]609 void createRenderPass() {
610 VkAttachmentDescription colorAttachment = {};
611 colorAttachment.format = swapChainImageFormat;
612 colorAttachment.samples = VK_SAMPLE_COUNT_1_BIT;
613 colorAttachment.loadOp = VK_ATTACHMENT_LOAD_OP_CLEAR;
614 colorAttachment.storeOp = VK_ATTACHMENT_STORE_OP_STORE;
615 colorAttachment.stencilLoadOp = VK_ATTACHMENT_LOAD_OP_DONT_CARE;
616 colorAttachment.stencilStoreOp = VK_ATTACHMENT_STORE_OP_DONT_CARE;
617 colorAttachment.initialLayout = VK_IMAGE_LAYOUT_UNDEFINED;
618 colorAttachment.finalLayout = VK_IMAGE_LAYOUT_PRESENT_SRC_KHR;
619
620 VkAttachmentReference colorAttachmentRef = {};
621 colorAttachmentRef.attachment = 0;
622 colorAttachmentRef.layout = VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL;
623
624 VkSubpassDescription subpass = {};
625 subpass.pipelineBindPoint = VK_PIPELINE_BIND_POINT_GRAPHICS;
626 subpass.colorAttachmentCount = 1;
627 subpass.pColorAttachments = &colorAttachmentRef;
628
[621664a]629 VkSubpassDependency dependency = {};
[47bff4c]630 dependency.srcSubpass = VK_SUBPASS_EXTERNAL;
631 dependency.dstSubpass = 0;
632 dependency.srcStageMask = VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT;
633 dependency.srcAccessMask = 0;
634 dependency.dstStageMask = VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT;
635 dependency.dstAccessMask = VK_ACCESS_COLOR_ATTACHMENT_READ_BIT | VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT;
636
[be34c9a]637 VkRenderPassCreateInfo renderPassInfo = {};
638 renderPassInfo.sType = VK_STRUCTURE_TYPE_RENDER_PASS_CREATE_INFO;
639 renderPassInfo.attachmentCount = 1;
640 renderPassInfo.pAttachments = &colorAttachment;
641 renderPassInfo.subpassCount = 1;
642 renderPassInfo.pSubpasses = &subpass;
[47bff4c]643 renderPassInfo.dependencyCount = 1;
644 renderPassInfo.pDependencies = &dependency;
[be34c9a]645
646 if (vkCreateRenderPass(device, &renderPassInfo, nullptr, &renderPass) != VK_SUCCESS) {
647 throw runtime_error("failed to create render pass!");
648 }
649 }
650
[de32fda]651 void createDescriptorSetLayout() {
652 VkDescriptorSetLayoutBinding uboLayoutBinding = {};
653 uboLayoutBinding.binding = 0;
654 uboLayoutBinding.descriptorType = VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER;
655 uboLayoutBinding.descriptorCount = 1;
656 uboLayoutBinding.stageFlags = VK_SHADER_STAGE_VERTEX_BIT;
657 uboLayoutBinding.pImmutableSamplers = nullptr;
658
659 VkDescriptorSetLayoutCreateInfo layoutInfo = {};
660 layoutInfo.sType = VK_STRUCTURE_TYPE_DESCRIPTOR_SET_LAYOUT_CREATE_INFO;
661 layoutInfo.bindingCount = 1;
662 layoutInfo.pBindings = &uboLayoutBinding;
663
664 if (vkCreateDescriptorSetLayout(device, &layoutInfo, nullptr, &descriptorSetLayout) != VK_SUCCESS) {
665 throw runtime_error("failed to create descriptor set layout!");
666 }
667 }
668
[4befb76]669 void createGraphicsPipeline() {
[e09ad38]670 auto vertShaderCode = readFile("shaders/vert.spv");
671 auto fragShaderCode = readFile("shaders/frag.spv");
672
673 VkShaderModule vertShaderModule = createShaderModule(vertShaderCode);
674 VkShaderModule fragShaderModule = createShaderModule(fragShaderCode);
675
676 VkPipelineShaderStageCreateInfo vertShaderStageInfo = {};
677 vertShaderStageInfo.sType = VK_STRUCTURE_TYPE_PIPELINE_SHADER_STAGE_CREATE_INFO;
678 vertShaderStageInfo.stage = VK_SHADER_STAGE_VERTEX_BIT;
679 vertShaderStageInfo.module = vertShaderModule;
680 vertShaderStageInfo.pName = "main";
681
682 VkPipelineShaderStageCreateInfo fragShaderStageInfo = {};
683 fragShaderStageInfo.sType = VK_STRUCTURE_TYPE_PIPELINE_SHADER_STAGE_CREATE_INFO;
684 fragShaderStageInfo.stage = VK_SHADER_STAGE_FRAGMENT_BIT;
685 fragShaderStageInfo.module = fragShaderModule;
686 fragShaderStageInfo.pName = "main";
687
688 VkPipelineShaderStageCreateInfo shaderStages[] = { vertShaderStageInfo, fragShaderStageInfo };
689
[84216c7]690 VkPipelineVertexInputStateCreateInfo vertexInputInfo = {};
691 vertexInputInfo.sType = VK_STRUCTURE_TYPE_PIPELINE_VERTEX_INPUT_STATE_CREATE_INFO;
[80edd70]692
693 auto bindingDescription = Vertex::getBindingDescription();
694 auto attributeDescriptions = Vertex::getAttributeDescriptions();
695
696 vertexInputInfo.vertexBindingDescriptionCount = 1;
697 vertexInputInfo.vertexAttributeDescriptionCount = static_cast<uint32_t>(attributeDescriptions.size());
698 vertexInputInfo.pVertexBindingDescriptions = &bindingDescription;
699 vertexInputInfo.pVertexAttributeDescriptions = attributeDescriptions.data();
[84216c7]700
701 VkPipelineInputAssemblyStateCreateInfo inputAssembly = {};
702 inputAssembly.sType = VK_STRUCTURE_TYPE_PIPELINE_INPUT_ASSEMBLY_STATE_CREATE_INFO;
703 inputAssembly.topology = VK_PRIMITIVE_TOPOLOGY_TRIANGLE_LIST;
704 inputAssembly.primitiveRestartEnable = VK_FALSE;
705
706 VkViewport viewport = {};
707 viewport.x = 0.0f;
708 viewport.y = 0.0f;
709 viewport.width = (float) swapChainExtent.width;
710 viewport.height = (float) swapChainExtent.height;
711 viewport.minDepth = 0.0f;
712 viewport.maxDepth = 1.0f;
713
714 VkRect2D scissor = {};
715 scissor.offset = { 0, 0 };
716 scissor.extent = swapChainExtent;
717
718 VkPipelineViewportStateCreateInfo viewportState = {};
719 viewportState.sType = VK_STRUCTURE_TYPE_PIPELINE_VIEWPORT_STATE_CREATE_INFO;
720 viewportState.viewportCount = 1;
721 viewportState.pViewports = &viewport;
722 viewportState.scissorCount = 1;
723 viewportState.pScissors = &scissor;
724
725 VkPipelineRasterizationStateCreateInfo rasterizer = {};
726 rasterizer.sType = VK_STRUCTURE_TYPE_PIPELINE_RASTERIZATION_STATE_CREATE_INFO;
727 rasterizer.depthClampEnable = VK_FALSE;
728 rasterizer.rasterizerDiscardEnable = VK_FALSE;
729 rasterizer.polygonMode = VK_POLYGON_MODE_FILL;
730 rasterizer.lineWidth = 1.0f;
731 rasterizer.cullMode = VK_CULL_MODE_BACK_BIT;
[c7fb883]732 rasterizer.frontFace = VK_FRONT_FACE_COUNTER_CLOCKWISE;
[621664a]733 rasterizer.depthBiasEnable = VK_FALSE;
[84216c7]734
735 VkPipelineMultisampleStateCreateInfo multisampling = {};
736 multisampling.sType = VK_STRUCTURE_TYPE_PIPELINE_MULTISAMPLE_STATE_CREATE_INFO;
737 multisampling.sampleShadingEnable = VK_FALSE;
738 multisampling.rasterizationSamples = VK_SAMPLE_COUNT_1_BIT;
739
740 VkPipelineColorBlendAttachmentState colorBlendAttachment = {};
741 colorBlendAttachment.colorWriteMask = VK_COLOR_COMPONENT_R_BIT | VK_COLOR_COMPONENT_G_BIT | VK_COLOR_COMPONENT_B_BIT | VK_COLOR_COMPONENT_A_BIT;
742 colorBlendAttachment.blendEnable = VK_FALSE;
743
744 VkPipelineColorBlendStateCreateInfo colorBlending = {};
745 colorBlending.sType = VK_STRUCTURE_TYPE_PIPELINE_COLOR_BLEND_STATE_CREATE_INFO;
746 colorBlending.logicOpEnable = VK_FALSE;
747 colorBlending.logicOp = VK_LOGIC_OP_COPY;
748 colorBlending.attachmentCount = 1;
749 colorBlending.pAttachments = &colorBlendAttachment;
750 colorBlending.blendConstants[0] = 0.0f;
751 colorBlending.blendConstants[1] = 0.0f;
752 colorBlending.blendConstants[2] = 0.0f;
753 colorBlending.blendConstants[3] = 0.0f;
754
755 VkPipelineLayoutCreateInfo pipelineLayoutInfo = {};
756 pipelineLayoutInfo.sType = VK_STRUCTURE_TYPE_PIPELINE_LAYOUT_CREATE_INFO;
[de32fda]757 pipelineLayoutInfo.setLayoutCount = 1;
758 pipelineLayoutInfo.pSetLayouts = &descriptorSetLayout;
[84216c7]759 pipelineLayoutInfo.pushConstantRangeCount = 0;
760
761 if (vkCreatePipelineLayout(device, &pipelineLayoutInfo, nullptr, &pipelineLayout) != VK_SUCCESS) {
762 throw runtime_error("failed to create pipeline layout!");
763 }
764
[fd70015]765 VkGraphicsPipelineCreateInfo pipelineInfo = {};
766 pipelineInfo.sType = VK_STRUCTURE_TYPE_GRAPHICS_PIPELINE_CREATE_INFO;
767 pipelineInfo.stageCount = 2;
768 pipelineInfo.pStages = shaderStages;
769 pipelineInfo.pVertexInputState = &vertexInputInfo;
770 pipelineInfo.pInputAssemblyState = &inputAssembly;
771 pipelineInfo.pViewportState = &viewportState;
772 pipelineInfo.pRasterizationState = &rasterizer;
773 pipelineInfo.pMultisampleState = &multisampling;
774 pipelineInfo.pDepthStencilState = nullptr;
775 pipelineInfo.pColorBlendState = &colorBlending;
776 pipelineInfo.pDynamicState = nullptr;
777 pipelineInfo.layout = pipelineLayout;
778 pipelineInfo.renderPass = renderPass;
779 pipelineInfo.subpass = 0;
780 pipelineInfo.basePipelineHandle = VK_NULL_HANDLE;
781 pipelineInfo.basePipelineIndex = -1;
782
783 if (vkCreateGraphicsPipelines(device, VK_NULL_HANDLE, 1, &pipelineInfo, nullptr, &graphicsPipeline) != VK_SUCCESS) {
784 throw runtime_error("failed to create graphics pipeline!");
785 }
786
[e09ad38]787 vkDestroyShaderModule(device, vertShaderModule, nullptr);
788 vkDestroyShaderModule(device, fragShaderModule, nullptr);
789 }
790
791 VkShaderModule createShaderModule(const vector<char>& code) {
792 VkShaderModuleCreateInfo createInfo = {};
793 createInfo.sType = VK_STRUCTURE_TYPE_SHADER_MODULE_CREATE_INFO;
794 createInfo.codeSize = code.size();
795 createInfo.pCode = reinterpret_cast<const uint32_t*>(code.data());
796
797 VkShaderModule shaderModule;
798 if (vkCreateShaderModule(device, &createInfo, nullptr, &shaderModule) != VK_SUCCESS) {
799 throw runtime_error("failed to create shader module!");
800 }
801
802 return shaderModule;
[4befb76]803 }
804
[ebeb3aa]805 void createFramebuffers() {
806 swapChainFramebuffers.resize(swapChainImageViews.size());
807
808 for (size_t i = 0; i < swapChainImageViews.size(); i++) {
809 VkImageView attachments[] = {
810 swapChainImageViews[i]
811 };
812
813 VkFramebufferCreateInfo framebufferInfo = {};
814 framebufferInfo.sType = VK_STRUCTURE_TYPE_FRAMEBUFFER_CREATE_INFO;
815 framebufferInfo.renderPass = renderPass;
816 framebufferInfo.attachmentCount = 1;
817 framebufferInfo.pAttachments = attachments;
818 framebufferInfo.width = swapChainExtent.width;
819 framebufferInfo.height = swapChainExtent.height;
820 framebufferInfo.layers = 1;
821
822 if (vkCreateFramebuffer(device, &framebufferInfo, nullptr, &swapChainFramebuffers[i]) != VK_SUCCESS) {
823 throw runtime_error("failed to create framebuffer!");
824 }
825 }
826 }
827
[47bff4c]828 void createCommandPool() {
829 QueueFamilyIndices queueFamilyIndices = findQueueFamilies(physicalDevice);
830
831 VkCommandPoolCreateInfo poolInfo = {};
832 poolInfo.sType = VK_STRUCTURE_TYPE_COMMAND_POOL_CREATE_INFO;
833 poolInfo.queueFamilyIndex = queueFamilyIndices.graphicsFamily.value();
834 poolInfo.flags = 0;
835
836 if (vkCreateCommandPool(device, &poolInfo, nullptr, &commandPool) != VK_SUCCESS) {
[621664a]837 throw runtime_error("failed to create graphics command pool!");
[47bff4c]838 }
839 }
840
[621664a]841 QueueFamilyIndices findQueueFamilies(VkPhysicalDevice device) {
842 QueueFamilyIndices indices;
843
844 uint32_t queueFamilyCount = 0;
845 vkGetPhysicalDeviceQueueFamilyProperties(device, &queueFamilyCount, nullptr);
846
847 vector<VkQueueFamilyProperties> queueFamilies(queueFamilyCount);
848 vkGetPhysicalDeviceQueueFamilyProperties(device, &queueFamilyCount, queueFamilies.data());
849
850 int i = 0;
851 for (const auto& queueFamily : queueFamilies) {
852 if (queueFamily.queueCount > 0 && queueFamily.queueFlags & VK_QUEUE_GRAPHICS_BIT) {
853 indices.graphicsFamily = i;
854 }
855
856 VkBool32 presentSupport = false;
857 vkGetPhysicalDeviceSurfaceSupportKHR(device, i, surface, &presentSupport);
858
859 if (queueFamily.queueCount > 0 && presentSupport) {
860 indices.presentFamily = i;
861 }
862
863 if (indices.isComplete()) {
864 break;
865 }
866
867 i++;
868 }
869
870 return indices;
871 }
872
[eea05dd]873 void createTextureImage() {
874 int texWidth, texHeight, texChannels;
875
876 stbi_uc* pixels = stbi_load("textures/texture.jpg", &texWidth, &texHeight, &texChannels, STBI_rgb_alpha);
877 VkDeviceSize imageSize = texWidth * texHeight * 4;
878
879 if (!pixels) {
880 throw runtime_error("failed to load texture image!");
881 }
882
883 VkBuffer stagingBuffer;
884 VkDeviceMemory stagingBufferMemory;
885
886 createBuffer(imageSize, VK_BUFFER_USAGE_TRANSFER_SRC_BIT,
887 VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT | VK_MEMORY_PROPERTY_HOST_COHERENT_BIT,
888 stagingBuffer, stagingBufferMemory);
889
890 void* data;
891
892 vkMapMemory(device, stagingBufferMemory, 0, imageSize, 0, &data);
893 memcpy(data, pixels, static_cast<size_t>(imageSize));
894 vkUnmapMemory(device, stagingBufferMemory);
895
896 stbi_image_free(pixels);
897
898 createImage(texWidth, texHeight, VK_FORMAT_R8G8B8A8_UNORM, VK_IMAGE_TILING_OPTIMAL,
899 VK_IMAGE_USAGE_TRANSFER_DST_BIT | VK_IMAGE_USAGE_SAMPLED_BIT,
900 VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT, textureImage, textureImageMemory);
901
902 transitionImageLayout(textureImage, VK_FORMAT_R8G8B8A8_UNORM, VK_IMAGE_LAYOUT_UNDEFINED, VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL);
903 copyBufferToImage(stagingBuffer, textureImage, static_cast<uint32_t>(texWidth), static_cast<uint32_t>(texHeight));
904 transitionImageLayout(textureImage, VK_FORMAT_R8G8B8A8_UNORM, VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL);
905
906 vkDestroyBuffer(device, stagingBuffer, nullptr);
[f5d5686]907 vkFreeMemory(device, stagingBufferMemory, nullptr);
[eea05dd]908 }
909
[621664a]910 void createImage(uint32_t width, uint32_t height, VkFormat format, VkImageTiling tiling, VkImageUsageFlags usage,
911 VkMemoryPropertyFlags properties, VkImage& image, VkDeviceMemory& imageMemory) {
[eea05dd]912 VkImageCreateInfo imageInfo = {};
913 imageInfo.sType = VK_STRUCTURE_TYPE_IMAGE_CREATE_INFO;
914 imageInfo.imageType = VK_IMAGE_TYPE_2D;
915 imageInfo.extent.width = width;
916 imageInfo.extent.height = height;
917 imageInfo.extent.depth = 1;
918 imageInfo.mipLevels = 1;
919 imageInfo.arrayLayers = 1;
920 imageInfo.format = format;
921 imageInfo.tiling = tiling;
922 imageInfo.initialLayout = VK_IMAGE_LAYOUT_UNDEFINED;
923 imageInfo.usage = usage;
924 imageInfo.samples = VK_SAMPLE_COUNT_1_BIT;
925 imageInfo.sharingMode = VK_SHARING_MODE_EXCLUSIVE;
926
927 if (vkCreateImage(device, &imageInfo, nullptr, &image) != VK_SUCCESS) {
928 throw runtime_error("failed to create image!");
929 }
930
931 VkMemoryRequirements memRequirements;
932 vkGetImageMemoryRequirements(device, image, &memRequirements);
933
[621664a]934 VkMemoryAllocateInfo allocInfo = {};
[eea05dd]935 allocInfo.sType = VK_STRUCTURE_TYPE_MEMORY_ALLOCATE_INFO;
936 allocInfo.allocationSize = memRequirements.size;
937 allocInfo.memoryTypeIndex = findMemoryType(memRequirements.memoryTypeBits, properties);
938
939 if (vkAllocateMemory(device, &allocInfo, nullptr, &imageMemory) != VK_SUCCESS) {
940 throw runtime_error("failed to allocate image memory!");
941 }
942
943 vkBindImageMemory(device, image, imageMemory, 0);
944 }
945
[621664a]946 void transitionImageLayout(VkImage image, VkFormat format, VkImageLayout oldLayout, VkImageLayout newLayout) {
[eea05dd]947 VkCommandBuffer commandBuffer = beginSingleTimeCommands();
948
949 VkImageMemoryBarrier barrier = {};
950 barrier.sType = VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER;
951 barrier.oldLayout = oldLayout;
952 barrier.newLayout = newLayout;
953 barrier.srcQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED;
954 barrier.dstQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED;
955 barrier.image = image;
956 barrier.subresourceRange.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT;
957 barrier.subresourceRange.baseMipLevel = 0;
958 barrier.subresourceRange.levelCount = 1;
959 barrier.subresourceRange.baseArrayLayer = 0;
960 barrier.subresourceRange.layerCount = 1;
[f5d5686]961
962 VkPipelineStageFlags sourceStage;
963 VkPipelineStageFlags destinationStage;
[eea05dd]964
965 if (oldLayout == VK_IMAGE_LAYOUT_UNDEFINED && newLayout == VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL) {
966 barrier.srcAccessMask = 0;
967 barrier.dstAccessMask = VK_ACCESS_TRANSFER_WRITE_BIT;
968
969 sourceStage = VK_PIPELINE_STAGE_TOP_OF_PIPE_BIT;
970 destinationStage = VK_PIPELINE_STAGE_TRANSFER_BIT;
971 } else if (oldLayout == VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL && newLayout == VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL) {
972 barrier.srcAccessMask = VK_ACCESS_TRANSFER_WRITE_BIT;
973 barrier.dstAccessMask = VK_ACCESS_SHADER_READ_BIT;
974
975 sourceStage = VK_PIPELINE_STAGE_TRANSFER_BIT;
976 destinationStage = VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT;
977 } else {
978 throw invalid_argument("unsupported layout transition!");
979 }
980
981 vkCmdPipelineBarrier(
982 commandBuffer,
[f5d5686]983 sourceStage, destinationStage,
[eea05dd]984 0,
985 0, nullptr,
986 0, nullptr,
987 1, &barrier
988 );
989
990 endSingleTimeCommands(commandBuffer);
991 }
992
993 void copyBufferToImage(VkBuffer buffer, VkImage image, uint32_t width, uint32_t height) {
994 VkCommandBuffer commandBuffer = beginSingleTimeCommands();
995
996 VkBufferImageCopy region = {};
997 region.bufferOffset = 0;
998 region.bufferRowLength = 0;
999 region.bufferImageHeight = 0;
1000 region.imageSubresource.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT;
1001 region.imageSubresource.mipLevel = 0;
1002 region.imageSubresource.baseArrayLayer = 0;
1003 region.imageSubresource.layerCount = 1;
1004 region.imageOffset = { 0, 0, 0 };
1005 region.imageExtent = { width, height, 1 };
1006
1007 vkCmdCopyBufferToImage(
1008 commandBuffer,
1009 buffer,
1010 image,
1011 VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL,
1012 1,
1013 &region
1014 );
1015
1016 endSingleTimeCommands(commandBuffer);
1017 }
1018
[80edd70]1019 void createVertexBuffer() {
[d9ef6ab]1020 VkDeviceSize bufferSize = sizeof(vertices[0]) * vertices.size();
1021
1022 VkBuffer stagingBuffer;
1023 VkDeviceMemory stagingBufferMemory;
[621664a]1024 createBuffer(bufferSize, VK_BUFFER_USAGE_TRANSFER_SRC_BIT,
[d9ef6ab]1025 VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT | VK_MEMORY_PROPERTY_HOST_COHERENT_BIT,
1026 stagingBuffer, stagingBufferMemory);
1027
1028 void* data;
1029 vkMapMemory(device, stagingBufferMemory, 0, bufferSize, 0, &data);
[621664a]1030 memcpy(data, vertices.data(), (size_t) bufferSize);
[d9ef6ab]1031 vkUnmapMemory(device, stagingBufferMemory);
1032
1033 createBuffer(bufferSize, VK_BUFFER_USAGE_TRANSFER_DST_BIT | VK_BUFFER_USAGE_VERTEX_BUFFER_BIT,
1034 VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT, vertexBuffer, vertexBufferMemory);
1035
1036 copyBuffer(stagingBuffer, vertexBuffer, bufferSize);
1037
1038 vkDestroyBuffer(device, stagingBuffer, nullptr);
1039 vkFreeMemory(device, stagingBufferMemory, nullptr);
1040 }
1041
[cae7a2c]1042 void createIndexBuffer() {
1043 VkDeviceSize bufferSize = sizeof(indices[0]) * indices.size();
1044
1045 VkBuffer stagingBuffer;
1046 VkDeviceMemory stagingBufferMemory;
1047 createBuffer(bufferSize, VK_BUFFER_USAGE_TRANSFER_SRC_BIT,
1048 VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT | VK_MEMORY_PROPERTY_HOST_COHERENT_BIT,
1049 stagingBuffer, stagingBufferMemory);
1050
1051 void* data;
1052 vkMapMemory(device, stagingBufferMemory, 0, bufferSize, 0, &data);
[621664a]1053 memcpy(data, indices.data(), (size_t) bufferSize);
[cae7a2c]1054 vkUnmapMemory(device, stagingBufferMemory);
1055
1056 createBuffer(bufferSize, VK_BUFFER_USAGE_TRANSFER_DST_BIT | VK_BUFFER_USAGE_INDEX_BUFFER_BIT,
1057 VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT, indexBuffer, indexBufferMemory);
1058
1059 copyBuffer(stagingBuffer, indexBuffer, bufferSize);
1060
1061 vkDestroyBuffer(device, stagingBuffer, nullptr);
1062 vkFreeMemory(device, stagingBufferMemory, nullptr);
1063 }
1064
[621664a]1065 void createUniformBuffers() {
1066 VkDeviceSize bufferSize = sizeof(UniformBufferObject);
1067
1068 uniformBuffers.resize(swapChainImages.size());
1069 uniformBuffersMemory.resize(swapChainImages.size());
1070
1071 for (size_t i = 0; i < swapChainImages.size(); i++) {
1072 createBuffer(bufferSize, VK_BUFFER_USAGE_UNIFORM_BUFFER_BIT,
1073 VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT | VK_MEMORY_PROPERTY_HOST_COHERENT_BIT,
1074 uniformBuffers[i], uniformBuffersMemory[i]);
1075 }
1076 }
1077
1078 void createBuffer(VkDeviceSize size, VkBufferUsageFlags usage, VkMemoryPropertyFlags properties, VkBuffer& buffer, VkDeviceMemory& bufferMemory) {
[80edd70]1079 VkBufferCreateInfo bufferInfo = {};
1080 bufferInfo.sType = VK_STRUCTURE_TYPE_BUFFER_CREATE_INFO;
[d9ef6ab]1081 bufferInfo.size = size;
1082 bufferInfo.usage = usage;
[80edd70]1083 bufferInfo.sharingMode = VK_SHARING_MODE_EXCLUSIVE;
1084
[d9ef6ab]1085 if (vkCreateBuffer(device, &bufferInfo, nullptr, &buffer) != VK_SUCCESS) {
1086 throw runtime_error("failed to create buffer!");
[80edd70]1087 }
1088
[d9ef6ab]1089 VkMemoryRequirements memRequirements;
1090 vkGetBufferMemoryRequirements(device, buffer, &memRequirements);
[80edd70]1091
1092 VkMemoryAllocateInfo allocInfo = {};
1093 allocInfo.sType = VK_STRUCTURE_TYPE_MEMORY_ALLOCATE_INFO;
[d9ef6ab]1094 allocInfo.allocationSize = memRequirements.size;
1095 allocInfo.memoryTypeIndex = findMemoryType(memRequirements.memoryTypeBits, properties);
[621664a]1096
[d9ef6ab]1097 if (vkAllocateMemory(device, &allocInfo, nullptr, &bufferMemory) != VK_SUCCESS) {
1098 throw runtime_error("failed to allocate buffer memory!");
[80edd70]1099 }
1100
[d9ef6ab]1101 vkBindBufferMemory(device, buffer, bufferMemory, 0);
1102 }
[80edd70]1103
[d9ef6ab]1104 void copyBuffer(VkBuffer srcBuffer, VkBuffer dstBuffer, VkDeviceSize size) {
[eea05dd]1105 VkCommandBuffer commandBuffer = beginSingleTimeCommands();
1106
1107 VkBufferCopy copyRegion = {};
1108 copyRegion.size = size;
1109 vkCmdCopyBuffer(commandBuffer, srcBuffer, dstBuffer, 1, &copyRegion);
1110
1111 endSingleTimeCommands(commandBuffer);
1112 }
1113
1114 VkCommandBuffer beginSingleTimeCommands() {
[d9ef6ab]1115 VkCommandBufferAllocateInfo allocInfo = {};
1116 allocInfo.sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_ALLOCATE_INFO;
1117 allocInfo.level = VK_COMMAND_BUFFER_LEVEL_PRIMARY;
1118 allocInfo.commandPool = commandPool;
1119 allocInfo.commandBufferCount = 1;
1120
1121 VkCommandBuffer commandBuffer;
1122 vkAllocateCommandBuffers(device, &allocInfo, &commandBuffer);
1123
1124 VkCommandBufferBeginInfo beginInfo = {};
1125 beginInfo.sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_BEGIN_INFO;
1126 beginInfo.flags = VK_COMMAND_BUFFER_USAGE_ONE_TIME_SUBMIT_BIT;
1127
1128 vkBeginCommandBuffer(commandBuffer, &beginInfo);
1129
[eea05dd]1130 return commandBuffer;
1131 }
[d9ef6ab]1132
[eea05dd]1133 void endSingleTimeCommands(VkCommandBuffer commandBuffer) {
[d9ef6ab]1134 vkEndCommandBuffer(commandBuffer);
1135
1136 VkSubmitInfo submitInfo = {};
1137 submitInfo.sType = VK_STRUCTURE_TYPE_SUBMIT_INFO;
1138 submitInfo.commandBufferCount = 1;
1139 submitInfo.pCommandBuffers = &commandBuffer;
1140
1141 vkQueueSubmit(graphicsQueue, 1, &submitInfo, VK_NULL_HANDLE);
1142 vkQueueWaitIdle(graphicsQueue);
1143
1144 vkFreeCommandBuffers(device, commandPool, 1, &commandBuffer);
[80edd70]1145 }
1146
1147 uint32_t findMemoryType(uint32_t typeFilter, VkMemoryPropertyFlags properties) {
1148 VkPhysicalDeviceMemoryProperties memProperties;
1149 vkGetPhysicalDeviceMemoryProperties(physicalDevice, &memProperties);
1150
1151 for (uint32_t i = 0; i < memProperties.memoryTypeCount; i++) {
1152 if ((typeFilter & (1 << i)) && (memProperties.memoryTypes[i].propertyFlags & properties) == properties) {
1153 return i;
1154 }
1155 }
1156
1157 throw runtime_error("failed to find suitable memory type!");
1158 }
1159
[c7fb883]1160 void createDescriptorPool() {
1161 VkDescriptorPoolSize poolSize = {};
1162 poolSize.type = VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER;
1163 poolSize.descriptorCount = static_cast<uint32_t>(swapChainImages.size());
1164
1165 VkDescriptorPoolCreateInfo poolInfo = {};
1166 poolInfo.sType = VK_STRUCTURE_TYPE_DESCRIPTOR_POOL_CREATE_INFO;
1167 poolInfo.poolSizeCount = 1;
1168 poolInfo.pPoolSizes = &poolSize;
1169 poolInfo.maxSets = static_cast<uint32_t>(swapChainImages.size());
1170
1171 if (vkCreateDescriptorPool(device, &poolInfo, nullptr, &descriptorPool) != VK_SUCCESS) {
1172 throw runtime_error("failed to create descriptor pool!");
1173 }
1174 }
1175
1176 void createDescriptorSets() {
1177 vector<VkDescriptorSetLayout> layouts(swapChainImages.size(), descriptorSetLayout);
[621664a]1178
[c7fb883]1179 VkDescriptorSetAllocateInfo allocInfo = {};
1180 allocInfo.sType = VK_STRUCTURE_TYPE_DESCRIPTOR_SET_ALLOCATE_INFO;
1181 allocInfo.descriptorPool = descriptorPool;
1182 allocInfo.descriptorSetCount = static_cast<uint32_t>(swapChainImages.size());
1183 allocInfo.pSetLayouts = layouts.data();
1184
1185 descriptorSets.resize(swapChainImages.size());
1186 if (vkAllocateDescriptorSets(device, &allocInfo, descriptorSets.data()) != VK_SUCCESS) {
1187 throw runtime_error("failed to allocate descriptor sets!");
1188 }
1189
1190 for (size_t i = 0; i < swapChainImages.size(); i++) {
1191 VkDescriptorBufferInfo bufferInfo = {};
1192 bufferInfo.buffer = uniformBuffers[i];
1193 bufferInfo.offset = 0;
1194 bufferInfo.range = sizeof(UniformBufferObject);
1195
1196 VkWriteDescriptorSet descriptorWrite = {};
1197 descriptorWrite.sType = VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET;
1198 descriptorWrite.dstSet = descriptorSets[i];
1199 descriptorWrite.dstBinding = 0;
1200 descriptorWrite.dstArrayElement = 0;
1201 descriptorWrite.descriptorType = VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER;
1202 descriptorWrite.descriptorCount = 1;
1203 descriptorWrite.pBufferInfo = &bufferInfo;
1204 descriptorWrite.pImageInfo = nullptr;
1205 descriptorWrite.pTexelBufferView = nullptr;
1206
1207 vkUpdateDescriptorSets(device, 1, &descriptorWrite, 0, nullptr);
1208 }
1209 }
1210
[47bff4c]1211 void createCommandBuffers() {
1212 commandBuffers.resize(swapChainFramebuffers.size());
1213
1214 VkCommandBufferAllocateInfo allocInfo = {};
1215 allocInfo.sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_ALLOCATE_INFO;
1216 allocInfo.commandPool = commandPool;
1217 allocInfo.level = VK_COMMAND_BUFFER_LEVEL_PRIMARY;
[621664a]1218 allocInfo.commandBufferCount = (uint32_t) commandBuffers.size();
[47bff4c]1219
1220 if (vkAllocateCommandBuffers(device, &allocInfo, commandBuffers.data()) != VK_SUCCESS) {
[621664a]1221 throw runtime_error("failed to allocate command buffers!");
[47bff4c]1222 }
1223
1224 for (size_t i = 0; i < commandBuffers.size(); i++) {
1225 VkCommandBufferBeginInfo beginInfo = {};
1226 beginInfo.sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_BEGIN_INFO;
1227 beginInfo.flags = VK_COMMAND_BUFFER_USAGE_SIMULTANEOUS_USE_BIT;
1228 beginInfo.pInheritanceInfo = nullptr;
1229
1230 if (vkBeginCommandBuffer(commandBuffers[i], &beginInfo) != VK_SUCCESS) {
1231 throw runtime_error("failed to begin recording command buffer!");
1232 }
1233
1234 VkRenderPassBeginInfo renderPassInfo = {};
1235 renderPassInfo.sType = VK_STRUCTURE_TYPE_RENDER_PASS_BEGIN_INFO;
1236 renderPassInfo.renderPass = renderPass;
1237 renderPassInfo.framebuffer = swapChainFramebuffers[i];
1238 renderPassInfo.renderArea.offset = { 0, 0 };
1239 renderPassInfo.renderArea.extent = swapChainExtent;
1240
1241 VkClearValue clearColor = { 0.0f, 0.0f, 0.0f, 1.0f };
1242 renderPassInfo.clearValueCount = 1;
1243 renderPassInfo.pClearValues = &clearColor;
1244
1245 vkCmdBeginRenderPass(commandBuffers[i], &renderPassInfo, VK_SUBPASS_CONTENTS_INLINE);
[621664a]1246
[47bff4c]1247 vkCmdBindPipeline(commandBuffers[i], VK_PIPELINE_BIND_POINT_GRAPHICS, graphicsPipeline);
[80edd70]1248
1249 VkBuffer vertexBuffers[] = { vertexBuffer };
1250 VkDeviceSize offsets[] = { 0 };
1251 vkCmdBindVertexBuffers(commandBuffers[i], 0, 1, vertexBuffers, offsets);
1252
[cae7a2c]1253 vkCmdBindIndexBuffer(commandBuffers[i], indexBuffer, 0, VK_INDEX_TYPE_UINT16);
[c7fb883]1254 vkCmdBindDescriptorSets(commandBuffers[i], VK_PIPELINE_BIND_POINT_GRAPHICS, pipelineLayout, 0, 1, &descriptorSets[i], 0, nullptr);
[cae7a2c]1255
1256 vkCmdDrawIndexed(commandBuffers[i], static_cast<uint32_t>(indices.size()), 1, 0, 0, 0);
[621664a]1257
[47bff4c]1258 vkCmdEndRenderPass(commandBuffers[i]);
1259
1260 if (vkEndCommandBuffer(commandBuffers[i]) != VK_SUCCESS) {
1261 throw runtime_error("failed to record command buffer!");
1262 }
1263 }
1264 }
1265
1266 void createSyncObjects() {
1267 imageAvailableSemaphores.resize(MAX_FRAMES_IN_FLIGHT);
1268 renderFinishedSemaphores.resize(MAX_FRAMES_IN_FLIGHT);
1269 inFlightFences.resize(MAX_FRAMES_IN_FLIGHT);
1270
1271 VkSemaphoreCreateInfo semaphoreInfo = {};
1272 semaphoreInfo.sType = VK_STRUCTURE_TYPE_SEMAPHORE_CREATE_INFO;
1273
1274 VkFenceCreateInfo fenceInfo = {};
1275 fenceInfo.sType = VK_STRUCTURE_TYPE_FENCE_CREATE_INFO;
1276 fenceInfo.flags = VK_FENCE_CREATE_SIGNALED_BIT;
1277
1278 for (size_t i = 0; i < MAX_FRAMES_IN_FLIGHT; i++) {
1279 if (vkCreateSemaphore(device, &semaphoreInfo, nullptr, &imageAvailableSemaphores[i]) != VK_SUCCESS ||
1280 vkCreateSemaphore(device, &semaphoreInfo, nullptr, &renderFinishedSemaphores[i]) != VK_SUCCESS ||
1281 vkCreateFence(device, &fenceInfo, nullptr, &inFlightFences[i]) != VK_SUCCESS) {
1282 throw runtime_error("failed to create synchronization objects for a frame!");
1283 }
1284 }
1285 }
1286
[826df16]1287 void mainLoop() {
1288 // TODO: Create some generic event-handling functions in game-gui-*
1289 SDL_Event e;
1290 bool quit = false;
1291
[7dcd925]1292 while (!quit) {
[826df16]1293 while (SDL_PollEvent(&e)) {
1294 if (e.type == SDL_QUIT) {
1295 quit = true;
1296 }
1297 if (e.type == SDL_KEYDOWN) {
1298 quit = true;
1299 }
1300 if (e.type == SDL_MOUSEBUTTONDOWN) {
1301 quit = true;
1302 }
[75108ef]1303 if (e.type == SDL_WINDOWEVENT) {
1304 if (e.window.event == SDL_WINDOWEVENT_SIZE_CHANGED) {
1305 framebufferResized = true;
1306 } else if (e.window.event == SDL_WINDOWEVENT_MINIMIZED) {
1307 framebufferResized = true;
1308 }
1309 }
[47bff4c]1310 }
[321272c]1311
[47bff4c]1312 drawFrame();
[321272c]1313
[47bff4c]1314 //SDL_FillRect(sdlSurface, nullptr, SDL_MapRGB(sdlSurface->format, 0x00, 0x99, 0x99));
1315 //SDL_UpdateWindowSurface(window);
1316 }
1317
1318 vkDeviceWaitIdle(device);
1319 }
1320
1321 void drawFrame() {
1322 vkWaitForFences(device, 1, &inFlightFences[currentFrame], VK_TRUE, numeric_limits<uint64_t>::max());
1323
1324 uint32_t imageIndex;
1325
[621664a]1326 VkResult result = vkAcquireNextImageKHR(device, swapChain, numeric_limits<uint64_t>::max(),
1327 imageAvailableSemaphores[currentFrame], VK_NULL_HANDLE, &imageIndex);
[75108ef]1328
1329 if (result == VK_ERROR_OUT_OF_DATE_KHR) {
1330 recreateSwapChain();
1331 return;
1332 } else if (result != VK_SUCCESS && result != VK_SUBOPTIMAL_KHR) {
1333 throw runtime_error("failed to acquire swap chain image!");
1334 }
[47bff4c]1335
[de32fda]1336 updateUniformBuffer(imageIndex);
1337
[47bff4c]1338 VkSubmitInfo submitInfo = {};
1339 submitInfo.sType = VK_STRUCTURE_TYPE_SUBMIT_INFO;
1340
1341 VkSemaphore waitSemaphores[] = { imageAvailableSemaphores[currentFrame] };
1342 VkPipelineStageFlags waitStages[] = { VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT };
1343
1344 submitInfo.waitSemaphoreCount = 1;
1345 submitInfo.pWaitSemaphores = waitSemaphores;
1346 submitInfo.pWaitDstStageMask = waitStages;
1347 submitInfo.commandBufferCount = 1;
1348 submitInfo.pCommandBuffers = &commandBuffers[imageIndex];
1349
1350 VkSemaphore signalSemaphores[] = { renderFinishedSemaphores[currentFrame] };
1351
1352 submitInfo.signalSemaphoreCount = 1;
1353 submitInfo.pSignalSemaphores = signalSemaphores;
1354
[75108ef]1355 vkResetFences(device, 1, &inFlightFences[currentFrame]);
1356
[47bff4c]1357 if (vkQueueSubmit(graphicsQueue, 1, &submitInfo, inFlightFences[currentFrame]) != VK_SUCCESS) {
1358 throw runtime_error("failed to submit draw command buffer!");
[bfd620e]1359 }
[47bff4c]1360
1361 VkPresentInfoKHR presentInfo = {};
1362 presentInfo.sType = VK_STRUCTURE_TYPE_PRESENT_INFO_KHR;
1363 presentInfo.waitSemaphoreCount = 1;
1364 presentInfo.pWaitSemaphores = signalSemaphores;
1365
1366 VkSwapchainKHR swapChains[] = { swapChain };
1367 presentInfo.swapchainCount = 1;
1368 presentInfo.pSwapchains = swapChains;
1369 presentInfo.pImageIndices = &imageIndex;
1370 presentInfo.pResults = nullptr;
1371
[75108ef]1372 result = vkQueuePresentKHR(presentQueue, &presentInfo);
1373
1374 if (result == VK_ERROR_OUT_OF_DATE_KHR || result == VK_SUBOPTIMAL_KHR || framebufferResized) {
1375 framebufferResized = false;
1376 recreateSwapChain();
1377 } else if (result != VK_SUCCESS) {
1378 throw runtime_error("failed to present swap chain image!");
1379 }
[47bff4c]1380
1381 currentFrame = (currentFrame + 1) % MAX_FRAMES_IN_FLIGHT;
[826df16]1382 }
1383
[de32fda]1384 void updateUniformBuffer(uint32_t currentImage) {
1385 static auto startTime = chrono::high_resolution_clock::now();
1386
1387 auto currentTime = chrono::high_resolution_clock::now();
1388 float time = chrono::duration<float, chrono::seconds::period>(currentTime - startTime).count();
1389
1390 UniformBufferObject ubo = {};
1391 ubo.model = glm::rotate(glm::mat4(1.0f), time * glm::radians(90.0f), glm::vec3(0.0f, 0.0f, 1.0f));
1392 ubo.view = glm::lookAt(glm::vec3(2.0f, 2.0f, 2.0f), glm::vec3(0.0f, 0.0f, 0.0f), glm::vec3(0.0f, 0.0f, 1.0f));
[621664a]1393 ubo.proj = glm::perspective(glm::radians(45.0f), swapChainExtent.width / (float)swapChainExtent.height, 0.1f, 10.0f);
[de32fda]1394 ubo.proj[1][1] *= -1;
1395
1396 void* data;
1397 vkMapMemory(device, uniformBuffersMemory[currentImage], 0, sizeof(ubo), 0, &data);
1398 memcpy(data, &ubo, sizeof(ubo));
1399 vkUnmapMemory(device, uniformBuffersMemory[currentImage]);
1400 }
1401
[621664a]1402 void recreateSwapChain() {
1403 int width = 0, height = 0;
1404
1405 gui->GetWindowSize(&width, &height);
1406
1407 while (width == 0 || height == 0 ||
1408 (SDL_GetWindowFlags(window) & SDL_WINDOW_MINIMIZED) != 0) {
1409 SDL_WaitEvent(nullptr);
1410 gui->GetWindowSize(&width, &height);
1411 }
1412
1413 vkDeviceWaitIdle(device);
1414
1415 cleanupSwapChain();
1416
1417 createSwapChain();
1418 createImageViews();
1419 createRenderPass();
1420 createGraphicsPipeline();
1421 createFramebuffers();
1422 createUniformBuffers();
1423 createDescriptorPool();
1424 createDescriptorSets();
1425 createCommandBuffers();
1426 }
1427
[826df16]1428 void cleanup() {
[75108ef]1429 cleanupSwapChain();
1430
[eea05dd]1431 vkDestroyImage(device, textureImage, nullptr);
[f5d5686]1432 vkFreeMemory(device, textureImageMemory, nullptr);
[eea05dd]1433
[de32fda]1434 vkDestroyDescriptorSetLayout(device, descriptorSetLayout, nullptr);
1435
[cae7a2c]1436 vkDestroyBuffer(device, indexBuffer, nullptr);
1437 vkFreeMemory(device, indexBufferMemory, nullptr);
1438
[80edd70]1439 vkDestroyBuffer(device, vertexBuffer, nullptr);
1440 vkFreeMemory(device, vertexBufferMemory, nullptr);
1441
[47bff4c]1442 for (size_t i = 0; i < MAX_FRAMES_IN_FLIGHT; i++) {
1443 vkDestroySemaphore(device, renderFinishedSemaphores[i], nullptr);
[621664a]1444 vkDestroySemaphore(device, imageAvailableSemaphores[i], nullptr);
[47bff4c]1445 vkDestroyFence(device, inFlightFences[i], nullptr);
1446 }
1447
1448 vkDestroyCommandPool(device, commandPool, nullptr);
1449
[909b51a]1450 vkDestroyDevice(device, nullptr);
1451
[80de39d]1452 if (enableValidationLayers) {
1453 DestroyDebugUtilsMessengerEXT(instance, debugMessenger, nullptr);
1454 }
1455
[b3671b5]1456 vkDestroySurfaceKHR(instance, surface, nullptr);
[826df16]1457 vkDestroyInstance(instance, nullptr);
1458
[0e6ecf3]1459 gui->DestroyWindow();
[98f3232]1460 gui->Shutdown();
1461 delete gui;
[826df16]1462 }
[e09ad38]1463
[621664a]1464 void cleanupSwapChain() {
1465 for (auto framebuffer : swapChainFramebuffers) {
1466 vkDestroyFramebuffer(device, framebuffer, nullptr);
1467 }
1468
1469 vkFreeCommandBuffers(device, commandPool, static_cast<uint32_t>(commandBuffers.size()), commandBuffers.data());
1470
1471 vkDestroyPipeline(device, graphicsPipeline, nullptr);
1472 vkDestroyPipelineLayout(device, pipelineLayout, nullptr);
1473 vkDestroyRenderPass(device, renderPass, nullptr);
1474
1475 for (auto imageView : swapChainImageViews) {
1476 vkDestroyImageView(device, imageView, nullptr);
1477 }
1478
1479 vkDestroySwapchainKHR(device, swapChain, nullptr);
1480
1481 for (size_t i = 0; i < swapChainImages.size(); i++) {
1482 vkDestroyBuffer(device, uniformBuffers[i], nullptr);
1483 vkFreeMemory(device, uniformBuffersMemory[i], nullptr);
1484 }
1485
1486 vkDestroyDescriptorPool(device, descriptorPool, nullptr);
1487 }
1488
[e09ad38]1489 static VKAPI_ATTR VkBool32 VKAPI_CALL debugCallback(
[621664a]1490 VkDebugUtilsMessageSeverityFlagBitsEXT messageSeverity,
1491 VkDebugUtilsMessageTypeFlagsEXT messageType,
1492 const VkDebugUtilsMessengerCallbackDataEXT* pCallbackData,
1493 void* pUserData) {
[e09ad38]1494 cerr << "validation layer: " << pCallbackData->pMessage << endl;
1495
1496 return VK_FALSE;
[0e6ecf3]1497 }
[e09ad38]1498
1499 static vector<char> readFile(const string& filename) {
1500 ifstream file(filename, ios::ate | ios::binary);
1501
1502 if (!file.is_open()) {
1503 throw runtime_error("failed to open file!");
1504 }
1505
[621664a]1506 size_t fileSize = (size_t) file.tellg();
[e09ad38]1507 vector<char> buffer(fileSize);
1508
1509 file.seekg(0);
1510 file.read(buffer.data(), fileSize);
1511
1512 file.close();
1513
1514 return buffer;
1515 }
[826df16]1516};
1517
[1c6cd5e]1518int main(int argc, char* argv[]) {
[826df16]1519
[b6127d2]1520#ifdef NDEBUG
1521 cout << "DEBUGGING IS OFF" << endl;
1522#else
1523 cout << "DEBUGGING IS ON" << endl;
1524#endif
[a8f0577]1525
[826df16]1526 cout << "Starting Vulkan game..." << endl;
1527
1528 VulkanGame game;
1529
1530 try {
1531 game.run();
1532 } catch (const exception& e) {
1533 cerr << e.what() << endl;
1534 return EXIT_FAILURE;
1535 }
[03f4c64]1536
[826df16]1537 cout << "Finished running the game" << endl;
[03f4c64]1538
[826df16]1539 return EXIT_SUCCESS;
[03f4c64]1540}
Note: See TracBrowser for help on using the repository browser.