diff --git a/openVulkanoCpp/Vulkan/Context.cpp b/openVulkanoCpp/Vulkan/Context.cpp new file mode 100644 index 0000000..53f2ab4 --- /dev/null +++ b/openVulkanoCpp/Vulkan/Context.cpp @@ -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 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());; + } +} \ No newline at end of file diff --git a/openVulkanoCpp/Vulkan/Context.hpp b/openVulkanoCpp/Vulkan/Context.hpp index ec125ab..8569f1b 100644 --- a/openVulkanoCpp/Vulkan/Context.hpp +++ b/openVulkanoCpp/Vulkan/Context.hpp @@ -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 + #include -#include "../Base/IGraphicsApp.hpp" -#include "../Base/IGraphicsAppManager.hpp" -#include "../Base/EngineConstants.hpp" -#include "../Base/Utils.hpp" -#include "Debuging/ValidationLayer.hpp" #include "DeviceManager.hpp" #include "SwapChain.hpp" #include "RenderPass.hpp" @@ -12,8 +14,13 @@ namespace openVulkanoCpp { + class IVulkanWindow; + class IGraphicsAppManager; + namespace Vulkan { + class Device; + class Context final : virtual public ICloseable { bool enableValidationLayer, initialized; @@ -44,77 +51,20 @@ namespace openVulkanoCpp if (initialized) Close(); } - void Init(IGraphicsAppManager* graphicsAppManager, IVulkanWindow* window) - { - if (initialized) throw std::runtime_error("The context is already initialized"); - this->graphicsAppManager = graphicsAppManager; - this->window = window; + void Init(IGraphicsAppManager* graphicsAppManager, IVulkanWindow* window); - // Get the extensions required to display on the window - for (const auto& requiredExtension : window->GetRequiredInstanceExtensions()) { RequireExtension(requiredExtension.c_str()); } + void Close() override; - 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 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 Resize(uint32_t newWidth, uint32_t newHeight); void RequireExtension(const char* extension) { requiredExtensions.emplace(extension); } private: - 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 extensions = Utils::toCString(requiredExtensions), layers = Debug::GetValidationLayers(); + void CreateInstance(); - 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 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());; - } + void CreateDevice(); }; } } diff --git a/openVulkanoCpp/Vulkan/SwapChain.cpp b/openVulkanoCpp/Vulkan/SwapChain.cpp new file mode 100644 index 0000000..41caa15 --- /dev/null +++ b/openVulkanoCpp/Vulkan/SwapChain.cpp @@ -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 + +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(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 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 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 SwapChain::GetImages() + { + std::vector imgs; + for (auto& image : images) + { + imgs.push_back(&image); + } + return imgs; + } +} \ No newline at end of file diff --git a/openVulkanoCpp/Vulkan/SwapChain.hpp b/openVulkanoCpp/Vulkan/SwapChain.hpp index ef5676c..c7d3f29 100644 --- a/openVulkanoCpp/Vulkan/SwapChain.hpp +++ b/openVulkanoCpp/Vulkan/SwapChain.hpp @@ -6,13 +6,11 @@ #pragma once -#include #include #include "Device.hpp" #include "Image.hpp" #include "FrameBuffer.hpp" #include "../Base/UI/IWindow.hpp" -#include "../Base/Logger.hpp" namespace openVulkanoCpp { @@ -24,7 +22,6 @@ namespace openVulkanoCpp vk::ImageView view; vk::Fence fence; - vk::Image GetImage() override { return image; @@ -36,7 +33,7 @@ namespace openVulkanoCpp } }; - class SwapChain : public FrameBuffer + class SwapChain final : public FrameBuffer { vk::SurfaceKHR surface; std::vector images; @@ -56,37 +53,13 @@ namespace openVulkanoCpp vk::Semaphore imageAvailableSemaphore; SwapChain() = default; - ~SwapChain() { if (device) SwapChain::Close(); } + ~SwapChain() override { if (device) SwapChain::Close(); } - 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; + void Init(Device* device, vk::SurfaceKHR surface, IVulkanWindow* window); - imageAvailableSemaphore = device->device.createSemaphore({}); - CreateSwapChain({window->GetWidth(), window->GetHeight() }); + void Close() override; - FrameBuffer::Init(device, vk::Extent3D(size, 1)); - } - - 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)); - } + void Resize(uint32_t newWidth, uint32_t newHeight); [[nodiscard]] vk::Extent2D GetSize() const { @@ -103,19 +76,7 @@ namespace openVulkanoCpp return fullscreenScissor; } - 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; - } + uint32_t AcquireNextImage(const vk::Fence& fence = vk::Fence()); vk::Fence& GetCurrentSubmitFence() { @@ -128,7 +89,7 @@ namespace openVulkanoCpp 1, &swapChain, ¤tFrameBufferId)); } - bool UseVsync() const { return useVsync; } + [[nodiscard]] bool UseVsync() const { return useVsync; } void SetVsync(bool useVsync) { //TODO change swap chain @@ -141,75 +102,11 @@ namespace openVulkanoCpp } private: - 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(0)) - { // The surface does provide it's size to the vulkan driver - size = surfaceCapabilities.currentExtent; - } + void CreateSwapChain(vk::Extent2D size); - 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; } + void CreateSwapChainImages(); - 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 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); - } + void DestroySwapChain() const; protected: vk::Format FindColorFormat() override @@ -217,56 +114,13 @@ namespace openVulkanoCpp return surfaceFormat.format; } - virtual vk::PresentModeKHR ChosePresentMode() - { - std::vector 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::PresentModeKHR ChosePresentMode(); - virtual vk::SurfaceFormatKHR ChoseSurfaceFormat() - { //TODO allow to chose output format - std::vector 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]; - } - } + virtual vk::SurfaceFormatKHR ChoseSurfaceFormat(); public: - std::vector GetImages() override - { - std::vector imgs; - for (auto& image : images) - { - imgs.push_back(&image); - } - return imgs; - } + std::vector GetImages() override; }; } }