source: opengl-game/vulkan-game.cpp@ 8667f76

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

Move getWindowSize and getRequiredExtensions to the game gui

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