handle window resizing
This commit is contained in:
parent
2d9c2a45b5
commit
494e455bf4
1 changed files with 72 additions and 12 deletions
84
main.cpp
84
main.cpp
|
|
@ -8,6 +8,17 @@
|
|||
#include <vector>
|
||||
#include <cstring>
|
||||
#include <fstream>
|
||||
#include <cassert>
|
||||
#include <chrono>
|
||||
|
||||
using TimePoint = std::chrono::time_point<std::chrono::system_clock, std::chrono::nanoseconds>;
|
||||
using TimeMs = long;
|
||||
|
||||
TimeMs timeDeltaMs(const TimePoint& point) {
|
||||
auto timeDelta = std::chrono::system_clock::now() - point;
|
||||
auto timeDelayMs = std::chrono::duration_cast<std::chrono::milliseconds>(timeDelta).count();
|
||||
return timeDelayMs;
|
||||
}
|
||||
|
||||
const std::vector<const char *> deviceExtensions = {
|
||||
VK_KHR_SWAPCHAIN_EXTENSION_NAME,
|
||||
|
|
@ -35,13 +46,27 @@ public:
|
|||
cleanup();
|
||||
}
|
||||
|
||||
void scheduleWindowResize(int sizeX, int sizeY) {
|
||||
mWindowSizeDirtyFlagTime = std::chrono::system_clock::now();
|
||||
mWindowSizeDirtyFlag = true;
|
||||
mWindowFramebufferSize = std::make_pair(sizeX, sizeY);
|
||||
assert(!(sizeX <= 0 || sizeY <= 0));
|
||||
}
|
||||
|
||||
private:
|
||||
void initWindow() {
|
||||
// glfwInitHint(GLFW_PLATFORM, GLFW_PLATFORM_X11);
|
||||
glfwInit();
|
||||
|
||||
glfwWindowHint(GLFW_CLIENT_API, GLFW_NO_API);
|
||||
glfwWindowHint(GLFW_RESIZABLE, GLFW_FALSE);
|
||||
// glfwWindowHint(GLFW_RESIZABLE, GLFW_FALSE);
|
||||
mWindow = glfwCreateWindow(800, 600, "App", nullptr, nullptr);
|
||||
scheduleWindowResize(800, 600);
|
||||
|
||||
glfwSetWindowUserPointer(mWindow, this);
|
||||
glfwSetFramebufferSizeCallback(mWindow, [](GLFWwindow* window, int sizeX, int sizeY){
|
||||
((Application*) glfwGetWindowUserPointer(window))->scheduleWindowResize(sizeX, sizeY);
|
||||
});
|
||||
}
|
||||
|
||||
void initVulkan() {
|
||||
|
|
@ -52,7 +77,10 @@ private:
|
|||
createLogicalDevice();
|
||||
getQueues();
|
||||
|
||||
createSwapChain();
|
||||
int width, height;
|
||||
glfwGetFramebufferSize(mWindow, &width, &height);
|
||||
|
||||
createSwapChain(width, height);
|
||||
createSwapChainImageViews();
|
||||
|
||||
createRenderPass();
|
||||
|
|
@ -69,6 +97,15 @@ private:
|
|||
void mainLoop() {
|
||||
while (!glfwWindowShouldClose(mWindow)) {
|
||||
glfwPollEvents();
|
||||
|
||||
if (mWindowSizeDirtyFlag) {
|
||||
auto timeDelayMs = timeDeltaMs(mWindowSizeDirtyFlagTime);
|
||||
if (timeDelayMs > mWindowSizeApplyMinDelay) {
|
||||
recreateSwapChain(mWindowFramebufferSize.first, mWindowFramebufferSize.second);
|
||||
mWindowSizeDirtyFlag = false;
|
||||
}
|
||||
}
|
||||
|
||||
drawFrame();
|
||||
}
|
||||
|
||||
|
|
@ -291,12 +328,24 @@ private:
|
|||
}
|
||||
}
|
||||
|
||||
void createSwapChain() {
|
||||
void recreateSwapChain(int sizeX, int sizeY) {
|
||||
vkDeviceWaitIdle(mDevice);
|
||||
|
||||
destroySwapChainFramebuffers();
|
||||
destroySwapChainImageViews();
|
||||
destroySwapChain();
|
||||
|
||||
createSwapChain(sizeX, sizeY);
|
||||
createSwapChainImageViews();
|
||||
createSwapChainFramebuffers();
|
||||
}
|
||||
|
||||
void createSwapChain(int sizeX, int sizeY) {
|
||||
SwapChainSupportDetails details = querySwapChainSupportDetails(mPhysicalDevice);
|
||||
|
||||
VkSurfaceFormatKHR surfaceFormat = pickSwapChainSurfaceFormat(details);
|
||||
VkPresentModeKHR presentMode = pickSwapChainPresentMode(details);
|
||||
VkExtent2D extent2D = pickSwapChainExtent(details.capabilities);
|
||||
VkExtent2D extent2D = pickSwapChainExtent(details.capabilities, sizeX, sizeY);
|
||||
|
||||
// +1 so will not have to wait for device to finish frame to query an image to render to
|
||||
uint32_t imageCount = details.capabilities.minImageCount + 1;
|
||||
|
|
@ -363,16 +412,13 @@ private:
|
|||
return VK_PRESENT_MODE_FIFO_KHR; // guaranteed exists
|
||||
}
|
||||
|
||||
VkExtent2D pickSwapChainExtent(const VkSurfaceCapabilitiesKHR &capabilities) {
|
||||
static VkExtent2D pickSwapChainExtent(const VkSurfaceCapabilitiesKHR &capabilities, int sizeX, int sizeY) {
|
||||
// if set by vulkan just keep it
|
||||
if (capabilities.currentExtent.width != std::numeric_limits<uint32_t>::max()) {
|
||||
return capabilities.currentExtent;
|
||||
}
|
||||
|
||||
int width, height;
|
||||
glfwGetFramebufferSize(mWindow, &width, &height);
|
||||
|
||||
VkExtent2D out = {(uint32_t) width, (uint32_t) height};
|
||||
VkExtent2D out = {(uint32_t) sizeX, (uint32_t) sizeY};
|
||||
|
||||
out.width = std::clamp(out.width, capabilities.minImageExtent.width, capabilities.maxImageExtent.width);
|
||||
out.height = std::clamp(out.height, capabilities.minImageExtent.height, capabilities.maxImageExtent.height);
|
||||
|
|
@ -445,6 +491,10 @@ private:
|
|||
}
|
||||
}
|
||||
|
||||
void destroySwapChain() {
|
||||
vkDestroySwapchainKHR(mDevice, mSwapChain, nullptr);
|
||||
}
|
||||
|
||||
void destroySwapChainImageViews() {
|
||||
for (const auto &imageView: mSwapChainImageViews) {
|
||||
vkDestroyImageView(mDevice, imageView, nullptr);
|
||||
|
|
@ -816,9 +866,14 @@ private:
|
|||
.pImageIndices = &imageIndex,
|
||||
};
|
||||
|
||||
if (vkQueuePresentKHR(mPresentQueue, &presentInfo) != VK_SUCCESS) {
|
||||
throw std::runtime_error("failed to submit to presentation queue");
|
||||
vkQueuePresentKHR(mPresentQueue, &presentInfo);
|
||||
/* Somehow res is always VK_SUCCESS
|
||||
if (res == VK_ERROR_OUT_OF_DATE_KHR || res == VK_SUBOPTIMAL_KHR) {
|
||||
recreateSwapChain();
|
||||
} else if (res != VK_SUCCESS) {
|
||||
throw std::runtime_error("cannot acquire new khr image");
|
||||
}
|
||||
*/
|
||||
}
|
||||
|
||||
void destroySynchronizationObjects() {
|
||||
|
|
@ -838,8 +893,8 @@ private:
|
|||
|
||||
destroyGraphicsPipeline();
|
||||
destroySwapChainImageViews();
|
||||
destroySwapChain();
|
||||
|
||||
vkDestroySwapchainKHR(mDevice, mSwapChain, nullptr);
|
||||
vkDestroyDevice(mDevice, nullptr);
|
||||
vkDestroySurfaceKHR(mInstance, mSurface, nullptr);
|
||||
vkDestroyInstance(mInstance, nullptr);
|
||||
|
|
@ -850,6 +905,11 @@ private:
|
|||
private:
|
||||
GLFWwindow *mWindow = nullptr;
|
||||
|
||||
bool mWindowSizeDirtyFlag = true;
|
||||
TimePoint mWindowSizeDirtyFlagTime = std::chrono::system_clock::now();
|
||||
TimeMs mWindowSizeApplyMinDelay = 200;
|
||||
std::pair<int, int> mWindowFramebufferSize = { 0, 0 };
|
||||
|
||||
uint32_t mGraphicsQueueFamilyIndex = -1;
|
||||
uint32_t mPresentationQueueFamilyIndex = -1;
|
||||
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue