More code cleanup
This commit is contained in:
83
openVulkanoCpp/Vulkan/Context.cpp
Normal file
83
openVulkanoCpp/Vulkan/Context.cpp
Normal file
@@ -0,0 +1,83 @@
|
|||||||
|
/*
|
||||||
|
* This Source Code Form is subject to the terms of the Mozilla Public
|
||||||
|
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||||
|
* file, You can obtain one at https://mozilla.org/MPL/2.0/.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include "Context.hpp"
|
||||||
|
#include "../Base/Utils.hpp"
|
||||||
|
#include "../Base/Logger.hpp"
|
||||||
|
#include "../Base/IGraphicsApp.hpp"
|
||||||
|
#include "../Base/IGraphicsAppManager.hpp"
|
||||||
|
#include "../Base/EngineConstants.hpp"
|
||||||
|
#include "Debuging/ValidationLayer.hpp"
|
||||||
|
|
||||||
|
namespace openVulkanoCpp::Vulkan
|
||||||
|
{
|
||||||
|
void Context::Init(IGraphicsAppManager* graphicsAppManager, IVulkanWindow* window)
|
||||||
|
{
|
||||||
|
if (initialized) throw std::runtime_error("The context is already initialized");
|
||||||
|
this->graphicsAppManager = graphicsAppManager;
|
||||||
|
this->window = window;
|
||||||
|
|
||||||
|
// Get the extensions required to display on the window
|
||||||
|
for (const auto& requiredExtension : window->GetRequiredInstanceExtensions()) { RequireExtension(requiredExtension.c_str()); }
|
||||||
|
|
||||||
|
CreateInstance(); // Create the vulkan instance
|
||||||
|
surface = window->CreateSurface(instance); // Create the surface from the window
|
||||||
|
CreateDevice();
|
||||||
|
|
||||||
|
|
||||||
|
swapChain.Init(device, surface, window);
|
||||||
|
swapChainRenderPass.Init(device, &swapChain);
|
||||||
|
|
||||||
|
pipeline.Init(device->device);
|
||||||
|
|
||||||
|
initialized = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
void Context::Close()
|
||||||
|
{
|
||||||
|
if (!initialized) return;
|
||||||
|
device->WaitIdle();
|
||||||
|
|
||||||
|
pipeline.Close();
|
||||||
|
swapChainRenderPass.Close();
|
||||||
|
swapChain.Close();
|
||||||
|
deviceManager.Close();
|
||||||
|
//TODO
|
||||||
|
|
||||||
|
if (enableValidationLayer) Debug::CloseValidationLayers(instance);
|
||||||
|
initialized = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
void Context::Resize(const uint32_t newWidth, const uint32_t newHeight)
|
||||||
|
{
|
||||||
|
device->WaitIdle();
|
||||||
|
swapChain.Resize(newWidth, newHeight);
|
||||||
|
}
|
||||||
|
|
||||||
|
void Context::CreateInstance()
|
||||||
|
{
|
||||||
|
if (enableValidationLayer) RequireExtension(VK_EXT_DEBUG_REPORT_EXTENSION_NAME);
|
||||||
|
vk::ApplicationInfo appInfo(graphicsAppManager->GetGraphicsApp()->GetAppName().c_str(), graphicsAppManager->GetGraphicsApp()->GetAppVersionAsInt(), ENGINE_NAME, ENGINE_VERSION.intVersion, VK_MAKE_VERSION(1, 1, 0));
|
||||||
|
std::vector<const char*> extensions = Utils::toCString(requiredExtensions), layers = Debug::GetValidationLayers();
|
||||||
|
|
||||||
|
const vk::InstanceCreateInfo createInfo(vk::InstanceCreateFlags(), &appInfo, enableValidationLayer ? layers.size() : 0,
|
||||||
|
layers.data(), extensions.size(), extensions.data());
|
||||||
|
|
||||||
|
instance = vk::createInstance(createInfo);
|
||||||
|
|
||||||
|
if (enableValidationLayer) Debug::SetupValidationLayers(instance, vk::DebugReportFlagBitsEXT::eError | vk::DebugReportFlagBitsEXT::eWarning | vk::DebugReportFlagBitsEXT::ePerformanceWarning /*| vk::DebugReportFlagBitsEXT::eInformation | vk::DebugReportFlagBitsEXT::eDebug*/);
|
||||||
|
dynamicDispatch.init(instance, &vkGetInstanceProcAddr);
|
||||||
|
}
|
||||||
|
|
||||||
|
void Context::CreateDevice()
|
||||||
|
{
|
||||||
|
deviceManager.Init(instance);
|
||||||
|
device = deviceManager.GetCompatibleDevice({ VK_KHR_SWAPCHAIN_EXTENSION_NAME });
|
||||||
|
device->PrepareDevice({ VK_KHR_SWAPCHAIN_EXTENSION_NAME }, surface);
|
||||||
|
dynamicDispatch.init(instance, &vkGetInstanceProcAddr, device->device, &vkGetDeviceProcAddr);
|
||||||
|
Logger::RENDER->info("Found device: {0}", device->GetDeviceName());;
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -1,10 +1,12 @@
|
|||||||
|
/*
|
||||||
|
* This Source Code Form is subject to the terms of the Mozilla Public
|
||||||
|
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||||
|
* file, You can obtain one at https://mozilla.org/MPL/2.0/.
|
||||||
|
*/
|
||||||
|
|
||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
#include <vulkan/vulkan.hpp>
|
#include <vulkan/vulkan.hpp>
|
||||||
#include "../Base/IGraphicsApp.hpp"
|
|
||||||
#include "../Base/IGraphicsAppManager.hpp"
|
|
||||||
#include "../Base/EngineConstants.hpp"
|
|
||||||
#include "../Base/Utils.hpp"
|
|
||||||
#include "Debuging/ValidationLayer.hpp"
|
|
||||||
#include "DeviceManager.hpp"
|
#include "DeviceManager.hpp"
|
||||||
#include "SwapChain.hpp"
|
#include "SwapChain.hpp"
|
||||||
#include "RenderPass.hpp"
|
#include "RenderPass.hpp"
|
||||||
@@ -12,8 +14,13 @@
|
|||||||
|
|
||||||
namespace openVulkanoCpp
|
namespace openVulkanoCpp
|
||||||
{
|
{
|
||||||
|
class IVulkanWindow;
|
||||||
|
class IGraphicsAppManager;
|
||||||
|
|
||||||
namespace Vulkan
|
namespace Vulkan
|
||||||
{
|
{
|
||||||
|
class Device;
|
||||||
|
|
||||||
class Context final : virtual public ICloseable
|
class Context final : virtual public ICloseable
|
||||||
{
|
{
|
||||||
bool enableValidationLayer, initialized;
|
bool enableValidationLayer, initialized;
|
||||||
@@ -44,77 +51,20 @@ namespace openVulkanoCpp
|
|||||||
if (initialized) Close();
|
if (initialized) Close();
|
||||||
}
|
}
|
||||||
|
|
||||||
void Init(IGraphicsAppManager* graphicsAppManager, IVulkanWindow* window)
|
void Init(IGraphicsAppManager* graphicsAppManager, IVulkanWindow* window);
|
||||||
{
|
|
||||||
if (initialized) throw std::runtime_error("The context is already initialized");
|
|
||||||
this->graphicsAppManager = graphicsAppManager;
|
|
||||||
this->window = window;
|
|
||||||
|
|
||||||
// Get the extensions required to display on the window
|
void Close() override;
|
||||||
for (const auto& requiredExtension : window->GetRequiredInstanceExtensions()) { RequireExtension(requiredExtension.c_str()); }
|
|
||||||
|
|
||||||
CreateInstance(); // Create the vulkan instance
|
void Resize(uint32_t newWidth, uint32_t newHeight);
|
||||||
surface = window->CreateSurface(instance); // Create the surface from the window
|
|
||||||
CreateDevice();
|
|
||||||
|
|
||||||
|
|
||||||
swapChain.Init(device, surface, window);
|
|
||||||
swapChainRenderPass.Init(device, &swapChain);
|
|
||||||
|
|
||||||
pipeline.Init(device->device);
|
|
||||||
|
|
||||||
initialized = true;
|
|
||||||
}
|
|
||||||
|
|
||||||
void Close() override
|
|
||||||
{
|
|
||||||
if (!initialized) return;
|
|
||||||
device->WaitIdle();
|
|
||||||
|
|
||||||
pipeline.Close();
|
|
||||||
swapChainRenderPass.Close();
|
|
||||||
swapChain.Close();
|
|
||||||
deviceManager.Close();
|
|
||||||
//TODO
|
|
||||||
|
|
||||||
if (enableValidationLayer) Debug::CloseValidationLayers(instance);
|
|
||||||
initialized = false;
|
|
||||||
}
|
|
||||||
|
|
||||||
void Resize(const uint32_t newWidth, const uint32_t newHeight)
|
|
||||||
{
|
|
||||||
device->WaitIdle();
|
|
||||||
swapChain.Resize(newWidth, newHeight);
|
|
||||||
}
|
|
||||||
|
|
||||||
void RequireExtension(const char* extension)
|
void RequireExtension(const char* extension)
|
||||||
{
|
{
|
||||||
requiredExtensions.emplace(extension);
|
requiredExtensions.emplace(extension);
|
||||||
}
|
}
|
||||||
private:
|
private:
|
||||||
void CreateInstance()
|
void CreateInstance();
|
||||||
{
|
|
||||||
if (enableValidationLayer) RequireExtension(VK_EXT_DEBUG_REPORT_EXTENSION_NAME);
|
|
||||||
vk::ApplicationInfo appInfo(graphicsAppManager->GetGraphicsApp()->GetAppName().c_str(), graphicsAppManager->GetGraphicsApp()->GetAppVersionAsInt(), ENGINE_NAME, ENGINE_VERSION.intVersion, VK_MAKE_VERSION(1, 1, 0));
|
|
||||||
std::vector<const char*> extensions = Utils::toCString(requiredExtensions), layers = Debug::GetValidationLayers();
|
|
||||||
|
|
||||||
const vk::InstanceCreateInfo createInfo(vk::InstanceCreateFlags(), &appInfo, enableValidationLayer ? layers.size() : 0,
|
void CreateDevice();
|
||||||
layers.data(), extensions.size(), extensions.data());
|
|
||||||
|
|
||||||
instance = vk::createInstance(createInfo);
|
|
||||||
|
|
||||||
if (enableValidationLayer) Debug::SetupValidationLayers(instance, vk::DebugReportFlagBitsEXT::eError | vk::DebugReportFlagBitsEXT::eWarning | vk::DebugReportFlagBitsEXT::ePerformanceWarning /*| vk::DebugReportFlagBitsEXT::eInformation | vk::DebugReportFlagBitsEXT::eDebug*/);
|
|
||||||
dynamicDispatch.init(instance, &vkGetInstanceProcAddr);
|
|
||||||
}
|
|
||||||
|
|
||||||
void CreateDevice()
|
|
||||||
{
|
|
||||||
deviceManager.Init(instance);
|
|
||||||
device = deviceManager.GetCompatibleDevice({ VK_KHR_SWAPCHAIN_EXTENSION_NAME });
|
|
||||||
device->PrepareDevice({ VK_KHR_SWAPCHAIN_EXTENSION_NAME }, surface);
|
|
||||||
dynamicDispatch.init(instance, &vkGetInstanceProcAddr, device->device, &vkGetDeviceProcAddr);
|
|
||||||
Logger::RENDER->info("Found device: {0}", device->GetDeviceName());;
|
|
||||||
}
|
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
176
openVulkanoCpp/Vulkan/SwapChain.cpp
Normal file
176
openVulkanoCpp/Vulkan/SwapChain.cpp
Normal file
@@ -0,0 +1,176 @@
|
|||||||
|
/*
|
||||||
|
* This Source Code Form is subject to the terms of the Mozilla Public
|
||||||
|
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||||
|
* file, You can obtain one at https://mozilla.org/MPL/2.0/.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include "SwapChain.hpp"
|
||||||
|
#include "../Base/Logger.hpp"
|
||||||
|
#include "../Base/Utils.hpp"
|
||||||
|
#include <algorithm>
|
||||||
|
|
||||||
|
namespace openVulkanoCpp::Vulkan
|
||||||
|
{
|
||||||
|
void SwapChain::Init(Device* device, vk::SurfaceKHR surface, IVulkanWindow* window)
|
||||||
|
{
|
||||||
|
if (!device) throw std::runtime_error("The device must not be null");
|
||||||
|
if (!window) throw std::runtime_error("The window must not be null");
|
||||||
|
this->device = device;
|
||||||
|
this->surface = surface;
|
||||||
|
this->window = window;
|
||||||
|
|
||||||
|
imageAvailableSemaphore = device->device.createSemaphore({});
|
||||||
|
CreateSwapChain({window->GetWidth(), window->GetHeight() });
|
||||||
|
|
||||||
|
FrameBuffer::Init(device, vk::Extent3D(size, 1));
|
||||||
|
}
|
||||||
|
|
||||||
|
void SwapChain::Close()
|
||||||
|
{
|
||||||
|
DestroySwapChain();
|
||||||
|
device->device.destroySemaphore(imageAvailableSemaphore);
|
||||||
|
device = nullptr;
|
||||||
|
FrameBuffer::Close();
|
||||||
|
}
|
||||||
|
|
||||||
|
void SwapChain::Resize(const uint32_t newWidth, const uint32_t newHeight)
|
||||||
|
{
|
||||||
|
if(newWidth == 0 || newHeight == 0) return; // Swap chain size of 0 pixel is not allowed
|
||||||
|
|
||||||
|
CreateSwapChain({ newWidth, newHeight });
|
||||||
|
FrameBuffer::Resize(vk::Extent3D(size, 1));
|
||||||
|
}
|
||||||
|
|
||||||
|
uint32_t SwapChain::AcquireNextImage(const vk::Fence& fence)
|
||||||
|
{
|
||||||
|
const auto resultValue = device->device.acquireNextImageKHR(swapChain, UINT64_MAX, imageAvailableSemaphore, fence);
|
||||||
|
const vk::Result result = resultValue.result;
|
||||||
|
if (result != vk::Result::eSuccess && result != vk::Result::eSuboptimalKHR) throw std::error_code(result);
|
||||||
|
SetCurrentFrameId(resultValue.value);
|
||||||
|
|
||||||
|
vk::Fence submitFence = GetCurrentSubmitFence();
|
||||||
|
device->device.waitForFences(1, &submitFence, true, -1);
|
||||||
|
device->device.resetFences(1, &submitFence);
|
||||||
|
|
||||||
|
return currentFrameBufferId;
|
||||||
|
}
|
||||||
|
|
||||||
|
void SwapChain::CreateSwapChain(vk::Extent2D size)
|
||||||
|
{
|
||||||
|
Logger::RENDER->debug("Creating swap chain for window {0} ...", window->GetWindowId());
|
||||||
|
surfaceFormat = ChoseSurfaceFormat();
|
||||||
|
presentMode = ChosePresentMode();
|
||||||
|
const vk::SurfaceCapabilitiesKHR surfaceCapabilities = device->physicalDevice.getSurfaceCapabilitiesKHR(surface);
|
||||||
|
if(surfaceCapabilities.currentExtent.width != ~static_cast<uint32_t>(0))
|
||||||
|
{ // The surface does provide it's size to the vulkan driver
|
||||||
|
size = surfaceCapabilities.currentExtent;
|
||||||
|
}
|
||||||
|
|
||||||
|
vk::SurfaceTransformFlagBitsKHR preTransform; //TODO add option to allow rotation and other modifications
|
||||||
|
if (surfaceCapabilities.supportedTransforms & vk::SurfaceTransformFlagBitsKHR::eIdentity)
|
||||||
|
{ preTransform = vk::SurfaceTransformFlagBitsKHR::eIdentity; }
|
||||||
|
else { preTransform = surfaceCapabilities.currentTransform; }
|
||||||
|
|
||||||
|
uint32_t usingImages = std::max(preferredImageCount, surfaceCapabilities.minImageCount);
|
||||||
|
if (surfaceCapabilities.maxImageCount > 0) //GPU has limit of swap chain images
|
||||||
|
usingImages = std::min(usingImages, surfaceCapabilities.maxImageCount);
|
||||||
|
Logger::RENDER->debug("GPU supports {0} to {1} swap chain images. Preferred: {2}, Using: {3}", surfaceCapabilities.minImageCount, surfaceCapabilities.maxImageCount, preferredImageCount, usingImages);
|
||||||
|
|
||||||
|
const vk::SwapchainCreateInfoKHR createInfo({}, surface, usingImages, surfaceFormat.format,
|
||||||
|
surfaceFormat.colorSpace, size, 1,
|
||||||
|
vk::ImageUsageFlagBits::eColorAttachment | vk::ImageUsageFlagBits::eTransferDst,
|
||||||
|
vk::SharingMode::eExclusive, 0, nullptr, preTransform,
|
||||||
|
vk::CompositeAlphaFlagBitsKHR::eOpaque, presentMode, VK_TRUE, swapChain);
|
||||||
|
const vk::SwapchainKHR newSwapChain = device->device.createSwapchainKHR(createInfo);
|
||||||
|
|
||||||
|
DestroySwapChain();
|
||||||
|
swapChain = newSwapChain;
|
||||||
|
this->size = size;
|
||||||
|
|
||||||
|
CreateSwapChainImages();
|
||||||
|
|
||||||
|
fullscreenViewport = vk::Viewport{ 0, 0, (float)size.width, (float)size.height, 0, 1 };
|
||||||
|
fullscreenScissor = vk::Rect2D{ {0,0}, size };
|
||||||
|
Logger::RENDER->debug("Swap chain for window {0} created", window->GetWindowId());
|
||||||
|
}
|
||||||
|
|
||||||
|
void SwapChain::CreateSwapChainImages()
|
||||||
|
{
|
||||||
|
vk::ImageViewCreateInfo imgViewCreateInfo;
|
||||||
|
imgViewCreateInfo.format = surfaceFormat.format;
|
||||||
|
imgViewCreateInfo.subresourceRange.aspectMask = vk::ImageAspectFlagBits::eColor;
|
||||||
|
imgViewCreateInfo.subresourceRange.levelCount = 1;
|
||||||
|
imgViewCreateInfo.subresourceRange.layerCount = 1;
|
||||||
|
imgViewCreateInfo.viewType = vk::ImageViewType::e2D;
|
||||||
|
|
||||||
|
auto swapChainImages = device->device.getSwapchainImagesKHR(swapChain);
|
||||||
|
|
||||||
|
images.resize(swapChainImages.size());
|
||||||
|
for (uint32_t i = 0; i < swapChainImages.size(); i++)
|
||||||
|
{
|
||||||
|
images[i].image = swapChainImages[i];
|
||||||
|
imgViewCreateInfo.image = swapChainImages[i];
|
||||||
|
images[i].view = device->device.createImageView(imgViewCreateInfo);
|
||||||
|
images[i].fence = device->device.createFence({ vk::FenceCreateFlags(vk::FenceCreateFlagBits::eSignaled)});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void SwapChain::DestroySwapChain() const
|
||||||
|
{
|
||||||
|
for(auto& image : images)
|
||||||
|
{
|
||||||
|
device->device.destroyImageView(image.view);
|
||||||
|
device->device.destroyFence(image.fence);
|
||||||
|
}
|
||||||
|
device->device.destroySwapchainKHR(swapChain);
|
||||||
|
}
|
||||||
|
|
||||||
|
vk::PresentModeKHR SwapChain::ChosePresentMode()
|
||||||
|
{
|
||||||
|
std::vector<vk::PresentModeKHR> presentModes = device->physicalDevice.getSurfacePresentModesKHR(surface);
|
||||||
|
#ifdef DEBUG
|
||||||
|
std::string availableModes = "";
|
||||||
|
for (const auto& presentMode : presentModes)
|
||||||
|
{
|
||||||
|
if (availableModes.length() > 0) availableModes += ", ";
|
||||||
|
availableModes += vk::to_string(presentMode);
|
||||||
|
}
|
||||||
|
Logger::RENDER->debug("Available swap chain present modes {0}. Searching best mode for: vsync={1}", availableModes, useVsync);
|
||||||
|
#endif
|
||||||
|
vk::PresentModeKHR mode = vk::PresentModeKHR::eFifo;
|
||||||
|
if (useVsync)
|
||||||
|
{
|
||||||
|
if (Utils::Contains(presentModes, vk::PresentModeKHR::eMailbox)) mode = vk::PresentModeKHR::eMailbox;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
if (Utils::Contains(presentModes, vk::PresentModeKHR::eImmediate)) mode = vk::PresentModeKHR::eImmediate;
|
||||||
|
else if (Utils::Contains(presentModes, vk::PresentModeKHR::eFifoRelaxed)) mode = vk::PresentModeKHR::eFifoRelaxed;
|
||||||
|
}
|
||||||
|
Logger::RENDER->debug("Using swap chain present mode {0}", vk::to_string(mode));
|
||||||
|
return mode;
|
||||||
|
}
|
||||||
|
|
||||||
|
vk::SurfaceFormatKHR SwapChain::ChoseSurfaceFormat()
|
||||||
|
{ //TODO allow to chose output format
|
||||||
|
std::vector<vk::SurfaceFormatKHR> surfaceFormats = device->physicalDevice.getSurfaceFormatsKHR(surface);
|
||||||
|
if(surfaceFormats.size() == 1 && surfaceFormats[0].format == vk::Format::eUndefined)
|
||||||
|
{ // GPU does not have a preferred surface format
|
||||||
|
return vk::SurfaceFormatKHR{ vk::Format::eB8G8R8A8Unorm, surfaceFormats[0].colorSpace };
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{ //TODO chose best fitting
|
||||||
|
return surfaceFormats[0];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
std::vector<IImage*> SwapChain::GetImages()
|
||||||
|
{
|
||||||
|
std::vector<IImage*> imgs;
|
||||||
|
for (auto& image : images)
|
||||||
|
{
|
||||||
|
imgs.push_back(&image);
|
||||||
|
}
|
||||||
|
return imgs;
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -6,13 +6,11 @@
|
|||||||
|
|
||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
#include <algorithm>
|
|
||||||
#include <vulkan/vulkan.hpp>
|
#include <vulkan/vulkan.hpp>
|
||||||
#include "Device.hpp"
|
#include "Device.hpp"
|
||||||
#include "Image.hpp"
|
#include "Image.hpp"
|
||||||
#include "FrameBuffer.hpp"
|
#include "FrameBuffer.hpp"
|
||||||
#include "../Base/UI/IWindow.hpp"
|
#include "../Base/UI/IWindow.hpp"
|
||||||
#include "../Base/Logger.hpp"
|
|
||||||
|
|
||||||
namespace openVulkanoCpp
|
namespace openVulkanoCpp
|
||||||
{
|
{
|
||||||
@@ -24,7 +22,6 @@ namespace openVulkanoCpp
|
|||||||
vk::ImageView view;
|
vk::ImageView view;
|
||||||
vk::Fence fence;
|
vk::Fence fence;
|
||||||
|
|
||||||
|
|
||||||
vk::Image GetImage() override
|
vk::Image GetImage() override
|
||||||
{
|
{
|
||||||
return image;
|
return image;
|
||||||
@@ -36,7 +33,7 @@ namespace openVulkanoCpp
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
class SwapChain : public FrameBuffer
|
class SwapChain final : public FrameBuffer
|
||||||
{
|
{
|
||||||
vk::SurfaceKHR surface;
|
vk::SurfaceKHR surface;
|
||||||
std::vector<SwapChainImage> images;
|
std::vector<SwapChainImage> images;
|
||||||
@@ -56,37 +53,13 @@ namespace openVulkanoCpp
|
|||||||
vk::Semaphore imageAvailableSemaphore;
|
vk::Semaphore imageAvailableSemaphore;
|
||||||
|
|
||||||
SwapChain() = default;
|
SwapChain() = default;
|
||||||
~SwapChain() { if (device) SwapChain::Close(); }
|
~SwapChain() override { if (device) SwapChain::Close(); }
|
||||||
|
|
||||||
void Init(Device* device, vk::SurfaceKHR surface, IVulkanWindow* window)
|
void Init(Device* device, vk::SurfaceKHR surface, IVulkanWindow* window);
|
||||||
{
|
|
||||||
if (!device) throw std::runtime_error("The device must not be null");
|
|
||||||
if (!window) throw std::runtime_error("The window must not be null");
|
|
||||||
this->device = device;
|
|
||||||
this->surface = surface;
|
|
||||||
this->window = window;
|
|
||||||
|
|
||||||
imageAvailableSemaphore = device->device.createSemaphore({});
|
void Close() override;
|
||||||
CreateSwapChain({window->GetWidth(), window->GetHeight() });
|
|
||||||
|
|
||||||
FrameBuffer::Init(device, vk::Extent3D(size, 1));
|
void Resize(uint32_t newWidth, uint32_t newHeight);
|
||||||
}
|
|
||||||
|
|
||||||
void Close() override
|
|
||||||
{
|
|
||||||
DestroySwapChain();
|
|
||||||
device->device.destroySemaphore(imageAvailableSemaphore);
|
|
||||||
device = nullptr;
|
|
||||||
FrameBuffer::Close();
|
|
||||||
}
|
|
||||||
|
|
||||||
void Resize(const uint32_t newWidth, const uint32_t newHeight)
|
|
||||||
{
|
|
||||||
if(newWidth == 0 || newHeight == 0) return; // Swap chain size of 0 pixel is not allowed
|
|
||||||
|
|
||||||
CreateSwapChain({ newWidth, newHeight });
|
|
||||||
FrameBuffer::Resize(vk::Extent3D(size, 1));
|
|
||||||
}
|
|
||||||
|
|
||||||
[[nodiscard]] vk::Extent2D GetSize() const
|
[[nodiscard]] vk::Extent2D GetSize() const
|
||||||
{
|
{
|
||||||
@@ -103,19 +76,7 @@ namespace openVulkanoCpp
|
|||||||
return fullscreenScissor;
|
return fullscreenScissor;
|
||||||
}
|
}
|
||||||
|
|
||||||
uint32_t AcquireNextImage(const vk::Fence fence = vk::Fence())
|
uint32_t AcquireNextImage(const vk::Fence& fence = vk::Fence());
|
||||||
{
|
|
||||||
const auto resultValue = device->device.acquireNextImageKHR(swapChain, UINT64_MAX, imageAvailableSemaphore, fence);
|
|
||||||
const vk::Result result = resultValue.result;
|
|
||||||
if (result != vk::Result::eSuccess && result != vk::Result::eSuboptimalKHR) throw std::error_code(result);
|
|
||||||
SetCurrentFrameId(resultValue.value);
|
|
||||||
|
|
||||||
vk::Fence submitFence = GetCurrentSubmitFence();
|
|
||||||
device->device.waitForFences(1, &submitFence, true, -1);
|
|
||||||
device->device.resetFences(1, &submitFence);
|
|
||||||
|
|
||||||
return currentFrameBufferId;
|
|
||||||
}
|
|
||||||
|
|
||||||
vk::Fence& GetCurrentSubmitFence()
|
vk::Fence& GetCurrentSubmitFence()
|
||||||
{
|
{
|
||||||
@@ -128,7 +89,7 @@ namespace openVulkanoCpp
|
|||||||
1, &swapChain, ¤tFrameBufferId));
|
1, &swapChain, ¤tFrameBufferId));
|
||||||
}
|
}
|
||||||
|
|
||||||
bool UseVsync() const { return useVsync; }
|
[[nodiscard]] bool UseVsync() const { return useVsync; }
|
||||||
|
|
||||||
void SetVsync(bool useVsync)
|
void SetVsync(bool useVsync)
|
||||||
{ //TODO change swap chain
|
{ //TODO change swap chain
|
||||||
@@ -141,75 +102,11 @@ namespace openVulkanoCpp
|
|||||||
}
|
}
|
||||||
|
|
||||||
private:
|
private:
|
||||||
void CreateSwapChain(vk::Extent2D size)
|
void CreateSwapChain(vk::Extent2D size);
|
||||||
{
|
|
||||||
Logger::RENDER->debug("Creating swap chain for window {0} ...", window->GetWindowId());
|
|
||||||
surfaceFormat = ChoseSurfaceFormat();
|
|
||||||
presentMode = ChosePresentMode();
|
|
||||||
const vk::SurfaceCapabilitiesKHR surfaceCapabilities = device->physicalDevice.getSurfaceCapabilitiesKHR(surface);
|
|
||||||
if(surfaceCapabilities.currentExtent.width != ~static_cast<uint32_t>(0))
|
|
||||||
{ // The surface does provide it's size to the vulkan driver
|
|
||||||
size = surfaceCapabilities.currentExtent;
|
|
||||||
}
|
|
||||||
|
|
||||||
vk::SurfaceTransformFlagBitsKHR preTransform; //TODO add option to allow rotation and other modifications
|
void CreateSwapChainImages();
|
||||||
if (surfaceCapabilities.supportedTransforms & vk::SurfaceTransformFlagBitsKHR::eIdentity)
|
|
||||||
{ preTransform = vk::SurfaceTransformFlagBitsKHR::eIdentity; }
|
|
||||||
else { preTransform = surfaceCapabilities.currentTransform; }
|
|
||||||
|
|
||||||
uint32_t usingImages = std::max(preferredImageCount, surfaceCapabilities.minImageCount);
|
void DestroySwapChain() const;
|
||||||
if (surfaceCapabilities.maxImageCount > 0) //GPU has limit of swap chain images
|
|
||||||
usingImages = std::min(usingImages, surfaceCapabilities.maxImageCount);
|
|
||||||
Logger::RENDER->debug("GPU supports {0} to {1} swap chain images. Preferred: {2}, Using: {3}", surfaceCapabilities.minImageCount, surfaceCapabilities.maxImageCount, preferredImageCount, usingImages);
|
|
||||||
|
|
||||||
const vk::SwapchainCreateInfoKHR createInfo({}, surface, usingImages, surfaceFormat.format,
|
|
||||||
surfaceFormat.colorSpace, size, 1,
|
|
||||||
vk::ImageUsageFlagBits::eColorAttachment | vk::ImageUsageFlagBits::eTransferDst,
|
|
||||||
vk::SharingMode::eExclusive, 0, nullptr, preTransform,
|
|
||||||
vk::CompositeAlphaFlagBitsKHR::eOpaque, presentMode, VK_TRUE, swapChain);
|
|
||||||
const vk::SwapchainKHR newSwapChain = device->device.createSwapchainKHR(createInfo);
|
|
||||||
|
|
||||||
DestroySwapChain();
|
|
||||||
swapChain = newSwapChain;
|
|
||||||
this->size = size;
|
|
||||||
|
|
||||||
CreateSwapChainImages();
|
|
||||||
|
|
||||||
fullscreenViewport = vk::Viewport{ 0, 0, (float)size.width, (float)size.height, 0, 1 };
|
|
||||||
fullscreenScissor = vk::Rect2D{ {0,0}, size };
|
|
||||||
Logger::RENDER->debug("Swap chain for window {0} created", window->GetWindowId());
|
|
||||||
}
|
|
||||||
|
|
||||||
void CreateSwapChainImages()
|
|
||||||
{
|
|
||||||
vk::ImageViewCreateInfo imgViewCreateInfo;
|
|
||||||
imgViewCreateInfo.format = surfaceFormat.format;
|
|
||||||
imgViewCreateInfo.subresourceRange.aspectMask = vk::ImageAspectFlagBits::eColor;
|
|
||||||
imgViewCreateInfo.subresourceRange.levelCount = 1;
|
|
||||||
imgViewCreateInfo.subresourceRange.layerCount = 1;
|
|
||||||
imgViewCreateInfo.viewType = vk::ImageViewType::e2D;
|
|
||||||
|
|
||||||
auto swapChainImages = device->device.getSwapchainImagesKHR(swapChain);
|
|
||||||
|
|
||||||
images.resize(swapChainImages.size());
|
|
||||||
for (uint32_t i = 0; i < swapChainImages.size(); i++)
|
|
||||||
{
|
|
||||||
images[i].image = swapChainImages[i];
|
|
||||||
imgViewCreateInfo.image = swapChainImages[i];
|
|
||||||
images[i].view = device->device.createImageView(imgViewCreateInfo);
|
|
||||||
images[i].fence = device->device.createFence({ vk::FenceCreateFlags(vk::FenceCreateFlagBits::eSignaled)});
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void DestroySwapChain() const
|
|
||||||
{
|
|
||||||
for(auto& image : images)
|
|
||||||
{
|
|
||||||
device->device.destroyImageView(image.view);
|
|
||||||
device->device.destroyFence(image.fence);
|
|
||||||
}
|
|
||||||
device->device.destroySwapchainKHR(swapChain);
|
|
||||||
}
|
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
vk::Format FindColorFormat() override
|
vk::Format FindColorFormat() override
|
||||||
@@ -217,56 +114,13 @@ namespace openVulkanoCpp
|
|||||||
return surfaceFormat.format;
|
return surfaceFormat.format;
|
||||||
}
|
}
|
||||||
|
|
||||||
virtual vk::PresentModeKHR ChosePresentMode()
|
virtual vk::PresentModeKHR ChosePresentMode();
|
||||||
{
|
|
||||||
std::vector<vk::PresentModeKHR> presentModes = device->physicalDevice.getSurfacePresentModesKHR(surface);
|
|
||||||
#ifdef DEBUG
|
|
||||||
std::string availableModes = "";
|
|
||||||
for (const auto& presentMode : presentModes)
|
|
||||||
{
|
|
||||||
if (availableModes.length() > 0) availableModes += ", ";
|
|
||||||
availableModes += vk::to_string(presentMode);
|
|
||||||
}
|
|
||||||
Logger::RENDER->debug("Available swap chain present modes {0}. Searching best mode for: vsync={1}", availableModes, useVsync);
|
|
||||||
#endif
|
|
||||||
vk::PresentModeKHR mode = vk::PresentModeKHR::eFifo;
|
|
||||||
if (useVsync)
|
|
||||||
{
|
|
||||||
if (Utils::Contains(presentModes, vk::PresentModeKHR::eMailbox)) mode = vk::PresentModeKHR::eMailbox;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
if (Utils::Contains(presentModes, vk::PresentModeKHR::eImmediate)) mode = vk::PresentModeKHR::eImmediate;
|
|
||||||
else if (Utils::Contains(presentModes, vk::PresentModeKHR::eFifoRelaxed)) mode = vk::PresentModeKHR::eFifoRelaxed;
|
|
||||||
}
|
|
||||||
Logger::RENDER->debug("Using swap chain present mode {0}", vk::to_string(mode));
|
|
||||||
return mode;
|
|
||||||
}
|
|
||||||
|
|
||||||
virtual vk::SurfaceFormatKHR ChoseSurfaceFormat()
|
virtual vk::SurfaceFormatKHR ChoseSurfaceFormat();
|
||||||
{ //TODO allow to chose output format
|
|
||||||
std::vector<vk::SurfaceFormatKHR> surfaceFormats = device->physicalDevice.getSurfaceFormatsKHR(surface);
|
|
||||||
if(surfaceFormats.size() == 1 && surfaceFormats[0].format == vk::Format::eUndefined)
|
|
||||||
{ // GPU does not have a preferred surface format
|
|
||||||
return vk::SurfaceFormatKHR{ vk::Format::eB8G8R8A8Unorm, surfaceFormats[0].colorSpace };
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{ //TODO chose best fitting
|
|
||||||
return surfaceFormats[0];
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
public:
|
public:
|
||||||
std::vector<IImage*> GetImages() override
|
std::vector<IImage*> GetImages() override;
|
||||||
{
|
|
||||||
std::vector<IImage*> imgs;
|
|
||||||
for (auto& image : images)
|
|
||||||
{
|
|
||||||
imgs.push_back(&image);
|
|
||||||
}
|
|
||||||
return imgs;
|
|
||||||
}
|
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user