source: opengl-game/vulkan-game.cpp@ d9ef6ab

feature/imgui-sdl points-test
Last change on this file since d9ef6ab was d9ef6ab, checked in by Dmitry Portnoy <dmitry.portnoy@…>, 5 years ago

Use a staging buffer to help move the vertex data to device local memory on the graphics card

  • Property mode set to 100644
File size: 45.1 KB
Line 
1#include "game-gui-glfw.hpp"
2
3#include "game-gui-sdl.hpp"
4
5//#define _USE_MATH_DEFINES // Will be needed when/if I need to # include <cmath>
6
7#define GLM_FORCE_RADIANS
8#define GLM_FORCE_DEPTH_ZERO_TO_ONE
9#include <glm/glm.hpp>
10
11#include <iostream>
12#include <fstream>
13#include <algorithm>
14#include <vector>
15#include <array>
16#include <set>
17#include <optional>
18
19using namespace std;
20
21const int SCREEN_WIDTH = 800;
22const int SCREEN_HEIGHT = 600;
23
24const int MAX_FRAMES_IN_FLIGHT = 2;
25
26#ifdef NDEBUG
27 const bool enableValidationLayers = false;
28#else
29 const bool enableValidationLayers = true;
30#endif
31
32const vector<const char*> validationLayers = {
33 "VK_LAYER_KHRONOS_validation"
34};
35
36const vector<const char*> deviceExtensions = {
37 VK_KHR_SWAPCHAIN_EXTENSION_NAME
38};
39
40struct QueueFamilyIndices {
41 optional<uint32_t> graphicsFamily;
42 optional<uint32_t> presentFamily;
43
44 bool isComplete() {
45 return graphicsFamily.has_value() && presentFamily.has_value();
46 }
47};
48
49struct SwapChainSupportDetails {
50 VkSurfaceCapabilitiesKHR capabilities;
51 vector<VkSurfaceFormatKHR> formats;
52 vector<VkPresentModeKHR> presentModes;
53};
54
55struct Vertex {
56 glm::vec2 pos;
57 glm::vec3 color;
58
59 static VkVertexInputBindingDescription getBindingDescription() {
60 VkVertexInputBindingDescription bindingDescription = {};
61
62 bindingDescription.binding = 0;
63 bindingDescription.stride = sizeof(Vertex);
64 bindingDescription.inputRate = VK_VERTEX_INPUT_RATE_VERTEX;
65
66 return bindingDescription;
67 }
68
69 static array<VkVertexInputAttributeDescription, 2> getAttributeDescriptions() {
70 array<VkVertexInputAttributeDescription, 2> attributeDescriptions = {};
71
72 attributeDescriptions[0].binding = 0;
73 attributeDescriptions[0].location = 0;
74 attributeDescriptions[0].format = VK_FORMAT_R32G32_SFLOAT;
75 attributeDescriptions[0].offset = offsetof(Vertex, pos);
76
77 attributeDescriptions[1].binding = 0;
78 attributeDescriptions[1].location = 1;
79 attributeDescriptions[1].format = VK_FORMAT_R32G32B32_SFLOAT;
80 attributeDescriptions[1].offset = offsetof(Vertex, color);
81
82 return attributeDescriptions;
83 }
84};
85
86const vector<Vertex> vertices = {
87 {{ 0.0f, -0.5f}, {1.0f, 1.0f, 1.0f}},
88 {{ 0.5f, 0.5f}, {0.0f, 1.0f, 0.0f}},
89 {{-0.5f, 0.5f}, {0.0f, 0.0f, 1.0f}}
90};
91
92VkResult CreateDebugUtilsMessengerEXT(VkInstance instance,
93 const VkDebugUtilsMessengerCreateInfoEXT* pCreateInfo,
94 const VkAllocationCallbacks* pAllocator,
95 VkDebugUtilsMessengerEXT* pDebugMessenger) {
96 auto func = (PFN_vkCreateDebugUtilsMessengerEXT) vkGetInstanceProcAddr(
97 instance, "vkCreateDebugUtilsMessengerEXT");
98
99 if (func != nullptr) {
100 return func(instance, pCreateInfo, pAllocator, pDebugMessenger);
101 } else {
102 return VK_ERROR_EXTENSION_NOT_PRESENT;
103 }
104}
105
106void DestroyDebugUtilsMessengerEXT(VkInstance instance,
107 VkDebugUtilsMessengerEXT debugMessenger,
108 const VkAllocationCallbacks* pAllocator) {
109 auto func = (PFN_vkDestroyDebugUtilsMessengerEXT) vkGetInstanceProcAddr(
110 instance, "vkDestroyDebugUtilsMessengerEXT");
111
112 if (func != nullptr) {
113 func(instance, debugMessenger, pAllocator);
114 }
115}
116
117class VulkanGame {
118 public:
119 void run() {
120 if (initWindow() == RTWO_ERROR) {
121 return;
122 }
123 initVulkan();
124 mainLoop();
125 cleanup();
126 }
127 private:
128 GameGui* gui = new GameGui_SDL();
129 SDL_Window* window = nullptr;
130
131 VkInstance instance;
132 VkDebugUtilsMessengerEXT debugMessenger;
133 VkSurfaceKHR surface;
134 SDL_Surface* sdlSurface = nullptr;
135
136 VkPhysicalDevice physicalDevice = VK_NULL_HANDLE;
137 VkDevice device;
138
139 VkQueue graphicsQueue;
140 VkQueue presentQueue;
141
142 VkSwapchainKHR swapChain;
143 vector<VkImage> swapChainImages;
144 VkFormat swapChainImageFormat;
145 VkExtent2D swapChainExtent;
146
147 vector<VkImageView> swapChainImageViews;
148 VkRenderPass renderPass;
149 VkPipelineLayout pipelineLayout;
150 VkPipeline graphicsPipeline;
151 VkCommandPool commandPool;
152
153 VkBuffer vertexBuffer;
154 VkDeviceMemory vertexBufferMemory;
155
156 vector<VkFramebuffer> swapChainFramebuffers;
157 vector<VkCommandBuffer> commandBuffers;
158
159 vector<VkSemaphore> imageAvailableSemaphores;
160 vector<VkSemaphore> renderFinishedSemaphores;
161 vector<VkFence> inFlightFences;
162
163 size_t currentFrame = 0;
164
165 bool framebufferResized = false;
166
167 bool initWindow() {
168 if (gui->Init() == RTWO_ERROR) {
169 cout << "UI library could not be initialized!" << endl;
170 return RTWO_ERROR;
171 } else {
172 window = (SDL_Window*) gui->CreateWindow("Vulkan Game", SCREEN_WIDTH, SCREEN_HEIGHT);
173
174 if (window == nullptr) {
175 cout << "Window could not be created!" << endl;
176 return RTWO_ERROR;
177 } else {
178 return RTWO_SUCCESS;
179 }
180 }
181 }
182
183 void initVulkan() {
184 createInstance();
185 setupDebugMessenger();
186 createSurface();
187 pickPhysicalDevice();
188 createLogicalDevice();
189 createSwapChain();
190 createImageViews();
191 createRenderPass();
192 createGraphicsPipeline();
193 createFramebuffers();
194 createCommandPool();
195 createVertexBuffer();
196 createCommandBuffers();
197 createSyncObjects();
198 }
199
200 void recreateSwapChain() {
201 int width = 0, height = 0;
202 gui->GetWindowSize(&width, &height);
203
204 while (width == 0 || height == 0 ||
205 (SDL_GetWindowFlags(window) & SDL_WINDOW_MINIMIZED) != 0) {
206 SDL_WaitEvent(nullptr);
207 gui->GetWindowSize(&width, &height);
208 }
209
210 vkDeviceWaitIdle(device);
211
212 cleanupSwapChain();
213
214 createSwapChain();
215 createImageViews();
216 createRenderPass();
217 createGraphicsPipeline();
218 createFramebuffers();
219 createCommandBuffers();
220 }
221
222 void cleanupSwapChain() {
223 for (auto framebuffer : swapChainFramebuffers) {
224 vkDestroyFramebuffer(device, framebuffer, nullptr);
225 }
226
227 vkFreeCommandBuffers(device, commandPool, static_cast<uint32_t>(commandBuffers.size()), commandBuffers.data());
228
229 vkDestroyPipeline(device, graphicsPipeline, nullptr);
230 vkDestroyPipelineLayout(device, pipelineLayout, nullptr);
231 vkDestroyRenderPass(device, renderPass, nullptr);
232
233 for (auto imageView : swapChainImageViews) {
234 vkDestroyImageView(device, imageView, nullptr);
235 }
236
237 vkDestroySwapchainKHR(device, swapChain, nullptr);
238 }
239
240 void createInstance() {
241 if (enableValidationLayers && !checkValidationLayerSupport()) {
242 throw runtime_error("validation layers requested, but not available!");
243 }
244
245 VkApplicationInfo appInfo = {};
246 appInfo.sType = VK_STRUCTURE_TYPE_APPLICATION_INFO;
247 appInfo.pApplicationName = "Vulkan Game";
248 appInfo.applicationVersion = VK_MAKE_VERSION(1, 0, 0);
249 appInfo.pEngineName = "No Engine";
250 appInfo.engineVersion = VK_MAKE_VERSION(1, 0, 0);
251 appInfo.apiVersion = VK_API_VERSION_1_0;
252
253 VkInstanceCreateInfo createInfo = {};
254 createInfo.sType = VK_STRUCTURE_TYPE_INSTANCE_CREATE_INFO;
255 createInfo.pApplicationInfo = &appInfo;
256
257 vector<const char*> extensions = getRequiredExtensions();
258 createInfo.enabledExtensionCount = static_cast<uint32_t>(extensions.size());
259 createInfo.ppEnabledExtensionNames = extensions.data();
260
261 cout << endl << "Extensions:" << endl;
262 for (const char* extensionName : extensions) {
263 cout << extensionName << endl;
264 }
265 cout << endl;
266
267 VkDebugUtilsMessengerCreateInfoEXT debugCreateInfo;
268 if (enableValidationLayers) {
269 createInfo.enabledLayerCount = static_cast<uint32_t>(validationLayers.size());
270 createInfo.ppEnabledLayerNames = validationLayers.data();
271
272 populateDebugMessengerCreateInfo(debugCreateInfo);
273 createInfo.pNext = &debugCreateInfo;
274 } else {
275 createInfo.enabledLayerCount = 0;
276
277 createInfo.pNext = nullptr;
278 }
279
280 if (vkCreateInstance(&createInfo, nullptr, &instance) != VK_SUCCESS) {
281 throw runtime_error("failed to create instance!");
282 }
283 }
284
285 void setupDebugMessenger() {
286 if (!enableValidationLayers) return;
287
288 VkDebugUtilsMessengerCreateInfoEXT createInfo;
289 populateDebugMessengerCreateInfo(createInfo);
290
291 if (CreateDebugUtilsMessengerEXT(instance, &createInfo, nullptr, &debugMessenger) != VK_SUCCESS) {
292 throw runtime_error("failed to setup debug messenger!");
293 }
294 }
295
296 void createSurface() {
297 sdlSurface = SDL_GetWindowSurface(window);
298
299 if (sdlSurface == nullptr) {
300 cout << "Could not get SDL Surface! =(" << endl;
301 }
302
303 if (gui->CreateVulkanSurface(instance, &surface) == RTWO_ERROR) {
304 throw runtime_error("failed to create window surface!");
305 }
306 }
307
308 void pickPhysicalDevice() {
309 uint32_t deviceCount = 0;
310 vkEnumeratePhysicalDevices(instance, &deviceCount, nullptr);
311
312 if (deviceCount == 0) {
313 throw runtime_error("failed to find GPUs with Vulkan support!");
314 }
315
316 vector<VkPhysicalDevice> devices(deviceCount);
317 vkEnumeratePhysicalDevices(instance, &deviceCount, devices.data());
318
319 cout << endl << "Graphics cards:" << endl;
320 for (const VkPhysicalDevice& device : devices) {
321 if (isDeviceSuitable(device)) {
322 physicalDevice = device;
323 break;
324 }
325 }
326 cout << endl;
327
328 if (physicalDevice == VK_NULL_HANDLE) {
329 throw runtime_error("failed to find a suitable GPU!");
330 }
331 }
332
333 bool isDeviceSuitable(VkPhysicalDevice device) {
334 VkPhysicalDeviceProperties deviceProperties;
335 VkPhysicalDeviceFeatures deviceFeatures;
336
337 vkGetPhysicalDeviceProperties(device, &deviceProperties);
338 vkGetPhysicalDeviceFeatures(device, &deviceFeatures);
339
340 cout << "Device: " << deviceProperties.deviceName << endl;
341
342 QueueFamilyIndices indices = findQueueFamilies(device);
343
344 bool extensionsSupported = checkDeviceExtensionSupport(device);
345
346 bool swapChainAdequate = false;
347
348 if (extensionsSupported) {
349 SwapChainSupportDetails swapChainSupport = querySwapChainSupport(device);
350 swapChainAdequate = !swapChainSupport.formats.empty() && !swapChainSupport.presentModes.empty();
351 }
352
353 return indices.isComplete() && extensionsSupported && swapChainAdequate;
354 }
355
356 bool checkDeviceExtensionSupport(VkPhysicalDevice device) {
357 uint32_t extensionCount;
358 vkEnumerateDeviceExtensionProperties(device, nullptr, &extensionCount, nullptr);
359
360 vector<VkExtensionProperties> availableExtensions(extensionCount);
361 vkEnumerateDeviceExtensionProperties(device, nullptr, &extensionCount, availableExtensions.data());
362
363 set<string> requiredExtensions(deviceExtensions.begin(), deviceExtensions.end());
364
365 for (const auto& extension : availableExtensions) {
366 requiredExtensions.erase(extension.extensionName);
367 }
368
369 return requiredExtensions.empty();
370 }
371
372 void createLogicalDevice() {
373 QueueFamilyIndices indices = findQueueFamilies(physicalDevice);
374
375 vector<VkDeviceQueueCreateInfo> queueCreateInfos;
376 set<uint32_t> uniqueQueueFamilies = {indices.graphicsFamily.value(), indices.presentFamily.value()};
377
378 float queuePriority = 1.0f;
379 for (uint32_t queueFamily : uniqueQueueFamilies) {
380 VkDeviceQueueCreateInfo queueCreateInfo = {};
381
382 queueCreateInfo.sType = VK_STRUCTURE_TYPE_DEVICE_QUEUE_CREATE_INFO;
383 queueCreateInfo.queueFamilyIndex = queueFamily;
384 queueCreateInfo.queueCount = 1;
385 queueCreateInfo.pQueuePriorities = &queuePriority;
386
387 queueCreateInfos.push_back(queueCreateInfo);
388 }
389
390 VkPhysicalDeviceFeatures deviceFeatures = {};
391
392 VkDeviceCreateInfo createInfo = {};
393 createInfo.sType = VK_STRUCTURE_TYPE_DEVICE_CREATE_INFO;
394
395 createInfo.queueCreateInfoCount = static_cast<uint32_t>(queueCreateInfos.size());;
396 createInfo.pQueueCreateInfos = queueCreateInfos.data();
397
398 createInfo.pEnabledFeatures = &deviceFeatures;
399
400 createInfo.enabledExtensionCount = static_cast<uint32_t>(deviceExtensions.size());
401 createInfo.ppEnabledExtensionNames = deviceExtensions.data();
402
403 // These fields are ignored by up-to-date Vulkan implementations,
404 // but it's a good idea to set them for backwards compatibility
405 if (enableValidationLayers) {
406 createInfo.enabledLayerCount = static_cast<uint32_t>(validationLayers.size());
407 createInfo.ppEnabledLayerNames = validationLayers.data();
408 } else {
409 createInfo.enabledLayerCount = 0;
410 }
411
412 if (vkCreateDevice(physicalDevice, &createInfo, nullptr, &device) != VK_SUCCESS) {
413 throw runtime_error("failed to create logical device!");
414 }
415
416 vkGetDeviceQueue(device, indices.graphicsFamily.value(), 0, &graphicsQueue);
417 vkGetDeviceQueue(device, indices.presentFamily.value(), 0, &presentQueue);
418 }
419
420 bool checkValidationLayerSupport() {
421 uint32_t layerCount;
422 vkEnumerateInstanceLayerProperties(&layerCount, nullptr);
423
424 vector<VkLayerProperties> availableLayers(layerCount);
425 vkEnumerateInstanceLayerProperties(&layerCount, availableLayers.data());
426
427 for (const char* layerName : validationLayers) {
428 bool layerFound = false;
429
430 for (const auto& layerProperties : availableLayers) {
431 if (strcmp(layerName, layerProperties.layerName) == 0) {
432 layerFound = true;
433 break;
434 }
435 }
436
437 if (!layerFound) {
438 return false;
439 }
440 }
441
442 return true;
443 }
444
445 QueueFamilyIndices findQueueFamilies(VkPhysicalDevice device) {
446 QueueFamilyIndices indices;
447
448 uint32_t queueFamilyCount = 0;
449 vkGetPhysicalDeviceQueueFamilyProperties(device, &queueFamilyCount, nullptr);
450
451 vector<VkQueueFamilyProperties> queueFamilies(queueFamilyCount);
452 vkGetPhysicalDeviceQueueFamilyProperties(device, &queueFamilyCount, queueFamilies.data());
453
454 int i = 0;
455 for (const auto& queueFamily : queueFamilies) {
456 if (queueFamily.queueCount > 0 && queueFamily.queueFlags & VK_QUEUE_GRAPHICS_BIT) {
457 indices.graphicsFamily = i;
458 }
459
460 VkBool32 presentSupport = false;
461 vkGetPhysicalDeviceSurfaceSupportKHR(device, i, surface, &presentSupport);
462
463 if (queueFamily.queueCount > 0 && presentSupport) {
464 indices.presentFamily = i;
465 }
466
467 if (indices.isComplete()) {
468 break;
469 }
470
471 i++;
472 }
473
474 return indices;
475 }
476
477 SwapChainSupportDetails querySwapChainSupport(VkPhysicalDevice device) {
478 SwapChainSupportDetails details;
479
480 vkGetPhysicalDeviceSurfaceCapabilitiesKHR(device, surface, &details.capabilities);
481
482 uint32_t formatCount;
483 vkGetPhysicalDeviceSurfaceFormatsKHR(device, surface, &formatCount, nullptr);
484
485 if (formatCount != 0) {
486 details.formats.resize(formatCount);
487 vkGetPhysicalDeviceSurfaceFormatsKHR(device, surface, &formatCount, details.formats.data());
488 }
489
490 uint32_t presentModeCount;
491 vkGetPhysicalDeviceSurfacePresentModesKHR(device, surface, &presentModeCount, nullptr);
492
493 if (presentModeCount != 0) {
494 details.presentModes.resize(presentModeCount);
495 vkGetPhysicalDeviceSurfacePresentModesKHR(device, surface, &presentModeCount, details.presentModes.data());
496 }
497
498 return details;
499 }
500
501 VkSurfaceFormatKHR chooseSwapSurfaceFormat(const vector<VkSurfaceFormatKHR>& availableFormats) {
502 for (const auto& availableFormat : availableFormats) {
503 if (availableFormat.format == VK_FORMAT_B8G8R8A8_UNORM && availableFormat.colorSpace == VK_COLOR_SPACE_SRGB_NONLINEAR_KHR) {
504 return availableFormat;
505 }
506 }
507
508 return availableFormats[0];
509 }
510
511 VkPresentModeKHR chooseSwapPresentMode(const vector<VkPresentModeKHR>& availablePresentModes) {
512 VkPresentModeKHR bestMode = VK_PRESENT_MODE_FIFO_KHR;
513
514 for (const auto& availablePresentMode : availablePresentModes) {
515 if (availablePresentMode == VK_PRESENT_MODE_MAILBOX_KHR) {
516 return availablePresentMode;
517 } else if (availablePresentMode == VK_PRESENT_MODE_IMMEDIATE_KHR) {
518 bestMode = availablePresentMode;
519 }
520 }
521
522 return bestMode;
523 }
524
525 VkExtent2D chooseSwapExtent(const VkSurfaceCapabilitiesKHR& capabilities) {
526 if (capabilities.currentExtent.width != numeric_limits<uint32_t>::max()) {
527 return capabilities.currentExtent;
528 } else {
529 int width, height;
530 gui->GetWindowSize(&width, &height);
531
532 VkExtent2D actualExtent = {
533 static_cast<uint32_t>(width),
534 static_cast<uint32_t>(height)
535 };
536
537 actualExtent.width = max(capabilities.minImageExtent.width, min(capabilities.maxImageExtent.width, actualExtent.width));
538 actualExtent.height = max(capabilities.minImageExtent.height, min(capabilities.maxImageExtent.height, actualExtent.height));
539
540 return actualExtent;
541 }
542 }
543
544 void populateDebugMessengerCreateInfo(VkDebugUtilsMessengerCreateInfoEXT& createInfo) {
545 createInfo = {};
546 createInfo.sType = VK_STRUCTURE_TYPE_DEBUG_UTILS_MESSENGER_CREATE_INFO_EXT;
547 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;
548 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;
549 createInfo.pfnUserCallback = debugCallback;
550 }
551
552 vector<const char*> getRequiredExtensions() {
553 vector<const char*> extensions = gui->GetRequiredExtensions();
554
555 if (enableValidationLayers) {
556 extensions.push_back(VK_EXT_DEBUG_UTILS_EXTENSION_NAME);
557 }
558
559 return extensions;
560 }
561
562 void createSwapChain() {
563 SwapChainSupportDetails swapChainSupport = querySwapChainSupport(physicalDevice);
564
565 VkSurfaceFormatKHR surfaceFormat = chooseSwapSurfaceFormat(swapChainSupport.formats);
566 VkPresentModeKHR presentMode = chooseSwapPresentMode(swapChainSupport.presentModes);
567 VkExtent2D extent = chooseSwapExtent(swapChainSupport.capabilities);
568
569 uint32_t imageCount = swapChainSupport.capabilities.minImageCount + 1;
570 if (swapChainSupport.capabilities.maxImageCount > 0 &&
571 imageCount > swapChainSupport.capabilities.maxImageCount) {
572 imageCount = swapChainSupport.capabilities.maxImageCount;
573 }
574
575 VkSwapchainCreateInfoKHR createInfo = {};
576
577 createInfo.sType = VK_STRUCTURE_TYPE_SWAPCHAIN_CREATE_INFO_KHR;
578 createInfo.surface = surface;
579 createInfo.minImageCount = imageCount;
580 createInfo.imageFormat = surfaceFormat.format;
581 createInfo.imageColorSpace = surfaceFormat.colorSpace;
582 createInfo.imageExtent = extent;
583 createInfo.imageArrayLayers = 1;
584 createInfo.imageUsage = VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT;
585
586 QueueFamilyIndices indices = findQueueFamilies(physicalDevice);
587 uint32_t queueFamilyIndices[] = {indices.graphicsFamily.value(), indices.presentFamily.value()};
588
589 if (indices.graphicsFamily != indices.presentFamily) {
590 createInfo.imageSharingMode = VK_SHARING_MODE_CONCURRENT;
591 createInfo.queueFamilyIndexCount = 2;
592 createInfo.pQueueFamilyIndices = queueFamilyIndices;
593 } else {
594 createInfo.imageSharingMode = VK_SHARING_MODE_EXCLUSIVE;
595 createInfo.queueFamilyIndexCount = 0; // Optional
596 createInfo.pQueueFamilyIndices = nullptr;
597 }
598
599 createInfo.preTransform = swapChainSupport.capabilities.currentTransform;
600 createInfo.compositeAlpha = VK_COMPOSITE_ALPHA_OPAQUE_BIT_KHR;
601 createInfo.presentMode = presentMode;
602 createInfo.clipped = VK_TRUE;
603 createInfo.oldSwapchain = VK_NULL_HANDLE;
604
605 if (vkCreateSwapchainKHR(device, &createInfo, nullptr, &swapChain) != VK_SUCCESS) {
606 throw runtime_error("failed to create swap chain!");
607 }
608
609 vkGetSwapchainImagesKHR(device, swapChain, &imageCount, nullptr);
610 swapChainImages.resize(imageCount);
611 vkGetSwapchainImagesKHR(device, swapChain, &imageCount, swapChainImages.data());
612
613 swapChainImageFormat = surfaceFormat.format;
614 swapChainExtent = extent;
615 }
616
617 void createImageViews() {
618 swapChainImageViews.resize(swapChainImages.size());
619
620 for (size_t i=0; i<swapChainImages.size(); i++) {
621 VkImageViewCreateInfo createInfo = {};
622 createInfo.sType = VK_STRUCTURE_TYPE_IMAGE_VIEW_CREATE_INFO;
623 createInfo.image = swapChainImages[i];
624
625 createInfo.viewType = VK_IMAGE_VIEW_TYPE_2D;
626 createInfo.format = swapChainImageFormat;
627
628 createInfo.components.r = VK_COMPONENT_SWIZZLE_IDENTITY;
629 createInfo.components.g = VK_COMPONENT_SWIZZLE_IDENTITY;
630 createInfo.components.b = VK_COMPONENT_SWIZZLE_IDENTITY;
631 createInfo.components.a = VK_COMPONENT_SWIZZLE_IDENTITY;
632
633 createInfo.subresourceRange.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT;
634 createInfo.subresourceRange.baseMipLevel = 0;
635 createInfo.subresourceRange.levelCount = 1;
636 createInfo.subresourceRange.baseArrayLayer = 0;
637 createInfo.subresourceRange.layerCount = 1;
638
639 if (vkCreateImageView(device, &createInfo, nullptr, &swapChainImageViews[i]) != VK_SUCCESS) {
640 throw runtime_error("failed to create image views!");
641 }
642 }
643 }
644
645 void createRenderPass() {
646 VkAttachmentDescription colorAttachment = {};
647 colorAttachment.format = swapChainImageFormat;
648 colorAttachment.samples = VK_SAMPLE_COUNT_1_BIT;
649 colorAttachment.loadOp = VK_ATTACHMENT_LOAD_OP_CLEAR;
650 colorAttachment.storeOp = VK_ATTACHMENT_STORE_OP_STORE;
651 colorAttachment.stencilLoadOp = VK_ATTACHMENT_LOAD_OP_DONT_CARE;
652 colorAttachment.stencilStoreOp = VK_ATTACHMENT_STORE_OP_DONT_CARE;
653 colorAttachment.initialLayout = VK_IMAGE_LAYOUT_UNDEFINED;
654 colorAttachment.finalLayout = VK_IMAGE_LAYOUT_PRESENT_SRC_KHR;
655
656 VkAttachmentReference colorAttachmentRef = {};
657 colorAttachmentRef.attachment = 0;
658 colorAttachmentRef.layout = VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL;
659
660 VkSubpassDescription subpass = {};
661 subpass.pipelineBindPoint = VK_PIPELINE_BIND_POINT_GRAPHICS;
662 subpass.colorAttachmentCount = 1;
663 subpass.pColorAttachments = &colorAttachmentRef;
664
665 VkSubpassDependency dependency = {};
666 dependency.srcSubpass = VK_SUBPASS_EXTERNAL;
667 dependency.dstSubpass = 0;
668 dependency.srcStageMask = VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT;
669 dependency.srcAccessMask = 0;
670 dependency.dstStageMask = VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT;
671 dependency.dstAccessMask = VK_ACCESS_COLOR_ATTACHMENT_READ_BIT | VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT;
672
673 VkRenderPassCreateInfo renderPassInfo = {};
674 renderPassInfo.sType = VK_STRUCTURE_TYPE_RENDER_PASS_CREATE_INFO;
675 renderPassInfo.attachmentCount = 1;
676 renderPassInfo.pAttachments = &colorAttachment;
677 renderPassInfo.subpassCount = 1;
678 renderPassInfo.pSubpasses = &subpass;
679 renderPassInfo.dependencyCount = 1;
680 renderPassInfo.pDependencies = &dependency;
681
682 if (vkCreateRenderPass(device, &renderPassInfo, nullptr, &renderPass) != VK_SUCCESS) {
683 throw runtime_error("failed to create render pass!");
684 }
685 }
686
687 void createGraphicsPipeline() {
688 auto vertShaderCode = readFile("shaders/vert.spv");
689 auto fragShaderCode = readFile("shaders/frag.spv");
690
691 VkShaderModule vertShaderModule = createShaderModule(vertShaderCode);
692 VkShaderModule fragShaderModule = createShaderModule(fragShaderCode);
693
694 VkPipelineShaderStageCreateInfo vertShaderStageInfo = {};
695 vertShaderStageInfo.sType = VK_STRUCTURE_TYPE_PIPELINE_SHADER_STAGE_CREATE_INFO;
696 vertShaderStageInfo.stage = VK_SHADER_STAGE_VERTEX_BIT;
697 vertShaderStageInfo.module = vertShaderModule;
698 vertShaderStageInfo.pName = "main";
699
700 VkPipelineShaderStageCreateInfo fragShaderStageInfo = {};
701 fragShaderStageInfo.sType = VK_STRUCTURE_TYPE_PIPELINE_SHADER_STAGE_CREATE_INFO;
702 fragShaderStageInfo.stage = VK_SHADER_STAGE_FRAGMENT_BIT;
703 fragShaderStageInfo.module = fragShaderModule;
704 fragShaderStageInfo.pName = "main";
705
706 VkPipelineShaderStageCreateInfo shaderStages[] = { vertShaderStageInfo, fragShaderStageInfo };
707
708 VkPipelineVertexInputStateCreateInfo vertexInputInfo = {};
709 vertexInputInfo.sType = VK_STRUCTURE_TYPE_PIPELINE_VERTEX_INPUT_STATE_CREATE_INFO;
710
711 auto bindingDescription = Vertex::getBindingDescription();
712 auto attributeDescriptions = Vertex::getAttributeDescriptions();
713
714 vertexInputInfo.vertexBindingDescriptionCount = 1;
715 vertexInputInfo.vertexAttributeDescriptionCount = static_cast<uint32_t>(attributeDescriptions.size());
716 vertexInputInfo.pVertexBindingDescriptions = &bindingDescription;
717 vertexInputInfo.pVertexAttributeDescriptions = attributeDescriptions.data();
718
719 VkPipelineInputAssemblyStateCreateInfo inputAssembly = {};
720 inputAssembly.sType = VK_STRUCTURE_TYPE_PIPELINE_INPUT_ASSEMBLY_STATE_CREATE_INFO;
721 inputAssembly.topology = VK_PRIMITIVE_TOPOLOGY_TRIANGLE_LIST;
722 inputAssembly.primitiveRestartEnable = VK_FALSE;
723
724 VkViewport viewport = {};
725 viewport.x = 0.0f;
726 viewport.y = 0.0f;
727 viewport.width = (float) swapChainExtent.width;
728 viewport.height = (float) swapChainExtent.height;
729 viewport.minDepth = 0.0f;
730 viewport.maxDepth = 1.0f;
731
732 VkRect2D scissor = {};
733 scissor.offset = { 0, 0 };
734 scissor.extent = swapChainExtent;
735
736 VkPipelineViewportStateCreateInfo viewportState = {};
737 viewportState.sType = VK_STRUCTURE_TYPE_PIPELINE_VIEWPORT_STATE_CREATE_INFO;
738 viewportState.viewportCount = 1;
739 viewportState.pViewports = &viewport;
740 viewportState.scissorCount = 1;
741 viewportState.pScissors = &scissor;
742
743 VkPipelineRasterizationStateCreateInfo rasterizer = {};
744 rasterizer.sType = VK_STRUCTURE_TYPE_PIPELINE_RASTERIZATION_STATE_CREATE_INFO;
745 rasterizer.depthClampEnable = VK_FALSE;
746 rasterizer.rasterizerDiscardEnable = VK_FALSE;
747 rasterizer.polygonMode = VK_POLYGON_MODE_FILL;
748 rasterizer.lineWidth = 1.0f;
749 rasterizer.cullMode = VK_CULL_MODE_BACK_BIT;
750 rasterizer.frontFace = VK_FRONT_FACE_CLOCKWISE;
751 rasterizer.depthBiasEnable = false;
752
753 VkPipelineMultisampleStateCreateInfo multisampling = {};
754 multisampling.sType = VK_STRUCTURE_TYPE_PIPELINE_MULTISAMPLE_STATE_CREATE_INFO;
755 multisampling.sampleShadingEnable = VK_FALSE;
756 multisampling.rasterizationSamples = VK_SAMPLE_COUNT_1_BIT;
757
758 VkPipelineColorBlendAttachmentState colorBlendAttachment = {};
759 colorBlendAttachment.colorWriteMask = VK_COLOR_COMPONENT_R_BIT | VK_COLOR_COMPONENT_G_BIT | VK_COLOR_COMPONENT_B_BIT | VK_COLOR_COMPONENT_A_BIT;
760 colorBlendAttachment.blendEnable = VK_FALSE;
761
762 VkPipelineColorBlendStateCreateInfo colorBlending = {};
763 colorBlending.sType = VK_STRUCTURE_TYPE_PIPELINE_COLOR_BLEND_STATE_CREATE_INFO;
764 colorBlending.logicOpEnable = VK_FALSE;
765 colorBlending.logicOp = VK_LOGIC_OP_COPY;
766 colorBlending.attachmentCount = 1;
767 colorBlending.pAttachments = &colorBlendAttachment;
768 colorBlending.blendConstants[0] = 0.0f;
769 colorBlending.blendConstants[1] = 0.0f;
770 colorBlending.blendConstants[2] = 0.0f;
771 colorBlending.blendConstants[3] = 0.0f;
772
773 VkPipelineLayoutCreateInfo pipelineLayoutInfo = {};
774 pipelineLayoutInfo.sType = VK_STRUCTURE_TYPE_PIPELINE_LAYOUT_CREATE_INFO;
775 pipelineLayoutInfo.setLayoutCount = 0;
776 pipelineLayoutInfo.pushConstantRangeCount = 0;
777
778 if (vkCreatePipelineLayout(device, &pipelineLayoutInfo, nullptr, &pipelineLayout) != VK_SUCCESS) {
779 throw runtime_error("failed to create pipeline layout!");
780 }
781
782 VkGraphicsPipelineCreateInfo pipelineInfo = {};
783 pipelineInfo.sType = VK_STRUCTURE_TYPE_GRAPHICS_PIPELINE_CREATE_INFO;
784 pipelineInfo.stageCount = 2;
785 pipelineInfo.pStages = shaderStages;
786 pipelineInfo.pVertexInputState = &vertexInputInfo;
787 pipelineInfo.pInputAssemblyState = &inputAssembly;
788 pipelineInfo.pViewportState = &viewportState;
789 pipelineInfo.pRasterizationState = &rasterizer;
790 pipelineInfo.pMultisampleState = &multisampling;
791 pipelineInfo.pDepthStencilState = nullptr;
792 pipelineInfo.pColorBlendState = &colorBlending;
793 pipelineInfo.pDynamicState = nullptr;
794 pipelineInfo.layout = pipelineLayout;
795 pipelineInfo.renderPass = renderPass;
796 pipelineInfo.subpass = 0;
797 pipelineInfo.basePipelineHandle = VK_NULL_HANDLE;
798 pipelineInfo.basePipelineIndex = -1;
799
800 if (vkCreateGraphicsPipelines(device, VK_NULL_HANDLE, 1, &pipelineInfo, nullptr, &graphicsPipeline) != VK_SUCCESS) {
801 throw runtime_error("failed to create graphics pipeline!");
802 }
803
804 vkDestroyShaderModule(device, vertShaderModule, nullptr);
805 vkDestroyShaderModule(device, fragShaderModule, nullptr);
806 }
807
808 VkShaderModule createShaderModule(const vector<char>& code) {
809 VkShaderModuleCreateInfo createInfo = {};
810 createInfo.sType = VK_STRUCTURE_TYPE_SHADER_MODULE_CREATE_INFO;
811 createInfo.codeSize = code.size();
812 createInfo.pCode = reinterpret_cast<const uint32_t*>(code.data());
813
814 VkShaderModule shaderModule;
815 if (vkCreateShaderModule(device, &createInfo, nullptr, &shaderModule) != VK_SUCCESS) {
816 throw runtime_error("failed to create shader module!");
817 }
818
819 return shaderModule;
820 }
821
822 void createFramebuffers() {
823 swapChainFramebuffers.resize(swapChainImageViews.size());
824
825 for (size_t i = 0; i < swapChainImageViews.size(); i++) {
826 VkImageView attachments[] = {
827 swapChainImageViews[i]
828 };
829
830 VkFramebufferCreateInfo framebufferInfo = {};
831 framebufferInfo.sType = VK_STRUCTURE_TYPE_FRAMEBUFFER_CREATE_INFO;
832 framebufferInfo.renderPass = renderPass;
833 framebufferInfo.attachmentCount = 1;
834 framebufferInfo.pAttachments = attachments;
835 framebufferInfo.width = swapChainExtent.width;
836 framebufferInfo.height = swapChainExtent.height;
837 framebufferInfo.layers = 1;
838
839 if (vkCreateFramebuffer(device, &framebufferInfo, nullptr, &swapChainFramebuffers[i]) != VK_SUCCESS) {
840 throw runtime_error("failed to create framebuffer!");
841 }
842 }
843 }
844
845 void createCommandPool() {
846 QueueFamilyIndices queueFamilyIndices = findQueueFamilies(physicalDevice);
847
848 VkCommandPoolCreateInfo poolInfo = {};
849 poolInfo.sType = VK_STRUCTURE_TYPE_COMMAND_POOL_CREATE_INFO;
850 poolInfo.queueFamilyIndex = queueFamilyIndices.graphicsFamily.value();
851 poolInfo.flags = 0;
852
853 if (vkCreateCommandPool(device, &poolInfo, nullptr, &commandPool) != VK_SUCCESS) {
854 throw runtime_error("failed to create command pool!");
855 }
856 }
857
858 void createVertexBuffer() {
859 VkDeviceSize bufferSize = sizeof(vertices[0]) * vertices.size();
860
861 VkBuffer stagingBuffer;
862 VkDeviceMemory stagingBufferMemory;
863 createBuffer(bufferSize, VK_BUFFER_USAGE_TRANSFER_SRC_BIT,
864 VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT | VK_MEMORY_PROPERTY_HOST_COHERENT_BIT,
865 stagingBuffer, stagingBufferMemory);
866
867 void* data;
868 vkMapMemory(device, stagingBufferMemory, 0, bufferSize, 0, &data);
869 memcpy(data, vertices.data(), (size_t)bufferSize);
870 vkUnmapMemory(device, stagingBufferMemory);
871
872 createBuffer(bufferSize, VK_BUFFER_USAGE_TRANSFER_DST_BIT | VK_BUFFER_USAGE_VERTEX_BUFFER_BIT,
873 VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT, vertexBuffer, vertexBufferMemory);
874
875 copyBuffer(stagingBuffer, vertexBuffer, bufferSize);
876
877 vkDestroyBuffer(device, stagingBuffer, nullptr);
878 vkFreeMemory(device, stagingBufferMemory, nullptr);
879 }
880
881 void createBuffer(VkDeviceSize size, VkBufferUsageFlags usage, VkMemoryPropertyFlags properties,
882 VkBuffer& buffer, VkDeviceMemory& bufferMemory) {
883 VkBufferCreateInfo bufferInfo = {};
884 bufferInfo.sType = VK_STRUCTURE_TYPE_BUFFER_CREATE_INFO;
885 bufferInfo.size = size;
886 bufferInfo.usage = usage;
887 bufferInfo.sharingMode = VK_SHARING_MODE_EXCLUSIVE;
888
889 if (vkCreateBuffer(device, &bufferInfo, nullptr, &buffer) != VK_SUCCESS) {
890 throw runtime_error("failed to create buffer!");
891 }
892
893 VkMemoryRequirements memRequirements;
894 vkGetBufferMemoryRequirements(device, buffer, &memRequirements);
895
896 VkMemoryAllocateInfo allocInfo = {};
897 allocInfo.sType = VK_STRUCTURE_TYPE_MEMORY_ALLOCATE_INFO;
898 allocInfo.allocationSize = memRequirements.size;
899 allocInfo.memoryTypeIndex = findMemoryType(memRequirements.memoryTypeBits, properties);
900
901 if (vkAllocateMemory(device, &allocInfo, nullptr, &bufferMemory) != VK_SUCCESS) {
902 throw runtime_error("failed to allocate buffer memory!");
903 }
904
905 vkBindBufferMemory(device, buffer, bufferMemory, 0);
906 }
907
908 void copyBuffer(VkBuffer srcBuffer, VkBuffer dstBuffer, VkDeviceSize size) {
909 VkCommandBufferAllocateInfo allocInfo = {};
910 allocInfo.sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_ALLOCATE_INFO;
911 allocInfo.level = VK_COMMAND_BUFFER_LEVEL_PRIMARY;
912 allocInfo.commandPool = commandPool;
913 allocInfo.commandBufferCount = 1;
914
915 VkCommandBuffer commandBuffer;
916 vkAllocateCommandBuffers(device, &allocInfo, &commandBuffer);
917
918 VkCommandBufferBeginInfo beginInfo = {};
919 beginInfo.sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_BEGIN_INFO;
920 beginInfo.flags = VK_COMMAND_BUFFER_USAGE_ONE_TIME_SUBMIT_BIT;
921
922 vkBeginCommandBuffer(commandBuffer, &beginInfo);
923
924 VkBufferCopy copyRegion = {};
925 copyRegion.srcOffset = 0;
926 copyRegion.dstOffset = 0;
927 copyRegion.size = size;
928
929 vkCmdCopyBuffer(commandBuffer, srcBuffer, dstBuffer, 1, &copyRegion);
930
931 vkEndCommandBuffer(commandBuffer);
932
933 VkSubmitInfo submitInfo = {};
934 submitInfo.sType = VK_STRUCTURE_TYPE_SUBMIT_INFO;
935 submitInfo.commandBufferCount = 1;
936 submitInfo.pCommandBuffers = &commandBuffer;
937
938 vkQueueSubmit(graphicsQueue, 1, &submitInfo, VK_NULL_HANDLE);
939 vkQueueWaitIdle(graphicsQueue);
940
941 vkFreeCommandBuffers(device, commandPool, 1, &commandBuffer);
942 }
943
944 uint32_t findMemoryType(uint32_t typeFilter, VkMemoryPropertyFlags properties) {
945 VkPhysicalDeviceMemoryProperties memProperties;
946 vkGetPhysicalDeviceMemoryProperties(physicalDevice, &memProperties);
947
948 for (uint32_t i = 0; i < memProperties.memoryTypeCount; i++) {
949 if ((typeFilter & (1 << i)) && (memProperties.memoryTypes[i].propertyFlags & properties) == properties) {
950 return i;
951 }
952 }
953
954 throw runtime_error("failed to find suitable memory type!");
955 }
956
957 void createCommandBuffers() {
958 commandBuffers.resize(swapChainFramebuffers.size());
959
960 VkCommandBufferAllocateInfo allocInfo = {};
961 allocInfo.sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_ALLOCATE_INFO;
962 allocInfo.commandPool = commandPool;
963 allocInfo.level = VK_COMMAND_BUFFER_LEVEL_PRIMARY;
964 allocInfo.commandBufferCount = (uint32_t)commandBuffers.size();
965
966 if (vkAllocateCommandBuffers(device, &allocInfo, commandBuffers.data()) != VK_SUCCESS) {
967 throw runtime_error("failed to create command buffers!");
968 }
969
970 for (size_t i = 0; i < commandBuffers.size(); i++) {
971 VkCommandBufferBeginInfo beginInfo = {};
972 beginInfo.sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_BEGIN_INFO;
973 beginInfo.flags = VK_COMMAND_BUFFER_USAGE_SIMULTANEOUS_USE_BIT;
974 beginInfo.pInheritanceInfo = nullptr;
975
976 if (vkBeginCommandBuffer(commandBuffers[i], &beginInfo) != VK_SUCCESS) {
977 throw runtime_error("failed to begin recording command buffer!");
978 }
979
980 VkRenderPassBeginInfo renderPassInfo = {};
981 renderPassInfo.sType = VK_STRUCTURE_TYPE_RENDER_PASS_BEGIN_INFO;
982 renderPassInfo.renderPass = renderPass;
983 renderPassInfo.framebuffer = swapChainFramebuffers[i];
984 renderPassInfo.renderArea.offset = { 0, 0 };
985 renderPassInfo.renderArea.extent = swapChainExtent;
986
987 VkClearValue clearColor = { 0.0f, 0.0f, 0.0f, 1.0f };
988 renderPassInfo.clearValueCount = 1;
989 renderPassInfo.pClearValues = &clearColor;
990
991 vkCmdBeginRenderPass(commandBuffers[i], &renderPassInfo, VK_SUBPASS_CONTENTS_INLINE);
992 vkCmdBindPipeline(commandBuffers[i], VK_PIPELINE_BIND_POINT_GRAPHICS, graphicsPipeline);
993
994 VkBuffer vertexBuffers[] = { vertexBuffer };
995 VkDeviceSize offsets[] = { 0 };
996 vkCmdBindVertexBuffers(commandBuffers[i], 0, 1, vertexBuffers, offsets);
997
998 vkCmdDraw(commandBuffers[i], static_cast<uint32_t>(vertices.size()), 1, 0, 0);
999 vkCmdEndRenderPass(commandBuffers[i]);
1000
1001 if (vkEndCommandBuffer(commandBuffers[i]) != VK_SUCCESS) {
1002 throw runtime_error("failed to record command buffer!");
1003 }
1004 }
1005 }
1006
1007 void createSyncObjects() {
1008 imageAvailableSemaphores.resize(MAX_FRAMES_IN_FLIGHT);
1009 renderFinishedSemaphores.resize(MAX_FRAMES_IN_FLIGHT);
1010 inFlightFences.resize(MAX_FRAMES_IN_FLIGHT);
1011
1012 VkSemaphoreCreateInfo semaphoreInfo = {};
1013 semaphoreInfo.sType = VK_STRUCTURE_TYPE_SEMAPHORE_CREATE_INFO;
1014
1015 VkFenceCreateInfo fenceInfo = {};
1016 fenceInfo.sType = VK_STRUCTURE_TYPE_FENCE_CREATE_INFO;
1017 fenceInfo.flags = VK_FENCE_CREATE_SIGNALED_BIT;
1018
1019 for (size_t i = 0; i < MAX_FRAMES_IN_FLIGHT; i++) {
1020 if (vkCreateSemaphore(device, &semaphoreInfo, nullptr, &imageAvailableSemaphores[i]) != VK_SUCCESS ||
1021 vkCreateSemaphore(device, &semaphoreInfo, nullptr, &renderFinishedSemaphores[i]) != VK_SUCCESS ||
1022 vkCreateFence(device, &fenceInfo, nullptr, &inFlightFences[i]) != VK_SUCCESS) {
1023 throw runtime_error("failed to create synchronization objects for a frame!");
1024 }
1025 }
1026 }
1027
1028 void mainLoop() {
1029 // TODO: Create some generic event-handling functions in game-gui-*
1030 SDL_Event e;
1031 bool quit = false;
1032
1033 while (!quit) {
1034 while (SDL_PollEvent(&e)) {
1035 if (e.type == SDL_QUIT) {
1036 quit = true;
1037 }
1038 if (e.type == SDL_KEYDOWN) {
1039 quit = true;
1040 }
1041 if (e.type == SDL_MOUSEBUTTONDOWN) {
1042 quit = true;
1043 }
1044 if (e.type == SDL_WINDOWEVENT) {
1045 if (e.window.event == SDL_WINDOWEVENT_SIZE_CHANGED) {
1046 framebufferResized = true;
1047 } else if (e.window.event == SDL_WINDOWEVENT_MINIMIZED) {
1048 framebufferResized = true;
1049 }
1050 }
1051 }
1052
1053 drawFrame();
1054
1055 //SDL_FillRect(sdlSurface, nullptr, SDL_MapRGB(sdlSurface->format, 0x00, 0x99, 0x99));
1056 //SDL_UpdateWindowSurface(window);
1057 }
1058
1059 vkDeviceWaitIdle(device);
1060 }
1061
1062 void drawFrame() {
1063 vkWaitForFences(device, 1, &inFlightFences[currentFrame], VK_TRUE, numeric_limits<uint64_t>::max());
1064
1065 uint32_t imageIndex;
1066
1067 VkResult result = vkAcquireNextImageKHR(device, swapChain, numeric_limits<uint64_t>::max(), imageAvailableSemaphores[currentFrame], VK_NULL_HANDLE, &imageIndex);
1068
1069 if (result == VK_ERROR_OUT_OF_DATE_KHR) {
1070 recreateSwapChain();
1071 return;
1072 } else if (result != VK_SUCCESS && result != VK_SUBOPTIMAL_KHR) {
1073 throw runtime_error("failed to acquire swap chain image!");
1074 }
1075
1076 VkSubmitInfo submitInfo = {};
1077 submitInfo.sType = VK_STRUCTURE_TYPE_SUBMIT_INFO;
1078
1079 VkSemaphore waitSemaphores[] = { imageAvailableSemaphores[currentFrame] };
1080 VkPipelineStageFlags waitStages[] = { VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT };
1081
1082 submitInfo.waitSemaphoreCount = 1;
1083 submitInfo.pWaitSemaphores = waitSemaphores;
1084 submitInfo.pWaitDstStageMask = waitStages;
1085 submitInfo.commandBufferCount = 1;
1086 submitInfo.pCommandBuffers = &commandBuffers[imageIndex];
1087
1088 VkSemaphore signalSemaphores[] = { renderFinishedSemaphores[currentFrame] };
1089
1090 submitInfo.signalSemaphoreCount = 1;
1091 submitInfo.pSignalSemaphores = signalSemaphores;
1092
1093 vkResetFences(device, 1, &inFlightFences[currentFrame]);
1094
1095 if (vkQueueSubmit(graphicsQueue, 1, &submitInfo, inFlightFences[currentFrame]) != VK_SUCCESS) {
1096 throw runtime_error("failed to submit draw command buffer!");
1097 }
1098
1099 VkPresentInfoKHR presentInfo = {};
1100 presentInfo.sType = VK_STRUCTURE_TYPE_PRESENT_INFO_KHR;
1101
1102 presentInfo.waitSemaphoreCount = 1;
1103 presentInfo.pWaitSemaphores = signalSemaphores;
1104
1105 VkSwapchainKHR swapChains[] = { swapChain };
1106 presentInfo.swapchainCount = 1;
1107 presentInfo.pSwapchains = swapChains;
1108 presentInfo.pImageIndices = &imageIndex;
1109 presentInfo.pResults = nullptr;
1110
1111 result = vkQueuePresentKHR(presentQueue, &presentInfo);
1112
1113 if (result == VK_ERROR_OUT_OF_DATE_KHR || result == VK_SUBOPTIMAL_KHR || framebufferResized) {
1114 framebufferResized = false;
1115 recreateSwapChain();
1116 } else if (result != VK_SUCCESS) {
1117 throw runtime_error("failed to present swap chain image!");
1118 }
1119
1120 currentFrame = (currentFrame + 1) % MAX_FRAMES_IN_FLIGHT;
1121 }
1122
1123 void cleanup() {
1124 cleanupSwapChain();
1125
1126 vkDestroyBuffer(device, vertexBuffer, nullptr);
1127 vkFreeMemory(device, vertexBufferMemory, nullptr);
1128
1129 for (size_t i = 0; i < MAX_FRAMES_IN_FLIGHT; i++) {
1130 vkDestroySemaphore(device, imageAvailableSemaphores[i], nullptr);
1131 vkDestroySemaphore(device, renderFinishedSemaphores[i], nullptr);
1132 vkDestroyFence(device, inFlightFences[i], nullptr);
1133 }
1134
1135 vkDestroyCommandPool(device, commandPool, nullptr);
1136
1137 vkDestroyDevice(device, nullptr);
1138
1139 if (enableValidationLayers) {
1140 DestroyDebugUtilsMessengerEXT(instance, debugMessenger, nullptr);
1141 }
1142
1143 vkDestroySurfaceKHR(instance, surface, nullptr);
1144 vkDestroyInstance(instance, nullptr);
1145
1146 gui->DestroyWindow();
1147 gui->Shutdown();
1148 delete gui;
1149 }
1150
1151 static VKAPI_ATTR VkBool32 VKAPI_CALL debugCallback(
1152 VkDebugUtilsMessageSeverityFlagBitsEXT messageSeverity,
1153 VkDebugUtilsMessageTypeFlagsEXT messageType,
1154 const VkDebugUtilsMessengerCallbackDataEXT* pCallbackData,
1155 void* pUserData) {
1156 cerr << "validation layer: " << pCallbackData->pMessage << endl;
1157
1158 return VK_FALSE;
1159 }
1160
1161 static vector<char> readFile(const string& filename) {
1162 ifstream file(filename, ios::ate | ios::binary);
1163
1164 if (!file.is_open()) {
1165 throw runtime_error("failed to open file!");
1166 }
1167
1168 size_t fileSize = (size_t)file.tellg();
1169 vector<char> buffer(fileSize);
1170
1171 file.seekg(0);
1172 file.read(buffer.data(), fileSize);
1173
1174 file.close();
1175
1176 return buffer;
1177 }
1178};
1179
1180int main(int argc, char* argv[]) {
1181
1182#ifdef NDEBUG
1183 cout << "DEBUGGING IS OFF" << endl;
1184#else
1185 cout << "DEBUGGING IS ON" << endl;
1186#endif
1187
1188 cout << "Starting Vulkan game..." << endl;
1189
1190 VulkanGame game;
1191
1192 try {
1193 game.run();
1194 } catch (const exception& e) {
1195 cerr << e.what() << endl;
1196 return EXIT_FAILURE;
1197 }
1198
1199 cout << "Finished running the game" << endl;
1200
1201 return EXIT_SUCCESS;
1202}
Note: See TracBrowser for help on using the repository browser.