Complete "Hello Triangle" program with resizing and minimization handled

This commit is contained in:
macmacmac 2024-08-31 13:47:29 -04:00
parent 54e69982eb
commit 75e9921d45
5 changed files with 168 additions and 60 deletions

2
.gitignore vendored
View File

@ -1,3 +1,3 @@
.cache/ .cache/
.vscode/
build/ build/

View File

@ -42,6 +42,13 @@ add_executable(${EXE_NAME} ${CMAKE_SOURCE_DIR}/src/main.cc ${PROGRAM_SOURCES} ${
target_include_directories(${EXE_NAME} PRIVATE ${CMAKE_SOURCE_DIR}/include) target_include_directories(${EXE_NAME} PRIVATE ${CMAKE_SOURCE_DIR}/include)
add_dependencies(${EXE_NAME} shaders) add_dependencies(${EXE_NAME} shaders)
if ( CMAKE_COMPILER_IS_GNUCC )
target_compile_options(${EXE_NAME} PRIVATE -Wall -Wextra)
endif()
if ( MSVC )
target_compile_options(${EXE_NAME} PRIVATE /W4)
endif()
# Linking # Linking
target_link_libraries(${EXE_NAME} PRIVATE SDL2::SDL2) target_link_libraries(${EXE_NAME} PRIVATE SDL2::SDL2)
target_link_libraries(${EXE_NAME} PRIVATE Vulkan::Vulkan) target_link_libraries(${EXE_NAME} PRIVATE Vulkan::Vulkan)

View File

@ -17,6 +17,8 @@ const std::vector<const char*> deviceExtensions = {
VK_KHR_SWAPCHAIN_EXTENSION_NAME VK_KHR_SWAPCHAIN_EXTENSION_NAME
}; };
const int MAX_FRAMES_IN_FLIGHT = 2;
#ifdef NDEBUG #ifdef NDEBUG
const bool enableValidationLayers = false; const bool enableValidationLayers = false;
#else #else
@ -44,7 +46,7 @@ struct SwapChainSupportDetails {
class VulkanApp { class VulkanApp {
public: public:
VulkanApp(const uint32_t& _w, const uint32_t& _h) : VulkanApp(const uint32_t& _w, const uint32_t& _h) :
mWidth(_w), mHeight(_h), mWin(nullptr), mActive(false) {} mWin(nullptr), mWidth(_w), mHeight(_h) {}
void init(); void init();
void loop(); void loop();
@ -55,9 +57,11 @@ private:
SDL_Event mEvent; SDL_Event mEvent;
// Not tied to library // Not tied to library
const uint32_t mWidth; uint32_t mWidth;
const uint32_t mHeight; uint32_t mHeight;
bool mActive; bool mActive = false;
bool mResized = false;
bool mMinimized = false;
// Vulkan // Vulkan
VkInstance mInstance; VkInstance mInstance;
@ -77,14 +81,14 @@ private:
VkPipeline mGraphicsPipeline; VkPipeline mGraphicsPipeline;
VkCommandPool mCommandPool; VkCommandPool mCommandPool;
VkCommandBuffer mCommandBuffer; std::vector<VkCommandBuffer> mCommandBuffers;
VkQueue mGraphicsQueue; VkQueue mGraphicsQueue;
VkQueue mPresentQueue; VkQueue mPresentQueue;
VkSemaphore mImageAvailableSemaphore; std::vector<VkSemaphore> mImageAvailableSemaphores;
VkSemaphore mRenderFinishedSemaphore; std::vector<VkSemaphore> mRenderFinishedSemaphores;
VkFence mInFlightFence; std::vector<VkFence> mInFlightFences;
VkDebugUtilsMessengerEXT mDebugMessenger; VkDebugUtilsMessengerEXT mDebugMessenger;
@ -92,7 +96,11 @@ private:
void createInstance(); void createInstance();
void selectPhysicalDevice(); void selectPhysicalDevice();
void createLogicalDevice(); void createLogicalDevice();
void createSwapChain(); void createSwapChain();
void recreateSwapChain();
void cleanupSwapChain();
void createImageViews(); void createImageViews();
void createRenderPass(); void createRenderPass();
void createGraphicsPipeline(); void createGraphicsPipeline();
@ -118,7 +126,15 @@ private:
static VKAPI_ATTR VkBool32 VKAPI_CALL debugCallback(VkDebugUtilsMessageSeverityFlagBitsEXT messageSeverity, static VKAPI_ATTR VkBool32 VKAPI_CALL debugCallback(VkDebugUtilsMessageSeverityFlagBitsEXT messageSeverity,
VkDebugUtilsMessageTypeFlagsEXT messageType, VkDebugUtilsMessageTypeFlagsEXT messageType,
const VkDebugUtilsMessengerCallbackDataEXT* pCallbackData, void* pUserData) { const VkDebugUtilsMessengerCallbackDataEXT* pCallbackData, void* pUserData) {
fprintf(stderr, "Validation Layer: %s \n", pCallbackData->pMessage); (void)pUserData;
if(messageSeverity >= VK_DEBUG_UTILS_MESSAGE_SEVERITY_WARNING_BIT_EXT) {
fprintf(stderr, "Validation Layer [Error/Warning]: %s \n", pCallbackData->pMessage);
} else if(messageType & VK_DEBUG_UTILS_MESSAGE_TYPE_GENERAL_BIT_EXT) {
fprintf(stderr, "Validation Layer [General]: %s \n", pCallbackData->pMessage);
} else {
fprintf(stderr, "Validation Layer: %s \n", pCallbackData->pMessage);
}
return VK_FALSE; return VK_FALSE;
} }

View File

@ -2,13 +2,13 @@
layout(location = 0) out vec3 fragColor; layout(location = 0) out vec3 fragColor;
vec2 positions[3] = vec2[]( const vec2 positions[3] = vec2[](
vec2(0.0, -0.5), vec2(0.0, -0.5),
vec2(0.5, 0.5), vec2(0.5, 0.5),
vec2(-0.5, 0.5) vec2(-0.5, 0.5)
); );
vec3 colors[3] = vec3[]( const vec3 colors[3] = vec3[](
vec3(1.0, 0.0, 0.0), vec3(1.0, 0.0, 0.0),
vec3(0.0, 1.0, 0.0), vec3(0.0, 1.0, 0.0),
vec3(0.0, 0.0, 1.0) vec3(0.0, 0.0, 1.0)

View File

@ -83,7 +83,7 @@ QueueFamilyIndices VulkanApp::findQueueFamilies(VkPhysicalDevice device) {
vkGetPhysicalDeviceQueueFamilyProperties(device, &queueFamilyCount, queueFamilies.data()); vkGetPhysicalDeviceQueueFamilyProperties(device, &queueFamilyCount, queueFamilies.data());
// Get queue families and check them // Get queue families and check them
for(int i=0;i<queueFamilies.size();i++) { for(size_t i=0;i<queueFamilies.size();i++) {
const VkQueueFamilyProperties& queueFamily = queueFamilies[i]; const VkQueueFamilyProperties& queueFamily = queueFamilies[i];
VkBool32 presentSupport = false; VkBool32 presentSupport = false;
@ -197,7 +197,7 @@ void VulkanApp::recordCommandBuffer(VkCommandBuffer commandBuffer, uint32_t imag
renderPassInfo.renderArea.offset = {0, 0}; renderPassInfo.renderArea.offset = {0, 0};
renderPassInfo.renderArea.extent = mSwapChainExtent; renderPassInfo.renderArea.extent = mSwapChainExtent;
VkClearValue clearColor = {{{0.5f, 0.0f, 0.5f, 1.0f}}}; VkClearValue clearColor = {{{0.0f, 0.0f, 0.0f, 1.0f}}};
renderPassInfo.clearValueCount = 1; renderPassInfo.clearValueCount = 1;
renderPassInfo.pClearValues = &clearColor; renderPassInfo.pClearValues = &clearColor;
@ -218,6 +218,7 @@ void VulkanApp::recordCommandBuffer(VkCommandBuffer commandBuffer, uint32_t imag
scissor.extent = mSwapChainExtent; scissor.extent = mSwapChainExtent;
vkCmdSetScissor(commandBuffer, 0, 1, &scissor); vkCmdSetScissor(commandBuffer, 0, 1, &scissor);
// Actually draw the vertices
vkCmdDraw(commandBuffer, 3, 1, 0, 0); vkCmdDraw(commandBuffer, 3, 1, 0, 0);
vkCmdEndRenderPass(commandBuffer); vkCmdEndRenderPass(commandBuffer);
@ -227,32 +228,48 @@ void VulkanApp::recordCommandBuffer(VkCommandBuffer commandBuffer, uint32_t imag
} }
void VulkanApp::drawFrame() { void VulkanApp::drawFrame() {
vkWaitForFences(mLogicalDevice, 1, &mInFlightFence, VK_TRUE, UINT64_MAX); uint32_t currentFrame = 0;
vkResetFences(mLogicalDevice, 1, &mInFlightFence); VkResult result = VK_SUCCESS;
uint32_t imageIndex = 0;
uint32_t imageIndex; vkWaitForFences(mLogicalDevice, 1, &mInFlightFences[currentFrame], VK_TRUE, UINT64_MAX);
vkAcquireNextImageKHR(mLogicalDevice, mSwapChain, UINT64_MAX, mImageAvailableSemaphore, VK_NULL_HANDLE, &imageIndex); vkResetFences(mLogicalDevice, 1, &mInFlightFences[currentFrame]);
vkResetCommandBuffer(mCommandBuffer, /*VkCommandBufferResetFlagBits*/ 0);
recordCommandBuffer(mCommandBuffer, imageIndex); result = vkAcquireNextImageKHR(mLogicalDevice,
mSwapChain,
UINT64_MAX,
mImageAvailableSemaphores[currentFrame], VK_NULL_HANDLE, &imageIndex);
if (result == VK_ERROR_OUT_OF_DATE_KHR) {
recreateSwapChain();
return;
} else if (result != VK_SUCCESS && result != VK_SUBOPTIMAL_KHR) {
throw std::runtime_error("Could not get Vulkan swap chain image!");
}
vkResetFences(mLogicalDevice, 1, &mInFlightFences[currentFrame]);
vkResetCommandBuffer(mCommandBuffers[currentFrame], /*VkCommandBufferResetFlagBits*/ 0);
recordCommandBuffer(mCommandBuffers[currentFrame], imageIndex);
VkSubmitInfo submitInfo{}; VkSubmitInfo submitInfo{};
submitInfo.sType = VK_STRUCTURE_TYPE_SUBMIT_INFO; submitInfo.sType = VK_STRUCTURE_TYPE_SUBMIT_INFO;
VkSemaphore waitSemaphores[] = {mImageAvailableSemaphore}; VkSemaphore waitSemaphores[] = {mImageAvailableSemaphores[currentFrame]};
VkPipelineStageFlags waitStages[] = {VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT}; VkPipelineStageFlags waitStages[] = {VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT};
submitInfo.waitSemaphoreCount = 1; submitInfo.waitSemaphoreCount = 1;
submitInfo.pWaitSemaphores = waitSemaphores; submitInfo.pWaitSemaphores = waitSemaphores;
submitInfo.pWaitDstStageMask = waitStages; submitInfo.pWaitDstStageMask = waitStages;
submitInfo.commandBufferCount = 1; submitInfo.commandBufferCount = 1;
submitInfo.pCommandBuffers = &mCommandBuffer; submitInfo.pCommandBuffers = &mCommandBuffers[currentFrame];
VkSemaphore signalSemaphores[] = {mRenderFinishedSemaphore}; VkSemaphore signalSemaphores[] = {mRenderFinishedSemaphores[currentFrame]};
submitInfo.signalSemaphoreCount = 1; submitInfo.signalSemaphoreCount = 1;
submitInfo.pSignalSemaphores = signalSemaphores; submitInfo.pSignalSemaphores = signalSemaphores;
if (vkQueueSubmit(mGraphicsQueue, 1, &submitInfo, mInFlightFence) != VK_SUCCESS) { if (vkQueueSubmit(mGraphicsQueue, 1, &submitInfo, mInFlightFences[currentFrame]) != VK_SUCCESS) {
throw std::runtime_error("Could not submit Vulkan command buffer!"); throw std::runtime_error("Could not submit Vulkan command buffer!");
} }
@ -268,7 +285,17 @@ void VulkanApp::drawFrame() {
presentInfo.pImageIndices = &imageIndex; presentInfo.pImageIndices = &imageIndex;
vkQueuePresentKHR(mPresentQueue, &presentInfo); result = vkQueuePresentKHR(mPresentQueue, &presentInfo);
if (result == VK_ERROR_OUT_OF_DATE_KHR || result == VK_SUBOPTIMAL_KHR || mResized) {
mResized = false;
recreateSwapChain();
return;
} else if (result != VK_SUCCESS) {
throw std::runtime_error("Could not present Vulkan swap chain image!");
}
currentFrame = (currentFrame + 1) % MAX_FRAMES_IN_FLIGHT;
} }
void VulkanApp::init() { void VulkanApp::init() {
@ -276,18 +303,13 @@ void VulkanApp::init() {
SDL_Init(SDL_INIT_VIDEO | SDL_INIT_EVENTS); SDL_Init(SDL_INIT_VIDEO | SDL_INIT_EVENTS);
//SDL_Vulkan_LoadLibrary(nullptr); //SDL_Vulkan_LoadLibrary(nullptr);
#ifndef NDEBUG
// I really hate GNOME
SDL_VideoInit("x11");
#endif
// Create the window // Create the window
mWin = SDL_CreateWindow("Vulkan+SDL2 Application", mWin = SDL_CreateWindow("Vulkan+SDL2 Application",
SDL_WINDOWPOS_CENTERED, SDL_WINDOWPOS_CENTERED,
SDL_WINDOWPOS_CENTERED, SDL_WINDOWPOS_CENTERED,
mWidth, mWidth,
mHeight, mHeight,
SDL_WINDOW_SHOWN | SDL_WINDOW_VULKAN SDL_WINDOW_SHOWN | SDL_WINDOW_VULKAN | SDL_WINDOW_RESIZABLE
); );
if(mWin == nullptr) { if(mWin == nullptr) {
@ -355,8 +377,12 @@ void VulkanApp::createInstance() {
debugCreateInfo = {}; debugCreateInfo = {};
debugCreateInfo.sType = VK_STRUCTURE_TYPE_DEBUG_UTILS_MESSENGER_CREATE_INFO_EXT; debugCreateInfo.sType = VK_STRUCTURE_TYPE_DEBUG_UTILS_MESSENGER_CREATE_INFO_EXT;
debugCreateInfo.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; debugCreateInfo.messageSeverity = VK_DEBUG_UTILS_MESSAGE_SEVERITY_VERBOSE_BIT_EXT |
debugCreateInfo.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; VK_DEBUG_UTILS_MESSAGE_SEVERITY_WARNING_BIT_EXT |
VK_DEBUG_UTILS_MESSAGE_SEVERITY_ERROR_BIT_EXT;
debugCreateInfo.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;
debugCreateInfo.pfnUserCallback = debugCallback; debugCreateInfo.pfnUserCallback = debugCallback;
createInfo.pNext = reinterpret_cast<VkDebugUtilsMessengerCreateInfoEXT*>(&debugCreateInfo); createInfo.pNext = reinterpret_cast<VkDebugUtilsMessengerCreateInfoEXT*>(&debugCreateInfo);
@ -415,12 +441,17 @@ void VulkanApp::createLogicalDevice() {
} }
VkPhysicalDeviceFeatures deviceFeatures{}; VkPhysicalDeviceFeatures deviceFeatures{};
vkGetPhysicalDeviceFeatures(mPhysicalDevice, &deviceFeatures);
VkDeviceCreateInfo createInfo{}; VkDeviceCreateInfo createInfo{};
createInfo.sType = VK_STRUCTURE_TYPE_DEVICE_CREATE_INFO; createInfo.sType = VK_STRUCTURE_TYPE_DEVICE_CREATE_INFO;
createInfo.queueCreateInfoCount = static_cast<uint32_t>(queueCreateInfos.size()); createInfo.queueCreateInfoCount = static_cast<uint32_t>(queueCreateInfos.size());
createInfo.pQueueCreateInfos = queueCreateInfos.data(); createInfo.pQueueCreateInfos = queueCreateInfos.data();
createInfo.pEnabledFeatures = &deviceFeatures;
createInfo.enabledExtensionCount = static_cast<uint32_t>(deviceExtensions.size()); createInfo.enabledExtensionCount = static_cast<uint32_t>(deviceExtensions.size());
createInfo.ppEnabledExtensionNames = deviceExtensions.data(); createInfo.ppEnabledExtensionNames = deviceExtensions.data();
@ -493,6 +524,28 @@ void VulkanApp::createSwapChain() {
mSwapChainExtent = extent; mSwapChainExtent = extent;
} }
void VulkanApp::recreateSwapChain() {
vkDeviceWaitIdle(mLogicalDevice);
cleanupSwapChain();
createSwapChain();
createImageViews();
createFramebuffers();
}
void VulkanApp::cleanupSwapChain() {
for (VkFramebuffer framebuffer : mSwapChainFramebuffers) {
vkDestroyFramebuffer(mLogicalDevice, framebuffer, nullptr);
}
for (VkImageView imageView : mSwapChainImageViews) {
vkDestroyImageView(mLogicalDevice, imageView, nullptr);
}
vkDestroySwapchainKHR(mLogicalDevice, mSwapChain, nullptr);
}
void VulkanApp::createImageViews() { void VulkanApp::createImageViews() {
mSwapChainImageViews.resize(mSwapChainImages.size()); mSwapChainImageViews.resize(mSwapChainImages.size());
@ -652,7 +705,12 @@ void VulkanApp::createGraphicsPipeline() {
pipelineInfo.subpass = 0; pipelineInfo.subpass = 0;
pipelineInfo.basePipelineHandle = VK_NULL_HANDLE; pipelineInfo.basePipelineHandle = VK_NULL_HANDLE;
if (vkCreateGraphicsPipelines(mLogicalDevice, VK_NULL_HANDLE, 1, &pipelineInfo, nullptr, &mGraphicsPipeline) != VK_SUCCESS) { if (vkCreateGraphicsPipelines(mLogicalDevice,
VK_NULL_HANDLE,
1,
&pipelineInfo,
nullptr,
&mGraphicsPipeline) != VK_SUCCESS) {
throw std::runtime_error("Could not create Vulkan graphics pipeline!"); throw std::runtime_error("Could not create Vulkan graphics pipeline!");
} }
@ -699,18 +757,24 @@ void VulkanApp::createCommandPool() {
} }
void VulkanApp::createCommandBuffer() { void VulkanApp::createCommandBuffer() {
mCommandBuffers.resize(MAX_FRAMES_IN_FLIGHT);
VkCommandBufferAllocateInfo allocInfo{}; VkCommandBufferAllocateInfo allocInfo{};
allocInfo.sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_ALLOCATE_INFO; allocInfo.sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_ALLOCATE_INFO;
allocInfo.commandPool = mCommandPool; allocInfo.commandPool = mCommandPool;
allocInfo.level = VK_COMMAND_BUFFER_LEVEL_PRIMARY; allocInfo.level = VK_COMMAND_BUFFER_LEVEL_PRIMARY;
allocInfo.commandBufferCount = 1; allocInfo.commandBufferCount = static_cast<uint32_t>(mCommandBuffers.size());
if (vkAllocateCommandBuffers(mLogicalDevice, &allocInfo, &mCommandBuffer) != VK_SUCCESS) { if (vkAllocateCommandBuffers(mLogicalDevice, &allocInfo, mCommandBuffers.data()) != VK_SUCCESS) {
throw std::runtime_error("Could not allocate Vulkan command buffers!"); throw std::runtime_error("Could not allocate Vulkan command buffers!");
} }
} }
void VulkanApp::createSyncObjects() { void VulkanApp::createSyncObjects() {
mImageAvailableSemaphores.resize(MAX_FRAMES_IN_FLIGHT);
mRenderFinishedSemaphores.resize(MAX_FRAMES_IN_FLIGHT);
mInFlightFences.resize(MAX_FRAMES_IN_FLIGHT);
VkSemaphoreCreateInfo semaphoreInfo{}; VkSemaphoreCreateInfo semaphoreInfo{};
semaphoreInfo.sType = VK_STRUCTURE_TYPE_SEMAPHORE_CREATE_INFO; semaphoreInfo.sType = VK_STRUCTURE_TYPE_SEMAPHORE_CREATE_INFO;
@ -718,14 +782,15 @@ void VulkanApp::createSyncObjects() {
fenceInfo.sType = VK_STRUCTURE_TYPE_FENCE_CREATE_INFO; fenceInfo.sType = VK_STRUCTURE_TYPE_FENCE_CREATE_INFO;
fenceInfo.flags = VK_FENCE_CREATE_SIGNALED_BIT; fenceInfo.flags = VK_FENCE_CREATE_SIGNALED_BIT;
VkResult imageAvailableResult = vkCreateSemaphore(mLogicalDevice, &semaphoreInfo, nullptr, &mImageAvailableSemaphore); for(size_t i = 0;i<MAX_FRAMES_IN_FLIGHT;i++) {
VkResult renderFinishedResult = vkCreateSemaphore(mLogicalDevice, &semaphoreInfo, nullptr, &mRenderFinishedSemaphore); VkResult imageAvailableResult = vkCreateSemaphore(mLogicalDevice, &semaphoreInfo, nullptr, &mImageAvailableSemaphores[i]);
VkResult inFlightResult = vkCreateFence(mLogicalDevice, &fenceInfo, nullptr, &mInFlightFence); VkResult renderFinishedResult = vkCreateSemaphore(mLogicalDevice, &semaphoreInfo, nullptr, &mRenderFinishedSemaphores[i]);
VkResult inFlightResult = vkCreateFence(mLogicalDevice, &fenceInfo, nullptr, &mInFlightFences[i]);
if(imageAvailableResult != VK_SUCCESS || renderFinishedResult != VK_SUCCESS || inFlightResult != VK_SUCCESS) { if(imageAvailableResult != VK_SUCCESS || renderFinishedResult != VK_SUCCESS || inFlightResult != VK_SUCCESS) {
throw std::runtime_error("Could not create needed semaphores or other memory handling objects for Vulkan!"); throw std::runtime_error("Could not create needed semaphores or other memory handling objects for Vulkan!");
}
} }
} }
bool VulkanApp::checkDeviceExtensionSupport(VkPhysicalDevice device) { bool VulkanApp::checkDeviceExtensionSupport(VkPhysicalDevice device) {
@ -775,8 +840,12 @@ void VulkanApp::setupDebugMessenger() {
VkDebugUtilsMessengerCreateInfoEXT createInfo; VkDebugUtilsMessengerCreateInfoEXT createInfo;
createInfo = {}; createInfo = {};
createInfo.sType = VK_STRUCTURE_TYPE_DEBUG_UTILS_MESSENGER_CREATE_INFO_EXT; createInfo.sType = VK_STRUCTURE_TYPE_DEBUG_UTILS_MESSENGER_CREATE_INFO_EXT;
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; createInfo.messageSeverity = VK_DEBUG_UTILS_MESSAGE_SEVERITY_VERBOSE_BIT_EXT |
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; VK_DEBUG_UTILS_MESSAGE_SEVERITY_WARNING_BIT_EXT |
VK_DEBUG_UTILS_MESSAGE_SEVERITY_ERROR_BIT_EXT;
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;
createInfo.pfnUserCallback = debugCallback; createInfo.pfnUserCallback = debugCallback;
if (CreateDebugUtilsMessengerEXT(mInstance, &createInfo, nullptr, &mDebugMessenger) != VK_SUCCESS) { if (CreateDebugUtilsMessengerEXT(mInstance, &createInfo, nullptr, &mDebugMessenger) != VK_SUCCESS) {
@ -796,18 +865,37 @@ void VulkanApp::loop() {
// Main loop // Main loop
while(mActive) { while(mActive) {
while(SDL_PollEvent(&mEvent)) while(SDL_PollEvent(&mEvent)) {
if(mEvent.type == SDL_QUIT) { switch (mEvent.type) {
case SDL_QUIT:
mActive = false; mActive = false;
break; break;
case SDL_WINDOWEVENT:
switch(mEvent.window.event) {
case SDL_WINDOWEVENT_SIZE_CHANGED:
mResized = true;
break;
case SDL_WINDOWEVENT_MINIMIZED:
mMinimized = true;
break;
case SDL_WINDOWEVENT_RESTORED:
mMinimized = false;
break;
default:
break;
}
break;
default:
break;
} }
}
//SDL_SetRenderDrawColor(rend, 255, 0, 0, 255); //SDL_SetRenderDrawColor(rend, 255, 0, 0, 255);
//SDL_RenderClear(rend); //SDL_RenderClear(rend);
//SDL_RenderPresent(rend); //SDL_RenderPresent(rend);
drawFrame();
SDL_ShowWindow(mWin); if(!mMinimized) drawFrame();
} }
vkDeviceWaitIdle(mLogicalDevice); vkDeviceWaitIdle(mLogicalDevice);
@ -815,30 +903,27 @@ void VulkanApp::loop() {
} }
void VulkanApp::cleanup() { void VulkanApp::cleanup() {
vkDestroySemaphore(mLogicalDevice, mImageAvailableSemaphore, nullptr); cleanupSwapChain();
vkDestroySemaphore(mLogicalDevice, mRenderFinishedSemaphore, nullptr);
vkDestroyFence(mLogicalDevice, mInFlightFence, nullptr);
vkDestroyCommandPool(mLogicalDevice, mCommandPool, nullptr);
for (VkFramebuffer framebuffer : mSwapChainFramebuffers) {
vkDestroyFramebuffer(mLogicalDevice, framebuffer, nullptr);
}
vkDestroyPipeline(mLogicalDevice, mGraphicsPipeline, nullptr); vkDestroyPipeline(mLogicalDevice, mGraphicsPipeline, nullptr);
vkDestroyPipelineLayout(mLogicalDevice, mPipelineLayout, nullptr); vkDestroyPipelineLayout(mLogicalDevice, mPipelineLayout, nullptr);
vkDestroyRenderPass(mLogicalDevice, mRenderPass, nullptr); vkDestroyRenderPass(mLogicalDevice, mRenderPass, nullptr);
for (VkImageView imageView : mSwapChainImageViews) { for(size_t i=0;i<MAX_FRAMES_IN_FLIGHT;i++) {
vkDestroyImageView(mLogicalDevice, imageView, nullptr); vkDestroySemaphore(mLogicalDevice, mImageAvailableSemaphores[i], nullptr);
vkDestroySemaphore(mLogicalDevice, mRenderFinishedSemaphores[i], nullptr);
vkDestroyFence(mLogicalDevice, mInFlightFences[i], nullptr);
} }
vkDestroySwapchainKHR(mLogicalDevice, mSwapChain, nullptr); vkDestroyCommandPool(mLogicalDevice, mCommandPool, nullptr);
vkDestroyDevice(mLogicalDevice, nullptr); vkDestroyDevice(mLogicalDevice, nullptr);
if (enableValidationLayers) { if (enableValidationLayers) {
DestroyDebugUtilsMessengerEXT(mInstance, mDebugMessenger, nullptr); DestroyDebugUtilsMessengerEXT(mInstance, mDebugMessenger, nullptr);
} }
vkDestroySurfaceKHR(mInstance, mSurface, nullptr); vkDestroySurfaceKHR(mInstance, mSurface, nullptr);
vkDestroyInstance(mInstance, nullptr); vkDestroyInstance(mInstance, nullptr);