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

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

In vulkangame, detect when the framebuffer is resized

  • Property mode set to 100644
File size: 17.8 KB
RevLine 
[99d44b2]1#include "vulkan-game.hpp"
[850e84c]2
[6fc24c7]3#include <array>
[0df3c9a]4#include <iostream>
[c1c2021]5#include <set>
[0df3c9a]6
[5edbd58]7#include "consts.hpp"
[c559904]8#include "logger.hpp"
[5edbd58]9
[c1d9b2a]10#include "vulkan-utils.hpp"
11
[0df3c9a]12using namespace std;
13
[99d44b2]14VulkanGame::VulkanGame() {
[0df3c9a]15 gui = nullptr;
16 window = nullptr;
17}
18
[99d44b2]19VulkanGame::~VulkanGame() {
[0df3c9a]20}
21
[b6e60b4]22void VulkanGame::run(int width, int height, unsigned char guiFlags) {
[2e77b3f]23 cout << "DEBUGGING IS " << (ENABLE_VALIDATION_LAYERS ? "ON" : "OFF") << endl;
24
25 cout << "Vulkan Game" << endl;
26
[c559904]27 // This gets the runtime version, use SDL_VERSION() for the comppile-time version
28 // TODO: Create a game-gui function to get the gui version and retrieve it that way
29 SDL_GetVersion(&sdlVersion);
30
31 // TODO: Refactor the logger api to be more flexible,
32 // esp. since gl_log() and gl_log_err() have issues printing anything besides stirngs
33 restart_gl_log();
34 gl_log("starting SDL\n%s.%s.%s",
35 to_string(sdlVersion.major).c_str(),
36 to_string(sdlVersion.minor).c_str(),
37 to_string(sdlVersion.patch).c_str());
38
39 open_log();
40 get_log() << "starting SDL" << endl;
41 get_log() <<
42 (int)sdlVersion.major << "." <<
43 (int)sdlVersion.minor << "." <<
44 (int)sdlVersion.patch << endl;
45
[5edbd58]46 if (initWindow(width, height, guiFlags) == RTWO_ERROR) {
[0df3c9a]47 return;
48 }
[b6e60b4]49
[0df3c9a]50 initVulkan();
51 mainLoop();
52 cleanup();
[c559904]53
54 close_log();
[0df3c9a]55}
56
[c559904]57// TODO: Make some more initi functions, or call this initUI if the
58// amount of things initialized here keeps growing
[b6e60b4]59bool VulkanGame::initWindow(int width, int height, unsigned char guiFlags) {
[c559904]60 // TODO: Put all fonts, textures, and images in the assets folder
[0df3c9a]61 gui = new GameGui_SDL();
62
[b6e60b4]63 if (gui->init() == RTWO_ERROR) {
[c559904]64 // TODO: Also print these sorts of errors to the log
[0df3c9a]65 cout << "UI library could not be initialized!" << endl;
[b6e60b4]66 cout << gui->getError() << endl;
[0df3c9a]67 return RTWO_ERROR;
68 }
69
[b6e60b4]70 window = (SDL_Window*) gui->createWindow("Vulkan Game", width, height, guiFlags & GUI_FLAGS_WINDOW_FULLSCREEN);
[0df3c9a]71 if (window == nullptr) {
72 cout << "Window could not be created!" << endl;
[ed7c953]73 cout << gui->getError() << endl;
[0df3c9a]74 return RTWO_ERROR;
75 }
76
[b6e60b4]77 cout << "Target window size: (" << width << ", " << height << ")" << endl;
[a6f6833]78 cout << "Actual window size: (" << gui->getWindowWidth() << ", " << gui->getWindowHeight() << ")" << endl;
[b6e60b4]79
[c1d9b2a]80 renderer = SDL_CreateRenderer(window, -1, SDL_RENDERER_ACCELERATED | SDL_RENDERER_PRESENTVSYNC);
81 if (renderer == nullptr) {
82 cout << "Renderer could not be created!" << endl;
83 cout << gui->getError() << endl;
84 return RTWO_ERROR;
85 }
86
[0df3c9a]87 return RTWO_SUCCESS;
88}
89
[99d44b2]90void VulkanGame::initVulkan() {
[c1d9b2a]91 const vector<const char*> validationLayers = {
92 "VK_LAYER_KHRONOS_validation"
93 };
[fe5c3ba]94 const vector<const char*> deviceExtensions = {
95 VK_KHR_SWAPCHAIN_EXTENSION_NAME
96 };
[c1d9b2a]97
98 createVulkanInstance(validationLayers);
99 setupDebugMessenger();
[90a424f]100 createVulkanSurface();
[fe5c3ba]101 pickPhysicalDevice(deviceExtensions);
[c1c2021]102 createLogicalDevice(validationLayers, deviceExtensions);
[502bd0b]103 createSwapChain();
[f94eea9]104 createImageViews();
[6fc24c7]105 createRenderPass();
[0df3c9a]106}
107
[99d44b2]108void VulkanGame::mainLoop() {
[f6521fb]109 UIEvent e;
[0df3c9a]110 bool quit = false;
111
[c1d9b2a]112 SDL_SetRenderDrawColor(renderer, 0, 0, 0, 255);
113
[0df3c9a]114 while (!quit) {
[27c40ce]115 gui->processEvents();
116
[f6521fb]117 while (gui->pollEvent(&e)) {
118 switch(e.type) {
119 case UI_EVENT_QUIT:
120 cout << "Quit event detected" << endl;
121 quit = true;
122 break;
123 case UI_EVENT_WINDOW:
124 cout << "Window event detected" << endl;
125 // Currently unused
126 break;
[0e09340]127 case UI_EVENT_WINDOWRESIZE:
128 cout << "Window resize event detected" << endl;
129 framebufferResized = true;
130 break;
[f6521fb]131 case UI_EVENT_KEY:
132 if (e.key.keycode == SDL_SCANCODE_ESCAPE) {
133 quit = true;
134 } else {
135 cout << "Key event detected" << endl;
136 }
137 break;
138 case UI_EVENT_MOUSEBUTTONDOWN:
139 cout << "Mouse button down event detected" << endl;
140 break;
141 case UI_EVENT_MOUSEBUTTONUP:
142 cout << "Mouse button up event detected" << endl;
143 break;
144 case UI_EVENT_MOUSEMOTION:
145 break;
[c61323a]146 default:
147 cout << "Unhandled UI event: " << e.type << endl;
[0df3c9a]148 }
149 }
[c1d9b2a]150
[a0c5f28]151 renderUI();
152 renderScene();
[0df3c9a]153 }
[c1c2021]154
155 vkDeviceWaitIdle(device);
[0df3c9a]156}
157
[a0c5f28]158void VulkanGame::renderUI() {
159 SDL_RenderClear(renderer);
160 SDL_RenderPresent(renderer);
161}
162
163void VulkanGame::renderScene() {
164}
165
[99d44b2]166void VulkanGame::cleanup() {
[c1c2021]167 cleanupSwapChain();
168
169 vkDestroyDevice(device, nullptr);
170 vkDestroySurfaceKHR(instance, surface, nullptr);
171
[c1d9b2a]172 if (ENABLE_VALIDATION_LAYERS) {
173 VulkanUtils::destroyDebugUtilsMessengerEXT(instance, debugMessenger, nullptr);
174 }
[c1c2021]175
[c1d9b2a]176 vkDestroyInstance(instance, nullptr);
177
178 SDL_DestroyRenderer(renderer);
179 renderer = nullptr;
180
[b6e60b4]181 gui->destroyWindow();
182 gui->shutdown();
[0df3c9a]183 delete gui;
[c1d9b2a]184}
185
186void VulkanGame::createVulkanInstance(const vector<const char*> &validationLayers) {
187 if (ENABLE_VALIDATION_LAYERS && !VulkanUtils::checkValidationLayerSupport(validationLayers)) {
188 throw runtime_error("validation layers requested, but not available!");
189 }
190
191 VkApplicationInfo appInfo = {};
192 appInfo.sType = VK_STRUCTURE_TYPE_APPLICATION_INFO;
193 appInfo.pApplicationName = "Vulkan Game";
194 appInfo.applicationVersion = VK_MAKE_VERSION(1, 0, 0);
195 appInfo.pEngineName = "No Engine";
196 appInfo.engineVersion = VK_MAKE_VERSION(1, 0, 0);
197 appInfo.apiVersion = VK_API_VERSION_1_0;
198
199 VkInstanceCreateInfo createInfo = {};
200 createInfo.sType = VK_STRUCTURE_TYPE_INSTANCE_CREATE_INFO;
201 createInfo.pApplicationInfo = &appInfo;
202
203 vector<const char*> extensions = gui->getRequiredExtensions();
204 if (ENABLE_VALIDATION_LAYERS) {
205 extensions.push_back(VK_EXT_DEBUG_UTILS_EXTENSION_NAME);
206 }
207
208 createInfo.enabledExtensionCount = static_cast<uint32_t>(extensions.size());
209 createInfo.ppEnabledExtensionNames = extensions.data();
210
211 cout << endl << "Extensions:" << endl;
212 for (const char* extensionName : extensions) {
213 cout << extensionName << endl;
214 }
215 cout << endl;
216
217 VkDebugUtilsMessengerCreateInfoEXT debugCreateInfo;
218 if (ENABLE_VALIDATION_LAYERS) {
219 createInfo.enabledLayerCount = static_cast<uint32_t>(validationLayers.size());
220 createInfo.ppEnabledLayerNames = validationLayers.data();
221
222 populateDebugMessengerCreateInfo(debugCreateInfo);
223 createInfo.pNext = &debugCreateInfo;
224 } else {
225 createInfo.enabledLayerCount = 0;
226
227 createInfo.pNext = nullptr;
228 }
229
230 if (vkCreateInstance(&createInfo, nullptr, &instance) != VK_SUCCESS) {
231 throw runtime_error("failed to create instance!");
232 }
233}
234
235void VulkanGame::setupDebugMessenger() {
236 if (!ENABLE_VALIDATION_LAYERS) return;
237
238 VkDebugUtilsMessengerCreateInfoEXT createInfo;
239 populateDebugMessengerCreateInfo(createInfo);
240
241 if (VulkanUtils::createDebugUtilsMessengerEXT(instance, &createInfo, nullptr, &debugMessenger) != VK_SUCCESS) {
242 throw runtime_error("failed to set up debug messenger!");
243 }
244}
245
246void VulkanGame::populateDebugMessengerCreateInfo(VkDebugUtilsMessengerCreateInfoEXT& createInfo) {
247 createInfo = {};
248 createInfo.sType = VK_STRUCTURE_TYPE_DEBUG_UTILS_MESSENGER_CREATE_INFO_EXT;
249 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;
250 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;
251 createInfo.pfnUserCallback = debugCallback;
252}
253
254VKAPI_ATTR VkBool32 VKAPI_CALL VulkanGame::debugCallback(
255 VkDebugUtilsMessageSeverityFlagBitsEXT messageSeverity,
256 VkDebugUtilsMessageTypeFlagsEXT messageType,
257 const VkDebugUtilsMessengerCallbackDataEXT* pCallbackData,
258 void* pUserData) {
259 cerr << "validation layer: " << pCallbackData->pMessage << endl;
260
261 return VK_FALSE;
262}
[90a424f]263
264void VulkanGame::createVulkanSurface() {
265 if (gui->createVulkanSurface(instance, &surface) == RTWO_ERROR) {
266 throw runtime_error("failed to create window surface!");
267 }
268}
269
[fe5c3ba]270void VulkanGame::pickPhysicalDevice(const vector<const char*>& deviceExtensions) {
[90a424f]271 uint32_t deviceCount = 0;
272 vkEnumeratePhysicalDevices(instance, &deviceCount, nullptr);
273
274 if (deviceCount == 0) {
275 throw runtime_error("failed to find GPUs with Vulkan support!");
276 }
277
278 vector<VkPhysicalDevice> devices(deviceCount);
279 vkEnumeratePhysicalDevices(instance, &deviceCount, devices.data());
280
281 cout << endl << "Graphics cards:" << endl;
282 for (const VkPhysicalDevice& device : devices) {
[fe5c3ba]283 if (isDeviceSuitable(device, deviceExtensions)) {
[90a424f]284 physicalDevice = device;
285 break;
286 }
287 }
288 cout << endl;
289
290 if (physicalDevice == VK_NULL_HANDLE) {
291 throw runtime_error("failed to find a suitable GPU!");
292 }
293}
294
[fe5c3ba]295bool VulkanGame::isDeviceSuitable(VkPhysicalDevice device, const vector<const char*>& deviceExtensions) {
[90a424f]296 VkPhysicalDeviceProperties deviceProperties;
297 vkGetPhysicalDeviceProperties(device, &deviceProperties);
298
299 cout << "Device: " << deviceProperties.deviceName << endl;
300
301 QueueFamilyIndices indices = VulkanUtils::findQueueFamilies(device, surface);
302 bool extensionsSupported = VulkanUtils::checkDeviceExtensionSupport(device, deviceExtensions);
303 bool swapChainAdequate = false;
304
305 if (extensionsSupported) {
306 SwapChainSupportDetails swapChainSupport = VulkanUtils::querySwapChainSupport(device, surface);
307 swapChainAdequate = !swapChainSupport.formats.empty() && !swapChainSupport.presentModes.empty();
308 }
309
310 VkPhysicalDeviceFeatures supportedFeatures;
311 vkGetPhysicalDeviceFeatures(device, &supportedFeatures);
312
313 return indices.isComplete() && extensionsSupported && swapChainAdequate && supportedFeatures.samplerAnisotropy;
[c1c2021]314}
315
316void VulkanGame::createLogicalDevice(
317 const vector<const char*> validationLayers,
318 const vector<const char*>& deviceExtensions) {
319 QueueFamilyIndices indices = VulkanUtils::findQueueFamilies(physicalDevice, surface);
320
321 vector<VkDeviceQueueCreateInfo> queueCreateInfos;
322 set<uint32_t> uniqueQueueFamilies = { indices.graphicsFamily.value(), indices.presentFamily.value() };
323
324 float queuePriority = 1.0f;
325 for (uint32_t queueFamily : uniqueQueueFamilies) {
326 VkDeviceQueueCreateInfo queueCreateInfo = {};
327 queueCreateInfo.sType = VK_STRUCTURE_TYPE_DEVICE_QUEUE_CREATE_INFO;
328 queueCreateInfo.queueFamilyIndex = queueFamily;
329 queueCreateInfo.queueCount = 1;
330 queueCreateInfo.pQueuePriorities = &queuePriority;
331
332 queueCreateInfos.push_back(queueCreateInfo);
333 }
334
335 VkPhysicalDeviceFeatures deviceFeatures = {};
336 deviceFeatures.samplerAnisotropy = VK_TRUE;
337
338 VkDeviceCreateInfo createInfo = {};
339 createInfo.sType = VK_STRUCTURE_TYPE_DEVICE_CREATE_INFO;
340 createInfo.queueCreateInfoCount = static_cast<uint32_t>(queueCreateInfos.size());
341 createInfo.pQueueCreateInfos = queueCreateInfos.data();
342
343 createInfo.pEnabledFeatures = &deviceFeatures;
344
345 createInfo.enabledExtensionCount = static_cast<uint32_t>(deviceExtensions.size());
346 createInfo.ppEnabledExtensionNames = deviceExtensions.data();
347
348 // These fields are ignored by up-to-date Vulkan implementations,
349 // but it's a good idea to set them for backwards compatibility
350 if (ENABLE_VALIDATION_LAYERS) {
351 createInfo.enabledLayerCount = static_cast<uint32_t>(validationLayers.size());
352 createInfo.ppEnabledLayerNames = validationLayers.data();
353 } else {
354 createInfo.enabledLayerCount = 0;
355 }
356
357 if (vkCreateDevice(physicalDevice, &createInfo, nullptr, &device) != VK_SUCCESS) {
358 throw runtime_error("failed to create logical device!");
359 }
360
361 vkGetDeviceQueue(device, indices.graphicsFamily.value(), 0, &graphicsQueue);
362 vkGetDeviceQueue(device, indices.presentFamily.value(), 0, &presentQueue);
[502bd0b]363}
364
365void VulkanGame::createSwapChain() {
366 SwapChainSupportDetails swapChainSupport = VulkanUtils::querySwapChainSupport(physicalDevice, surface);
367
368 VkSurfaceFormatKHR surfaceFormat = VulkanUtils::chooseSwapSurfaceFormat(swapChainSupport.formats);
369 VkPresentModeKHR presentMode = VulkanUtils::chooseSwapPresentMode(swapChainSupport.presentModes);
370 VkExtent2D extent = VulkanUtils::chooseSwapExtent(swapChainSupport.capabilities, gui->getWindowWidth(), gui->getWindowHeight());
371
372 uint32_t imageCount = swapChainSupport.capabilities.minImageCount + 1;
373 if (swapChainSupport.capabilities.maxImageCount > 0 && imageCount > swapChainSupport.capabilities.maxImageCount) {
374 imageCount = swapChainSupport.capabilities.maxImageCount;
375 }
376
377 VkSwapchainCreateInfoKHR createInfo = {};
378 createInfo.sType = VK_STRUCTURE_TYPE_SWAPCHAIN_CREATE_INFO_KHR;
379 createInfo.surface = surface;
380 createInfo.minImageCount = imageCount;
381 createInfo.imageFormat = surfaceFormat.format;
382 createInfo.imageColorSpace = surfaceFormat.colorSpace;
383 createInfo.imageExtent = extent;
384 createInfo.imageArrayLayers = 1;
385 createInfo.imageUsage = VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT;
386
387 QueueFamilyIndices indices = VulkanUtils::findQueueFamilies(physicalDevice, surface);
388 uint32_t queueFamilyIndices[] = { indices.graphicsFamily.value(), indices.presentFamily.value() };
389
390 if (indices.graphicsFamily != indices.presentFamily) {
391 createInfo.imageSharingMode = VK_SHARING_MODE_CONCURRENT;
392 createInfo.queueFamilyIndexCount = 2;
393 createInfo.pQueueFamilyIndices = queueFamilyIndices;
[f94eea9]394 } else {
[502bd0b]395 createInfo.imageSharingMode = VK_SHARING_MODE_EXCLUSIVE;
396 createInfo.queueFamilyIndexCount = 0;
397 createInfo.pQueueFamilyIndices = nullptr;
398 }
399
400 createInfo.preTransform = swapChainSupport.capabilities.currentTransform;
401 createInfo.compositeAlpha = VK_COMPOSITE_ALPHA_OPAQUE_BIT_KHR;
402 createInfo.presentMode = presentMode;
403 createInfo.clipped = VK_TRUE;
404 createInfo.oldSwapchain = VK_NULL_HANDLE;
405
406 if (vkCreateSwapchainKHR(device, &createInfo, nullptr, &swapChain) != VK_SUCCESS) {
407 throw runtime_error("failed to create swap chain!");
408 }
409
410 vkGetSwapchainImagesKHR(device, swapChain, &imageCount, nullptr);
411 swapChainImages.resize(imageCount);
412 vkGetSwapchainImagesKHR(device, swapChain, &imageCount, swapChainImages.data());
413
414 swapChainImageFormat = surfaceFormat.format;
415 swapChainExtent = extent;
[f94eea9]416}
417
418void VulkanGame::createImageViews() {
419 swapChainImageViews.resize(swapChainImages.size());
420
421 for (size_t i = 0; i < swapChainImages.size(); i++) {
422 swapChainImageViews[i] = VulkanUtils::createImageView(device, swapChainImages[i], swapChainImageFormat,
423 VK_IMAGE_ASPECT_COLOR_BIT);
424 }
425}
426
[6fc24c7]427void VulkanGame::createRenderPass() {
428 VkAttachmentDescription colorAttachment = {};
429 colorAttachment.format = swapChainImageFormat;
430 colorAttachment.samples = VK_SAMPLE_COUNT_1_BIT;
431 colorAttachment.loadOp = VK_ATTACHMENT_LOAD_OP_CLEAR;
432 colorAttachment.storeOp = VK_ATTACHMENT_STORE_OP_STORE;
433 colorAttachment.stencilLoadOp = VK_ATTACHMENT_LOAD_OP_DONT_CARE;
434 colorAttachment.stencilStoreOp = VK_ATTACHMENT_STORE_OP_DONT_CARE;
435 colorAttachment.initialLayout = VK_IMAGE_LAYOUT_UNDEFINED;
436 colorAttachment.finalLayout = VK_IMAGE_LAYOUT_PRESENT_SRC_KHR;
437
438 VkAttachmentReference colorAttachmentRef = {};
439 colorAttachmentRef.attachment = 0;
440 colorAttachmentRef.layout = VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL;
441
442 VkAttachmentDescription depthAttachment = {};
443 depthAttachment.format = findDepthFormat();
444 depthAttachment.samples = VK_SAMPLE_COUNT_1_BIT;
445 depthAttachment.loadOp = VK_ATTACHMENT_LOAD_OP_CLEAR;
446 depthAttachment.storeOp = VK_ATTACHMENT_STORE_OP_DONT_CARE;
447 depthAttachment.stencilLoadOp = VK_ATTACHMENT_LOAD_OP_DONT_CARE;
448 depthAttachment.stencilStoreOp = VK_ATTACHMENT_STORE_OP_DONT_CARE;
449 depthAttachment.initialLayout = VK_IMAGE_LAYOUT_UNDEFINED;
450 depthAttachment.finalLayout = VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL;
451
452 VkAttachmentReference depthAttachmentRef = {};
453 depthAttachmentRef.attachment = 1;
454 depthAttachmentRef.layout = VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL;
455
456 VkSubpassDescription subpass = {};
457 subpass.pipelineBindPoint = VK_PIPELINE_BIND_POINT_GRAPHICS;
458 subpass.colorAttachmentCount = 1;
459 subpass.pColorAttachments = &colorAttachmentRef;
460 subpass.pDepthStencilAttachment = &depthAttachmentRef;
461
462 VkSubpassDependency dependency = {};
463 dependency.srcSubpass = VK_SUBPASS_EXTERNAL;
464 dependency.dstSubpass = 0;
465 dependency.srcStageMask = VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT;
466 dependency.srcAccessMask = 0;
467 dependency.dstStageMask = VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT;
468 dependency.dstAccessMask = VK_ACCESS_COLOR_ATTACHMENT_READ_BIT | VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT;
469
470 array<VkAttachmentDescription, 2> attachments = { colorAttachment, depthAttachment };
471 VkRenderPassCreateInfo renderPassInfo = {};
472 renderPassInfo.sType = VK_STRUCTURE_TYPE_RENDER_PASS_CREATE_INFO;
473 renderPassInfo.attachmentCount = static_cast<uint32_t>(attachments.size());
474 renderPassInfo.pAttachments = attachments.data();
475 renderPassInfo.subpassCount = 1;
476 renderPassInfo.pSubpasses = &subpass;
477 renderPassInfo.dependencyCount = 1;
478 renderPassInfo.pDependencies = &dependency;
479
480 if (vkCreateRenderPass(device, &renderPassInfo, nullptr, &renderPass) != VK_SUCCESS) {
481 throw runtime_error("failed to create render pass!");
482 }
483}
484
485VkFormat VulkanGame::findDepthFormat() {
486 return VulkanUtils::findSupportedFormat(
487 physicalDevice,
488 { VK_FORMAT_D32_SFLOAT, VK_FORMAT_D32_SFLOAT_S8_UINT, VK_FORMAT_D24_UNORM_S8_UINT },
489 VK_IMAGE_TILING_OPTIMAL,
490 VK_FORMAT_FEATURE_DEPTH_STENCIL_ATTACHMENT_BIT
491 );
492}
493
[f94eea9]494void VulkanGame::cleanupSwapChain() {
[6fc24c7]495 vkDestroyRenderPass(device, renderPass, nullptr);
496
[f94eea9]497 for (auto imageView : swapChainImageViews) {
498 vkDestroyImageView(device, imageView, nullptr);
499 }
500
501 vkDestroySwapchainKHR(device, swapChain, nullptr);
[90a424f]502}
Note: See TracBrowser for help on using the repository browser.