More code cleanup
This commit is contained in:
@@ -17,7 +17,7 @@ namespace openVulkanoCpp
|
|||||||
class Utils
|
class Utils
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
static std::vector<const char*> toCString(const std::vector<std::string>& values)
|
static inline std::vector<const char*> toCString(const std::vector<std::string>& values)
|
||||||
{
|
{
|
||||||
std::vector<const char*> result;
|
std::vector<const char*> result;
|
||||||
result.reserve(values.size());
|
result.reserve(values.size());
|
||||||
@@ -27,7 +27,7 @@ namespace openVulkanoCpp
|
|||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
static std::vector<const char*> toCString(const std::set<std::string>& values)
|
static inline std::vector<const char*> toCString(const std::set<std::string>& values)
|
||||||
{
|
{
|
||||||
std::vector<const char*> result;
|
std::vector<const char*> result;
|
||||||
result.reserve(values.size());
|
result.reserve(values.size());
|
||||||
@@ -38,27 +38,32 @@ namespace openVulkanoCpp
|
|||||||
}
|
}
|
||||||
|
|
||||||
template <typename T>
|
template <typename T>
|
||||||
static bool Contains(std::vector<T>& vec, const T& element)
|
static inline bool Contains(std::vector<T>& vec, const T& element)
|
||||||
{
|
{
|
||||||
return (std::find(vec.begin(), vec.end(), element) != vec.end());
|
return (std::find(vec.begin(), vec.end(), element) != vec.end());
|
||||||
}
|
}
|
||||||
|
|
||||||
template <typename T>
|
template <typename T>
|
||||||
static void Remove(std::vector<T>& vec, const T& element)
|
static inline void Remove(std::vector<T>& vec, const T& element)
|
||||||
{
|
{
|
||||||
vec.erase(std::remove(vec.begin(), vec.end(), element), vec.end());
|
vec.erase(std::remove(vec.begin(), vec.end(), element), vec.end());
|
||||||
}
|
}
|
||||||
|
|
||||||
template <typename Enumeration>
|
template <typename Enumeration>
|
||||||
static auto EnumAsInt(Enumeration const value)
|
static inline auto EnumAsInt(Enumeration const value)
|
||||||
-> typename std::underlying_type<Enumeration>::type
|
-> typename std::underlying_type<Enumeration>::type
|
||||||
{
|
{
|
||||||
return static_cast<typename std::underlying_type<Enumeration>::type>(value);
|
return static_cast<typename std::underlying_type<Enumeration>::type>(value);
|
||||||
}
|
}
|
||||||
|
|
||||||
static bool MatchesAnyElementWise(const glm::vec3& a, const glm::vec3& b)
|
static inline bool MatchesAnyElementWise(const glm::vec3& a, const glm::vec3& b)
|
||||||
{
|
{
|
||||||
return a.x == b.x || a.y == b.y || a.z == b.z;
|
return a.x == b.x || a.y == b.y || a.z == b.z;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static inline size_t Align(size_t size, size_t alignment)
|
||||||
|
{
|
||||||
|
return (size + alignment - 1) & ~(alignment - 1);
|
||||||
|
}
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -16,7 +16,7 @@ namespace openVulkanoCpp::GLFW
|
|||||||
std::string name = glfwGetJoystickName(joystickId);
|
std::string name = glfwGetJoystickName(joystickId);
|
||||||
if (gamepad) name += " - " + std::string(glfwGetGamepadName(joystickId));
|
if (gamepad) name += " - " + std::string(glfwGetGamepadName(joystickId));
|
||||||
InputDeviceController::Init(joystickId, name);
|
InputDeviceController::Init(joystickId, name);
|
||||||
if (!gamepad) Logger::INPUT->warn("Joysticks currently are not supported");
|
if (!gamepad) Logger::INPUT->warn("Joysticks are currently not supported");
|
||||||
}
|
}
|
||||||
|
|
||||||
void ControllerGLFW::Tick()
|
void ControllerGLFW::Tick()
|
||||||
|
|||||||
@@ -5,6 +5,9 @@
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
#include "Renderer.hpp"
|
#include "Renderer.hpp"
|
||||||
|
#include "Scene/VulkanGeometry.hpp"
|
||||||
|
#include "Scene/VulkanNode.hpp"
|
||||||
|
#include "Scene/VulkanShader.hpp"
|
||||||
#include <stdexcept>
|
#include <stdexcept>
|
||||||
|
|
||||||
namespace openVulkanoCpp::Vulkan
|
namespace openVulkanoCpp::Vulkan
|
||||||
|
|||||||
22
openVulkanoCpp/Vulkan/Resources/ManagedResource.cpp
Normal file
22
openVulkanoCpp/Vulkan/Resources/ManagedResource.cpp
Normal file
@@ -0,0 +1,22 @@
|
|||||||
|
/*
|
||||||
|
* 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 "ManagedResource.hpp"
|
||||||
|
#include "../../Base/Logger.hpp"
|
||||||
|
|
||||||
|
namespace openVulkanoCpp::Vulkan
|
||||||
|
{
|
||||||
|
void MemoryAllocation::HandleChildMappingValidation() const
|
||||||
|
{
|
||||||
|
if (IsChildMapped())
|
||||||
|
{
|
||||||
|
Logger::RENDER->error("A single memory allocation should only be mapped once! Mapping a single allocation multiple times might not work or might not work reliable with all driver implementations.");
|
||||||
|
#ifdef CRASH_ON_MULTIPLE_MAPPINGS_TO_SAME_ALLOCATION
|
||||||
|
throw std::runtime_error("A single memory allocation should only be mapped once!");
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -1,3 +1,9 @@
|
|||||||
|
/*
|
||||||
|
* 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
|
||||||
|
|
||||||
#define CRASH_ON_MULTIPLE_MAPPINGS_TO_SAME_ALLOCATION
|
#define CRASH_ON_MULTIPLE_MAPPINGS_TO_SAME_ALLOCATION
|
||||||
@@ -27,21 +33,12 @@ namespace openVulkanoCpp
|
|||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
size_t FreeSpace() const
|
[[nodiscard]] size_t FreeSpace() const
|
||||||
{
|
{
|
||||||
return size - used;
|
return size - used;
|
||||||
}
|
}
|
||||||
|
|
||||||
void HandleChildMappingValidation() const
|
void HandleChildMappingValidation() const;
|
||||||
{
|
|
||||||
if (IsChildMapped())
|
|
||||||
{
|
|
||||||
Logger::RENDER->error("A single memory allocation should only be mapped once! Mapping a single allocation multiple times might not work or might not work reliable with all driver implementations.");
|
|
||||||
#ifdef CRASH_ON_MULTIPLE_MAPPINGS_TO_SAME_ALLOCATION
|
|
||||||
throw std::runtime_error("A single memory allocation should only be mapped once!");
|
|
||||||
#endif
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void* Map()
|
void* Map()
|
||||||
{
|
{
|
||||||
|
|||||||
223
openVulkanoCpp/Vulkan/Resources/ResourceManager.cpp
Normal file
223
openVulkanoCpp/Vulkan/Resources/ResourceManager.cpp
Normal file
@@ -0,0 +1,223 @@
|
|||||||
|
/*
|
||||||
|
* 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 "ResourceManager.hpp"
|
||||||
|
#include "../Context.hpp"
|
||||||
|
#include "../Scene/VulkanShader.hpp"
|
||||||
|
#include "../Scene/VulkanGeometry.hpp"
|
||||||
|
#include "../Scene/VulkanNode.hpp"
|
||||||
|
|
||||||
|
namespace openVulkanoCpp::Vulkan
|
||||||
|
{
|
||||||
|
ResourceManager::ResourceManager() = default;
|
||||||
|
|
||||||
|
ResourceManager::~ResourceManager() noexcept
|
||||||
|
{
|
||||||
|
if (device) ResourceManager::Close();
|
||||||
|
}
|
||||||
|
|
||||||
|
void ResourceManager::Init(Context* context, int buffers)
|
||||||
|
{
|
||||||
|
this->context = context;
|
||||||
|
this->device = context->device->device;
|
||||||
|
this->buffers = buffers;
|
||||||
|
|
||||||
|
uniformBufferAlignment = context->device->properties.limits.minUniformBufferOffsetAlignment;
|
||||||
|
|
||||||
|
cmdPools = new vk::CommandPool[buffers];
|
||||||
|
cmdBuffers = new vk::CommandBuffer[buffers];
|
||||||
|
semaphores = new vk::Semaphore[buffers];
|
||||||
|
for (int i = 0; i < buffers; i++)
|
||||||
|
{
|
||||||
|
cmdPools[i] = this->device.createCommandPool({ {}, context->device->queueIndices.transfer });
|
||||||
|
cmdBuffers[i] = this->device.allocateCommandBuffers({ cmdPools[i], vk::CommandBufferLevel::ePrimary, 1 })[0];
|
||||||
|
semaphores[i] = this->device.createSemaphore({});
|
||||||
|
}
|
||||||
|
toFree.resize(buffers);
|
||||||
|
|
||||||
|
transferQueue = this->device.getQueue(context->device->queueIndices.transfer, 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
void ResourceManager::Close()
|
||||||
|
{
|
||||||
|
transferQueue.waitIdle();
|
||||||
|
for (int i = 0; i < buffers; i++)
|
||||||
|
{
|
||||||
|
device.freeCommandBuffers(cmdPools[i], 1, &cmdBuffers[i]);
|
||||||
|
device.destroyCommandPool(cmdPools[0]);
|
||||||
|
}
|
||||||
|
for (auto shader : shaders)
|
||||||
|
{
|
||||||
|
shader->Close();
|
||||||
|
}
|
||||||
|
cmdBuffers = nullptr;
|
||||||
|
cmdPools = nullptr;
|
||||||
|
device = nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
void ResourceManager::StartFrame(uint64_t frameId)
|
||||||
|
{
|
||||||
|
currentBuffer = frameId;
|
||||||
|
FreeBuffers();
|
||||||
|
device.resetCommandPool(cmdPools[currentBuffer], {});
|
||||||
|
cmdBuffers[currentBuffer].begin({ vk::CommandBufferUsageFlagBits::eOneTimeSubmit });
|
||||||
|
}
|
||||||
|
|
||||||
|
vk::Semaphore ResourceManager::EndFrame()
|
||||||
|
{
|
||||||
|
cmdBuffers[currentBuffer].end();
|
||||||
|
vk::SubmitInfo si = { 0, nullptr, nullptr, 1, &cmdBuffers[currentBuffer], 1, &semaphores[currentBuffer] };
|
||||||
|
transferQueue.submit(1, &si, vk::Fence());
|
||||||
|
return semaphores[currentBuffer];
|
||||||
|
}
|
||||||
|
|
||||||
|
void ResourceManager::Resize()
|
||||||
|
{
|
||||||
|
for (auto shader : shaders)
|
||||||
|
{
|
||||||
|
shader->Resize();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void ResourceManager::PrepareGeometry(Scene::Geometry* geometry)
|
||||||
|
{
|
||||||
|
const std::unique_lock lock(mutex);
|
||||||
|
if(!geometry->renderGeo)
|
||||||
|
{
|
||||||
|
VulkanGeometry* vkGeometry = new VulkanGeometry();
|
||||||
|
ManagedBuffer* vertexBuffer = CreateDeviceOnlyBufferWithData(sizeof(Vertex) * geometry->GetVertexCount(), vk::BufferUsageFlagBits::eVertexBuffer, geometry->GetVertices());
|
||||||
|
ManagedBuffer* indexBuffer = CreateDeviceOnlyBufferWithData(Utils::EnumAsInt(geometry->indexType) * geometry->GetIndexCount(), vk::BufferUsageFlagBits::eIndexBuffer, geometry->GetIndices());
|
||||||
|
vkGeometry->Init(geometry, vertexBuffer->buffer, indexBuffer->buffer);
|
||||||
|
geometry->renderGeo = vkGeometry;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void ResourceManager::PrepareMaterial(Scene::Material* material)
|
||||||
|
{
|
||||||
|
const std::unique_lock lock(mutex);
|
||||||
|
if(!material->shader->renderShader)
|
||||||
|
{
|
||||||
|
material->shader->renderShader = CreateShader(material->shader);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void ResourceManager::PrepareNode(Scene::Node* node)
|
||||||
|
{
|
||||||
|
const std::unique_lock lock(mutex);
|
||||||
|
if (!node->renderNode)
|
||||||
|
{
|
||||||
|
UniformBuffer* uBuffer = new UniformBuffer();
|
||||||
|
ManagedBuffer* buffer;
|
||||||
|
VulkanNode* vkNode;
|
||||||
|
const vk::DeviceSize allocSize = Utils::Align(sizeof(glm::mat4x4), uniformBufferAlignment);
|
||||||
|
if (node->GetUpdateFrequency() != Scene::UpdateFrequency::Never)
|
||||||
|
{
|
||||||
|
vkNode = new VulkanNodeDynamic();
|
||||||
|
uint32_t imgs = context->swapChain.GetImageCount();
|
||||||
|
buffer = CreateBuffer(imgs * allocSize, vk::BufferUsageFlagBits::eUniformBuffer, vk::MemoryPropertyFlagBits::eHostCoherent | vk::MemoryPropertyFlagBits::eHostVisible);
|
||||||
|
buffer->Map();
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
vkNode = new VulkanNode();
|
||||||
|
buffer = CreateDeviceOnlyBufferWithData(sizeof(glm::mat4), vk::BufferUsageFlagBits::eUniformBuffer, &node->worldMat);
|
||||||
|
}
|
||||||
|
uBuffer->Init(buffer, allocSize, &context->pipeline.descriptorSetLayout, context->pipeline.pipelineLayout);
|
||||||
|
vkNode->Init(node, uBuffer);
|
||||||
|
node->renderNode = vkNode;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void ResourceManager::RemoveShader(VulkanShader* shader)
|
||||||
|
{
|
||||||
|
Utils::Remove(shaders, shader);
|
||||||
|
}
|
||||||
|
|
||||||
|
void ResourceManager::FreeBuffer(ManagedBuffer* buffer)
|
||||||
|
{
|
||||||
|
toFree[currentBuffer].push_back(buffer);
|
||||||
|
}
|
||||||
|
|
||||||
|
void ResourceManager::DoFreeBuffer(ManagedBuffer* buffer)
|
||||||
|
{
|
||||||
|
if (buffer->IsLast())
|
||||||
|
{
|
||||||
|
device.destroyBuffer(buffer->buffer);
|
||||||
|
buffer->allocation->used -= buffer->size;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
recycleBuffers.push_back(buffer);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void ResourceManager::FreeBuffers()
|
||||||
|
{
|
||||||
|
for (auto& i : toFree[currentBuffer])
|
||||||
|
{
|
||||||
|
DoFreeBuffer(i);
|
||||||
|
}
|
||||||
|
toFree[currentBuffer].clear();
|
||||||
|
}
|
||||||
|
|
||||||
|
ManagedBuffer* ResourceManager::CreateDeviceOnlyBufferWithData(vk::DeviceSize size, vk::BufferUsageFlagBits usage, void* data)
|
||||||
|
{
|
||||||
|
ManagedBuffer* target = CreateBuffer(size, usage | vk::BufferUsageFlagBits::eTransferDst, vk::MemoryPropertyFlagBits::eDeviceLocal);
|
||||||
|
ManagedBuffer* uploadBuffer = CreateBuffer(size, vk::BufferUsageFlagBits::eTransferSrc, vk::MemoryPropertyFlagBits::eHostCoherent | vk::MemoryPropertyFlagBits::eHostVisible);
|
||||||
|
uploadBuffer->Copy(data, size, 0);
|
||||||
|
RecordCopy(uploadBuffer->buffer, target->buffer, size);
|
||||||
|
FreeBuffer(uploadBuffer);
|
||||||
|
return target;
|
||||||
|
}
|
||||||
|
|
||||||
|
ManagedBuffer* ResourceManager::CreateBuffer(vk::DeviceSize size, const vk::BufferUsageFlags& usage, const vk::MemoryPropertyFlags& properties)
|
||||||
|
{
|
||||||
|
size = Utils::Align(size, 16);
|
||||||
|
const vk::BufferCreateInfo bufferCreateInfo = { {}, size, usage, vk::SharingMode::eExclusive };
|
||||||
|
vk::Buffer buffer = device.createBuffer(bufferCreateInfo);
|
||||||
|
const vk::MemoryRequirements memoryRequirements = device.getBufferMemoryRequirements(buffer);
|
||||||
|
uint32_t memtype = context->device->GetMemoryType(memoryRequirements.memoryTypeBits, properties);
|
||||||
|
if (memoryRequirements.size != size) Logger::DATA->warn("Memory Requirement Size ({0}) != Size ({1})", memoryRequirements.size, size);
|
||||||
|
MemoryAllocation* allocation = GetFreeMemoryAllocation(memoryRequirements.size, memtype);
|
||||||
|
uint32_t offset = allocation->used;
|
||||||
|
device.bindBufferMemory(buffer, allocation->memory, offset);
|
||||||
|
allocation->used += memoryRequirements.size;
|
||||||
|
return new ManagedBuffer{ allocation, offset, size, buffer, usage, properties, nullptr };
|
||||||
|
}
|
||||||
|
|
||||||
|
MemoryAllocation* ResourceManager::CreateMemoryAllocation(size_t size, uint32_t type, bool addToCache)
|
||||||
|
{
|
||||||
|
MemoryAllocation* alloc = new MemoryAllocation(size, type, device);
|
||||||
|
const vk::MemoryAllocateInfo allocInfo = { size, type };
|
||||||
|
alloc->memory = device.allocateMemory(allocInfo);
|
||||||
|
if (addToCache) allocations.push_back(alloc);
|
||||||
|
return alloc;
|
||||||
|
}
|
||||||
|
|
||||||
|
MemoryAllocation* ResourceManager::GetFreeMemoryAllocation(size_t size, uint32_t type, bool createIfAllFull)
|
||||||
|
{
|
||||||
|
MemoryAllocation* alloc = nullptr;
|
||||||
|
for (MemoryAllocation* allocation : allocations)
|
||||||
|
{
|
||||||
|
if (allocation->type == type && allocation->FreeSpace() >= size)
|
||||||
|
{
|
||||||
|
alloc = allocation;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if(!alloc && createIfAllFull) alloc = CreateMemoryAllocation(256 * 1024 * 1024, type, true);
|
||||||
|
if(alloc) lastAllocation = alloc;
|
||||||
|
return alloc;
|
||||||
|
}
|
||||||
|
|
||||||
|
VulkanShader* ResourceManager::CreateShader(Scene::Shader* shader)
|
||||||
|
{
|
||||||
|
VulkanShader* vkShader = new VulkanShader();
|
||||||
|
vkShader->Init(context, shader, this);
|
||||||
|
shaders.push_back(vkShader);
|
||||||
|
return vkShader;
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -7,16 +7,20 @@
|
|||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
#include "vulkan/vulkan.hpp"
|
#include "vulkan/vulkan.hpp"
|
||||||
#include "../Device.hpp"
|
|
||||||
#include "../../Base/ICloseable.hpp"
|
#include "../../Base/ICloseable.hpp"
|
||||||
#include "../Scene/VulkanShader.hpp"
|
|
||||||
#include "IShaderOwner.hpp"
|
#include "IShaderOwner.hpp"
|
||||||
#include "../Scene/VulkanGeometry.hpp"
|
|
||||||
#include "ManagedResource.hpp"
|
#include "ManagedResource.hpp"
|
||||||
#include "../Scene/VulkanNode.hpp"
|
#include <mutex>
|
||||||
|
|
||||||
namespace openVulkanoCpp
|
namespace openVulkanoCpp
|
||||||
{
|
{
|
||||||
|
namespace Scene
|
||||||
|
{
|
||||||
|
class Node;
|
||||||
|
class Geometry;
|
||||||
|
class Material;
|
||||||
|
}
|
||||||
|
|
||||||
namespace Vulkan
|
namespace Vulkan
|
||||||
{
|
{
|
||||||
class ResourceManager : virtual public ICloseable, virtual public IShaderOwner
|
class ResourceManager : virtual public ICloseable, virtual public IShaderOwner
|
||||||
@@ -38,226 +42,50 @@ namespace openVulkanoCpp
|
|||||||
int buffers = -1, currentBuffer = -1;
|
int buffers = -1, currentBuffer = -1;
|
||||||
|
|
||||||
public:
|
public:
|
||||||
ResourceManager() = default;
|
ResourceManager();
|
||||||
virtual ~ResourceManager() { if (device) ResourceManager::Close(); }
|
virtual ~ResourceManager() noexcept;
|
||||||
|
|
||||||
void Init(Context* context, int buffers = 2)
|
void Init(Context* context, int buffers = 2);
|
||||||
{
|
|
||||||
this->context = context;
|
|
||||||
this->device = context->device->device;
|
|
||||||
this->buffers = buffers;
|
|
||||||
|
|
||||||
uniformBufferAlignment = context->device->properties.limits.minUniformBufferOffsetAlignment;
|
void Close() override;
|
||||||
|
|
||||||
cmdPools = new vk::CommandPool[buffers];
|
void StartFrame(uint64_t frameId);
|
||||||
cmdBuffers = new vk::CommandBuffer[buffers];
|
|
||||||
semaphores = new vk::Semaphore[buffers];
|
|
||||||
for (int i = 0; i < buffers; i++)
|
|
||||||
{
|
|
||||||
cmdPools[i] = this->device.createCommandPool({ {}, context->device->queueIndices.transfer });
|
|
||||||
cmdBuffers[i] = this->device.allocateCommandBuffers({ cmdPools[i], vk::CommandBufferLevel::ePrimary, 1 })[0];
|
|
||||||
semaphores[i] = this->device.createSemaphore({});
|
|
||||||
}
|
|
||||||
toFree.resize(buffers);
|
|
||||||
|
|
||||||
transferQueue = this->device.getQueue(context->device->queueIndices.transfer, 0);
|
vk::Semaphore EndFrame();
|
||||||
}
|
|
||||||
|
|
||||||
void Close() override
|
void Resize();
|
||||||
{
|
|
||||||
transferQueue.waitIdle();
|
|
||||||
for (int i = 0; i < buffers; i++)
|
|
||||||
{
|
|
||||||
device.freeCommandBuffers(cmdPools[i], 1, &cmdBuffers[i]);
|
|
||||||
device.destroyCommandPool(cmdPools[0]);
|
|
||||||
}
|
|
||||||
for (auto shader : shaders)
|
|
||||||
{
|
|
||||||
shader->Close();
|
|
||||||
}
|
|
||||||
cmdBuffers = nullptr;
|
|
||||||
cmdPools = nullptr;
|
|
||||||
device = nullptr;
|
|
||||||
}
|
|
||||||
|
|
||||||
void StartFrame(uint64_t frameId)
|
void PrepareGeometry(Scene::Geometry* geometry);
|
||||||
{
|
|
||||||
currentBuffer = frameId;
|
|
||||||
FreeBuffers();
|
|
||||||
device.resetCommandPool(cmdPools[currentBuffer], {});
|
|
||||||
cmdBuffers[currentBuffer].begin({ vk::CommandBufferUsageFlagBits::eOneTimeSubmit });
|
|
||||||
}
|
|
||||||
|
|
||||||
vk::Semaphore EndFrame()
|
void PrepareMaterial(Scene::Material* material);
|
||||||
{
|
|
||||||
cmdBuffers[currentBuffer].end();
|
|
||||||
vk::SubmitInfo si = { 0, nullptr, nullptr, 1, &cmdBuffers[currentBuffer], 1, &semaphores[currentBuffer] };
|
|
||||||
transferQueue.submit(1, &si, vk::Fence());
|
|
||||||
return semaphores[currentBuffer];
|
|
||||||
}
|
|
||||||
|
|
||||||
void Resize()
|
void PrepareNode(Scene::Node* node);
|
||||||
{
|
|
||||||
for (auto shader : shaders)
|
|
||||||
{
|
|
||||||
shader->Resize();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void PrepareGeometry(Scene::Geometry* geometry)
|
void RemoveShader(VulkanShader* shader) override;
|
||||||
{
|
|
||||||
mutex.lock();
|
|
||||||
if(!geometry->renderGeo)
|
|
||||||
{
|
|
||||||
VulkanGeometry* vkGeometry = new VulkanGeometry();
|
|
||||||
ManagedBuffer* vertexBuffer = CreateDeviceOnlyBufferWithData(sizeof(Vertex) * geometry->GetVertexCount(), vk::BufferUsageFlagBits::eVertexBuffer, geometry->GetVertices());
|
|
||||||
ManagedBuffer* indexBuffer = CreateDeviceOnlyBufferWithData(Utils::EnumAsInt(geometry->indexType) * geometry->GetIndexCount(), vk::BufferUsageFlagBits::eIndexBuffer, geometry->GetIndices());
|
|
||||||
vkGeometry->Init(geometry, vertexBuffer->buffer, indexBuffer->buffer);
|
|
||||||
geometry->renderGeo = vkGeometry;
|
|
||||||
}
|
|
||||||
mutex.unlock();
|
|
||||||
}
|
|
||||||
|
|
||||||
void PrepareMaterial(Scene::Material* material)
|
|
||||||
{
|
|
||||||
mutex.lock();
|
|
||||||
if(!material->shader->renderShader)
|
|
||||||
{
|
|
||||||
material->shader->renderShader = CreateShader(material->shader);
|
|
||||||
}
|
|
||||||
mutex.unlock();
|
|
||||||
}
|
|
||||||
|
|
||||||
void PrepareNode(Scene::Node* node)
|
|
||||||
{
|
|
||||||
mutex.lock();
|
|
||||||
if (!node->renderNode)
|
|
||||||
{
|
|
||||||
UniformBuffer* uBuffer = new UniformBuffer();
|
|
||||||
ManagedBuffer* buffer;
|
|
||||||
VulkanNode* vkNode;
|
|
||||||
const vk::DeviceSize allocSize = aligned(sizeof(glm::mat4x4), uniformBufferAlignment);
|
|
||||||
if (node->GetUpdateFrequency() != Scene::UpdateFrequency::Never)
|
|
||||||
{
|
|
||||||
vkNode = new VulkanNodeDynamic();
|
|
||||||
uint32_t imgs = context->swapChain.GetImageCount();
|
|
||||||
buffer = CreateBuffer(imgs * allocSize, vk::BufferUsageFlagBits::eUniformBuffer, vk::MemoryPropertyFlagBits::eHostCoherent | vk::MemoryPropertyFlagBits::eHostVisible);
|
|
||||||
buffer->Map();
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
vkNode = new VulkanNode();
|
|
||||||
buffer = CreateDeviceOnlyBufferWithData(sizeof(glm::mat4), vk::BufferUsageFlagBits::eUniformBuffer, &node->worldMat);
|
|
||||||
}
|
|
||||||
uBuffer->Init(buffer, allocSize, &context->pipeline.descriptorSetLayout, context->pipeline.pipelineLayout);
|
|
||||||
vkNode->Init(node, uBuffer);
|
|
||||||
node->renderNode = vkNode;
|
|
||||||
}
|
|
||||||
mutex.unlock();
|
|
||||||
}
|
|
||||||
|
|
||||||
void RemoveShader(VulkanShader* shader) override
|
|
||||||
{
|
|
||||||
Utils::Remove(shaders, shader);
|
|
||||||
}
|
|
||||||
|
|
||||||
protected: // Allocation management
|
protected: // Allocation management
|
||||||
static vk::DeviceSize aligned(vk::DeviceSize size, vk::DeviceSize byteAlignment)
|
void FreeBuffer(ManagedBuffer* buffer);
|
||||||
{
|
|
||||||
return (size + byteAlignment - 1) & ~(byteAlignment - 1);
|
|
||||||
}
|
|
||||||
|
|
||||||
void FreeBuffer(ManagedBuffer* buffer)
|
void DoFreeBuffer(ManagedBuffer* buffer);
|
||||||
{
|
|
||||||
toFree[currentBuffer].push_back(buffer);
|
|
||||||
}
|
|
||||||
|
|
||||||
void DoFreeBuffer(ManagedBuffer* buffer)
|
void FreeBuffers();
|
||||||
{
|
|
||||||
if (buffer->IsLast())
|
|
||||||
{
|
|
||||||
device.destroyBuffer(buffer->buffer);
|
|
||||||
buffer->allocation->used -= buffer->size;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
recycleBuffers.push_back(buffer);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void FreeBuffers()
|
ManagedBuffer* CreateDeviceOnlyBufferWithData(vk::DeviceSize size, vk::BufferUsageFlagBits usage, void* data);
|
||||||
{
|
|
||||||
for (auto& i : toFree[currentBuffer])
|
|
||||||
{
|
|
||||||
DoFreeBuffer(i);
|
|
||||||
}
|
|
||||||
toFree[currentBuffer].clear();
|
|
||||||
}
|
|
||||||
|
|
||||||
ManagedBuffer* CreateDeviceOnlyBufferWithData(vk::DeviceSize size, vk::BufferUsageFlagBits usage, void* data)
|
inline void RecordCopy(vk::Buffer src, vk::Buffer dest, vk::DeviceSize size) const
|
||||||
{
|
|
||||||
ManagedBuffer* target = CreateBuffer(size, usage | vk::BufferUsageFlagBits::eTransferDst, vk::MemoryPropertyFlagBits::eDeviceLocal);
|
|
||||||
ManagedBuffer* uploadBuffer = CreateBuffer(size, vk::BufferUsageFlagBits::eTransferSrc, vk::MemoryPropertyFlagBits::eHostCoherent | vk::MemoryPropertyFlagBits::eHostVisible);
|
|
||||||
uploadBuffer->Copy(data, size, 0);
|
|
||||||
RecordCopy(uploadBuffer->buffer, target->buffer, size);
|
|
||||||
FreeBuffer(uploadBuffer);
|
|
||||||
return target;
|
|
||||||
}
|
|
||||||
|
|
||||||
void RecordCopy(vk::Buffer src, vk::Buffer dest, vk::DeviceSize size) const
|
|
||||||
{
|
{
|
||||||
vk::BufferCopy copyRegion = { 0, 0, size };
|
vk::BufferCopy copyRegion = { 0, 0, size };
|
||||||
cmdBuffers[currentBuffer].copyBuffer(src, dest, 1, ©Region);
|
cmdBuffers[currentBuffer].copyBuffer(src, dest, 1, ©Region);
|
||||||
}
|
}
|
||||||
|
|
||||||
ManagedBuffer* CreateBuffer(vk::DeviceSize size, const vk::BufferUsageFlags& usage, const vk::MemoryPropertyFlags& properties)
|
ManagedBuffer* CreateBuffer(vk::DeviceSize size, const vk::BufferUsageFlags& usage, const vk::MemoryPropertyFlags& properties);
|
||||||
{
|
|
||||||
size = aligned(size, uniformBufferAlignment);
|
|
||||||
const vk::BufferCreateInfo bufferCreateInfo = { {}, size, usage, vk::SharingMode::eExclusive };
|
|
||||||
vk::Buffer buffer = device.createBuffer(bufferCreateInfo);
|
|
||||||
const vk::MemoryRequirements memoryRequirements = device.getBufferMemoryRequirements(buffer);
|
|
||||||
uint32_t memtype = context->device->GetMemoryType(memoryRequirements.memoryTypeBits, properties);
|
|
||||||
if (memoryRequirements.size != size) Logger::DATA->warn("Memory Requirement Size ({0}) != Size ({1})", memoryRequirements.size, size);
|
|
||||||
MemoryAllocation* allocation = GetFreeMemoryAllocation(memoryRequirements.size, memtype);
|
|
||||||
uint32_t offset = allocation->used;
|
|
||||||
device.bindBufferMemory(buffer, allocation->memory, offset);
|
|
||||||
allocation->used += memoryRequirements.size;
|
|
||||||
return new ManagedBuffer{ allocation, offset, size, buffer, usage, properties, nullptr };
|
|
||||||
}
|
|
||||||
|
|
||||||
MemoryAllocation* CreateMemoryAllocation(size_t size, uint32_t type, bool addToCache = true)
|
MemoryAllocation* CreateMemoryAllocation(size_t size, uint32_t type, bool addToCache = true);
|
||||||
{
|
|
||||||
MemoryAllocation* alloc = new MemoryAllocation(size, type, device);
|
|
||||||
const vk::MemoryAllocateInfo allocInfo = { size, type };
|
|
||||||
alloc->memory = device.allocateMemory(allocInfo);
|
|
||||||
if (addToCache) allocations.push_back(alloc);
|
|
||||||
return alloc;
|
|
||||||
}
|
|
||||||
|
|
||||||
MemoryAllocation* GetFreeMemoryAllocation(size_t size, uint32_t type, bool createIfAllFull = true)
|
MemoryAllocation* GetFreeMemoryAllocation(size_t size, uint32_t type, bool createIfAllFull = true);
|
||||||
{
|
|
||||||
MemoryAllocation* alloc = nullptr;
|
|
||||||
for (MemoryAllocation* allocation : allocations)
|
|
||||||
{
|
|
||||||
if (allocation->type == type && allocation->FreeSpace() >= size)
|
|
||||||
{
|
|
||||||
alloc = allocation;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if(!alloc && createIfAllFull) alloc = CreateMemoryAllocation(256 * 1024 * 1024, type, true);
|
|
||||||
if(alloc) lastAllocation = alloc;
|
|
||||||
return alloc;
|
|
||||||
}
|
|
||||||
|
|
||||||
public:
|
public:
|
||||||
VulkanShader* CreateShader(Scene::Shader* shader)
|
VulkanShader* CreateShader(Scene::Shader* shader);
|
||||||
{
|
|
||||||
VulkanShader* vkShader = new VulkanShader();
|
|
||||||
vkShader->Init(context, shader, this);
|
|
||||||
shaders.push_back(vkShader);
|
|
||||||
return vkShader;
|
|
||||||
}
|
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -6,8 +6,9 @@
|
|||||||
|
|
||||||
#include "VulkanShader.hpp"
|
#include "VulkanShader.hpp"
|
||||||
#include "../Context.hpp"
|
#include "../Context.hpp"
|
||||||
#include "../Device.hpp"
|
|
||||||
#include "../../Scene/Vertex.hpp"
|
#include "../../Scene/Vertex.hpp"
|
||||||
|
#include "../../Scene/Shader.hpp"
|
||||||
|
#include "../Resources/IShaderOwner.hpp"
|
||||||
|
|
||||||
namespace openVulkanoCpp::Vulkan
|
namespace openVulkanoCpp::Vulkan
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -7,14 +7,20 @@
|
|||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
#include <vulkan/vulkan.hpp>
|
#include <vulkan/vulkan.hpp>
|
||||||
#include "../../Scene/Shader.hpp"
|
|
||||||
#include "../../Base/ICloseable.hpp"
|
#include "../../Base/ICloseable.hpp"
|
||||||
#include "../Resources/IShaderOwner.hpp"
|
|
||||||
#include "IRecordable.hpp"
|
#include "IRecordable.hpp"
|
||||||
|
|
||||||
namespace openVulkanoCpp::Vulkan
|
namespace openVulkanoCpp
|
||||||
{
|
{
|
||||||
|
namespace Scene
|
||||||
|
{
|
||||||
|
class Shader;
|
||||||
|
}
|
||||||
|
|
||||||
|
namespace Vulkan
|
||||||
|
{
|
||||||
class Context;
|
class Context;
|
||||||
|
class IShaderOwner;
|
||||||
|
|
||||||
struct VulkanShader final : virtual public ICloseable, virtual public IRecordable
|
struct VulkanShader final : virtual public ICloseable, virtual public IRecordable
|
||||||
{
|
{
|
||||||
@@ -26,7 +32,9 @@ namespace openVulkanoCpp::Vulkan
|
|||||||
Context* context;
|
Context* context;
|
||||||
|
|
||||||
VulkanShader() = default;
|
VulkanShader() = default;
|
||||||
~VulkanShader() override { if (shader) VulkanShader::Close(); }
|
|
||||||
|
~VulkanShader() override
|
||||||
|
{ if (shader) VulkanShader::Close(); }
|
||||||
|
|
||||||
void Init(Context* context, Scene::Shader* shader, IShaderOwner* owner);
|
void Init(Context* context, Scene::Shader* shader, IShaderOwner* owner);
|
||||||
|
|
||||||
@@ -39,5 +47,5 @@ namespace openVulkanoCpp::Vulkan
|
|||||||
private:
|
private:
|
||||||
void BuildPipeline();
|
void BuildPipeline();
|
||||||
};
|
};
|
||||||
|
}
|
||||||
}
|
}
|
||||||
Reference in New Issue
Block a user