From 54cf3b4588294011cf0c26db263bcc043100d12e Mon Sep 17 00:00:00 2001 From: Sebastian Gaida <gaida@ca-digit.com> Date: Thu, 6 May 2021 17:49:09 +0200 Subject: [PATCH] [#16] added basic functionality to swapchain and made it dependent on window big push sorry :) to long to say what happend ;) --- projects/first_triangle/src/main.cpp | 22 ++--- src/vkcv/Context.cpp | 15 +++- src/vkcv/Context.hpp | 2 + src/vkcv/CoreManager.cpp | 12 +++ src/vkcv/CoreManager.hpp | 16 ++++ src/vkcv/SwapChain.cpp | 129 ++++++++++++++++++++++++--- src/vkcv/SwapChain.hpp | 20 +++-- src/vkcv/Window.cpp | 24 ++--- src/vkcv/Window.hpp | 23 ++--- 9 files changed, 199 insertions(+), 64 deletions(-) diff --git a/projects/first_triangle/src/main.cpp b/projects/first_triangle/src/main.cpp index 624d1a40..5b014bbd 100644 --- a/projects/first_triangle/src/main.cpp +++ b/projects/first_triangle/src/main.cpp @@ -5,12 +5,6 @@ int main(int argc, const char** argv) { const char* applicationName = "First Triangle"; - vkcv::Window window = vkcv::Window::create( - applicationName, - 800, - 600, - false - ); vkcv::Context context = vkcv::Context::create( applicationName, VK_MAKE_VERSION(0, 0, 1), @@ -20,11 +14,17 @@ int main(int argc, const char** argv) { {"VK_KHR_swapchain"} ); - GLFWwindow *glWindow = window.getWindow(); - const vk::Instance& instance = context.getInstance(); - const vk::PhysicalDevice& physicalDevice = context.getPhysicalDevice(); - const vk::Device& device = context.getDevice(); - const vkcv::SwapChain& swapChain = vkcv::SwapChain::create(glWindow, instance, physicalDevice, device); + const vk::Instance& instance = context.getInstance(); + const vk::PhysicalDevice& physicalDevice = context.getPhysicalDevice(); + const vk::Device& device = context.getDevice(); + + vkcv::Window window = vkcv::Window::create( + context, + applicationName, + 800, + 600, + false + ); std::cout << "Physical device: " << physicalDevice.getProperties().deviceName << std::endl; diff --git a/src/vkcv/Context.cpp b/src/vkcv/Context.cpp index 3d5dfca6..ce94145a 100644 --- a/src/vkcv/Context.cpp +++ b/src/vkcv/Context.cpp @@ -6,6 +6,7 @@ #include "Context.hpp" #include "CoreManager.hpp" +#include <iostream> namespace vkcv { @@ -124,7 +125,12 @@ namespace vkcv { vk::Device device = physicalDevice.createDevice(deviceCreateInfo); - // TODO: implement device.getQueue() to access the queues, if needed + // TODO: implement device.getQueue() to access the queues, if neede + //std::vector<vk::QueueFamilyProperties> queueFamilyProperties = physicalDevice.getQueueFamilyProperties(); + //uint32_t graphicsQueueFamilyIndex = vkcv::findGraphicsQueueFamilyIndex( queueFamilyProperties ); + // for(uint32_t i = 0; true; i++){ + // vk::Queue graphicsQueue = device.getQueue( graphicsQueueFamilyIndex, i ); + // } return Context(instance, physicalDevice, device); } @@ -253,4 +259,11 @@ namespace vkcv { return extensions; } + + uint32_t Context::findGraphicsQueueFamilyIndex(uint32_t queueCount, std::vector<vk::DeviceQueueCreateInfo> &createInfos){ + for(auto createInfo: createInfos){ + std::cout << createInfo.queueCount << std::endl; + } + return 0; + } } diff --git a/src/vkcv/Context.hpp b/src/vkcv/Context.hpp index 1d11f827..bcfb648b 100644 --- a/src/vkcv/Context.hpp +++ b/src/vkcv/Context.hpp @@ -144,6 +144,8 @@ namespace vkcv { * @return */ static std::vector<vk::DeviceQueueCreateInfo> getQueueCreateInfos(vk::PhysicalDevice& physicalDevice, uint32_t queueCount, std::vector<float>& qPriorities, std::vector<vk::QueueFlagBits> &queueFlags); + + static uint32_t findGraphicsQueueFamilyIndex(uint32_t queueCount, std::vector<vk::DeviceQueueCreateInfo> &createInfos); }; } diff --git a/src/vkcv/CoreManager.cpp b/src/vkcv/CoreManager.cpp index 471075e3..be33bee0 100644 --- a/src/vkcv/CoreManager.cpp +++ b/src/vkcv/CoreManager.cpp @@ -28,4 +28,16 @@ namespace vkcv { } glfwCounter--; } + + int getWidth(GLFWwindow *window) { + int width; + glfwGetWindowSize(window, &width, nullptr); + return width; + } + + int getHeight(GLFWwindow *window) { + int height; + glfwGetWindowSize(window, nullptr, &height); + return height; + } } diff --git a/src/vkcv/CoreManager.hpp b/src/vkcv/CoreManager.hpp index a4104ae4..90095b37 100644 --- a/src/vkcv/CoreManager.hpp +++ b/src/vkcv/CoreManager.hpp @@ -6,7 +6,9 @@ */ #include <GLFW/glfw3.h> +#include "vulkan/vulkan.hpp" #include <stdexcept> +#include <vector> namespace vkcv { @@ -19,4 +21,18 @@ namespace vkcv { * terminates glfw once, if it was initialized or decreases the counter */ void terminateGLFW(); + + /** + * gets the window width + * @param window glfwWindow + * @return int with window width + */ + int getWidth(GLFWwindow *window); + + /** + * gets the window height + * @param window glfwWindow + * @return int with window height + */ + int getHeight(GLFWwindow *window); } diff --git a/src/vkcv/SwapChain.cpp b/src/vkcv/SwapChain.cpp index ed999fcd..ceee227e 100644 --- a/src/vkcv/SwapChain.cpp +++ b/src/vkcv/SwapChain.cpp @@ -1,40 +1,141 @@ #include "SwapChain.hpp" #include "CoreManager.hpp" -#include <iostream> namespace vkcv { - SwapChain::SwapChain(vk::SurfaceKHR surface) - : m_surface(surface) + SwapChain::SwapChain(vk::SurfaceKHR surface, const vkcv::Context* context) + : m_surface(surface), m_context(context) {} - SwapChain SwapChain::create(GLFWwindow* window, const vk::Instance& instance, const vk::PhysicalDevice& physicalDevice, const vk::Device& device){ - vk::SurfaceKHR surface = VK_NULL_HANDLE; - createSurface(window,surface,instance,physicalDevice); - vk::SurfaceCapabilitiesKHR surfaceCapabilities; - if(physicalDevice.getSurfaceCapabilitiesKHR(surface,&surfaceCapabilities) != vk::Result::eSuccess){ - throw std::runtime_error("cannot get surface capabilites. There is an issue with the surface."); - } + SwapChain SwapChain::create(GLFWwindow* window, const vkcv::Context* context){ + + const vk::Instance& instance = context->getInstance(); + const vk::PhysicalDevice& physicalDevice = context->getPhysicalDevice(); + const vk::Device& device = context->getDevice(); + vk::SurfaceKHR surface = createSurface(window,instance,physicalDevice); + vk::Extent2D extent2D = chooseSwapExtent(physicalDevice, surface, window); + vk::SurfaceFormatKHR surfaceFormat = chooseSwapSurfaceFormat(physicalDevice, surface); + vk::PresentModeKHR presentMode = choosePresentMode(physicalDevice, surface); - return SwapChain(surface); +// vk::SwapchainCreateInfoKHR swapchainCreateInfo( +// vk::SwapchainCreateFlagBitsKHR() +// VK_STRUCTURE_TYPE_SWAPCHAIN_CREATE_INFO_KHR, // VkStructureType sType +// nullptr, // const void *pNext +// 0, // VkSwapchainCreateFlagsKHR flags +// surface, // VkSurfaceKHR surface +// desired_number_of_images, // uint32_t minImageCount +// desired_format.format, // VkFormat imageFormat +// desired_format.colorSpace, // VkColorSpaceKHR imageColorSpace +// desired_extent, // VkExtent2D imageExtent +// 1, // uint32_t imageArrayLayers +// desired_usage, // VkImageUsageFlags imageUsage +// VK_SHARING_MODE_EXCLUSIVE, // VkSharingMode imageSharingMode +// 0, // uint32_t queueFamilyIndexCount +// nullptr, // const uint32_t *pQueueFamilyIndices +// desired_transform, // VkSurfaceTransformFlagBitsKHR preTransform +// VK_COMPOSITE_ALPHA_OPAQUE_BIT_KHR, // VkCompositeAlphaFlagBitsKHR compositeAlpha +// desired_present_mode, // VkPresentModeKHR presentMode +// VK_TRUE, // VkBool32 clipped +// old_swap_chain // VkSwapchainKHR oldSwapchain +// ); + +// vk::SwapchainCreateInfoKHR swapchainCreateInfo( +// vk::SwapchainCreateFlagsKHR(), //flags +// surface, // surface +// surfaceCapabilities.minImageCount, // minImageCount TODO: how many do we need for our application?? "must be less than or equal to the value returned in maxImageCount" +// vk::Format::eB8G8R8A8Unorm, // imageFormat TODO: what image format should be used? +// vk::ColorSpaceKHR::eSrgbNonlinear, // imageColorSpace TODO: which color space should be used? +// vk::Extent2D(width, height), // imageExtent +// 1, // imageArrayLayers TODO: should we only allow non-stereoscopic applications? yes -> 1, no -> ? "must be greater than 0, less or equal to maxImageArrayLayers" +// vk::ImageUsageFlagBits::eColorAttachment | vk::ImageUsageFlagBits::eDepthStencilAttachment, // imageUsage TODO: what attachments? only color? depth? +// vk::SharingMode::eExclusive, // imageSharingMode TODO: which sharing mode? "VK_SHARING_MODE_EXCLUSIV access exclusive to a single queue family, better performance", "VK_SHARING_MODE_CONCURRENT access from multiple queues" +// 0, // queueFamilyIndexCount, the number of queue families having access to the image(s) of the swapchain when imageSharingMode is VK_SHARING_MODE_CONCURRENT +// nullptr, // pQueueFamilyIndices, the pointer to an array of queue family indices having access to the images(s) of the swapchain when imageSharingMode is VK_SHARING_MODE_CONCURRENT +// vk::SurfaceTransformFlagBitsKHR::eIdentity, // preTransform, transformations applied onto the image before display +// vk::CompositeAlphaFlagBitsKHR::eOpaque, // compositeAlpha, TODO: how to handle transparent pixels? do we need transparency? If no -> opaque +// vk::PresentModeKHR::eFifo, // presentMode +// true, // clipped +// nullptr // oldSwapchain +// ); + + return SwapChain(surface, context); } - void SwapChain::createSurface(GLFWwindow *window, vk::SurfaceKHR &surface, const vk::Instance &instance, const vk::PhysicalDevice& physicalDevice) { + vk::SurfaceKHR SwapChain::createSurface(GLFWwindow *window, const vk::Instance &instance, const vk::PhysicalDevice& physicalDevice) { //create surface - auto newSurface = VkSurfaceKHR(surface); + VkSurfaceKHR surface; // 0 means VK_SUCCESS //std::cout << "FAIL: " << glfwCreateWindowSurface(VkInstance(instance), window, nullptr, &newSurface) << std::endl; - if(glfwCreateWindowSurface(VkInstance(instance), window, nullptr, &newSurface) != VK_SUCCESS) { + if(glfwCreateWindowSurface(VkInstance(instance), window, nullptr, &surface) != VK_SUCCESS) { throw std::runtime_error("failed to create a window surface!"); } vk::Bool32 surfaceSupport = false; // ToDo: hierfuer brauchen wir jetzt den queuefamiliy Index -> siehe ToDo in Context.cpp //if(physicalDevice.getSurfaceSupportKHR()) + return vk::SurfaceKHR(surface); + } + + vk::Extent2D SwapChain::chooseSwapExtent(vk::PhysicalDevice physicalDevice, vk::SurfaceKHR surface, GLFWwindow* window){ + vk::SurfaceCapabilitiesKHR surfaceCapabilities; + if(physicalDevice.getSurfaceCapabilitiesKHR(surface,&surfaceCapabilities) != vk::Result::eSuccess){ + throw std::runtime_error("cannot get surface capabilities. There is an issue with the surface."); + } + + VkExtent2D extent2D = { + static_cast<uint32_t>(vkcv::getWidth(window)), + static_cast<uint32_t>(vkcv::getHeight(window)) + }; + extent2D.width = std::max(surfaceCapabilities.minImageExtent.width, std::min(surfaceCapabilities.maxImageExtent.width, extent2D.width)); + extent2D.height = std::max(surfaceCapabilities.minImageExtent.height, std::min(surfaceCapabilities.maxImageExtent.height, extent2D.height)); + + if (extent2D.width > surfaceCapabilities.maxImageExtent.width || + extent2D.width < surfaceCapabilities.minImageExtent.width || + extent2D.height > surfaceCapabilities.maxImageExtent.height || + extent2D.height < surfaceCapabilities.minImageExtent.height) { + std::printf("Surface size not matching. Resizing to allowed value."); + } + return extent2D; + } + + vk::SurfaceFormatKHR SwapChain::chooseSwapSurfaceFormat(vk::PhysicalDevice physicalDevice, vk::SurfaceKHR surface) { + uint32_t formatCount; + physicalDevice.getSurfaceFormatsKHR(surface, &formatCount, nullptr); + std::vector<vk::SurfaceFormatKHR> availableFormats(formatCount); + if (physicalDevice.getSurfaceFormatsKHR(surface, &formatCount, &availableFormats[0]) != vk::Result::eSuccess) { + throw std::runtime_error("Failed to get surface formats"); + } + + for (const auto& availableFormat : availableFormats) { + if (availableFormat.format == vk::Format::eB8G8R8A8Unorm && availableFormat.colorSpace == vk::ColorSpaceKHR::eSrgbNonlinear) { + return availableFormat; + } + } + return availableFormats[0]; + } + + vk::PresentModeKHR SwapChain::choosePresentMode(vk::PhysicalDevice physicalDevice, vk::SurfaceKHR surface) { + uint32_t modeCount; + physicalDevice.getSurfacePresentModesKHR( surface, &modeCount, nullptr ); + std::vector<vk::PresentModeKHR> availablePresentModes(modeCount); + if (physicalDevice.getSurfacePresentModesKHR(surface, &modeCount, &availablePresentModes[0]) != vk::Result::eSuccess) { + throw std::runtime_error("Failed to get presentation modes"); + } + + for (const auto& availablePresentMode : availablePresentModes) { + if (availablePresentMode == vk::PresentModeKHR::eMailbox) { + return availablePresentMode; + } + } + return vk::PresentModeKHR::eFifo; + } + SwapChain::~SwapChain() { +// m_context->getDevice().destroySwapchainKHR( m_swapChain ); + m_context->getInstance().destroySurfaceKHR( m_surface ); } } \ No newline at end of file diff --git a/src/vkcv/SwapChain.hpp b/src/vkcv/SwapChain.hpp index 925cc694..d6f24ef5 100644 --- a/src/vkcv/SwapChain.hpp +++ b/src/vkcv/SwapChain.hpp @@ -1,28 +1,38 @@ #pragma once #include "vulkan/vulkan.hpp" #include "Context.hpp" -#include "Window.hpp" +#include <GLFW/glfw3.h> +#include <iostream> // glfw is not initialized in this class because ist must be sure that there exists a context first // glfw is already initialized by the context or the window class namespace vkcv { - class SwapChain final { private: + vk::SurfaceKHR m_surface; + const vkcv::Context* m_context; + + SwapChain(vk::SurfaceKHR surface, const vkcv::Context* context); - SwapChain(vk::SurfaceKHR); + static vk::SurfaceFormatKHR chooseSwapSurfaceFormat(vk::PhysicalDevice physicalDevice, vk::SurfaceKHR surface); + + static vk::PresentModeKHR choosePresentMode(vk::PhysicalDevice physicalDevice, vk::SurfaceKHR surface); + + static vk::Extent2D chooseSwapExtent(vk::PhysicalDevice physicalDevice, vk::SurfaceKHR surface, GLFWwindow* window ); public: // bin mir grade unsicher wegen der Mehrfachinstanziierung der Klasse // es muessen ja oefter mal neue erstellt werden, aber diese existieren ja nicht gleichzeitig, oder? SwapChain(const SwapChain &other) = delete; SwapChain(SwapChain &&other) = default; - static SwapChain create(GLFWwindow *window, const vk::Instance& instance,const vk::PhysicalDevice& physicalDevice,const vk::Device& device); - static void createSurface(GLFWwindow *window, vk::SurfaceKHR& surface, const vk::Instance& instance, const vk::PhysicalDevice& physicalDevice); + static SwapChain create(GLFWwindow *window, const vkcv::Context* Context); + static vk::SurfaceKHR createSurface(GLFWwindow *window, const vk::Instance& instance, const vk::PhysicalDevice& physicalDevice); + + virtual ~SwapChain(); }; } \ No newline at end of file diff --git a/src/vkcv/Window.cpp b/src/vkcv/Window.cpp index 7d8b86e0..b6514b48 100644 --- a/src/vkcv/Window.cpp +++ b/src/vkcv/Window.cpp @@ -7,10 +7,11 @@ #include "Window.hpp" #include "CoreManager.hpp" + namespace vkcv { - Window::Window(GLFWwindow *window) - : m_window(window) { + Window::Window(GLFWwindow *window, const vkcv::SwapChain *swapChain) + : m_window(window), m_swapChain(swapChain){ } Window::~Window() { @@ -27,7 +28,12 @@ namespace vkcv { glfwWindowHint(GLFW_RESIZABLE, resizable ? GLFW_TRUE : GLFW_FALSE); GLFWwindow *window; window = glfwCreateWindow(width, height, windowTitle, nullptr, nullptr); - return Window(window); + + const vkcv::SwapChain swapChain = vkcv::SwapChain::create( + window, + &context); + + return Window(window, &swapChain); } bool Window::isWindowOpen() const { @@ -41,16 +47,4 @@ namespace vkcv { GLFWwindow *Window::getWindow() const { return m_window; } - - int Window::getWidth() const { - int width; - glfwGetWindowSize(m_window, &width, nullptr); - return width; - } - - int Window::getHeight() const { - int height; - glfwGetWindowSize(m_window, nullptr, &height); - return height; - } } \ No newline at end of file diff --git a/src/vkcv/Window.hpp b/src/vkcv/Window.hpp index 62440d90..816ed3b7 100644 --- a/src/vkcv/Window.hpp +++ b/src/vkcv/Window.hpp @@ -7,18 +7,20 @@ #define GLFW_INCLUDE_VULKAN #include <GLFW/glfw3.h> +#include "SwapChain.hpp" namespace vkcv { - class Window final { private: GLFWwindow *m_window; + const vkcv::SwapChain* m_swapChain; + /** * * @param GLFWwindow of the class */ - explicit Window(GLFWwindow *window); + Window(GLFWwindow *window, const vkcv::SwapChain *swapChain); public: /** @@ -29,8 +31,7 @@ namespace vkcv { * @param[in] resizable resize ability of the window (optional) * @return Window class */ - static Window create(const char *windowTitle, int width = -1, int height = -1, bool resizable = false); - + static Window create(const vkcv::Context& context, const char *windowTitle, int width = -1, int height = -1, bool resizable = false); /** * checks if the window is still open, or the close event was called * This function should be changed/removed later on @@ -51,20 +52,6 @@ namespace vkcv { [[nodiscard]] GLFWwindow *getWindow() const; - /** - * gets the current window width - * @return int with window width - */ - [[nodiscard]] - int getWidth() const; - - /** - * gets the current window height - * @return int with window height - */ - [[nodiscard]] - int getHeight() const; - /** * Copy-operator of #Window is deleted! * -- GitLab