source: opengl-game/vulkan-game.cpp@ 0e6ecf3

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

Create a game gui implementation using glfw3 and move window create/destruction and Vulkan surface creation to the game gui

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