Added resize + fullscreen support
This commit is contained in:
2
main.cpp
2
main.cpp
@@ -36,7 +36,7 @@ int main()
|
|||||||
glfwPollEvents();
|
glfwPollEvents();
|
||||||
GLFWManager::UpdateWindowTitleFPSInfo();
|
GLFWManager::UpdateWindowTitleFPSInfo();
|
||||||
|
|
||||||
if (!VulkanManager::RenderPass())
|
if (!VulkanManager::RenderPass(window))
|
||||||
CleanupAllAndExit(EXIT_FAILURE);
|
CleanupAllAndExit(EXIT_FAILURE);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -12,6 +12,13 @@ namespace PB::Renderer
|
|||||||
|
|
||||||
std::string GLFWManager::s_BaseWindowTitle = {};
|
std::string GLFWManager::s_BaseWindowTitle = {};
|
||||||
|
|
||||||
|
bool GLFWManager::s_Fullscreen = false;
|
||||||
|
|
||||||
|
int GLFWManager::s_WindowedWidth = 800;
|
||||||
|
int GLFWManager::s_WindowedHeight = 600;
|
||||||
|
int GLFWManager::s_WindowedPosX = 50;
|
||||||
|
int GLFWManager::s_WindowedPosY = 50;
|
||||||
|
|
||||||
GLFWwindow* GLFWManager::Init(const int width, const int height, const char* title)
|
GLFWwindow* GLFWManager::Init(const int width, const int height, const char* title)
|
||||||
{
|
{
|
||||||
const bool success = glfwInit();
|
const bool success = glfwInit();
|
||||||
@@ -31,10 +38,13 @@ namespace PB::Renderer
|
|||||||
return nullptr;
|
return nullptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* Creates the window */
|
||||||
|
s_Window = glfwCreateWindow(width, height, title, nullptr, nullptr);
|
||||||
s_BaseWindowTitle = title;
|
s_BaseWindowTitle = title;
|
||||||
|
|
||||||
/* Stores the window and returns it to the user */
|
/* Adds callbacks to the window and returns it */
|
||||||
s_Window = glfwCreateWindow(width, height, title, nullptr, nullptr);
|
glfwSetKeyCallback(s_Window, KeyCallback);
|
||||||
|
|
||||||
return s_Window;
|
return s_Window;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -59,13 +69,44 @@ namespace PB::Renderer
|
|||||||
s_LastFPSUpdateTime = currentTime;
|
s_LastFPSUpdateTime = currentTime;
|
||||||
}
|
}
|
||||||
|
|
||||||
double deltaTime = currentTime - s_LastDeltaUpdateTime;
|
const double deltaTime = currentTime - s_LastDeltaUpdateTime;
|
||||||
s_LastDeltaUpdateTime = currentTime;
|
s_LastDeltaUpdateTime = currentTime;
|
||||||
|
|
||||||
std::string fullTitle = s_BaseWindowTitle + '('
|
const std::string fullTitle = s_BaseWindowTitle + '('
|
||||||
+ std::to_string(s_FpsCounter) + " FPS | "
|
+ std::to_string(s_FpsCounter) + " FPS | "
|
||||||
+ std::to_string(deltaTime) + " ms)";
|
+ std::to_string(deltaTime) + " ms)";
|
||||||
|
|
||||||
glfwSetWindowTitle(s_Window, fullTitle.c_str());
|
glfwSetWindowTitle(s_Window, fullTitle.c_str());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void GLFWManager::KeyCallback(GLFWwindow* window, const int key, const int scancode, const int action, const int mode)
|
||||||
|
{
|
||||||
|
if (action != GLFW_PRESS)
|
||||||
|
return;
|
||||||
|
|
||||||
|
switch (key)
|
||||||
|
{
|
||||||
|
case GLFW_KEY_F11:
|
||||||
|
{
|
||||||
|
s_Fullscreen = !s_Fullscreen;
|
||||||
|
if (s_Fullscreen)
|
||||||
|
{
|
||||||
|
GLFWmonitor* monitor = glfwGetPrimaryMonitor();
|
||||||
|
const GLFWvidmode* videoMode = glfwGetVideoMode(monitor);
|
||||||
|
|
||||||
|
glfwGetWindowPos(window, &s_WindowedPosX, &s_WindowedPosY);
|
||||||
|
glfwGetWindowSize(window, &s_WindowedWidth, &s_WindowedHeight);
|
||||||
|
|
||||||
|
glfwSetWindowMonitor(window, monitor, 0, 0, videoMode->width, videoMode->height, videoMode->refreshRate);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
glfwSetWindowMonitor(window, nullptr, s_WindowedPosX, s_WindowedPosY, s_WindowedWidth, s_WindowedHeight, 0);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
default:
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -6,6 +6,15 @@ namespace PB::Renderer
|
|||||||
{
|
{
|
||||||
class GLFWManager
|
class GLFWManager
|
||||||
{
|
{
|
||||||
|
public:
|
||||||
|
static GLFWwindow* Init(int width, int height, const char* title = "Unnamed window");
|
||||||
|
__forceinline static GLFWwindow* GetWindow() { return s_Window; }
|
||||||
|
|
||||||
|
static bool Cleanup();
|
||||||
|
|
||||||
|
static __forceinline void PollEvents() { glfwPollEvents(); }
|
||||||
|
static void UpdateWindowTitleFPSInfo();
|
||||||
|
|
||||||
private:
|
private:
|
||||||
static GLFWwindow* s_Window;
|
static GLFWwindow* s_Window;
|
||||||
|
|
||||||
@@ -16,13 +25,12 @@ namespace PB::Renderer
|
|||||||
|
|
||||||
static std::string s_BaseWindowTitle;
|
static std::string s_BaseWindowTitle;
|
||||||
|
|
||||||
public:
|
static bool s_Fullscreen;
|
||||||
static GLFWwindow* Init(int width, int height, const char* title = "Unnamed window");
|
static int s_WindowedWidth;
|
||||||
__forceinline static GLFWwindow* GetWindow() { return s_Window; }
|
static int s_WindowedHeight;
|
||||||
|
static int s_WindowedPosX;
|
||||||
|
static int s_WindowedPosY;
|
||||||
|
|
||||||
static bool Cleanup();
|
static void KeyCallback(GLFWwindow* window, int key, int scancode, int action, int mode);
|
||||||
|
|
||||||
static __forceinline void PollEvents() { glfwPollEvents(); }
|
|
||||||
static void UpdateWindowTitleFPSInfo();
|
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -89,7 +89,7 @@ namespace PB::Renderer
|
|||||||
|
|
||||||
/*
|
/*
|
||||||
Assembles shaders, fixed function state and creates the render pipeline.
|
Assembles shaders, fixed function state and creates the render pipeline.
|
||||||
Also checks that the render pass is compatiable.
|
Also checks that the render pass is compatible.
|
||||||
*/
|
*/
|
||||||
static bool CreateGraphicsPipeline();
|
static bool CreateGraphicsPipeline();
|
||||||
|
|
||||||
@@ -108,9 +108,11 @@ namespace PB::Renderer
|
|||||||
/*
|
/*
|
||||||
Draws a frame to the screen using the command buffers and sync objects.
|
Draws a frame to the screen using the command buffers and sync objects.
|
||||||
*/
|
*/
|
||||||
static bool RenderPass();
|
static bool RenderPass(GLFWwindow* window);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
// === Vulkan init helpers === //
|
||||||
|
|
||||||
static bool IsDeviceSuitable(const VkPhysicalDevice& device);
|
static bool IsDeviceSuitable(const VkPhysicalDevice& device);
|
||||||
static QueueFamilyIndices FindQueueFamilies(const VkPhysicalDevice& device);
|
static QueueFamilyIndices FindQueueFamilies(const VkPhysicalDevice& device);
|
||||||
static bool CheckDeviceExtensionSupport(const VkPhysicalDevice& device);
|
static bool CheckDeviceExtensionSupport(const VkPhysicalDevice& device);
|
||||||
@@ -122,6 +124,15 @@ namespace PB::Renderer
|
|||||||
|
|
||||||
static VkShaderModule CreateShaderModule(const std::string& filename);
|
static VkShaderModule CreateShaderModule(const std::string& filename);
|
||||||
|
|
||||||
|
// === Vulkan render helpers === //
|
||||||
|
|
||||||
|
static VkResult RenderPassInternal();
|
||||||
|
|
||||||
|
static void RecreateSwapChain(GLFWwindow* window);
|
||||||
|
static void CleanupSwapChain();
|
||||||
|
|
||||||
|
// === Vulkan resources === //
|
||||||
|
|
||||||
static VkInstance s_Instance;
|
static VkInstance s_Instance;
|
||||||
static VkSurfaceKHR s_Surface;
|
static VkSurfaceKHR s_Surface;
|
||||||
|
|
||||||
|
|||||||
@@ -1,8 +1,70 @@
|
|||||||
#include "VulkanManager.h"
|
#include "VulkanManager.h"
|
||||||
|
|
||||||
|
#define CHECK_RESULT(res) if (res != VK_SUCCESS) { return res; }
|
||||||
|
|
||||||
namespace PB::Renderer
|
namespace PB::Renderer
|
||||||
{
|
{
|
||||||
bool VulkanManager::RenderPass()
|
bool VulkanManager::RenderPass(GLFWwindow* window)
|
||||||
|
{
|
||||||
|
switch (const VkResult result = RenderPassInternal())
|
||||||
|
{
|
||||||
|
case VK_ERROR_OUT_OF_DATE_KHR:
|
||||||
|
case VK_SUBOPTIMAL_KHR:
|
||||||
|
RecreateSwapChain(window);
|
||||||
|
return true;
|
||||||
|
|
||||||
|
default:
|
||||||
|
return result == VK_SUCCESS;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void VulkanManager::RecreateSwapChain(GLFWwindow* window)
|
||||||
|
{
|
||||||
|
int width, height;
|
||||||
|
glfwGetFramebufferSize(window, &width, &height);
|
||||||
|
|
||||||
|
/* Pauses if minimised */
|
||||||
|
while (width == 0 || height == 0)
|
||||||
|
{
|
||||||
|
glfwGetFramebufferSize(window, &width, &height);
|
||||||
|
glfwWaitEvents();
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Waits until device is idle before recreating swap chain */
|
||||||
|
vkDeviceWaitIdle(s_Device);
|
||||||
|
CleanupSwapChain();
|
||||||
|
|
||||||
|
CreateSwapChain(window);
|
||||||
|
CreateImageViews();
|
||||||
|
CreateRenderPass();
|
||||||
|
CreateFramebuffer();
|
||||||
|
CreateGraphicsPipeline();
|
||||||
|
CreateCommandBuffers();
|
||||||
|
CreateSemaphores();
|
||||||
|
}
|
||||||
|
|
||||||
|
void VulkanManager::CleanupSwapChain()
|
||||||
|
{
|
||||||
|
for (const VkFramebuffer framebuffer : s_Framebuffers)
|
||||||
|
{
|
||||||
|
vkDestroyFramebuffer(s_Device, framebuffer, nullptr);
|
||||||
|
}
|
||||||
|
s_Framebuffers.clear();
|
||||||
|
|
||||||
|
vkFreeCommandBuffers(s_Device, s_CommandPool, static_cast<uint32_t>(s_CommandBuffers.size()), s_CommandBuffers.data());
|
||||||
|
vkDestroyPipeline(s_Device, s_RenderPipeline, nullptr);
|
||||||
|
vkDestroyPipelineLayout(s_Device, s_PipelineLayout, nullptr);
|
||||||
|
vkDestroyRenderPass(s_Device, s_RenderPass, nullptr);
|
||||||
|
|
||||||
|
for (const VkImageView view : s_SwapChainImageViews)
|
||||||
|
{
|
||||||
|
vkDestroyImageView(s_Device, view, nullptr);
|
||||||
|
}
|
||||||
|
|
||||||
|
vkDestroySwapchainKHR(s_Device, s_SwapChain, nullptr);
|
||||||
|
}
|
||||||
|
|
||||||
|
VkResult VulkanManager::RenderPassInternal()
|
||||||
{
|
{
|
||||||
uint32_t imageIndex;
|
uint32_t imageIndex;
|
||||||
VkResult result = vkAcquireNextImageKHR(
|
VkResult result = vkAcquireNextImageKHR(
|
||||||
@@ -13,17 +75,7 @@ namespace PB::Renderer
|
|||||||
VK_NULL_HANDLE,
|
VK_NULL_HANDLE,
|
||||||
&imageIndex
|
&imageIndex
|
||||||
);
|
);
|
||||||
|
CHECK_RESULT(result);
|
||||||
if (result == VK_ERROR_OUT_OF_DATE_KHR)
|
|
||||||
{
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (result != VK_SUCCESS && result != VK_SUBOPTIMAL_KHR)
|
|
||||||
{
|
|
||||||
std::cout << "PB::Renderer::VulkanManager::RenderPass(): Failed to acquire swap chain image!" << std::endl;
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
VkSubmitInfo submitInfo{};
|
VkSubmitInfo submitInfo{};
|
||||||
submitInfo.sType = VK_STRUCTURE_TYPE_SUBMIT_INFO;
|
submitInfo.sType = VK_STRUCTURE_TYPE_SUBMIT_INFO;
|
||||||
@@ -41,11 +93,8 @@ namespace PB::Renderer
|
|||||||
submitInfo.signalSemaphoreCount = 1;
|
submitInfo.signalSemaphoreCount = 1;
|
||||||
submitInfo.pSignalSemaphores = signalSemaphores;
|
submitInfo.pSignalSemaphores = signalSemaphores;
|
||||||
|
|
||||||
if (vkQueueSubmit(s_GraphicsQueue, 1, &submitInfo, VK_NULL_HANDLE) != VK_SUCCESS)
|
result = vkQueueSubmit(s_GraphicsQueue, 1, &submitInfo, VK_NULL_HANDLE);
|
||||||
{
|
CHECK_RESULT(result);
|
||||||
std::cout << "PB::Renderer::VulkanManager::RenderPass(): Failed to submit draw command buffer!" << std::endl;
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
VkPresentInfoKHR presentInfo{};
|
VkPresentInfoKHR presentInfo{};
|
||||||
presentInfo.sType = VK_STRUCTURE_TYPE_PRESENT_INFO_KHR;
|
presentInfo.sType = VK_STRUCTURE_TYPE_PRESENT_INFO_KHR;
|
||||||
@@ -58,19 +107,9 @@ namespace PB::Renderer
|
|||||||
presentInfo.pImageIndices = &imageIndex;
|
presentInfo.pImageIndices = &imageIndex;
|
||||||
|
|
||||||
result = vkQueuePresentKHR(s_PresentQueue, &presentInfo);
|
result = vkQueuePresentKHR(s_PresentQueue, &presentInfo);
|
||||||
|
CHECK_RESULT(result);
|
||||||
if (result == VK_ERROR_OUT_OF_DATE_KHR || result == VK_SUBOPTIMAL_KHR)
|
|
||||||
{
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (result != VK_SUCCESS)
|
|
||||||
{
|
|
||||||
std::cout << "PB::Renderer::VulkanManager::RenderPass(): Failed to present swap chain image!" << std::endl;
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
vkQueueWaitIdle(s_PresentQueue);
|
vkQueueWaitIdle(s_PresentQueue);
|
||||||
return true;
|
return VK_SUCCESS;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user