diff --git a/openVulkanoCpp/Base/EngineConfiguration.hpp b/openVulkanoCpp/Base/EngineConfiguration.hpp index bb26429..23df0e4 100644 --- a/openVulkanoCpp/Base/EngineConfiguration.hpp +++ b/openVulkanoCpp/Base/EngineConfiguration.hpp @@ -1,5 +1,5 @@ #pragma once -#include +#include #include namespace openVulkanoCpp diff --git a/openVulkanoCpp/Base/EngineConstants.hpp b/openVulkanoCpp/Base/EngineConstants.hpp index 0fd6c6e..4b4ecec 100644 --- a/openVulkanoCpp/Base/EngineConstants.hpp +++ b/openVulkanoCpp/Base/EngineConstants.hpp @@ -4,9 +4,7 @@ namespace openVulkanoCpp { -#define MAKE_VERSION(major, minor, patch) (((major) << 22) | ((minor) << 12) | (patch)) - - const char* ENGINE_NAME = "openVulkanoCpp"; + inline const char* ENGINE_NAME = "openVulkanoCpp"; struct EngineVersion { @@ -17,15 +15,15 @@ namespace openVulkanoCpp EngineVersion(int major, int minor, int patch, int build = 0) : major(major), minor(minor), patch(patch) { intVersion = ((major) << 24) | ((minor) << 16) | (patch); - std::string buildConfig = ""; + std::string_view buildConfig; #ifdef _DEBUG - buildConfig += "-MSVC_DEBUG"; + buildConfig = "MSVC_DEBUG"; #elif DEBUG - buildConfig += "-DEBUG"; + buildConfig = "DEBUG"; #endif stringVersion = fmt::format("v{0}.{1}.{2}.{3}{4}", major, minor, patch, build, buildConfig); } }; - const EngineVersion ENGINE_VERSION(0, 0, 1); + inline const EngineVersion ENGINE_VERSION(0, 0, 1); } diff --git a/openVulkanoCpp/Base/Utils.hpp b/openVulkanoCpp/Base/Utils.hpp index 4f89534..ccaa307 100644 --- a/openVulkanoCpp/Base/Utils.hpp +++ b/openVulkanoCpp/Base/Utils.hpp @@ -1,8 +1,16 @@ +/* + * 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 #include #include +#include namespace openVulkanoCpp { diff --git a/openVulkanoCpp/Scene/Vertex.hpp b/openVulkanoCpp/Scene/Vertex.hpp index 1c7c038..e22fd90 100644 --- a/openVulkanoCpp/Scene/Vertex.hpp +++ b/openVulkanoCpp/Scene/Vertex.hpp @@ -2,6 +2,7 @@ #include #include #include +#include namespace openVulkanoCpp { diff --git a/openVulkanoCpp/Vulkan/Context.hpp b/openVulkanoCpp/Vulkan/Context.hpp index 1621be2..ec125ab 100644 --- a/openVulkanoCpp/Vulkan/Context.hpp +++ b/openVulkanoCpp/Vulkan/Context.hpp @@ -14,7 +14,7 @@ namespace openVulkanoCpp { namespace Vulkan { - class Context : virtual public ICloseable + class Context final : virtual public ICloseable { bool enableValidationLayer, initialized; std::set requiredExtensions; @@ -38,7 +38,8 @@ namespace openVulkanoCpp enableValidationLayer = false; #endif } - virtual ~Context() + + ~Context() override { if (initialized) Close(); } diff --git a/openVulkanoCpp/Vulkan/Debuging/ValidationLayer.cpp b/openVulkanoCpp/Vulkan/Debuging/ValidationLayer.cpp new file mode 100644 index 0000000..90343dd --- /dev/null +++ b/openVulkanoCpp/Vulkan/Debuging/ValidationLayer.cpp @@ -0,0 +1,94 @@ +/* + * 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 "ValidationLayer.hpp" +#include "../../Base/Logger.hpp" +#include + +#define RENDER_DOC + +namespace openVulkanoCpp::Vulkan +{ + const std::initializer_list activeValidationLayerNames = { + "VK_LAYER_LUNARG_assistant_layer", + "VK_LAYER_LUNARG_standard_validation", + //"VK_EXT_debug_marker", +#ifdef RENDER_DOC + "VK_LAYER_RENDERDOC_Capture", // RenderDoc must be open for this layer to work! +#endif + }; + + std::set Debug::GetAvailableValidationLayers() + { + static std::set availableLayers; + if (availableLayers.empty()) + { + auto layers = vk::enumerateInstanceLayerProperties(); + for (const auto& layer: layers) + { + availableLayers.insert(layer.layerName); + } + Logger::RENDER->debug("Available Vulkan Validation Layers: {0}", fmt::join(availableLayers, ", ")); + } + return availableLayers; + } + + std::vector Debug::GetValidationLayers() + { + std::set availableLayers = GetAvailableValidationLayers(); + std::vector layers; + for (const auto& name : activeValidationLayerNames) + { + if (availableLayers.count(name) != 0) + { + layers.push_back(name.c_str()); + } + } + Logger::RENDER->debug("Active Vulkan Validation Layers: {0}", fmt::join(layers, ", ")); + return layers; + } + + VkBool32 ValidationLayerCallback(VkDebugReportFlagsEXT flags, VkDebugReportObjectTypeEXT objType, + uint64_t srcObject, size_t location, int32_t msgCode, const char* layerPrefix, + const char* msg, void* pUserData) + { + std::string prefix = "VK_DEBUG:"; + spdlog::level::level_enum level = spdlog::level::info; + if (flags & VK_DEBUG_REPORT_ERROR_BIT_EXT) level = spdlog::level::err; + else if (flags & VK_DEBUG_REPORT_WARNING_BIT_EXT) level = spdlog::level::warn; + else if (flags & VK_DEBUG_REPORT_PERFORMANCE_WARNING_BIT_EXT) + { + level = spdlog::level::warn; + prefix = "[PERF] " + prefix; + } + else if (flags & VK_DEBUG_REPORT_DEBUG_BIT_EXT) level = spdlog::level::debug; + + Logger::RENDER->log(level, "{0} [{1}] Code {2}: {3}", prefix, layerPrefix, msgCode, msg); + + return false; + } + + static std::once_flag dispatcherInitFlag; + vk::DispatchLoaderDynamic dispatcher; + vk::DebugReportCallbackEXT msgCallback; + + void Debug::SetupValidationLayers(const vk::Instance& instance, const vk::DebugReportFlagsEXT& flags) + { + Logger::RENDER->info("Setting up Vulkan Validation Layer"); + std::call_once(dispatcherInitFlag, [&] { dispatcher.init(instance, &vkGetInstanceProcAddr); }); + vk::DebugReportCallbackCreateInfoEXT dbgCreateInfo = {}; + dbgCreateInfo.pfnCallback = (PFN_vkDebugReportCallbackEXT)ValidationLayerCallback; + dbgCreateInfo.flags = flags; + msgCallback = instance.createDebugReportCallbackEXT(dbgCreateInfo, nullptr, dispatcher); + Logger::RENDER->info("Vulkan Validation Layer setup"); + } + + void Debug::CloseValidationLayers(const vk::Instance& instance) + { + std::call_once(dispatcherInitFlag, [&] { dispatcher.init(instance, &vkGetInstanceProcAddr); }); + instance.destroyDebugReportCallbackEXT(msgCallback, nullptr, dispatcher); + } +} \ No newline at end of file diff --git a/openVulkanoCpp/Vulkan/Debuging/ValidationLayer.hpp b/openVulkanoCpp/Vulkan/Debuging/ValidationLayer.hpp index 2b66583..97681e0 100644 --- a/openVulkanoCpp/Vulkan/Debuging/ValidationLayer.hpp +++ b/openVulkanoCpp/Vulkan/Debuging/ValidationLayer.hpp @@ -1,98 +1,27 @@ +/* + * 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 +#include +#include #include -#define RENDER_DOC - -namespace openVulkanoCpp +namespace openVulkanoCpp::Vulkan { - namespace Vulkan + class Debug { - namespace Debug - { - std::list activeValidationLayerNames = { - "VK_LAYER_LUNARG_assistant_layer", - "VK_LAYER_LUNARG_standard_validation", - //"VK_EXT_debug_marker", -#ifdef RENDER_DOC - "VK_LAYER_RENDERDOC_Capture", // RenderDoc must be open for this layer to work! -#endif - }; + public: + static std::set GetAvailableValidationLayers(); - static std::set GetAvailableValidationLayers() - { - auto layers = vk::enumerateInstanceLayerProperties(); - std::set layersVector; - std::string layerList = ""; - for(const auto& layer : layers) - { - std::string name = layer.layerName; - layersVector.insert(name); - if (layerList.length() > 0) layerList += ", "; - layerList += name; - } - Logger::RENDER->debug("Available Vulkan Validation Layers: {0}", layerList); - return layersVector; - } + static std::vector GetValidationLayers(); - static std::vector GetValidationLayers() - { - std::set availableLayers = GetAvailableValidationLayers(); - std::vector layers; - std::string layerList = ""; - for (const auto& name : activeValidationLayerNames) - { - if (availableLayers.count(name) != 0) - { - layers.push_back(name.c_str()); - if (layerList.length() > 0) layerList += ", "; - layerList += name; - } - } - Logger::RENDER->debug("Active Vulkan Validation Layers: {0}", layerList); - return layers; - } + static void SetupValidationLayers(const vk::Instance& instance, const vk::DebugReportFlagsEXT& flags); - static std::once_flag dispatcherInitFlag; - vk::DispatchLoaderDynamic dispatcher; - vk::DebugReportCallbackEXT msgCallback; - - inline VkBool32 ValidationLayerCallback(VkDebugReportFlagsEXT flags, VkDebugReportObjectTypeEXT objType, - uint64_t srcObject, size_t location, int32_t msgCode, const char* layerPrefix, - const char* msg, void* pUserData) - { - std::string prefix = "VK_DEBUG:"; - spdlog::level::level_enum level = spdlog::level::info; - if (flags & VK_DEBUG_REPORT_ERROR_BIT_EXT) level = spdlog::level::err; - else if (flags & VK_DEBUG_REPORT_WARNING_BIT_EXT) level = spdlog::level::warn; - else if (flags & VK_DEBUG_REPORT_PERFORMANCE_WARNING_BIT_EXT) - { - level = spdlog::level::warn; - prefix = "[PERF] " + prefix; - } - else if (flags & VK_DEBUG_REPORT_DEBUG_BIT_EXT) level = spdlog::level::debug; - - Logger::RENDER->log(level, "{0} [{1}] Code {2}: {3}", prefix, layerPrefix, msgCode, msg); - - return false; - } - - static void SetupValidationLayers(const vk::Instance& instance, const vk::DebugReportFlagsEXT& flags) - { - Logger::RENDER->info("Setting up Vulkan Validation Layer"); - std::call_once(dispatcherInitFlag, [&] { dispatcher.init(instance, &vkGetInstanceProcAddr); }); - vk::DebugReportCallbackCreateInfoEXT dbgCreateInfo = {}; - dbgCreateInfo.pfnCallback = (PFN_vkDebugReportCallbackEXT)ValidationLayerCallback; - dbgCreateInfo.flags = flags; - msgCallback = instance.createDebugReportCallbackEXT(dbgCreateInfo, nullptr, dispatcher); - Logger::RENDER->info("Vulkan Validation Layer setup"); - } - - static void CloseValidationLayers(const vk::Instance& instance) { - std::call_once(dispatcherInitFlag, [&] { dispatcher.init(instance, &vkGetInstanceProcAddr); }); - instance.destroyDebugReportCallbackEXT(msgCallback, nullptr, dispatcher); - } - }; - } + static void CloseValidationLayers(const vk::Instance& instance); + }; } diff --git a/openVulkanoCpp/Vulkan/Renderer.cpp b/openVulkanoCpp/Vulkan/Renderer.cpp new file mode 100644 index 0000000..f6cbaba --- /dev/null +++ b/openVulkanoCpp/Vulkan/Renderer.cpp @@ -0,0 +1,168 @@ +/* + * 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 "Renderer.hpp" +#include + +namespace openVulkanoCpp::Vulkan +{ + void Renderer::Init(IGraphicsAppManager* graphicsAppManager, IWindow* window) + { + logger = Logger::RENDER; + logger->info("Initializing Vulkan renderer ..."); + IVulkanWindow* vulkanWindow = window->GetVulkanWindow(); + if (!vulkanWindow) + { + logger->error("The provided window is not compatible with Vulkan."); + throw std::runtime_error("The provided window is not compatible with Vulkan."); + } + context.Init(graphicsAppManager, vulkanWindow); + for (int i = 0; i < context.swapChain.GetImageCount(); i++) + { + waitSemaphores.emplace_back(); + waitSemaphores[i].renderComplete.push_back(context.device->device.createSemaphore({})); + waitSemaphores[i].renderReady.resize(2); + } + resourceManager.Init(&context, context.swapChain.GetImageCount()); + threadPool.resize(EngineConfiguration::GetEngineConfiguration()->GetNumThreads() - 1); + + //Setup cmd pools and buffers + commands.resize(threadPool.size() + 2); // One extra cmd object for the primary buffer and one for the main thread + for(uint32_t i = 0; i < commands.size(); i++) + { + commands[i] = std::vector(context.swapChain.GetImageCount()); + for(size_t j = 0; j < commands[i].size(); j++) + { + commands[i][j].Init(context.device->device, context.device->queueIndices.GetGraphics(), + (i == commands.size() - 1) ? vk::CommandBufferLevel::ePrimary : vk::CommandBufferLevel::eSecondary); + } + } + submitBuffers.resize(context.swapChain.GetImageCount()); + for(uint32_t i = 0; i < submitBuffers.size(); i++) + { + submitBuffers[i].resize(commands.size() - 1); + for (size_t j = 0; j < submitBuffers[i].size(); j++) + { + submitBuffers[i][j] = commands[j][i].cmdBuffer; + } + } + + shader = resourceManager.CreateShader(scene->shader); + + logger->info("Vulkan renderer initialized"); + } + + void Renderer::Tick() + { + currentImageId = context.swapChain.AcquireNextImage(); + Render(); + } + + void Renderer::Close() + { + context.Close(); + } + + std::string Renderer::GetMainRenderDeviceName() + { + return (context.device) ? context.device->GetDeviceName() : "Unknown"; + } + + void Renderer::Resize(const uint32_t newWidth, const uint32_t newHeight) + { + context.Resize(newWidth, newHeight); + resourceManager.Resize(); + } + + CommandHelper* Renderer::GetCommandData(uint32_t poolId) + { + return &commands[poolId][currentImageId]; + } + + void Renderer::RunThread(Renderer* renderer, Data::ReadOnlyAtomicArrayQueue* jobQueue, uint32_t id) + { + renderer->RecordSecondaryBuffer(jobQueue, id); + } + + void Renderer::StartThreads(Data::ReadOnlyAtomicArrayQueue* jobQueue) + { + for(uint32_t i = 0; i < threadPool.size(); i++) + { + threadPool[i] = std::thread(RunThread, this, jobQueue, i); + } + } + + void Renderer::RecordPrimaryBuffer() + { + CommandHelper* cmdHelper = GetCommandData(commands.size() - 1); + cmdHelper->Reset(); + cmdHelper->cmdBuffer.begin(vk::CommandBufferBeginInfo(vk::CommandBufferUsageFlagBits::eOneTimeSubmit)); + context.swapChainRenderPass.Begin(cmdHelper->cmdBuffer); + } + + void Renderer::Submit() + { + for (auto& thread : threadPool) { thread.join(); } // Wait till everything is recorded + CommandHelper* cmdHelper = GetCommandData(commands.size() - 1); + cmdHelper->cmdBuffer.executeCommands(submitBuffers[currentImageId].size(), submitBuffers[currentImageId].data()); + context.swapChainRenderPass.End(cmdHelper->cmdBuffer); + cmdHelper->cmdBuffer.end(); + std::array stateFlags = { vk::PipelineStageFlags(vk::PipelineStageFlagBits::eColorAttachmentOutput), vk::PipelineStageFlags(vk::PipelineStageFlagBits::eColorAttachmentOutput) }; + waitSemaphores[currentImageId].renderReady[0] = resourceManager.EndFrame(); + waitSemaphores[currentImageId].renderReady[1] = context.swapChain.imageAvailableSemaphore; + vk::SubmitInfo si = vk::SubmitInfo( + waitSemaphores[currentImageId].renderReady.size(), waitSemaphores[currentImageId].renderReady.data(), stateFlags.data(), + 1, &cmdHelper->cmdBuffer, + waitSemaphores[currentImageId].renderComplete.size(), waitSemaphores[currentImageId].renderComplete.data()); + context.device->graphicsQueue.submit(1, &si, context.swapChain.GetCurrentSubmitFence()); + context.swapChain.Present(context.device->graphicsQueue, waitSemaphores[currentImageId].renderComplete); + } + + void Renderer::Render() + { + resourceManager.StartFrame(currentImageId); + Data::ReadOnlyAtomicArrayQueue jobQueue(scene->shapeList); + StartThreads(&jobQueue); + RecordPrimaryBuffer(); + RecordSecondaryBuffer(&jobQueue, threadPool.size()); + Submit(); + } + + void Renderer::RecordSecondaryBuffer(Data::ReadOnlyAtomicArrayQueue* jobQueue, uint32_t poolId) + { + Scene::Geometry* lastGeo = nullptr; + Scene::Node* lastNode = nullptr; + CommandHelper* cmdHelper = GetCommandData(poolId); + cmdHelper->Reset(); + vk::CommandBufferInheritanceInfo inheritance = { context.swapChainRenderPass.renderPass, 0, context.swapChainRenderPass.GetFrameBuffer()->GetCurrentFrameBuffer() }; + cmdHelper->cmdBuffer.begin(vk::CommandBufferBeginInfo{ vk::CommandBufferUsageFlagBits::eOneTimeSubmit | vk::CommandBufferUsageFlagBits::eRenderPassContinue, &inheritance }); + shader->Record(cmdHelper->cmdBuffer, currentImageId); + cmdHelper->cmdBuffer.pushConstants(context.pipeline.pipelineLayout, vk::ShaderStageFlagBits::eVertex, 0, 64, scene->GetCamera()->GetViewProjectionMatrixPointer()); + Scene::Drawable** drawablePointer; + while((drawablePointer = jobQueue->Pop()) != nullptr) + { + Scene::Drawable* drawable = *drawablePointer; + Scene::Geometry* mesh = drawable->mesh; + if (mesh != lastGeo) + { + if (!mesh->renderGeo) resourceManager.PrepareGeometry(mesh); + dynamic_cast(mesh->renderGeo)->Record(cmdHelper->cmdBuffer, currentImageId); + lastGeo = mesh; + } + for(Scene::Node* node : drawable->nodes) + { + if (node != lastNode) + { + if (!node->renderNode) resourceManager.PrepareNode(node); + dynamic_cast(node->renderNode)->Record(cmdHelper->cmdBuffer, currentImageId); + lastNode = node; + } + cmdHelper->cmdBuffer.drawIndexed(mesh->GetIndexCount(), 1, 0, 0, 0); + } + } + cmdHelper->cmdBuffer.end(); + } +} \ No newline at end of file diff --git a/openVulkanoCpp/Vulkan/Renderer.hpp b/openVulkanoCpp/Vulkan/Renderer.hpp index 8975e50..f219f23 100644 --- a/openVulkanoCpp/Vulkan/Renderer.hpp +++ b/openVulkanoCpp/Vulkan/Renderer.hpp @@ -1,5 +1,11 @@ +/* + * 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/Render/IRenderer.hpp" #include "../Base/UI/IWindow.hpp" #include "../Base/Logger.hpp" @@ -9,198 +15,56 @@ #include "CommandHelper.hpp" #include "../Base/EngineConfiguration.hpp" -namespace openVulkanoCpp +namespace openVulkanoCpp::Vulkan { - namespace Vulkan + struct WaitSemaphores { - struct WaitSemaphores - { - std::vector renderReady, renderComplete; - }; + std::vector renderReady, renderComplete; + }; - class Renderer : public IRenderer - { - Context context; - std::shared_ptr logger; - std::vector waitSemaphores; - Scene::Scene* scene = nullptr; - ResourceManager resourceManager; - uint32_t currentImageId = -1; - std::vector threadPool; - std::vector> commands; - std::vector> submitBuffers; - VulkanShader* shader; + class Renderer final : public IRenderer + { + Context context; + std::shared_ptr logger; + std::vector waitSemaphores; + Scene::Scene* scene = nullptr; + ResourceManager resourceManager; + uint32_t currentImageId = -1; + std::vector threadPool; + std::vector> commands; + std::vector> submitBuffers; + VulkanShader* shader; - public: - Renderer() = default; - virtual ~Renderer() = default; + public: + Renderer() = default; + virtual ~Renderer() = default; - void Init(IGraphicsAppManager* graphicsAppManager, IWindow* window) override - { - logger = Logger::RENDER; - logger->info("Initializing Vulkan renderer ..."); - IVulkanWindow* vulkanWindow = window->GetVulkanWindow(); - if (!vulkanWindow) - { - logger->error("The provided window is not compatible with Vulkan."); - throw std::runtime_error("The provided window is not compatible with Vulkan."); - } - context.Init(graphicsAppManager, vulkanWindow); - for (int i = 0; i < context.swapChain.GetImageCount(); i++) - { - waitSemaphores.emplace_back(); - waitSemaphores[i].renderComplete.push_back(context.device->device.createSemaphore({})); - waitSemaphores[i].renderReady.resize(2); - } - resourceManager.Init(&context, context.swapChain.GetImageCount()); - threadPool.resize(EngineConfiguration::GetEngineConfiguration()->GetNumThreads() - 1); + void Init(IGraphicsAppManager* graphicsAppManager, IWindow* window) override; - //Setup cmd pools and buffers - commands.resize(threadPool.size() + 2); // One extra cmd object for the primary buffer and one for the main thread - for(uint32_t i = 0; i < commands.size(); i++) - { - commands[i] = std::vector(context.swapChain.GetImageCount()); - for(size_t j = 0; j < commands[i].size(); j++) - { - commands[i][j].Init(context.device->device, context.device->queueIndices.GetGraphics(), - (i == commands.size() - 1) ? vk::CommandBufferLevel::ePrimary : vk::CommandBufferLevel::eSecondary); - } - } - submitBuffers.resize(context.swapChain.GetImageCount()); - for(uint32_t i = 0; i < submitBuffers.size(); i++) - { - submitBuffers[i].resize(commands.size() - 1); - for (size_t j = 0; j < submitBuffers[i].size(); j++) - { - submitBuffers[i][j] = commands[j][i].cmdBuffer; - } - } + void Tick() override; - shader = resourceManager.CreateShader(scene->shader); + void Close() override; - logger->info("Vulkan renderer initialized"); - } + std::string GetMainRenderDeviceName() override; - void Tick() override - { - currentImageId = context.swapChain.AcquireNextImage(); - Render(); - } + void Resize(uint32_t newWidth, uint32_t newHeight) override; - void Close() override - { - //context.Close(); - } + void SetScene(Scene::Scene* scene) override { this->scene = scene; } - std::string GetMainRenderDeviceName() override - { - return (context.device) ? context.device->GetDeviceName() : "Unknown"; - } + Scene::Scene* GetScene() override { return scene; } - void Resize(const uint32_t newWidth, const uint32_t newHeight) override - { - context.Resize(newWidth, newHeight); - resourceManager.Resize(); - } + CommandHelper* GetCommandData(uint32_t poolId); - void SetScene(Scene::Scene* scene) override - { - this->scene = scene; - } + static void RunThread(Renderer* renderer, Data::ReadOnlyAtomicArrayQueue* jobQueue, uint32_t id); - Scene::Scene* GetScene() override - { - return scene; - } + void StartThreads(Data::ReadOnlyAtomicArrayQueue* jobQueue); - CommandHelper* GetCommandData(uint32_t poolId) - { - return &commands[poolId][currentImageId]; - } + void RecordPrimaryBuffer(); - static void RunThread(Renderer* renderer, Data::ReadOnlyAtomicArrayQueue* jobQueue, uint32_t id) - { - renderer->RecordSecondaryBuffer(jobQueue, id); - } + void Submit(); - void StartThreads(Data::ReadOnlyAtomicArrayQueue* jobQueue) - { - for(uint32_t i = 0; i < threadPool.size(); i++) - { - threadPool[i] = std::thread(RunThread, this, jobQueue, i); - } - } + void Render(); - void RecordPrimaryBuffer() - { - CommandHelper* cmdHelper = GetCommandData(commands.size() - 1); - cmdHelper->Reset(); - cmdHelper->cmdBuffer.begin(vk::CommandBufferBeginInfo(vk::CommandBufferUsageFlagBits::eOneTimeSubmit)); - context.swapChainRenderPass.Begin(cmdHelper->cmdBuffer); - } - - void Submit() - { - for (auto& thread : threadPool) { thread.join(); } // Wait till everything is recorded - CommandHelper* cmdHelper = GetCommandData(commands.size() - 1); - cmdHelper->cmdBuffer.executeCommands(submitBuffers[currentImageId].size(), submitBuffers[currentImageId].data()); - context.swapChainRenderPass.End(cmdHelper->cmdBuffer); - cmdHelper->cmdBuffer.end(); - std::array stateFlags = { vk::PipelineStageFlags(vk::PipelineStageFlagBits::eColorAttachmentOutput), vk::PipelineStageFlags(vk::PipelineStageFlagBits::eColorAttachmentOutput) }; - waitSemaphores[currentImageId].renderReady[0] = resourceManager.EndFrame(); - waitSemaphores[currentImageId].renderReady[1] = context.swapChain.imageAvailableSemaphore; - vk::SubmitInfo si = vk::SubmitInfo( - waitSemaphores[currentImageId].renderReady.size(), waitSemaphores[currentImageId].renderReady.data(), stateFlags.data(), - 1, &cmdHelper->cmdBuffer, - waitSemaphores[currentImageId].renderComplete.size(), waitSemaphores[currentImageId].renderComplete.data()); - context.device->graphicsQueue.submit(1, &si, context.swapChain.GetCurrentSubmitFence()); - context.swapChain.Present(context.device->graphicsQueue, waitSemaphores[currentImageId].renderComplete); - } - - void Render() - { - resourceManager.StartFrame(currentImageId); - Data::ReadOnlyAtomicArrayQueue jobQueue(scene->shapeList); - StartThreads(&jobQueue); - RecordPrimaryBuffer(); - RecordSecondaryBuffer(&jobQueue, threadPool.size()); - Submit(); - } - - void RecordSecondaryBuffer(Data::ReadOnlyAtomicArrayQueue* jobQueue, uint32_t poolId) - { - Scene::Geometry* lastGeo = nullptr; - Scene::Node* lastNode = nullptr; - CommandHelper* cmdHelper = GetCommandData(poolId); - cmdHelper->Reset(); - vk::CommandBufferInheritanceInfo inheritance = { context.swapChainRenderPass.renderPass, 0, context.swapChainRenderPass.GetFrameBuffer()->GetCurrentFrameBuffer() }; - cmdHelper->cmdBuffer.begin(vk::CommandBufferBeginInfo{ vk::CommandBufferUsageFlagBits::eOneTimeSubmit | vk::CommandBufferUsageFlagBits::eRenderPassContinue, &inheritance }); - shader->Record(cmdHelper->cmdBuffer, currentImageId); - cmdHelper->cmdBuffer.pushConstants(context.pipeline.pipelineLayout, vk::ShaderStageFlagBits::eVertex, 0, 64, scene->GetCamera()->GetViewProjectionMatrixPointer()); - Scene::Drawable** drawablePointer; - while((drawablePointer = jobQueue->Pop()) != nullptr) - { - Scene::Drawable* drawable = *drawablePointer; - Scene::Geometry* mesh = drawable->mesh; - if (mesh != lastGeo) - { - if (!mesh->renderGeo) resourceManager.PrepareGeometry(mesh); - dynamic_cast(mesh->renderGeo)->Record(cmdHelper->cmdBuffer, currentImageId); - lastGeo = mesh; - } - for(Scene::Node* node : drawable->nodes) - { - if (node != lastNode) - { - if (!node->renderNode) resourceManager.PrepareNode(node); - dynamic_cast(node->renderNode)->Record(cmdHelper->cmdBuffer, currentImageId); - lastNode = node; - } - cmdHelper->cmdBuffer.drawIndexed(mesh->GetIndexCount(), 1, 0, 0, 0); - } - } - cmdHelper->cmdBuffer.end(); - } - }; - } + void RecordSecondaryBuffer(Data::ReadOnlyAtomicArrayQueue* jobQueue, uint32_t poolId); + }; } diff --git a/openVulkanoCpp/Vulkan/Scene/VulkanShader.cpp b/openVulkanoCpp/Vulkan/Scene/VulkanShader.cpp new file mode 100644 index 0000000..99fe1b2 --- /dev/null +++ b/openVulkanoCpp/Vulkan/Scene/VulkanShader.cpp @@ -0,0 +1,88 @@ +/* + * 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 "VulkanShader.hpp" +#include "../Context.hpp" +#include "../Device.hpp" +#include "../../Scene/Vertex.hpp" + +namespace openVulkanoCpp::Vulkan +{ + namespace + { + constexpr vk::PrimitiveTopology ToVkTopology(Scene::Topology topology) + { + switch (topology) + { + case Scene::Topology::PointList: return vk::PrimitiveTopology::ePointList; + case Scene::Topology::LineList: return vk::PrimitiveTopology::eLineList; + case Scene::Topology::LineStripe: return vk::PrimitiveTopology::eLineStrip; + case Scene::Topology::TriangleList: return vk::PrimitiveTopology::eTriangleList; + case Scene::Topology::TriangleStripe: return vk::PrimitiveTopology::eTriangleStrip; + default: throw std::runtime_error("Unknown topology!"); + } + } + } + + void VulkanShader::Init(Context* context, Scene::Shader* shader, IShaderOwner* owner) + { + this->device = context->device->device; + this->shader = shader; + this->owner = owner; + shaderModuleVertex = context->device->CreateShaderModule(shader->vertexShaderName + ".vert.spv"); + shaderModuleFragment = context->device->CreateShaderModule(shader->fragmentShaderName + ".frag.spv"); + std::vector shaderStageCreateInfos(2); + shaderStageCreateInfos[0] = { {}, vk::ShaderStageFlagBits::eVertex, shaderModuleVertex, "main" }; + shaderStageCreateInfos[1] = { {}, vk::ShaderStageFlagBits::eFragment, shaderModuleFragment, "main" }; + + auto vertexBindDesc = vk::VertexInputBindingDescription(0, sizeof(Vertex), vk::VertexInputRate::eVertex); + std::vector attributeDescriptions; + attributeDescriptions.emplace_back(0, 0, vk::Format::eR32G32B32Sfloat, offsetof(Vertex, position)); + attributeDescriptions.emplace_back(1, 0, vk::Format::eR32G32B32Sfloat, offsetof(Vertex, normal)); + attributeDescriptions.emplace_back(2, 0, vk::Format::eR32G32B32Sfloat, offsetof(Vertex, tangent)); + attributeDescriptions.emplace_back(3, 0, vk::Format::eR32G32B32Sfloat, offsetof(Vertex, biTangent)); + attributeDescriptions.emplace_back(4, 0, vk::Format::eR32G32B32Sfloat, offsetof(Vertex, textureCoordinates)); + attributeDescriptions.emplace_back(5, 0, vk::Format::eR32G32B32A32Sfloat, offsetof(Vertex, color)); + + auto viewport = context->swapChain.GetFullscreenViewport(); + auto scissor = context->swapChain.GetFullscreenScissor(); + vk::PipelineViewportStateCreateInfo viewportStateCreateInfo = { {}, 1, &viewport, 1, &scissor }; + vk::PipelineVertexInputStateCreateInfo pipelineVertexInputStateCreateInfo = { {}, 1, &vertexBindDesc, + static_cast(attributeDescriptions.size()), attributeDescriptions.data() }; + vk::PipelineInputAssemblyStateCreateInfo inputAssembly = { {}, ToVkTopology(shader->topology), 0 }; + vk::PipelineRasterizationStateCreateInfo rasterizer = {}; + rasterizer.cullMode = vk::CullModeFlagBits::eBack; + vk::PipelineMultisampleStateCreateInfo msaa = {}; + vk::PipelineDepthStencilStateCreateInfo depth = { {}, 1, 1, vk::CompareOp::eLess }; + depth.maxDepthBounds = 1; + vk::PipelineColorBlendAttachmentState colorBlendAttachment = {}; + colorBlendAttachment.colorWriteMask = vk::ColorComponentFlagBits::eA | vk::ColorComponentFlagBits::eB | vk::ColorComponentFlagBits::eG | vk::ColorComponentFlagBits::eR; + vk::PipelineColorBlendStateCreateInfo colorInfo = {}; + colorInfo.attachmentCount = 1; + colorInfo.pAttachments = &colorBlendAttachment; + + + + vk::GraphicsPipelineCreateInfo pipelineCreateInfo = { {}, static_cast(shaderStageCreateInfos.size()), shaderStageCreateInfos.data(), &pipelineVertexInputStateCreateInfo, &inputAssembly, + nullptr, &viewportStateCreateInfo, &rasterizer, &msaa, &depth, &colorInfo, nullptr, context->pipeline.pipelineLayout, context->swapChainRenderPass.renderPass }; + pipeline = this->device.createGraphicsPipeline({}, pipelineCreateInfo).value; + + } + + void VulkanShader::Record(vk::CommandBuffer& cmdBuffer, uint32_t bufferId) + { + cmdBuffer.bindPipeline(vk::PipelineBindPoint::eGraphics, pipeline); + } + + void VulkanShader::Close() + { + owner->RemoveShader(this); + shader = nullptr; + device.destroyPipeline(pipeline); + device.destroyShaderModule(shaderModuleVertex); + device.destroyShaderModule(shaderModuleFragment); + } +} \ No newline at end of file diff --git a/openVulkanoCpp/Vulkan/Scene/VulkanShader.hpp b/openVulkanoCpp/Vulkan/Scene/VulkanShader.hpp index e6c0f36..c67372e 100644 --- a/openVulkanoCpp/Vulkan/Scene/VulkanShader.hpp +++ b/openVulkanoCpp/Vulkan/Scene/VulkanShader.hpp @@ -1,98 +1,37 @@ +/* + * 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 "../Device.hpp" #include "../../Scene/Shader.hpp" -#include "../../Scene/Vertex.hpp" #include "../../Base/ICloseable.hpp" #include "../Resources/IShaderOwner.hpp" #include "IRecordable.hpp" -namespace openVulkanoCpp +namespace openVulkanoCpp::Vulkan { - namespace Vulkan + class Context; + + struct VulkanShader final : virtual public ICloseable, virtual public IRecordable { - vk::PrimitiveTopology ToVkTopology(Scene::Topology topology) - { - switch (topology) { - case Scene::Topology::PointList: return vk::PrimitiveTopology::ePointList; - case Scene::Topology::LineList: return vk::PrimitiveTopology::eLineList; - case Scene::Topology::LineStripe: return vk::PrimitiveTopology::eLineStrip; - case Scene::Topology::TriangleList: return vk::PrimitiveTopology::eTriangleList; - case Scene::Topology::TriangleStripe: return vk::PrimitiveTopology::eTriangleStrip; - default: throw std::runtime_error("Unknown topology!"); - } - } - - struct VulkanShader : virtual public ICloseable, virtual public IRecordable - { - Scene::Shader* shader = nullptr; - vk::Device device; - vk::ShaderModule shaderModuleVertex, shaderModuleFragment; - vk::Pipeline pipeline; - IShaderOwner* owner; + Scene::Shader* shader = nullptr; + vk::Device device; + vk::ShaderModule shaderModuleVertex, shaderModuleFragment; + vk::Pipeline pipeline; + IShaderOwner* owner; - VulkanShader() = default; - virtual ~VulkanShader() { if (shader) VulkanShader::Close(); } + VulkanShader() = default; + ~VulkanShader() override { if (shader) VulkanShader::Close(); } - void Init(Context* context, Scene::Shader* shader, IShaderOwner* owner) - { - this->device = context->device->device; - this->shader = shader; - this->owner = owner; - shaderModuleVertex = context->device->CreateShaderModule(shader->vertexShaderName + ".vert.spv"); - shaderModuleFragment = context->device->CreateShaderModule(shader->fragmentShaderName + ".frag.spv"); - std::vector shaderStageCreateInfos(2); - shaderStageCreateInfos[0] = { {}, vk::ShaderStageFlagBits::eVertex, shaderModuleVertex, "main" }; - shaderStageCreateInfos[1] = { {}, vk::ShaderStageFlagBits::eFragment, shaderModuleFragment, "main" }; - - auto vertexBindDesc = vk::VertexInputBindingDescription(0, sizeof(Vertex), vk::VertexInputRate::eVertex); - std::vector attributeDescriptions; - attributeDescriptions.emplace_back(0, 0, vk::Format::eR32G32B32Sfloat, offsetof(Vertex, position)); - attributeDescriptions.emplace_back(1, 0, vk::Format::eR32G32B32Sfloat, offsetof(Vertex, normal)); - attributeDescriptions.emplace_back(2, 0, vk::Format::eR32G32B32Sfloat, offsetof(Vertex, tangent)); - attributeDescriptions.emplace_back(3, 0, vk::Format::eR32G32B32Sfloat, offsetof(Vertex, biTangent)); - attributeDescriptions.emplace_back(4, 0, vk::Format::eR32G32B32Sfloat, offsetof(Vertex, textureCoordinates)); - attributeDescriptions.emplace_back(5, 0, vk::Format::eR32G32B32A32Sfloat, offsetof(Vertex, color)); + void Init(Context* context, Scene::Shader* shader, IShaderOwner* owner); - auto viewport = context->swapChain.GetFullscreenViewport(); - auto scissor = context->swapChain.GetFullscreenScissor(); - vk::PipelineViewportStateCreateInfo viewportStateCreateInfo = { {}, 1, &viewport, 1, &scissor }; - vk::PipelineVertexInputStateCreateInfo pipelineVertexInputStateCreateInfo = { {}, 1, &vertexBindDesc, - static_cast(attributeDescriptions.size()), attributeDescriptions.data() }; - vk::PipelineInputAssemblyStateCreateInfo inputAssembly = { {}, ToVkTopology(shader->topology), 0 }; - vk::PipelineRasterizationStateCreateInfo rasterizer = {}; - rasterizer.cullMode = vk::CullModeFlagBits::eBack; - vk::PipelineMultisampleStateCreateInfo msaa = {}; - vk::PipelineDepthStencilStateCreateInfo depth = { {}, 1, 1, vk::CompareOp::eLess }; - depth.maxDepthBounds = 1; - vk::PipelineColorBlendAttachmentState colorBlendAttachment = {}; - colorBlendAttachment.colorWriteMask = vk::ColorComponentFlagBits::eA | vk::ColorComponentFlagBits::eB | vk::ColorComponentFlagBits::eG | vk::ColorComponentFlagBits::eR; - vk::PipelineColorBlendStateCreateInfo colorInfo = {}; - colorInfo.attachmentCount = 1; - colorInfo.pAttachments = &colorBlendAttachment; + void Record(vk::CommandBuffer& cmdBuffer, uint32_t bufferId) override; - - - vk::GraphicsPipelineCreateInfo pipelineCreateInfo = { {}, static_cast(shaderStageCreateInfos.size()), shaderStageCreateInfos.data(), &pipelineVertexInputStateCreateInfo, &inputAssembly, - nullptr, &viewportStateCreateInfo, &rasterizer, &msaa, &depth, &colorInfo, nullptr, context->pipeline.pipelineLayout, context->swapChainRenderPass.renderPass }; - pipeline = this->device.createGraphicsPipeline({}, pipelineCreateInfo).value; - - } + void Close() override; + }; - void Record(vk::CommandBuffer& cmdBuffer, uint32_t bufferId) override - { - cmdBuffer.bindPipeline(vk::PipelineBindPoint::eGraphics, pipeline); - } - - void Close() override - { - owner->RemoveShader(this); - shader = nullptr; - device.destroyPipeline(pipeline); - device.destroyShaderModule(shaderModuleVertex); - device.destroyShaderModule(shaderModuleFragment); - } - }; - - } } diff --git a/openVulkanoCpp/Vulkan/SwapChain.hpp b/openVulkanoCpp/Vulkan/SwapChain.hpp index b775d41..03a951a 100644 --- a/openVulkanoCpp/Vulkan/SwapChain.hpp +++ b/openVulkanoCpp/Vulkan/SwapChain.hpp @@ -1,9 +1,18 @@ +/* + * 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 #include "Device.hpp" #include "Image.hpp" #include "FrameBuffer.hpp" +#include "../Base/UI/IWindow.hpp" +#include "../Base/Logger.hpp" namespace openVulkanoCpp {