Refactor code
This commit is contained in:
@@ -1,5 +1,5 @@
|
||||
#pragma once
|
||||
#include <stdint.h>
|
||||
#include <cstdint>
|
||||
#include <algorithm>
|
||||
|
||||
namespace openVulkanoCpp
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
@@ -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 <vector>
|
||||
#include <string>
|
||||
#include <set>
|
||||
#include <algorithm>
|
||||
#include <glm/vec3.hpp>
|
||||
|
||||
namespace openVulkanoCpp
|
||||
{
|
||||
|
||||
@@ -2,6 +2,7 @@
|
||||
#include <glm/glm.hpp>
|
||||
#include <assimp/vector2.h>
|
||||
#include <assimp/vector3.h>
|
||||
#include <assimp/color4.h>
|
||||
|
||||
namespace openVulkanoCpp
|
||||
{
|
||||
|
||||
@@ -14,7 +14,7 @@ namespace openVulkanoCpp
|
||||
{
|
||||
namespace Vulkan
|
||||
{
|
||||
class Context : virtual public ICloseable
|
||||
class Context final : virtual public ICloseable
|
||||
{
|
||||
bool enableValidationLayer, initialized;
|
||||
std::set<std::string> requiredExtensions;
|
||||
@@ -38,7 +38,8 @@ namespace openVulkanoCpp
|
||||
enableValidationLayer = false;
|
||||
#endif
|
||||
}
|
||||
virtual ~Context()
|
||||
|
||||
~Context() override
|
||||
{
|
||||
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
|
||||
|
||||
#include <set>
|
||||
#include <list>
|
||||
#include <string>
|
||||
#include <vector>
|
||||
#include <vulkan/vulkan.hpp>
|
||||
|
||||
#define RENDER_DOC
|
||||
|
||||
namespace openVulkanoCpp
|
||||
namespace openVulkanoCpp::Vulkan
|
||||
{
|
||||
namespace Vulkan
|
||||
class Debug
|
||||
{
|
||||
namespace Debug
|
||||
{
|
||||
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
|
||||
};
|
||||
public:
|
||||
static std::set<std::string> GetAvailableValidationLayers();
|
||||
|
||||
static std::set<std::string> GetAvailableValidationLayers()
|
||||
{
|
||||
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 std::vector<const char*> GetValidationLayers()
|
||||
{
|
||||
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 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);
|
||||
};
|
||||
}
|
||||
|
||||
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
|
||||
#include <stdexcept>
|
||||
|
||||
#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<vk::Semaphore> renderReady, renderComplete;
|
||||
};
|
||||
std::vector<vk::Semaphore> renderReady, renderComplete;
|
||||
};
|
||||
|
||||
class Renderer : public IRenderer
|
||||
{
|
||||
Context context;
|
||||
std::shared_ptr<spdlog::logger> logger;
|
||||
std::vector<WaitSemaphores> waitSemaphores;
|
||||
Scene::Scene* scene = nullptr;
|
||||
ResourceManager resourceManager;
|
||||
uint32_t currentImageId = -1;
|
||||
std::vector<std::thread> threadPool;
|
||||
std::vector<std::vector<CommandHelper>> commands;
|
||||
std::vector<std::vector<vk::CommandBuffer>> submitBuffers;
|
||||
VulkanShader* shader;
|
||||
class Renderer final : public IRenderer
|
||||
{
|
||||
Context context;
|
||||
std::shared_ptr<spdlog::logger> logger;
|
||||
std::vector<WaitSemaphores> waitSemaphores;
|
||||
Scene::Scene* scene = nullptr;
|
||||
ResourceManager resourceManager;
|
||||
uint32_t currentImageId = -1;
|
||||
std::vector<std::thread> threadPool;
|
||||
std::vector<std::vector<CommandHelper>> commands;
|
||||
std::vector<std::vector<vk::CommandBuffer>> 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<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;
|
||||
}
|
||||
}
|
||||
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<Scene::Drawable*>* jobQueue, uint32_t id);
|
||||
|
||||
Scene::Scene* GetScene() override
|
||||
{
|
||||
return scene;
|
||||
}
|
||||
void StartThreads(Data::ReadOnlyAtomicArrayQueue<Scene::Drawable*>* jobQueue);
|
||||
|
||||
CommandHelper* GetCommandData(uint32_t poolId)
|
||||
{
|
||||
return &commands[poolId][currentImageId];
|
||||
}
|
||||
void RecordPrimaryBuffer();
|
||||
|
||||
static void RunThread(Renderer* renderer, Data::ReadOnlyAtomicArrayQueue<Scene::Drawable*>* jobQueue, uint32_t id)
|
||||
{
|
||||
renderer->RecordSecondaryBuffer(jobQueue, id);
|
||||
}
|
||||
void Submit();
|
||||
|
||||
void StartThreads(Data::ReadOnlyAtomicArrayQueue<Scene::Drawable*>* 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<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();
|
||||
}
|
||||
};
|
||||
}
|
||||
void RecordSecondaryBuffer(Data::ReadOnlyAtomicArrayQueue<Scene::Drawable*>* jobQueue, uint32_t poolId);
|
||||
};
|
||||
}
|
||||
|
||||
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
|
||||
|
||||
#include <vulkan/vulkan.hpp>
|
||||
#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!");
|
||||
}
|
||||
}
|
||||
Scene::Shader* shader = nullptr;
|
||||
vk::Device device;
|
||||
vk::ShaderModule shaderModuleVertex, shaderModuleFragment;
|
||||
vk::Pipeline pipeline;
|
||||
IShaderOwner* owner;
|
||||
|
||||
struct VulkanShader : virtual public ICloseable, virtual public IRecordable
|
||||
{
|
||||
Scene::Shader* shader = nullptr;
|
||||
vk::Device device;
|
||||
vk::ShaderModule shaderModuleVertex, shaderModuleFragment;
|
||||
vk::Pipeline pipeline;
|
||||
IShaderOwner* owner;
|
||||
VulkanShader() = default;
|
||||
~VulkanShader() override { if (shader) VulkanShader::Close(); }
|
||||
|
||||
VulkanShader() = default;
|
||||
virtual ~VulkanShader() { if (shader) VulkanShader::Close(); }
|
||||
void Init(Context* context, Scene::Shader* shader, IShaderOwner* owner);
|
||||
|
||||
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<vk::PipelineShaderStageCreateInfo> shaderStageCreateInfos(2);
|
||||
shaderStageCreateInfos[0] = { {}, vk::ShaderStageFlagBits::eVertex, shaderModuleVertex, "main" };
|
||||
shaderStageCreateInfos[1] = { {}, vk::ShaderStageFlagBits::eFragment, shaderModuleFragment, "main" };
|
||||
void Record(vk::CommandBuffer& cmdBuffer, uint32_t bufferId) override;
|
||||
|
||||
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));
|
||||
void Close() override;
|
||||
};
|
||||
|
||||
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
|
||||
|
||||
#include <algorithm>
|
||||
#include <vulkan/vulkan.hpp>
|
||||
#include "Device.hpp"
|
||||
#include "Image.hpp"
|
||||
#include "FrameBuffer.hpp"
|
||||
#include "../Base/UI/IWindow.hpp"
|
||||
#include "../Base/Logger.hpp"
|
||||
|
||||
namespace openVulkanoCpp
|
||||
{
|
||||
|
||||
Reference in New Issue
Block a user