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

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

Create the frame buffers

  • Property mode set to 100644
File size: 31.6 KB
RevLine 
[826df16]1#include <vulkan/vulkan.h>
[03f4c64]2
[826df16]3#include <SDL2/SDL.h>
4#include <SDL2/SDL_vulkan.h>
5
6//#define _USE_MATH_DEFINES // Will be needed when/if I need to # include <cmath>
[03f4c64]7
8#define GLM_FORCE_RADIANS
9#define GLM_FORCE_DEPTH_ZERO_TO_ONE
10#include <glm/vec4.hpp>
11#include <glm/mat4x4.hpp>
12
13#include <iostream>
[826df16]14#include <vector>
[b3671b5]15#include <set>
[826df16]16#include <stdexcept>
17#include <cstdlib>
[909b51a]18#include <optional>
[bfd620e]19#include <algorithm>
[e09ad38]20#include <fstream>
[826df16]21
22#include "game-gui-sdl.hpp"
[03f4c64]23
24using namespace std;
[bfd620e]25//using namespace glm;
[03f4c64]26
[826df16]27const int SCREEN_WIDTH = 800;
28const int SCREEN_HEIGHT = 600;
29
30#ifdef NDEBUG
31 const bool enableValidationLayers = false;
32#else
33 const bool enableValidationLayers = true;
34#endif
35
[bfd620e]36const vector<const char*> validationLayers = {
37 "VK_LAYER_KHRONOS_validation"
38};
39
40const vector<const char*> deviceExtensions = {
41 VK_KHR_SWAPCHAIN_EXTENSION_NAME
42};
43
[909b51a]44struct QueueFamilyIndices {
45 optional<uint32_t> graphicsFamily;
[b3671b5]46 optional<uint32_t> presentFamily;
[909b51a]47
48 bool isComplete() {
[b3671b5]49 return graphicsFamily.has_value() && presentFamily.has_value();
[909b51a]50 }
51};
52
[bfd620e]53struct SwapChainSupportDetails {
54 VkSurfaceCapabilitiesKHR capabilities;
55 vector<VkSurfaceFormatKHR> formats;
56 vector<VkPresentModeKHR> presentModes;
57};
58
[b6127d2]59VkResult CreateDebugUtilsMessengerEXT(VkInstance instance,
60 const VkDebugUtilsMessengerCreateInfoEXT* pCreateInfo,
61 const VkAllocationCallbacks* pAllocator,
62 VkDebugUtilsMessengerEXT* pDebugMessenger) {
63 auto func = (PFN_vkCreateDebugUtilsMessengerEXT) vkGetInstanceProcAddr(
64 instance, "vkCreateDebugUtilsMessengerEXT");
65
66 if (func != nullptr) {
67 return func(instance, pCreateInfo, pAllocator, pDebugMessenger);
68 } else {
69 return VK_ERROR_EXTENSION_NOT_PRESENT;
70 }
71}
72
[80de39d]73void DestroyDebugUtilsMessengerEXT(VkInstance instance,
74 VkDebugUtilsMessengerEXT debugMessenger,
75 const VkAllocationCallbacks* pAllocator) {
76 auto func = (PFN_vkDestroyDebugUtilsMessengerEXT) vkGetInstanceProcAddr(
77 instance, "vkDestroyDebugUtilsMessengerEXT");
78
79 if (func != nullptr) {
80 func(instance, debugMessenger, pAllocator);
81 }
82}
83
[826df16]84class VulkanGame {
85 public:
86 void run() {
87 if (initWindow() == RTWO_ERROR) {
88 return;
89 }
90 initVulkan();
91 mainLoop();
92 cleanup();
93 }
94 private:
[98f3232]95 GameGui* gui = new GameGui_SDL();
[80de39d]96 SDL_Window* window = nullptr;
[826df16]97
98 VkInstance instance;
[b6127d2]99 VkDebugUtilsMessengerEXT debugMessenger;
[b3671b5]100 VkSurfaceKHR surface;
[321272c]101 SDL_Surface* sdlSurface = nullptr;
[b3671b5]102
[909b51a]103 VkPhysicalDevice physicalDevice = VK_NULL_HANDLE;
104 VkDevice device;
[b3671b5]105
[909b51a]106 VkQueue graphicsQueue;
[b3671b5]107 VkQueue presentQueue;
[826df16]108
[bfd620e]109 VkSwapchainKHR swapChain;
110 vector<VkImage> swapChainImages;
111 VkFormat swapChainImageFormat;
112 VkExtent2D swapChainExtent;
113
114 vector<VkImageView> swapChainImageViews;
[be34c9a]115 VkRenderPass renderPass;
[84216c7]116 VkPipelineLayout pipelineLayout;
[fd70015]117 VkPipeline graphicsPipeline;
[bfd620e]118
[ebeb3aa]119 vector<VkFramebuffer> swapChainFramebuffers;
120
[826df16]121 // both SDL and GLFW create window functions return NULL on failure
122 bool initWindow() {
[98f3232]123 if (gui->Init() == RTWO_ERROR) {
[826df16]124 cout << "UI library could not be initialized!" << endl;
125 return RTWO_ERROR;
126 } else {
127 // On Apple's OS X you must set the NSHighResolutionCapable Info.plist property to YES,
128 // otherwise you will not receive a High DPI OpenGL canvas.
129
130 // TODO: Move this into some generic method in game-gui-sdl
131 window = SDL_CreateWindow("Vulkan Game",
132 SDL_WINDOWPOS_CENTERED, SDL_WINDOWPOS_CENTERED,
133 SCREEN_WIDTH, SCREEN_HEIGHT,
134 SDL_WINDOW_VULKAN | SDL_WINDOW_SHOWN);
135
[80de39d]136 if (window == nullptr) {
[826df16]137 cout << "Window could not be created!" << endl;
138 return RTWO_ERROR;
139 } else {
140 return RTWO_SUCCESS;
141 }
142 }
143 }
144
145 void initVulkan() {
146 createInstance();
[7dcd925]147 setupDebugMessenger();
[b3671b5]148 createSurface();
[909b51a]149 pickPhysicalDevice();
150 createLogicalDevice();
[bfd620e]151 createSwapChain();
152 createImageViews();
[be34c9a]153 createRenderPass();
[4befb76]154 createGraphicsPipeline();
[ebeb3aa]155 createFramebuffers();
[826df16]156 }
157
158 void createInstance() {
[b6127d2]159 if (enableValidationLayers && !checkValidationLayerSupport()) {
160 throw runtime_error("validation layers requested, but not available!");
161 }
162
[826df16]163 VkApplicationInfo appInfo = {};
164 appInfo.sType = VK_STRUCTURE_TYPE_APPLICATION_INFO;
165 appInfo.pApplicationName = "Vulkan Game";
166 appInfo.applicationVersion = VK_MAKE_VERSION(1, 0, 0);
167 appInfo.pEngineName = "No Engine";
168 appInfo.engineVersion = VK_MAKE_VERSION(1, 0, 0);
169 appInfo.apiVersion = VK_API_VERSION_1_0;
170
171 VkInstanceCreateInfo createInfo = {};
172 createInfo.sType = VK_STRUCTURE_TYPE_INSTANCE_CREATE_INFO;
173 createInfo.pApplicationInfo = &appInfo;
174
[a8f0577]175 vector<const char*> extensions = getRequiredExtensions();
[b6127d2]176 createInfo.enabledExtensionCount = static_cast<uint32_t>(extensions.size());
177 createInfo.ppEnabledExtensionNames = extensions.data();
[826df16]178
[b3671b5]179 cout << endl << "SDL extensions:" << endl;
180 for (const char* extensionName : extensions) {
181 cout << extensionName << endl;
182 }
183 cout << endl;
184
[80de39d]185 VkDebugUtilsMessengerCreateInfoEXT debugCreateInfo;
[b6127d2]186 if (enableValidationLayers) {
187 createInfo.enabledLayerCount = static_cast<uint32_t>(validationLayers.size());
188 createInfo.ppEnabledLayerNames = validationLayers.data();
[80de39d]189
190 populateDebugMessengerCreateInfo(debugCreateInfo);
191 createInfo.pNext = &debugCreateInfo;
[b6127d2]192 } else {
193 createInfo.enabledLayerCount = 0;
[80de39d]194
195 createInfo.pNext = nullptr;
[b6127d2]196 }
[826df16]197
198 if (vkCreateInstance(&createInfo, nullptr, &instance) != VK_SUCCESS) {
199 throw runtime_error("failed to create instance!");
200 }
201 }
202
[80de39d]203 void setupDebugMessenger() {
204 if (!enableValidationLayers) return;
205
206 VkDebugUtilsMessengerCreateInfoEXT createInfo;
207 populateDebugMessengerCreateInfo(createInfo);
[b6127d2]208
209 if (CreateDebugUtilsMessengerEXT(instance, &createInfo, nullptr, &debugMessenger) != VK_SUCCESS) {
210 throw runtime_error("failed to setup debug messenger!");
211 }
212 }
213
[b3671b5]214 void createSurface() {
[321272c]215 sdlSurface = SDL_GetWindowSurface(window);
216
217 if (sdlSurface == nullptr) {
218 cout << "Could not get SDL Surface! =(" << endl;
219 }
[b3671b5]220
221 if (!SDL_Vulkan_CreateSurface(window, instance, &surface)) {
222 throw runtime_error("failed to create window surface!");
223 }
224
225 /*
226 if (glfwCreateWindowSurface(instance, window, nullptr, &surface) != VK_SUCCESS) {
227 throw runtime_error("failed to create window surface!");
228 }
229 */
230 }
231
[909b51a]232 void pickPhysicalDevice() {
233 uint32_t deviceCount = 0;
234 vkEnumeratePhysicalDevices(instance, &deviceCount, nullptr);
235
236 if (deviceCount == 0) {
237 throw runtime_error("failed to find GPUs with Vulkan support!");
238 }
239
240 vector<VkPhysicalDevice> devices(deviceCount);
241 vkEnumeratePhysicalDevices(instance, &deviceCount, devices.data());
242
243 cout << endl << "Graphics cards:" << endl;
244 for (const VkPhysicalDevice& device : devices) {
245 if (isDeviceSuitable(device)) {
246 physicalDevice = device;
247 break;
248 }
249 }
250 cout << endl;
251
252 if (physicalDevice == VK_NULL_HANDLE) {
253 throw runtime_error("failed to find a suitable GPU!");
254 }
255 }
256
257 bool isDeviceSuitable(VkPhysicalDevice device) {
258 VkPhysicalDeviceProperties deviceProperties;
259 VkPhysicalDeviceFeatures deviceFeatures;
260
261 vkGetPhysicalDeviceProperties(device, &deviceProperties);
262 vkGetPhysicalDeviceFeatures(device, &deviceFeatures);
263
264 cout << "Device: " << deviceProperties.deviceName << endl;
265
266 QueueFamilyIndices indices = findQueueFamilies(device);
267
[bfd620e]268 bool extensionsSupported = checkDeviceExtensionSupport(device);
269
270 bool swapChainAdequate = false;
271
272 if (extensionsSupported) {
273 SwapChainSupportDetails swapChainSupport = querySwapChainSupport(device);
274 swapChainAdequate = !swapChainSupport.formats.empty() && !swapChainSupport.presentModes.empty();
275 }
276
277 return indices.isComplete() && extensionsSupported && swapChainAdequate;
278 }
279
280 bool checkDeviceExtensionSupport(VkPhysicalDevice device) {
281 uint32_t extensionCount;
282 vkEnumerateDeviceExtensionProperties(device, nullptr, &extensionCount, nullptr);
283
284 vector<VkExtensionProperties> availableExtensions(extensionCount);
285 vkEnumerateDeviceExtensionProperties(device, nullptr, &extensionCount, availableExtensions.data());
286
287 set<string> requiredExtensions(deviceExtensions.begin(), deviceExtensions.end());
288
289 for (const auto& extension : availableExtensions) {
290 requiredExtensions.erase(extension.extensionName);
291 }
292
293 return requiredExtensions.empty();
[909b51a]294 }
295
296 void createLogicalDevice() {
297 QueueFamilyIndices indices = findQueueFamilies(physicalDevice);
298
[b3671b5]299 vector<VkDeviceQueueCreateInfo> queueCreateInfos;
300 set<uint32_t> uniqueQueueFamilies = {indices.graphicsFamily.value(), indices.presentFamily.value()};
[909b51a]301
302 float queuePriority = 1.0f;
[b3671b5]303 for (uint32_t queueFamily : uniqueQueueFamilies) {
304 VkDeviceQueueCreateInfo queueCreateInfo = {};
305
306 queueCreateInfo.sType = VK_STRUCTURE_TYPE_DEVICE_QUEUE_CREATE_INFO;
307 queueCreateInfo.queueFamilyIndex = queueFamily;
308 queueCreateInfo.queueCount = 1;
309 queueCreateInfo.pQueuePriorities = &queuePriority;
310
311 queueCreateInfos.push_back(queueCreateInfo);
312 }
[909b51a]313
314 VkPhysicalDeviceFeatures deviceFeatures = {};
315
316 VkDeviceCreateInfo createInfo = {};
317 createInfo.sType = VK_STRUCTURE_TYPE_DEVICE_CREATE_INFO;
318
[b3671b5]319 createInfo.queueCreateInfoCount = static_cast<uint32_t>(queueCreateInfos.size());;
320 createInfo.pQueueCreateInfos = queueCreateInfos.data();
[909b51a]321
322 createInfo.pEnabledFeatures = &deviceFeatures;
323
[bfd620e]324 createInfo.enabledExtensionCount = static_cast<uint32_t>(deviceExtensions.size());
325 createInfo.ppEnabledExtensionNames = deviceExtensions.data();
[909b51a]326
327 // These fields are ignored by up-to-date Vulkan implementations,
328 // but it's a good idea to set them for backwards compatibility
329 if (enableValidationLayers) {
330 createInfo.enabledLayerCount = static_cast<uint32_t>(validationLayers.size());
331 createInfo.ppEnabledLayerNames = validationLayers.data();
332 } else {
333 createInfo.enabledLayerCount = 0;
334 }
335
336 if (vkCreateDevice(physicalDevice, &createInfo, nullptr, &device) != VK_SUCCESS) {
337 throw runtime_error("failed to create logical device!");
338 }
339
340 vkGetDeviceQueue(device, indices.graphicsFamily.value(), 0, &graphicsQueue);
[b3671b5]341 vkGetDeviceQueue(device, indices.presentFamily.value(), 0, &presentQueue);
[909b51a]342 }
343
[a8f0577]344 bool checkValidationLayerSupport() {
345 uint32_t layerCount;
346 vkEnumerateInstanceLayerProperties(&layerCount, nullptr);
347
348 vector<VkLayerProperties> availableLayers(layerCount);
349 vkEnumerateInstanceLayerProperties(&layerCount, availableLayers.data());
350
351 for (const char* layerName : validationLayers) {
352 bool layerFound = false;
353
354 for (const auto& layerProperties : availableLayers) {
355 if (strcmp(layerName, layerProperties.layerName) == 0) {
356 layerFound = true;
357 break;
358 }
359 }
360
361 if (!layerFound) {
362 return false;
363 }
364 }
365
366 return true;
367 }
368
[909b51a]369 QueueFamilyIndices findQueueFamilies(VkPhysicalDevice device) {
370 QueueFamilyIndices indices;
371
372 uint32_t queueFamilyCount = 0;
373 vkGetPhysicalDeviceQueueFamilyProperties(device, &queueFamilyCount, nullptr);
374
375 vector<VkQueueFamilyProperties> queueFamilies(queueFamilyCount);
376 vkGetPhysicalDeviceQueueFamilyProperties(device, &queueFamilyCount, queueFamilies.data());
377
378 int i = 0;
379 for (const auto& queueFamily : queueFamilies) {
380 if (queueFamily.queueCount > 0 && queueFamily.queueFlags & VK_QUEUE_GRAPHICS_BIT) {
381 indices.graphicsFamily = i;
382 }
383
[b3671b5]384 VkBool32 presentSupport = false;
385 vkGetPhysicalDeviceSurfaceSupportKHR(device, i, surface, &presentSupport);
386
387 if (queueFamily.queueCount > 0 && presentSupport) {
388 indices.presentFamily = i;
389 }
390
[909b51a]391 if (indices.isComplete()) {
392 break;
393 }
394
395 i++;
396 }
397
398 return indices;
399 }
400
[bfd620e]401 SwapChainSupportDetails querySwapChainSupport(VkPhysicalDevice device) {
402 SwapChainSupportDetails details;
403
404 vkGetPhysicalDeviceSurfaceCapabilitiesKHR(device, surface, &details.capabilities);
405
406 uint32_t formatCount;
407 vkGetPhysicalDeviceSurfaceFormatsKHR(device, surface, &formatCount, nullptr);
408
409 if (formatCount != 0) {
410 details.formats.resize(formatCount);
411 vkGetPhysicalDeviceSurfaceFormatsKHR(device, surface, &formatCount, details.formats.data());
412 }
413
414 uint32_t presentModeCount;
415 vkGetPhysicalDeviceSurfacePresentModesKHR(device, surface, &presentModeCount, nullptr);
416
417 if (presentModeCount != 0) {
418 details.presentModes.resize(presentModeCount);
419 vkGetPhysicalDeviceSurfacePresentModesKHR(device, surface, &presentModeCount, details.presentModes.data());
420 }
421
422 return details;
423 }
424
425 VkSurfaceFormatKHR chooseSwapSurfaceFormat(const vector<VkSurfaceFormatKHR>& availableFormats) {
426 for (const auto& availableFormat : availableFormats) {
427 if (availableFormat.format == VK_FORMAT_B8G8R8A8_UNORM && availableFormat.colorSpace == VK_COLOR_SPACE_SRGB_NONLINEAR_KHR) {
428 return availableFormat;
429 }
430 }
431
432 return availableFormats[0];
433 }
434
435 VkPresentModeKHR chooseSwapPresentMode(const vector<VkPresentModeKHR>& availablePresentModes) {
436 VkPresentModeKHR bestMode = VK_PRESENT_MODE_FIFO_KHR;
437
438 for (const auto& availablePresentMode : availablePresentModes) {
439 if (availablePresentMode == VK_PRESENT_MODE_MAILBOX_KHR) {
440 return availablePresentMode;
441 } else if (availablePresentMode == VK_PRESENT_MODE_IMMEDIATE_KHR) {
442 bestMode = availablePresentMode;
443 }
444 }
445
446 return bestMode;
447 }
448
449 VkExtent2D chooseSwapExtent(const VkSurfaceCapabilitiesKHR& capabilities) {
450 if (capabilities.currentExtent.width != numeric_limits<uint32_t>::max()) {
451 return capabilities.currentExtent;
452 } else {
453 VkExtent2D actualExtent = { SCREEN_WIDTH, SCREEN_HEIGHT };
454
455 actualExtent.width = max(capabilities.minImageExtent.width, min(capabilities.maxImageExtent.width, actualExtent.width));
456 actualExtent.height = max(capabilities.minImageExtent.height, min(capabilities.maxImageExtent.height, actualExtent.height));
457
458 return actualExtent;
459 }
460 }
461
[909b51a]462 void populateDebugMessengerCreateInfo(VkDebugUtilsMessengerCreateInfoEXT& createInfo) {
463 createInfo = {};
464 createInfo.sType = VK_STRUCTURE_TYPE_DEBUG_UTILS_MESSENGER_CREATE_INFO_EXT;
465 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;
466 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;
467 createInfo.pfnUserCallback = debugCallback;
468 }
469
[a8f0577]470 vector<const char*> getRequiredExtensions() {
471 uint32_t extensionCount = 0;
472 SDL_Vulkan_GetInstanceExtensions(window, &extensionCount, nullptr);
473
474 vector<const char*> extensions(extensionCount);
475 SDL_Vulkan_GetInstanceExtensions(window, &extensionCount, extensions.data());
476
477 if (enableValidationLayers) {
478 extensions.push_back(VK_EXT_DEBUG_UTILS_EXTENSION_NAME);
479 }
480
481 return extensions;
482 }
483
[bfd620e]484 void createSwapChain() {
485 SwapChainSupportDetails swapChainSupport = querySwapChainSupport(physicalDevice);
486
487 VkSurfaceFormatKHR surfaceFormat = chooseSwapSurfaceFormat(swapChainSupport.formats);
488 VkPresentModeKHR presentMode = chooseSwapPresentMode(swapChainSupport.presentModes);
489 VkExtent2D extent = chooseSwapExtent(swapChainSupport.capabilities);
490
491 uint32_t imageCount = swapChainSupport.capabilities.minImageCount + 1;
492 if (swapChainSupport.capabilities.maxImageCount > 0 &&
493 imageCount > swapChainSupport.capabilities.maxImageCount) {
494 imageCount = swapChainSupport.capabilities.maxImageCount;
495 }
496
497 VkSwapchainCreateInfoKHR createInfo = {};
498
499 createInfo.sType = VK_STRUCTURE_TYPE_SWAPCHAIN_CREATE_INFO_KHR;
500 createInfo.surface = surface;
501 createInfo.minImageCount = imageCount;
502 createInfo.imageFormat = surfaceFormat.format;
503 createInfo.imageColorSpace = surfaceFormat.colorSpace;
504 createInfo.imageExtent = extent;
505 createInfo.imageArrayLayers = 1;
506 createInfo.imageUsage = VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT;
507
508 QueueFamilyIndices indices = findQueueFamilies(physicalDevice);
509 uint32_t queueFamilyIndices[] = {indices.graphicsFamily.value(), indices.presentFamily.value()};
510
511 if (indices.graphicsFamily != indices.presentFamily) {
512 createInfo.imageSharingMode = VK_SHARING_MODE_CONCURRENT;
513 createInfo.queueFamilyIndexCount = 2;
514 createInfo.pQueueFamilyIndices = queueFamilyIndices;
515 } else {
516 createInfo.imageSharingMode = VK_SHARING_MODE_EXCLUSIVE;
517 createInfo.queueFamilyIndexCount = 0; // Optional
518 createInfo.pQueueFamilyIndices = nullptr;
519 }
520
521 createInfo.preTransform = swapChainSupport.capabilities.currentTransform;
522 createInfo.compositeAlpha = VK_COMPOSITE_ALPHA_OPAQUE_BIT_KHR;
523 createInfo.presentMode = presentMode;
524 createInfo.clipped = VK_TRUE;
525 createInfo.oldSwapchain = VK_NULL_HANDLE;
526
527 if (vkCreateSwapchainKHR(device, &createInfo, nullptr, &swapChain) != VK_SUCCESS) {
528 throw runtime_error("failed to create swap chain!");
529 }
530
531 vkGetSwapchainImagesKHR(device, swapChain, &imageCount, nullptr);
532 swapChainImages.resize(imageCount);
533 vkGetSwapchainImagesKHR(device, swapChain, &imageCount, swapChainImages.data());
534
535 swapChainImageFormat = surfaceFormat.format;
536 swapChainExtent = extent;
537 }
538
539 void createImageViews() {
540 swapChainImageViews.resize(swapChainImages.size());
541
542 for (size_t i=0; i<swapChainImages.size(); i++) {
543 VkImageViewCreateInfo createInfo = {};
544 createInfo.sType = VK_STRUCTURE_TYPE_IMAGE_VIEW_CREATE_INFO;
545 createInfo.image = swapChainImages[i];
546
547 createInfo.viewType = VK_IMAGE_VIEW_TYPE_2D;
548 createInfo.format = swapChainImageFormat;
549
550 createInfo.components.r = VK_COMPONENT_SWIZZLE_IDENTITY;
551 createInfo.components.g = VK_COMPONENT_SWIZZLE_IDENTITY;
552 createInfo.components.b = VK_COMPONENT_SWIZZLE_IDENTITY;
553 createInfo.components.a = VK_COMPONENT_SWIZZLE_IDENTITY;
554
555 createInfo.subresourceRange.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT;
556 createInfo.subresourceRange.baseMipLevel = 0;
557 createInfo.subresourceRange.levelCount = 1;
558 createInfo.subresourceRange.baseArrayLayer = 0;
559 createInfo.subresourceRange.layerCount = 1;
560
561 if (vkCreateImageView(device, &createInfo, nullptr, &swapChainImageViews[i]) != VK_SUCCESS) {
562 throw runtime_error("failed to create image views!");
563 }
564 }
565 }
566
[be34c9a]567 void createRenderPass() {
568 VkAttachmentDescription colorAttachment = {};
569 colorAttachment.format = swapChainImageFormat;
570 colorAttachment.samples = VK_SAMPLE_COUNT_1_BIT;
571 colorAttachment.loadOp = VK_ATTACHMENT_LOAD_OP_CLEAR;
572 colorAttachment.storeOp = VK_ATTACHMENT_STORE_OP_STORE;
573 colorAttachment.stencilLoadOp = VK_ATTACHMENT_LOAD_OP_DONT_CARE;
574 colorAttachment.stencilStoreOp = VK_ATTACHMENT_STORE_OP_DONT_CARE;
575 colorAttachment.initialLayout = VK_IMAGE_LAYOUT_UNDEFINED;
576 colorAttachment.finalLayout = VK_IMAGE_LAYOUT_PRESENT_SRC_KHR;
577
578 VkAttachmentReference colorAttachmentRef = {};
579 colorAttachmentRef.attachment = 0;
580 colorAttachmentRef.layout = VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL;
581
582 VkSubpassDescription subpass = {};
583 subpass.pipelineBindPoint = VK_PIPELINE_BIND_POINT_GRAPHICS;
584 subpass.colorAttachmentCount = 1;
585 subpass.pColorAttachments = &colorAttachmentRef;
586
587 VkRenderPassCreateInfo renderPassInfo = {};
588 renderPassInfo.sType = VK_STRUCTURE_TYPE_RENDER_PASS_CREATE_INFO;
589 renderPassInfo.attachmentCount = 1;
590 renderPassInfo.pAttachments = &colorAttachment;
591 renderPassInfo.subpassCount = 1;
592 renderPassInfo.pSubpasses = &subpass;
593
594 if (vkCreateRenderPass(device, &renderPassInfo, nullptr, &renderPass) != VK_SUCCESS) {
595 throw runtime_error("failed to create render pass!");
596 }
597 }
598
[4befb76]599 void createGraphicsPipeline() {
[e09ad38]600 auto vertShaderCode = readFile("shaders/vert.spv");
601 auto fragShaderCode = readFile("shaders/frag.spv");
602
603 VkShaderModule vertShaderModule = createShaderModule(vertShaderCode);
604 VkShaderModule fragShaderModule = createShaderModule(fragShaderCode);
605
606 VkPipelineShaderStageCreateInfo vertShaderStageInfo = {};
607 vertShaderStageInfo.sType = VK_STRUCTURE_TYPE_PIPELINE_SHADER_STAGE_CREATE_INFO;
608 vertShaderStageInfo.stage = VK_SHADER_STAGE_VERTEX_BIT;
609 vertShaderStageInfo.module = vertShaderModule;
610 vertShaderStageInfo.pName = "main";
611
612 VkPipelineShaderStageCreateInfo fragShaderStageInfo = {};
613 fragShaderStageInfo.sType = VK_STRUCTURE_TYPE_PIPELINE_SHADER_STAGE_CREATE_INFO;
614 fragShaderStageInfo.stage = VK_SHADER_STAGE_FRAGMENT_BIT;
615 fragShaderStageInfo.module = fragShaderModule;
616 fragShaderStageInfo.pName = "main";
617
618 VkPipelineShaderStageCreateInfo shaderStages[] = { vertShaderStageInfo, fragShaderStageInfo };
619
[84216c7]620 VkPipelineVertexInputStateCreateInfo vertexInputInfo = {};
621 vertexInputInfo.sType = VK_STRUCTURE_TYPE_PIPELINE_VERTEX_INPUT_STATE_CREATE_INFO;
622 vertexInputInfo.vertexBindingDescriptionCount = 0;
623 vertexInputInfo.vertexAttributeDescriptionCount = 0;
624
625 VkPipelineInputAssemblyStateCreateInfo inputAssembly = {};
626 inputAssembly.sType = VK_STRUCTURE_TYPE_PIPELINE_INPUT_ASSEMBLY_STATE_CREATE_INFO;
627 inputAssembly.topology = VK_PRIMITIVE_TOPOLOGY_TRIANGLE_LIST;
628 inputAssembly.primitiveRestartEnable = VK_FALSE;
629
630 VkViewport viewport = {};
631 viewport.x = 0.0f;
632 viewport.y = 0.0f;
633 viewport.width = (float) swapChainExtent.width;
634 viewport.height = (float) swapChainExtent.height;
635 viewport.minDepth = 0.0f;
636 viewport.maxDepth = 1.0f;
637
638 VkRect2D scissor = {};
639 scissor.offset = { 0, 0 };
640 scissor.extent = swapChainExtent;
641
642 VkPipelineViewportStateCreateInfo viewportState = {};
643 viewportState.sType = VK_STRUCTURE_TYPE_PIPELINE_VIEWPORT_STATE_CREATE_INFO;
644 viewportState.viewportCount = 1;
645 viewportState.pViewports = &viewport;
646 viewportState.scissorCount = 1;
647 viewportState.pScissors = &scissor;
648
649 VkPipelineRasterizationStateCreateInfo rasterizer = {};
650 rasterizer.sType = VK_STRUCTURE_TYPE_PIPELINE_RASTERIZATION_STATE_CREATE_INFO;
651 rasterizer.depthClampEnable = VK_FALSE;
652 rasterizer.rasterizerDiscardEnable = VK_FALSE;
653 rasterizer.polygonMode = VK_POLYGON_MODE_FILL;
654 rasterizer.lineWidth = 1.0f;
655 rasterizer.cullMode = VK_CULL_MODE_BACK_BIT;
656 rasterizer.frontFace = VK_FRONT_FACE_CLOCKWISE;
657 rasterizer.depthBiasEnable = false;
658
659 VkPipelineMultisampleStateCreateInfo multisampling = {};
660 multisampling.sType = VK_STRUCTURE_TYPE_PIPELINE_MULTISAMPLE_STATE_CREATE_INFO;
661 multisampling.sampleShadingEnable = VK_FALSE;
662 multisampling.rasterizationSamples = VK_SAMPLE_COUNT_1_BIT;
663
664 VkPipelineColorBlendAttachmentState colorBlendAttachment = {};
665 colorBlendAttachment.colorWriteMask = VK_COLOR_COMPONENT_R_BIT | VK_COLOR_COMPONENT_G_BIT | VK_COLOR_COMPONENT_B_BIT | VK_COLOR_COMPONENT_A_BIT;
666 colorBlendAttachment.blendEnable = VK_FALSE;
667
668 VkPipelineColorBlendStateCreateInfo colorBlending = {};
669 colorBlending.sType = VK_STRUCTURE_TYPE_PIPELINE_COLOR_BLEND_STATE_CREATE_INFO;
670 colorBlending.logicOpEnable = VK_FALSE;
671 colorBlending.logicOp = VK_LOGIC_OP_COPY;
672 colorBlending.attachmentCount = 1;
673 colorBlending.pAttachments = &colorBlendAttachment;
674 colorBlending.blendConstants[0] = 0.0f;
675 colorBlending.blendConstants[1] = 0.0f;
676 colorBlending.blendConstants[2] = 0.0f;
677 colorBlending.blendConstants[3] = 0.0f;
678
679 VkPipelineLayoutCreateInfo pipelineLayoutInfo = {};
680 pipelineLayoutInfo.sType = VK_STRUCTURE_TYPE_PIPELINE_LAYOUT_CREATE_INFO;
681 pipelineLayoutInfo.setLayoutCount = 0;
682 pipelineLayoutInfo.pushConstantRangeCount = 0;
683
684 if (vkCreatePipelineLayout(device, &pipelineLayoutInfo, nullptr, &pipelineLayout) != VK_SUCCESS) {
685 throw runtime_error("failed to create pipeline layout!");
686 }
687
[fd70015]688 VkGraphicsPipelineCreateInfo pipelineInfo = {};
689 pipelineInfo.sType = VK_STRUCTURE_TYPE_GRAPHICS_PIPELINE_CREATE_INFO;
690 pipelineInfo.stageCount = 2;
691 pipelineInfo.pStages = shaderStages;
692 pipelineInfo.pVertexInputState = &vertexInputInfo;
693 pipelineInfo.pInputAssemblyState = &inputAssembly;
694 pipelineInfo.pViewportState = &viewportState;
695 pipelineInfo.pRasterizationState = &rasterizer;
696 pipelineInfo.pMultisampleState = &multisampling;
697 pipelineInfo.pDepthStencilState = nullptr;
698 pipelineInfo.pColorBlendState = &colorBlending;
699 pipelineInfo.pDynamicState = nullptr;
700 pipelineInfo.layout = pipelineLayout;
701 pipelineInfo.renderPass = renderPass;
702 pipelineInfo.subpass = 0;
703 pipelineInfo.basePipelineHandle = VK_NULL_HANDLE;
704 pipelineInfo.basePipelineIndex = -1;
705
706 if (vkCreateGraphicsPipelines(device, VK_NULL_HANDLE, 1, &pipelineInfo, nullptr, &graphicsPipeline) != VK_SUCCESS) {
707 throw runtime_error("failed to create graphics pipeline!");
708 }
709
[e09ad38]710 vkDestroyShaderModule(device, vertShaderModule, nullptr);
711 vkDestroyShaderModule(device, fragShaderModule, nullptr);
712 }
713
714 VkShaderModule createShaderModule(const vector<char>& code) {
715 VkShaderModuleCreateInfo createInfo = {};
716 createInfo.sType = VK_STRUCTURE_TYPE_SHADER_MODULE_CREATE_INFO;
717 createInfo.codeSize = code.size();
718 createInfo.pCode = reinterpret_cast<const uint32_t*>(code.data());
719
720 VkShaderModule shaderModule;
721 if (vkCreateShaderModule(device, &createInfo, nullptr, &shaderModule) != VK_SUCCESS) {
722 throw runtime_error("failed to create shader module!");
723 }
724
725 return shaderModule;
[4befb76]726 }
727
[ebeb3aa]728 void createFramebuffers() {
729 swapChainFramebuffers.resize(swapChainImageViews.size());
730
731 for (size_t i = 0; i < swapChainImageViews.size(); i++) {
732 VkImageView attachments[] = {
733 swapChainImageViews[i]
734 };
735
736 VkFramebufferCreateInfo framebufferInfo = {};
737 framebufferInfo.sType = VK_STRUCTURE_TYPE_FRAMEBUFFER_CREATE_INFO;
738 framebufferInfo.renderPass = renderPass;
739 framebufferInfo.attachmentCount = 1;
740 framebufferInfo.pAttachments = attachments;
741 framebufferInfo.width = swapChainExtent.width;
742 framebufferInfo.height = swapChainExtent.height;
743 framebufferInfo.layers = 1;
744
745 if (vkCreateFramebuffer(device, &framebufferInfo, nullptr, &swapChainFramebuffers[i]) != VK_SUCCESS) {
746 throw runtime_error("failed to create framebuffer!");
747 }
748 }
749 }
750
[826df16]751 void mainLoop() {
752 // TODO: Create some generic event-handling functions in game-gui-*
753 SDL_Event e;
754 bool quit = false;
755
[7dcd925]756 while (!quit) {
[826df16]757 while (SDL_PollEvent(&e)) {
758 if (e.type == SDL_QUIT) {
759 quit = true;
760 }
761 if (e.type == SDL_KEYDOWN) {
762 quit = true;
763 }
764 if (e.type == SDL_MOUSEBUTTONDOWN) {
765 quit = true;
766 }
[321272c]767
[e09ad38]768 /**/
[bfd620e]769 SDL_FillRect(sdlSurface, nullptr, SDL_MapRGB(sdlSurface->format, 0xFF, 0xFF, 0xFF));
[321272c]770
[bfd620e]771 SDL_UpdateWindowSurface(window);
[e09ad38]772 /**/
[bfd620e]773 }
774 }
[826df16]775 }
776
777 void cleanup() {
[ebeb3aa]778 for (auto framebuffer : swapChainFramebuffers) {
779 vkDestroyFramebuffer(device, framebuffer, nullptr);
780 }
781
[fd70015]782 vkDestroyPipeline(device, graphicsPipeline, nullptr);
[84216c7]783 vkDestroyPipelineLayout(device, pipelineLayout, nullptr);
[be34c9a]784 vkDestroyRenderPass(device, renderPass, nullptr);
[84216c7]785
[bfd620e]786 for (auto imageView : swapChainImageViews) {
787 vkDestroyImageView(device, imageView, nullptr);
788 }
789
790 vkDestroySwapchainKHR(device, swapChain, nullptr);
[909b51a]791 vkDestroyDevice(device, nullptr);
792
[80de39d]793 if (enableValidationLayers) {
794 DestroyDebugUtilsMessengerEXT(instance, debugMessenger, nullptr);
795 }
796
[b3671b5]797 vkDestroySurfaceKHR(instance, surface, nullptr);
[826df16]798 vkDestroyInstance(instance, nullptr);
799
800 // TODO: Move this into some generic method in game-gui-sdl
801 SDL_DestroyWindow(window);
802
[98f3232]803 gui->Shutdown();
804 delete gui;
[826df16]805 }
[e09ad38]806
807 static VKAPI_ATTR VkBool32 VKAPI_CALL debugCallback(
808 VkDebugUtilsMessageSeverityFlagBitsEXT messageSeverity,
809 VkDebugUtilsMessageTypeFlagsEXT messageType,
810 const VkDebugUtilsMessengerCallbackDataEXT* pCallbackData,
811 void* pUserData) {
812 cerr << "validation layer: " << pCallbackData->pMessage << endl;
813
814 return VK_FALSE;
815}
816
817 static vector<char> readFile(const string& filename) {
818 ifstream file(filename, ios::ate | ios::binary);
819
820 if (!file.is_open()) {
821 throw runtime_error("failed to open file!");
822 }
823
824 size_t fileSize = (size_t)file.tellg();
825 vector<char> buffer(fileSize);
826
827 file.seekg(0);
828 file.read(buffer.data(), fileSize);
829
830 file.close();
831
832 return buffer;
833 }
[826df16]834};
835
[1c6cd5e]836int main(int argc, char* argv[]) {
[826df16]837
[b6127d2]838#ifdef NDEBUG
839 cout << "DEBUGGING IS OFF" << endl;
840#else
841 cout << "DEBUGGING IS ON" << endl;
842#endif
[a8f0577]843
[bfd620e]844 glm::mat4 matrix;
845 glm::vec4 vec;
846 glm::vec4 test = matrix * vec;
[826df16]847
848 cout << "Starting Vulkan game..." << endl;
849
850 VulkanGame game;
851
852 try {
853 game.run();
854 } catch (const exception& e) {
855 cerr << e.what() << endl;
856 return EXIT_FAILURE;
857 }
[03f4c64]858
[826df16]859 cout << "Finished running the game" << endl;
[03f4c64]860
[826df16]861 return EXIT_SUCCESS;
[03f4c64]862}
Note: See TracBrowser for help on using the repository browser.