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

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

Create the graphics pipeline

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