Now able to render a cube and fixed numerous behind the scene issues with Vulkan abstractions #47

Merged
Pycorax merged 20 commits from SP3-1-Rendering into main 2022-09-23 23:36:52 +08:00
9 changed files with 158 additions and 109 deletions
Showing only changes of commit 23f0f9f77e - Show all commits

View File

@ -33,6 +33,9 @@ namespace SHADE
{ {
if (!pipeline) if (!pipeline)
throw std::invalid_argument("Attempted to create a SHBatch with an invalid SHPipeline!"); throw std::invalid_argument("Attempted to create a SHBatch with an invalid SHPipeline!");
// Mark all as dirty
setAllDirtyFlags();
} }
void SHBatch::Add(const SHRenderable* renderable) void SHBatch::Add(const SHRenderable* renderable)
@ -52,6 +55,9 @@ namespace SHADE
// Add renderable in // Add renderable in
subBatch->Renderables.insert(renderable); subBatch->Renderables.insert(renderable);
// Mark all as dirty
setAllDirtyFlags();
} }
void SHBatch::Remove(const SHRenderable* renderable) void SHBatch::Remove(const SHRenderable* renderable)
@ -67,6 +73,10 @@ namespace SHADE
return; return;
subBatch->Renderables.erase(renderable); subBatch->Renderables.erase(renderable);
// Mark all as dirty
for (bool& dirt : isDirty)
dirt = true;
} }
void SHBatch::Clear() void SHBatch::Clear()
@ -81,13 +91,22 @@ namespace SHADE
// Clear GPU buffers // Clear GPU buffers
drawDataBuffer.Free(); for (int i = 0; i < SHGraphicsConstants::NUM_FRAME_BUFFERS; ++i)
transformDataBuffer.Free(); {
matPropsBuffer.Free(); drawDataBuffer[i].Free();
transformDataBuffer[i].Free();
matPropsBuffer[i].Free();
}
} }
void SHBatch::UpdateTransformBuffer() void SHBatch::UpdateTransformBuffer(uint32_t frameIndex)
{ {
if (frameIndex >= SHGraphicsConstants::NUM_FRAME_BUFFERS)
{
SHLOG_WARNING("[SHBatch] Attempted to update transform buffers with an invalid frame index.");
return;
}
// Reset Transform Data // Reset Transform Data
transformData.clear(); transformData.clear();
@ -100,13 +119,19 @@ namespace SHADE
} }
// Transfer to GPU // Transfer to GPU
transformDataBuffer->WriteToMemory(transformData.data(), transformData.size() * sizeof(SHMatrix), 0, 0); transformDataBuffer[frameIndex]->WriteToMemory(transformData.data(), transformData.size() * sizeof(SHMatrix), 0, 0);
} }
void SHBatch::Build(Handle<SHVkLogicalDevice> device) void SHBatch::Build(Handle<SHVkLogicalDevice> device, uint32_t frameIndex)
{ {
if (frameIndex >= SHGraphicsConstants::NUM_FRAME_BUFFERS)
{
SHLOG_WARNING("[SHBatch] Attempted to update build batch buffers with an invalid frame index.");
return;
}
// No need to build as there are no changes // No need to build as there are no changes
if (!isDirty) if (!isDirty[frameIndex])
return; return;
// Count number of elements // Count number of elements
@ -116,61 +141,67 @@ namespace SHADE
numTotalElements += subBatch.Renderables.size(); numTotalElements += subBatch.Renderables.size();
} }
// Generate CPU buffers // Generate CPU buffers if there are changes
// - Draw data if (isCPUBuffersDirty)
drawData.reserve(subBatches.size());
drawData.clear();
// - Transform data
transformData.reserve(numTotalElements);
transformData.clear();
// - Material Properties Data
const Handle<SHShaderBlockInterface> SHADER_INFO = pipeline->GetPipelineLayout()->GetShaderBlockInterface
(
SHGraphicsConstants::DescriptorSetIndex::PER_INSTANCE,
SHGraphicsConstants::DescriptorSetBindings::BATCHED_PER_INST_DATA,
vk::ShaderStageFlagBits::eFragment
);
const bool EMPTY_MAT_PROPS = !SHADER_INFO;
Byte singleMatPropSize = 0;
Byte matPropTotalBytes = 0;
if (!EMPTY_MAT_PROPS)
{ {
singleMatPropSize = SHADER_INFO->GetBytesRequired(); // - Draw data
matPropTotalBytes = drawData.size() * singleMatPropSize; drawData.reserve(subBatches.size());
if (matPropsDataSize < matPropTotalBytes) drawData.clear();
// - Transform data
transformData.reserve(numTotalElements);
transformData.clear();
// - Material Properties Data
const Handle<SHShaderBlockInterface> SHADER_INFO = pipeline->GetPipelineLayout()->GetShaderBlockInterface
(
SHGraphicsConstants::DescriptorSetIndex::PER_INSTANCE,
SHGraphicsConstants::DescriptorSetBindings::BATCHED_PER_INST_DATA,
vk::ShaderStageFlagBits::eFragment
);
const bool EMPTY_MAT_PROPS = !SHADER_INFO;
Byte singleMatPropSize = 0;
Byte matPropTotalBytes = 0;
if (!EMPTY_MAT_PROPS)
{ {
matPropsData.reset(new char[matPropTotalBytes]); singleMatPropSize = SHADER_INFO->GetBytesRequired();
matPropsDataSize = matPropTotalBytes; matPropTotalBytes = drawData.size() * singleMatPropSize;
} if (matPropsDataSize < matPropTotalBytes)
}
// Build Sub Batches
uint32_t nextInstanceIndex = 0;
char* propsCurrPtr = matPropsData.get();
for (auto& subBatch : subBatches)
{
// Create command
drawData.emplace_back(vk::DrawIndexedIndirectCommand
{
.indexCount = subBatch.Mesh->IndexCount,
.instanceCount = static_cast<uint32_t>(subBatch.Renderables.size()),
.firstIndex = subBatch.Mesh->FirstIndex,
.vertexOffset = subBatch.Mesh->FirstVertex,
.firstInstance = nextInstanceIndex
});
// Fill in buffers (CPU)
for (const SHRenderable* renderable : subBatch.Renderables)
{
// Transform
transformData.emplace_back(renderable->TransformMatrix);
// Material Properties
if (!EMPTY_MAT_PROPS)
{ {
renderable->GetMaterial()->ExportProperties(propsCurrPtr); matPropsData.reset(new char[matPropTotalBytes]);
propsCurrPtr += singleMatPropSize; matPropsDataSize = matPropTotalBytes;
} }
} }
// Build Sub Batches
uint32_t nextInstanceIndex = 0;
char* propsCurrPtr = matPropsData.get();
for (auto& subBatch : subBatches)
{
// Create command
drawData.emplace_back(vk::DrawIndexedIndirectCommand
{
.indexCount = subBatch.Mesh->IndexCount,
.instanceCount = static_cast<uint32_t>(subBatch.Renderables.size()),
.firstIndex = subBatch.Mesh->FirstIndex,
.vertexOffset = subBatch.Mesh->FirstVertex,
.firstInstance = nextInstanceIndex
});
// Fill in buffers (CPU)
for (const SHRenderable* renderable : subBatch.Renderables)
{
// Transform
transformData.emplace_back(renderable->TransformMatrix);
// Material Properties
if (!EMPTY_MAT_PROPS)
{
renderable->GetMaterial()->ExportProperties(propsCurrPtr);
propsCurrPtr += singleMatPropSize;
}
}
}
// Successfully update CPU buffers
isCPUBuffersDirty = false;
} }
// Send all buffered data to the GPU buffers // Send all buffered data to the GPU buffers
@ -179,36 +210,52 @@ namespace SHADE
const uint32_t DRAW_DATA_BYTES = static_cast<uint32_t>(drawData.size() * sizeof(vk::DrawIndexedIndirectCommand)); const uint32_t DRAW_DATA_BYTES = static_cast<uint32_t>(drawData.size() * sizeof(vk::DrawIndexedIndirectCommand));
SHVkUtil::EnsureBufferAndCopyHostVisibleData SHVkUtil::EnsureBufferAndCopyHostVisibleData
( (
device, drawDataBuffer, drawData.data(), DRAW_DATA_BYTES, device, drawDataBuffer[frameIndex], drawData.data(), DRAW_DATA_BYTES,
BuffUsage::eIndirectBuffer BuffUsage::eIndirectBuffer
); );
// - Transform Buffer // - Transform Buffer
const uint32_t TF_DATA_BYTES = static_cast<uint32_t>(transformData.size() * sizeof(SHMatrix)); const uint32_t TF_DATA_BYTES = static_cast<uint32_t>(transformData.size() * sizeof(SHMatrix));
SHVkUtil::EnsureBufferAndCopyHostVisibleData SHVkUtil::EnsureBufferAndCopyHostVisibleData
( (
device, transformDataBuffer, transformData.data(), TF_DATA_BYTES, device, transformDataBuffer[frameIndex], transformData.data(), TF_DATA_BYTES,
BuffUsage::eVertexBuffer BuffUsage::eVertexBuffer
); );
// - Material Properties Buffer // - Material Properties Buffer
if (!EMPTY_MAT_PROPS) if (matPropsData)
{ {
SHVkUtil::EnsureBufferAndCopyHostVisibleData SHVkUtil::EnsureBufferAndCopyHostVisibleData
( (
device, matPropsBuffer, matPropsData.get(), static_cast<uint32_t>(matPropTotalBytes), device, matPropsBuffer[frameIndex], matPropsData.get(), static_cast<uint32_t>(matPropsDataSize),
BuffUsage::eStorageBuffer BuffUsage::eStorageBuffer
); );
} }
isDirty = false; isDirty[frameIndex] = false;
} }
/*---------------------------------------------------------------------------------*/ /*---------------------------------------------------------------------------------*/
/* SHBatch - Usage Functions */ /* SHBatch - Usage Functions */
/*---------------------------------------------------------------------------------*/ /*---------------------------------------------------------------------------------*/
void SHBatch::Draw(Handle<SHVkCommandBuffer> cmdBuffer) void SHBatch::Draw(Handle<SHVkCommandBuffer> cmdBuffer, uint32_t frameIndex)
{ {
if (frameIndex >= SHGraphicsConstants::NUM_FRAME_BUFFERS)
{
SHLOG_WARNING("[SHBatch] Attempted to draw a batch with an invalid frame index.");
return;
}
cmdBuffer->BindPipeline(pipeline); cmdBuffer->BindPipeline(pipeline);
cmdBuffer->BindVertexBuffer(SHGraphicsConstants::VertexBufferBindings::TRANSFORM, transformDataBuffer, 0); cmdBuffer->BindVertexBuffer(SHGraphicsConstants::VertexBufferBindings::TRANSFORM, transformDataBuffer[frameIndex], 0);
cmdBuffer->DrawMultiIndirect(drawDataBuffer, static_cast<uint32_t>(drawData.size())); cmdBuffer->DrawMultiIndirect(drawDataBuffer[frameIndex], static_cast<uint32_t>(drawData.size()));
}
/*---------------------------------------------------------------------------------*/
/* SHBatch - Helper Functions */
/*---------------------------------------------------------------------------------*/
void SHBatch::setAllDirtyFlags()
{
for (bool& dirt : isDirty)
dirt = true;
isCPUBuffersDirty = true;
} }
} }

View File

@ -14,12 +14,14 @@ of DigiPen Institute of Technology is prohibited.
// STL Includes // STL Includes
#include <unordered_set> #include <unordered_set>
#include <array>
// External Dependencies // External Dependencies
#include "Graphics/SHVulkanIncludes.h" #include "Graphics/SHVulkanIncludes.h"
// Project Includes // Project Includes
#include "Resource/Handle.h" #include "Resource/Handle.h"
#include "Graphics/MiddleEnd/Interface/SHMaterial.h" #include "Graphics/MiddleEnd/Interface/SHMaterial.h"
#include "Math/SHMatrix.h" #include "Math/SHMatrix.h"
#include "Graphics/MiddleEnd/Interface/SHGraphicsConstants.h"
namespace SHADE namespace SHADE
{ {
@ -71,9 +73,9 @@ namespace SHADE
void Add(const SHRenderable* renderable); void Add(const SHRenderable* renderable);
void Remove(const SHRenderable* renderable); void Remove(const SHRenderable* renderable);
void Clear(); void Clear();
void UpdateTransformBuffer(); void UpdateTransformBuffer(uint32_t frameIndex);
void Build(Handle<SHVkLogicalDevice> device); void Build(Handle<SHVkLogicalDevice> device, uint32_t frameIndex);
void Draw(Handle<SHVkCommandBuffer> cmdBuffer); void Draw(Handle<SHVkCommandBuffer> cmdBuffer, uint32_t frameIndex);
/*-----------------------------------------------------------------------------*/ /*-----------------------------------------------------------------------------*/
/* Getter Functions */ /* Getter Functions */
@ -88,15 +90,21 @@ namespace SHADE
Handle<SHVkPipeline> pipeline; Handle<SHVkPipeline> pipeline;
// Batch Tree // Batch Tree
std::vector<SHSubBatch> subBatches; std::vector<SHSubBatch> subBatches;
bool isDirty = true; std::array<bool, SHGraphicsConstants::NUM_FRAME_BUFFERS> isDirty;
// CPU Buffers // CPU Buffers
std::vector<vk::DrawIndexedIndirectCommand> drawData; std::vector<vk::DrawIndexedIndirectCommand> drawData;
std::vector<SHMatrix> transformData; std::vector<SHMatrix> transformData;
std::unique_ptr<char> matPropsData; std::unique_ptr<char> matPropsData;
Byte matPropsDataSize = 0; Byte matPropsDataSize = 0;
bool isCPUBuffersDirty = true;
// GPU Buffers // GPU Buffers
Handle<SHVkBuffer> drawDataBuffer; std::array<Handle<SHVkBuffer>, SHGraphicsConstants::NUM_FRAME_BUFFERS> drawDataBuffer;
Handle<SHVkBuffer> transformDataBuffer; std::array<Handle<SHVkBuffer>, SHGraphicsConstants::NUM_FRAME_BUFFERS> transformDataBuffer;
Handle<SHVkBuffer> matPropsBuffer; std::array<Handle<SHVkBuffer>, SHGraphicsConstants::NUM_FRAME_BUFFERS> matPropsBuffer;
/*-----------------------------------------------------------------------------*/
/* Helper Functions */
/*-----------------------------------------------------------------------------*/
void setAllDirtyFlags();
}; };
} }

View File

@ -91,12 +91,12 @@ namespace SHADE
(*superBatch)->Remove(renderable); (*superBatch)->Remove(renderable);
} }
void SHBatcher::FinaliseBatches(Handle<SHVkLogicalDevice> device) void SHBatcher::FinaliseBatches(Handle<SHVkLogicalDevice> device, uint32_t frameIndex)
{ {
// Build SuperBatches // Build SuperBatches
for (auto& batch : superBatches) for (auto& batch : superBatches)
{ {
batch->Build(device); batch->Build(device, frameIndex);
} }
} }
@ -109,11 +109,11 @@ namespace SHADE
superBatches.clear(); superBatches.clear();
} }
void SHBatcher::UpdateTransformBuffer() void SHBatcher::UpdateTransformBuffer(uint32_t frameIndex)
{ {
for (auto& batch : superBatches) for (auto& batch : superBatches)
{ {
batch->UpdateTransformBuffer(); batch->UpdateTransformBuffer(frameIndex);
} }
} }

View File

@ -51,9 +51,9 @@ namespace SHADE
void PrepareBatches(); void PrepareBatches();
void AddToBatch(SHRenderable const* renderable); void AddToBatch(SHRenderable const* renderable);
void RemoveFromBatch(SHRenderable const* renderable); void RemoveFromBatch(SHRenderable const* renderable);
void FinaliseBatches(Handle<SHVkLogicalDevice> device); void FinaliseBatches(Handle<SHVkLogicalDevice> device, uint32_t frameIndex);
void ClearBatches(); void ClearBatches();
void UpdateTransformBuffer(); void UpdateTransformBuffer(uint32_t frameIndex);
void RegisterSuperBatch(Handle<SHSuperBatch> superBatch); void RegisterSuperBatch(Handle<SHSuperBatch> superBatch);
void DeregisterSuperBatch(Handle<SHSuperBatch> superBatch); void DeregisterSuperBatch(Handle<SHSuperBatch> superBatch);

View File

@ -78,29 +78,29 @@ namespace SHADE
batches.clear(); batches.clear();
} }
void SHSuperBatch::UpdateTransformBuffer() void SHSuperBatch::UpdateTransformBuffer(uint32_t frameIndex)
{ {
for (auto& batch : batches) for (auto& batch : batches)
{ {
batch.UpdateTransformBuffer(); batch.UpdateTransformBuffer(frameIndex);
} }
} }
void SHSuperBatch::Build(Handle<SHVkLogicalDevice> device) noexcept void SHSuperBatch::Build(Handle<SHVkLogicalDevice> device, uint32_t frameIndex) noexcept
{ {
// Build all batches // Build all batches
for (auto& batch : batches) for (auto& batch : batches)
{ {
batch.Build(device); batch.Build(device, frameIndex);
} }
} }
void SHSuperBatch::Draw(Handle<SHVkCommandBuffer> cmdBuffer) noexcept void SHSuperBatch::Draw(Handle<SHVkCommandBuffer> cmdBuffer, uint32_t frameIndex) noexcept
{ {
// Build all batches // Build all batches
for (auto& batch : batches) for (auto& batch : batches)
{ {
batch.Draw(cmdBuffer); batch.Draw(cmdBuffer, frameIndex);
} }
} }

View File

@ -55,9 +55,9 @@ namespace SHADE
void Add(const SHRenderable* renderable) noexcept; void Add(const SHRenderable* renderable) noexcept;
void Remove(const SHRenderable* renderable) noexcept; void Remove(const SHRenderable* renderable) noexcept;
void Clear() noexcept; void Clear() noexcept;
void UpdateTransformBuffer(); void UpdateTransformBuffer(uint32_t frameIndex);
void Build(Handle<SHVkLogicalDevice> device) noexcept; void Build(Handle<SHVkLogicalDevice> device, uint32_t frameIndex) noexcept;
void Draw(Handle<SHVkCommandBuffer> cmdBuffer) noexcept; void Draw(Handle<SHVkCommandBuffer> cmdBuffer, uint32_t frameIndex) noexcept;
/*-----------------------------------------------------------------------------*/ /*-----------------------------------------------------------------------------*/
/* Getter Functions */ /* Getter Functions */

View File

@ -306,7 +306,7 @@ namespace SHADE
for (auto vp : viewports) for (auto vp : viewports)
for (auto renderer : vp->GetRenderers()) for (auto renderer : vp->GetRenderers())
{ {
renderer->GetRenderGraph()->FinaliseBatch(); renderer->GetRenderGraph()->FinaliseBatch(renderContext.GetCurrentFrame());
} }
// Resize // Resize

View File

@ -346,13 +346,13 @@ namespace SHADE
inputReferences.push_back({ resourceAttachmentMapping->at(ptrToResources->at(resourceToReference).GetId().Raw), vk::ImageLayout::eShaderReadOnlyOptimal }); inputReferences.push_back({ resourceAttachmentMapping->at(ptrToResources->at(resourceToReference).GetId().Raw), vk::ImageLayout::eShaderReadOnlyOptimal });
} }
void SHSubpass::Execute(Handle<SHVkCommandBuffer>& commandBuffer) noexcept void SHSubpass::Execute(Handle<SHVkCommandBuffer>& commandBuffer, uint32_t frameIndex) noexcept
{ {
// Ensure correct transforms are provided // Ensure correct transforms are provided
superBatch->UpdateTransformBuffer(); superBatch->UpdateTransformBuffer(frameIndex);
// Draw all the batches // Draw all the batches
superBatch->Draw(commandBuffer); superBatch->Draw(commandBuffer, frameIndex);
// Draw all the exterior draw calls // Draw all the exterior draw calls
for (auto& drawCall : exteriorDrawCalls) for (auto& drawCall : exteriorDrawCalls)
@ -591,7 +591,7 @@ namespace SHADE
for (uint32_t i = 0; i < subpasses.size(); ++i) for (uint32_t i = 0; i < subpasses.size(); ++i)
{ {
subpasses[i]->Execute(commandBuffer); subpasses[i]->Execute(commandBuffer, frameIndex);
// Go to next subpass if not last subpass // Go to next subpass if not last subpass
if (i != subpasses.size() - 1) if (i != subpasses.size() - 1)
@ -624,14 +624,9 @@ namespace SHADE
return pipeline; return pipeline;
} }
void SHRenderGraphNode::FinaliseBatch() void SHRenderGraphNode::FinaliseBatch(uint32_t frameIndex)
{ {
batcher.FinaliseBatches(logicalDeviceHdl); batcher.FinaliseBatches(logicalDeviceHdl, frameIndex);
}
void SHRenderGraphNode::UpdateBatchTransforms()
{
batcher.UpdateTransformBuffer();
} }
/***************************************************************************/ /***************************************************************************/
@ -1088,11 +1083,11 @@ namespace SHADE
node->Execute(cmdBuffer, frameIndex); node->Execute(cmdBuffer, frameIndex);
} }
void SHRenderGraph::FinaliseBatch() void SHRenderGraph::FinaliseBatch(uint32_t frameIndex)
{ {
for (auto& node : nodes) for (auto& node : nodes)
{ {
node->FinaliseBatch(); node->FinaliseBatch(frameIndex);
} }
} }

View File

@ -137,7 +137,7 @@ namespace SHADE
void AddInput(std::string resourceToReference) noexcept; void AddInput(std::string resourceToReference) noexcept;
// Runtime functions // Runtime functions
void Execute(Handle<SHVkCommandBuffer>& commandBuffer) noexcept; void Execute(Handle<SHVkCommandBuffer>& commandBuffer, uint32_t frameIndex) noexcept;
void AddExteriorDrawCalls(std::function<void(Handle<SHVkCommandBuffer>&)> const& newDrawCall) noexcept; void AddExteriorDrawCalls(std::function<void(Handle<SHVkCommandBuffer>&)> const& newDrawCall) noexcept;
/*-----------------------------------------------------------------------*/ /*-----------------------------------------------------------------------*/
@ -230,8 +230,7 @@ namespace SHADE
// TODO: RemoveSubpass() // TODO: RemoveSubpass()
void Execute (Handle<SHVkCommandBuffer>& commandBuffer, uint32_t frameIndex) noexcept; void Execute (Handle<SHVkCommandBuffer>& commandBuffer, uint32_t frameIndex) noexcept;
Handle<SHVkPipeline> GetOrCreatePipeline (std::pair<Handle<SHVkShaderModule>, Handle<SHVkShaderModule>> const& vsFsPair, Handle<SHSubpass> subpass) noexcept; Handle<SHVkPipeline> GetOrCreatePipeline (std::pair<Handle<SHVkShaderModule>, Handle<SHVkShaderModule>> const& vsFsPair, Handle<SHSubpass> subpass) noexcept;
void FinaliseBatch(); void FinaliseBatch(uint32_t frameIndex);
void UpdateBatchTransforms();
/*-----------------------------------------------------------------------*/ /*-----------------------------------------------------------------------*/
/* SETTERS AND GETTERS */ /* SETTERS AND GETTERS */
@ -289,7 +288,7 @@ namespace SHADE
Handle<SHRenderGraphNode> AddNode (std::string nodeName, std::initializer_list<std::string> resourceNames, std::initializer_list<std::string> predecessorNodes) noexcept; Handle<SHRenderGraphNode> AddNode (std::string nodeName, std::initializer_list<std::string> resourceNames, std::initializer_list<std::string> predecessorNodes) noexcept;
void Generate (void) noexcept; void Generate (void) noexcept;
void Execute (uint32_t frameIndex, Handle<SHVkCommandBuffer> cmdBuffer) noexcept; void Execute (uint32_t frameIndex, Handle<SHVkCommandBuffer> cmdBuffer) noexcept;
void FinaliseBatch(); void FinaliseBatch(uint32_t frameIndex);
/*-----------------------------------------------------------------------*/ /*-----------------------------------------------------------------------*/
/* SETTERS AND GETTERS */ /* SETTERS AND GETTERS */