Refactor code
This commit is contained in:
@@ -1,5 +1,5 @@
|
|||||||
#pragma once
|
#pragma once
|
||||||
#include <stdint.h>
|
#include <cstdint>
|
||||||
#include <algorithm>
|
#include <algorithm>
|
||||||
|
|
||||||
namespace openVulkanoCpp
|
namespace openVulkanoCpp
|
||||||
|
|||||||
@@ -4,9 +4,7 @@
|
|||||||
|
|
||||||
namespace openVulkanoCpp
|
namespace openVulkanoCpp
|
||||||
{
|
{
|
||||||
#define MAKE_VERSION(major, minor, patch) (((major) << 22) | ((minor) << 12) | (patch))
|
inline const char* ENGINE_NAME = "openVulkanoCpp";
|
||||||
|
|
||||||
const char* ENGINE_NAME = "openVulkanoCpp";
|
|
||||||
|
|
||||||
struct EngineVersion
|
struct EngineVersion
|
||||||
{
|
{
|
||||||
@@ -17,15 +15,15 @@ namespace openVulkanoCpp
|
|||||||
EngineVersion(int major, int minor, int patch, int build = 0) : major(major), minor(minor), patch(patch)
|
EngineVersion(int major, int minor, int patch, int build = 0) : major(major), minor(minor), patch(patch)
|
||||||
{
|
{
|
||||||
intVersion = ((major) << 24) | ((minor) << 16) | (patch);
|
intVersion = ((major) << 24) | ((minor) << 16) | (patch);
|
||||||
std::string buildConfig = "";
|
std::string_view buildConfig;
|
||||||
#ifdef _DEBUG
|
#ifdef _DEBUG
|
||||||
buildConfig += "-MSVC_DEBUG";
|
buildConfig = "MSVC_DEBUG";
|
||||||
#elif DEBUG
|
#elif DEBUG
|
||||||
buildConfig += "-DEBUG";
|
buildConfig = "DEBUG";
|
||||||
#endif
|
#endif
|
||||||
stringVersion = fmt::format("v{0}.{1}.{2}.{3}{4}", major, minor, patch, build, buildConfig);
|
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);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -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
|
#pragma once
|
||||||
|
|
||||||
#include <vector>
|
#include <vector>
|
||||||
#include <string>
|
#include <string>
|
||||||
#include <set>
|
#include <set>
|
||||||
#include <algorithm>
|
#include <algorithm>
|
||||||
|
#include <glm/vec3.hpp>
|
||||||
|
|
||||||
namespace openVulkanoCpp
|
namespace openVulkanoCpp
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -2,6 +2,7 @@
|
|||||||
#include <glm/glm.hpp>
|
#include <glm/glm.hpp>
|
||||||
#include <assimp/vector2.h>
|
#include <assimp/vector2.h>
|
||||||
#include <assimp/vector3.h>
|
#include <assimp/vector3.h>
|
||||||
|
#include <assimp/color4.h>
|
||||||
|
|
||||||
namespace openVulkanoCpp
|
namespace openVulkanoCpp
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -14,7 +14,7 @@ namespace openVulkanoCpp
|
|||||||
{
|
{
|
||||||
namespace Vulkan
|
namespace Vulkan
|
||||||
{
|
{
|
||||||
class Context : virtual public ICloseable
|
class Context final : virtual public ICloseable
|
||||||
{
|
{
|
||||||
bool enableValidationLayer, initialized;
|
bool enableValidationLayer, initialized;
|
||||||
std::set<std::string> requiredExtensions;
|
std::set<std::string> requiredExtensions;
|
||||||
@@ -38,7 +38,8 @@ namespace openVulkanoCpp
|
|||||||
enableValidationLayer = false;
|
enableValidationLayer = false;
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
virtual ~Context()
|
|
||||||
|
~Context() override
|
||||||
{
|
{
|
||||||
if (initialized) Close();
|
if (initialized) Close();
|
||||||
}
|
}
|
||||||
|
|||||||
94
openVulkanoCpp/Vulkan/Debuging/ValidationLayer.cpp
Normal file
94
openVulkanoCpp/Vulkan/Debuging/ValidationLayer.cpp
Normal file
@@ -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 <list>
|
||||||
|
|
||||||
|
#define RENDER_DOC
|
||||||
|
|
||||||
|
namespace openVulkanoCpp::Vulkan
|
||||||
|
{
|
||||||
|
const std::initializer_list<std::string> 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<std::string> Debug::GetAvailableValidationLayers()
|
||||||
|
{
|
||||||
|
static std::set<std::string> 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<const char*> Debug::GetValidationLayers()
|
||||||
|
{
|
||||||
|
std::set<std::string> availableLayers = GetAvailableValidationLayers();
|
||||||
|
std::vector<const char*> 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);
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -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
|
#pragma once
|
||||||
|
|
||||||
#include <set>
|
#include <set>
|
||||||
#include <list>
|
#include <string>
|
||||||
|
#include <vector>
|
||||||
#include <vulkan/vulkan.hpp>
|
#include <vulkan/vulkan.hpp>
|
||||||
|
|
||||||
#define RENDER_DOC
|
namespace openVulkanoCpp::Vulkan
|
||||||
|
|
||||||
namespace openVulkanoCpp
|
|
||||||
{
|
{
|
||||||
namespace Vulkan
|
class Debug
|
||||||
{
|
{
|
||||||
namespace Debug
|
public:
|
||||||
{
|
static std::set<std::string> GetAvailableValidationLayers();
|
||||||
std::list<std::string> 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
|
|
||||||
};
|
|
||||||
|
|
||||||
static std::set<std::string> GetAvailableValidationLayers()
|
static std::vector<const char*> GetValidationLayers();
|
||||||
{
|
|
||||||
auto layers = vk::enumerateInstanceLayerProperties();
|
|
||||||
std::set<std::string> 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<const char*> GetValidationLayers()
|
static void SetupValidationLayers(const vk::Instance& instance, const vk::DebugReportFlagsEXT& flags);
|
||||||
{
|
|
||||||
std::set<std::string> availableLayers = GetAvailableValidationLayers();
|
|
||||||
std::vector<const char*> 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 std::once_flag dispatcherInitFlag;
|
static void CloseValidationLayers(const vk::Instance& instance);
|
||||||
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);
|
|
||||||
}
|
|
||||||
};
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|||||||
168
openVulkanoCpp/Vulkan/Renderer.cpp
Normal file
168
openVulkanoCpp/Vulkan/Renderer.cpp
Normal file
@@ -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 <stdexcept>
|
||||||
|
|
||||||
|
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<CommandHelper>(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<Scene::Drawable*>* jobQueue, uint32_t id)
|
||||||
|
{
|
||||||
|
renderer->RecordSecondaryBuffer(jobQueue, id);
|
||||||
|
}
|
||||||
|
|
||||||
|
void Renderer::StartThreads(Data::ReadOnlyAtomicArrayQueue<Scene::Drawable*>* 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<vk::PipelineStageFlags, 2> 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<Scene::Drawable*> jobQueue(scene->shapeList);
|
||||||
|
StartThreads(&jobQueue);
|
||||||
|
RecordPrimaryBuffer();
|
||||||
|
RecordSecondaryBuffer(&jobQueue, threadPool.size());
|
||||||
|
Submit();
|
||||||
|
}
|
||||||
|
|
||||||
|
void Renderer::RecordSecondaryBuffer(Data::ReadOnlyAtomicArrayQueue<Scene::Drawable*>* 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<VulkanGeometry*>(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<VulkanNode*>(node->renderNode)->Record(cmdHelper->cmdBuffer, currentImageId);
|
||||||
|
lastNode = node;
|
||||||
|
}
|
||||||
|
cmdHelper->cmdBuffer.drawIndexed(mesh->GetIndexCount(), 1, 0, 0, 0);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
cmdHelper->cmdBuffer.end();
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -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
|
#pragma once
|
||||||
#include <stdexcept>
|
|
||||||
#include "../Base/Render/IRenderer.hpp"
|
#include "../Base/Render/IRenderer.hpp"
|
||||||
#include "../Base/UI/IWindow.hpp"
|
#include "../Base/UI/IWindow.hpp"
|
||||||
#include "../Base/Logger.hpp"
|
#include "../Base/Logger.hpp"
|
||||||
@@ -9,198 +15,56 @@
|
|||||||
#include "CommandHelper.hpp"
|
#include "CommandHelper.hpp"
|
||||||
#include "../Base/EngineConfiguration.hpp"
|
#include "../Base/EngineConfiguration.hpp"
|
||||||
|
|
||||||
namespace openVulkanoCpp
|
namespace openVulkanoCpp::Vulkan
|
||||||
{
|
{
|
||||||
namespace Vulkan
|
struct WaitSemaphores
|
||||||
{
|
{
|
||||||
struct WaitSemaphores
|
std::vector<vk::Semaphore> renderReady, renderComplete;
|
||||||
{
|
};
|
||||||
std::vector<vk::Semaphore> renderReady, renderComplete;
|
|
||||||
};
|
|
||||||
|
|
||||||
class Renderer : public IRenderer
|
class Renderer final : public IRenderer
|
||||||
{
|
{
|
||||||
Context context;
|
Context context;
|
||||||
std::shared_ptr<spdlog::logger> logger;
|
std::shared_ptr<spdlog::logger> logger;
|
||||||
std::vector<WaitSemaphores> waitSemaphores;
|
std::vector<WaitSemaphores> waitSemaphores;
|
||||||
Scene::Scene* scene = nullptr;
|
Scene::Scene* scene = nullptr;
|
||||||
ResourceManager resourceManager;
|
ResourceManager resourceManager;
|
||||||
uint32_t currentImageId = -1;
|
uint32_t currentImageId = -1;
|
||||||
std::vector<std::thread> threadPool;
|
std::vector<std::thread> threadPool;
|
||||||
std::vector<std::vector<CommandHelper>> commands;
|
std::vector<std::vector<CommandHelper>> commands;
|
||||||
std::vector<std::vector<vk::CommandBuffer>> submitBuffers;
|
std::vector<std::vector<vk::CommandBuffer>> submitBuffers;
|
||||||
VulkanShader* shader;
|
VulkanShader* shader;
|
||||||
|
|
||||||
public:
|
public:
|
||||||
Renderer() = default;
|
Renderer() = default;
|
||||||
virtual ~Renderer() = default;
|
virtual ~Renderer() = default;
|
||||||
|
|
||||||
void Init(IGraphicsAppManager* graphicsAppManager, IWindow* window) override
|
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);
|
|
||||||
|
|
||||||
//Setup cmd pools and buffers
|
void Tick() override;
|
||||||
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<CommandHelper>(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);
|
void Close() override;
|
||||||
|
|
||||||
logger->info("Vulkan renderer initialized");
|
std::string GetMainRenderDeviceName() override;
|
||||||
}
|
|
||||||
|
|
||||||
void Tick() override
|
void Resize(uint32_t newWidth, uint32_t newHeight) override;
|
||||||
{
|
|
||||||
currentImageId = context.swapChain.AcquireNextImage();
|
|
||||||
Render();
|
|
||||||
}
|
|
||||||
|
|
||||||
void Close() override
|
void SetScene(Scene::Scene* scene) override { this->scene = scene; }
|
||||||
{
|
|
||||||
//context.Close();
|
|
||||||
}
|
|
||||||
|
|
||||||
std::string GetMainRenderDeviceName() override
|
Scene::Scene* GetScene() override { return scene; }
|
||||||
{
|
|
||||||
return (context.device) ? context.device->GetDeviceName() : "Unknown";
|
|
||||||
}
|
|
||||||
|
|
||||||
void Resize(const uint32_t newWidth, const uint32_t newHeight) override
|
CommandHelper* GetCommandData(uint32_t poolId);
|
||||||
{
|
|
||||||
context.Resize(newWidth, newHeight);
|
|
||||||
resourceManager.Resize();
|
|
||||||
}
|
|
||||||
|
|
||||||
void SetScene(Scene::Scene* scene) override
|
static void RunThread(Renderer* renderer, Data::ReadOnlyAtomicArrayQueue<Scene::Drawable*>* jobQueue, uint32_t id);
|
||||||
{
|
|
||||||
this->scene = scene;
|
|
||||||
}
|
|
||||||
|
|
||||||
Scene::Scene* GetScene() override
|
void StartThreads(Data::ReadOnlyAtomicArrayQueue<Scene::Drawable*>* jobQueue);
|
||||||
{
|
|
||||||
return scene;
|
|
||||||
}
|
|
||||||
|
|
||||||
CommandHelper* GetCommandData(uint32_t poolId)
|
void RecordPrimaryBuffer();
|
||||||
{
|
|
||||||
return &commands[poolId][currentImageId];
|
|
||||||
}
|
|
||||||
|
|
||||||
static void RunThread(Renderer* renderer, Data::ReadOnlyAtomicArrayQueue<Scene::Drawable*>* jobQueue, uint32_t id)
|
void Submit();
|
||||||
{
|
|
||||||
renderer->RecordSecondaryBuffer(jobQueue, id);
|
|
||||||
}
|
|
||||||
|
|
||||||
void StartThreads(Data::ReadOnlyAtomicArrayQueue<Scene::Drawable*>* jobQueue)
|
void Render();
|
||||||
{
|
|
||||||
for(uint32_t i = 0; i < threadPool.size(); i++)
|
|
||||||
{
|
|
||||||
threadPool[i] = std::thread(RunThread, this, jobQueue, i);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void RecordPrimaryBuffer()
|
void RecordSecondaryBuffer(Data::ReadOnlyAtomicArrayQueue<Scene::Drawable*>* jobQueue, uint32_t poolId);
|
||||||
{
|
};
|
||||||
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<vk::PipelineStageFlags, 2> 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<Scene::Drawable*> jobQueue(scene->shapeList);
|
|
||||||
StartThreads(&jobQueue);
|
|
||||||
RecordPrimaryBuffer();
|
|
||||||
RecordSecondaryBuffer(&jobQueue, threadPool.size());
|
|
||||||
Submit();
|
|
||||||
}
|
|
||||||
|
|
||||||
void RecordSecondaryBuffer(Data::ReadOnlyAtomicArrayQueue<Scene::Drawable*>* 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<VulkanGeometry*>(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<VulkanNode*>(node->renderNode)->Record(cmdHelper->cmdBuffer, currentImageId);
|
|
||||||
lastNode = node;
|
|
||||||
}
|
|
||||||
cmdHelper->cmdBuffer.drawIndexed(mesh->GetIndexCount(), 1, 0, 0, 0);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
cmdHelper->cmdBuffer.end();
|
|
||||||
}
|
|
||||||
};
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|||||||
88
openVulkanoCpp/Vulkan/Scene/VulkanShader.cpp
Normal file
88
openVulkanoCpp/Vulkan/Scene/VulkanShader.cpp
Normal file
@@ -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<vk::PipelineShaderStageCreateInfo> 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<vk::VertexInputAttributeDescription> 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<uint32_t>(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<uint32_t>(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);
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -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
|
#pragma once
|
||||||
|
|
||||||
#include <vulkan/vulkan.hpp>
|
#include <vulkan/vulkan.hpp>
|
||||||
#include "../Device.hpp"
|
|
||||||
#include "../../Scene/Shader.hpp"
|
#include "../../Scene/Shader.hpp"
|
||||||
#include "../../Scene/Vertex.hpp"
|
|
||||||
#include "../../Base/ICloseable.hpp"
|
#include "../../Base/ICloseable.hpp"
|
||||||
#include "../Resources/IShaderOwner.hpp"
|
#include "../Resources/IShaderOwner.hpp"
|
||||||
#include "IRecordable.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)
|
Scene::Shader* shader = nullptr;
|
||||||
{
|
vk::Device device;
|
||||||
switch (topology) {
|
vk::ShaderModule shaderModuleVertex, shaderModuleFragment;
|
||||||
case Scene::Topology::PointList: return vk::PrimitiveTopology::ePointList;
|
vk::Pipeline pipeline;
|
||||||
case Scene::Topology::LineList: return vk::PrimitiveTopology::eLineList;
|
IShaderOwner* owner;
|
||||||
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
|
VulkanShader() = default;
|
||||||
{
|
~VulkanShader() override { if (shader) VulkanShader::Close(); }
|
||||||
Scene::Shader* shader = nullptr;
|
|
||||||
vk::Device device;
|
|
||||||
vk::ShaderModule shaderModuleVertex, shaderModuleFragment;
|
|
||||||
vk::Pipeline pipeline;
|
|
||||||
IShaderOwner* owner;
|
|
||||||
|
|
||||||
VulkanShader() = default;
|
void Init(Context* context, Scene::Shader* shader, IShaderOwner* owner);
|
||||||
virtual ~VulkanShader() { if (shader) VulkanShader::Close(); }
|
|
||||||
|
|
||||||
void Init(Context* context, Scene::Shader* shader, IShaderOwner* owner)
|
void Record(vk::CommandBuffer& cmdBuffer, uint32_t bufferId) override;
|
||||||
{
|
|
||||||
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<vk::PipelineShaderStageCreateInfo> 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);
|
void Close() override;
|
||||||
std::vector<vk::VertexInputAttributeDescription> 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<uint32_t>(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<uint32_t>(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 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);
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -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
|
#pragma once
|
||||||
|
|
||||||
#include <algorithm>
|
#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/Logger.hpp"
|
||||||
|
|
||||||
namespace openVulkanoCpp
|
namespace openVulkanoCpp
|
||||||
{
|
{
|
||||||
|
|||||||
Reference in New Issue
Block a user