diff --git a/SHADE_Engine/src/Graphics/MiddleEnd/Batching/SHBatch.cpp b/SHADE_Engine/src/Graphics/MiddleEnd/Batching/SHBatch.cpp index a68ee7fa..4667d5db 100644 --- a/SHADE_Engine/src/Graphics/MiddleEnd/Batching/SHBatch.cpp +++ b/SHADE_Engine/src/Graphics/MiddleEnd/Batching/SHBatch.cpp @@ -58,6 +58,9 @@ namespace SHADE // Add renderable in subBatch->Renderables.insert(renderable); + // Also add material instance in + referencedMatInstances.insert(renderable->GetMaterial()); + // Mark all as dirty setAllDirtyFlags(); } @@ -67,8 +70,8 @@ namespace SHADE // Check if we have a SubBatch with the same mesh yet auto subBatch = std::find_if(subBatches.begin(), subBatches.end(), [&](const SHSubBatch& batch) { - return batch.Mesh == renderable->Mesh; - }); + return batch.Mesh == renderable->Mesh; + }); // Attempt to remove if it exists if (subBatch == subBatches.end()) @@ -76,6 +79,22 @@ namespace SHADE subBatch->Renderables.erase(renderable); + // Check if other renderables in subBatches contain the same material instance + bool matUnused = true; + for (const auto& subBatch : subBatches) + for (const auto& rend : subBatch.Renderables) + { + if (rend->GetMaterial() == renderable->GetMaterial()) + { + matUnused = false; + break; + } + } + + // Material is no longer in this library, so we remove it + if (matUnused) + referencedMatInstances.erase(renderable->GetMaterial()); + // Mark all as dirty for (bool& dirt : isDirty) dirt = true; @@ -101,7 +120,63 @@ namespace SHADE } } - void SHBatch::UpdateTransformBuffer(uint32_t frameIndex) + void SHBatch::UpdateMaterialBuffer(uint32_t frameIndex) + { + if (frameIndex >= SHGraphicsConstants::NUM_FRAME_BUFFERS) + { + SHLOG_WARNING("[SHBatch] Attempted to update transform buffers with an invalid frame index."); + return; + } + + // Check if there are even material properties to update + if (!matPropsData) + return; + + // Check if any materials have changed + bool hasChanged = false; + for (auto material : referencedMatInstances) + { + if (material->HasChanged()) + { + hasChanged = true; + break; + } + } + + // We need to update all the material buffers if the materials have changed + if (hasChanged) + { + for (auto& dirt : matBufferDirty) + dirt = true; + } + + // Check if this frame's buffer is dirty + if (!matBufferDirty[frameIndex]) + return; + + // Build CPI Buffer + uint32_t nextInstanceIndex = 0; + char* propsCurrPtr = matPropsData.get(); + for (auto& subBatch : subBatches) + for (const SHRenderable* renderable : subBatch.Renderables) + { + + renderable->GetMaterial()->ExportProperties(propsCurrPtr); + propsCurrPtr += singleMatPropSize; + } + + // Transfer to GPU + SHVkUtil::EnsureBufferAndCopyHostVisibleData + ( + device, matPropsBuffer[frameIndex], matPropsData.get(), static_cast(matPropsDataSize), + vk::BufferUsageFlagBits::eStorageBuffer + ); + + // This frame is updated + matBufferDirty[frameIndex] = false; + } + + void SHBatch::UpdateTransformBuffer(uint32_t frameIndex) { if (frameIndex >= SHGraphicsConstants::NUM_FRAME_BUFFERS) { @@ -169,7 +244,6 @@ namespace SHADE vk::ShaderStageFlagBits::eFragment ); const bool EMPTY_MAT_PROPS = !SHADER_INFO; - Byte singleMatPropSize = 0; Byte matPropTotalBytes = 0; if (!EMPTY_MAT_PROPS) { @@ -252,6 +326,9 @@ namespace SHADE } isDirty[frameIndex] = false; + + // Save logical device + this->device = device; } /*---------------------------------------------------------------------------------*/ diff --git a/SHADE_Engine/src/Graphics/MiddleEnd/Batching/SHBatch.h b/SHADE_Engine/src/Graphics/MiddleEnd/Batching/SHBatch.h index a572adca..d40a66ea 100644 --- a/SHADE_Engine/src/Graphics/MiddleEnd/Batching/SHBatch.h +++ b/SHADE_Engine/src/Graphics/MiddleEnd/Batching/SHBatch.h @@ -34,6 +34,7 @@ namespace SHADE class SHMesh; class SHRenderable; class SHVkLogicalDevice; + class SHMaterialInstance; /*---------------------------------------------------------------------------------*/ /* Type Definitions */ @@ -73,6 +74,7 @@ namespace SHADE void Add(const SHRenderable* renderable); void Remove(const SHRenderable* renderable); void Clear(); + void UpdateMaterialBuffer(uint32_t frameIndex); void UpdateTransformBuffer(uint32_t frameIndex); void Build(Handle device, uint32_t frameIndex); void Draw(Handle cmdBuffer, uint32_t frameIndex); @@ -86,8 +88,12 @@ namespace SHADE /*-----------------------------------------------------------------------------*/ /* Data Members */ /*-----------------------------------------------------------------------------*/ + // Resources + Handle device; // Batch Properties Handle pipeline; + std::unordered_set> referencedMatInstances; + std::array matBufferDirty; // Batch Tree std::vector subBatches; std::array isDirty; @@ -96,6 +102,7 @@ namespace SHADE std::vector transformData; std::unique_ptr matPropsData; Byte matPropsDataSize = 0; + Byte singleMatPropSize = 0; bool isCPUBuffersDirty = true; // GPU Buffers std::array, SHGraphicsConstants::NUM_FRAME_BUFFERS> drawDataBuffer; diff --git a/SHADE_Engine/src/Graphics/MiddleEnd/Batching/SHBatcher.cpp b/SHADE_Engine/src/Graphics/MiddleEnd/Batching/SHBatcher.cpp index ecd99a20..c4320aac 100644 --- a/SHADE_Engine/src/Graphics/MiddleEnd/Batching/SHBatcher.cpp +++ b/SHADE_Engine/src/Graphics/MiddleEnd/Batching/SHBatcher.cpp @@ -109,11 +109,11 @@ namespace SHADE superBatches.clear(); } - void SHBatcher::UpdateTransformBuffer(uint32_t frameIndex) -{ + void SHBatcher::UpdateBuffers(uint32_t frameIndex) + { for (auto& batch : superBatches) { - batch->UpdateTransformBuffer(frameIndex); + batch->UpdateBuffers(frameIndex); } } diff --git a/SHADE_Engine/src/Graphics/MiddleEnd/Batching/SHBatcher.h b/SHADE_Engine/src/Graphics/MiddleEnd/Batching/SHBatcher.h index b4fff203..985e8e16 100644 --- a/SHADE_Engine/src/Graphics/MiddleEnd/Batching/SHBatcher.h +++ b/SHADE_Engine/src/Graphics/MiddleEnd/Batching/SHBatcher.h @@ -53,7 +53,7 @@ namespace SHADE void RemoveFromBatch(SHRenderable const* renderable); void FinaliseBatches(Handle device, uint32_t frameIndex); void ClearBatches(); - void UpdateTransformBuffer(uint32_t frameIndex); + void UpdateBuffers(uint32_t frameIndex); void RegisterSuperBatch(Handle superBatch); void DeregisterSuperBatch(Handle superBatch); diff --git a/SHADE_Engine/src/Graphics/MiddleEnd/Batching/SHSuperBatch.cpp b/SHADE_Engine/src/Graphics/MiddleEnd/Batching/SHSuperBatch.cpp index 633d40a9..b0173399 100644 --- a/SHADE_Engine/src/Graphics/MiddleEnd/Batching/SHSuperBatch.cpp +++ b/SHADE_Engine/src/Graphics/MiddleEnd/Batching/SHSuperBatch.cpp @@ -78,10 +78,11 @@ namespace SHADE batches.clear(); } - void SHSuperBatch::UpdateTransformBuffer(uint32_t frameIndex) + void SHSuperBatch::UpdateBuffers(uint32_t frameIndex) { for (auto& batch : batches) { + batch.UpdateMaterialBuffer(frameIndex); batch.UpdateTransformBuffer(frameIndex); } } diff --git a/SHADE_Engine/src/Graphics/MiddleEnd/Batching/SHSuperBatch.h b/SHADE_Engine/src/Graphics/MiddleEnd/Batching/SHSuperBatch.h index 5379ee61..a09fc64e 100644 --- a/SHADE_Engine/src/Graphics/MiddleEnd/Batching/SHSuperBatch.h +++ b/SHADE_Engine/src/Graphics/MiddleEnd/Batching/SHSuperBatch.h @@ -54,8 +54,8 @@ namespace SHADE /*-----------------------------------------------------------------------------*/ void Add(const SHRenderable* renderable) noexcept; void Remove(const SHRenderable* renderable) noexcept; - void Clear() noexcept; - void UpdateTransformBuffer(uint32_t frameIndex); + void Clear() noexcept; + void UpdateBuffers(uint32_t frameIndex); void Build(Handle device, uint32_t frameIndex) noexcept; void Draw(Handle cmdBuffer, uint32_t frameIndex) noexcept; diff --git a/SHADE_Engine/src/Graphics/MiddleEnd/Interface/SHMaterialInstance.cpp b/SHADE_Engine/src/Graphics/MiddleEnd/Interface/SHMaterialInstance.cpp index 57a91941..0e5a61dd 100644 --- a/SHADE_Engine/src/Graphics/MiddleEnd/Interface/SHMaterialInstance.cpp +++ b/SHADE_Engine/src/Graphics/MiddleEnd/Interface/SHMaterialInstance.cpp @@ -38,7 +38,7 @@ namespace SHADE dataStore.reset(); } - void SHMaterialInstance::ExportProperties(void* dest) const + void SHMaterialInstance::ExportProperties(void* dest) { assert(dataStore != nullptr); @@ -62,6 +62,9 @@ namespace SHADE const auto DATA_OFFSET = variable->offset; memcpy(static_cast(dest) + DATA_OFFSET, dataStore.get() + data.StoredDataOffset, data.DataSize); } + + // Data was exported so unflag + dataWasChanged = false; } /*---------------------------------------------------------------------------------*/ diff --git a/SHADE_Engine/src/Graphics/MiddleEnd/Interface/SHMaterialInstance.h b/SHADE_Engine/src/Graphics/MiddleEnd/Interface/SHMaterialInstance.h index db0201b7..5d6c4925 100644 --- a/SHADE_Engine/src/Graphics/MiddleEnd/Interface/SHMaterialInstance.h +++ b/SHADE_Engine/src/Graphics/MiddleEnd/Interface/SHMaterialInstance.h @@ -62,12 +62,13 @@ namespace SHADE template const T& GetProperty(const std::string& key) const; void ResetProperties() noexcept; - void ExportProperties(void* dest) const; + void ExportProperties(void* dest); /*-----------------------------------------------------------------------------*/ /* Getter Functions */ /*-----------------------------------------------------------------------------*/ - Handle GetBaseMaterial() const { return baseMaterial; } + Handle GetBaseMaterial() const noexcept { return baseMaterial; } + bool HasChanged() const noexcept { return dataWasChanged; } private: /*-----------------------------------------------------------------------------*/ @@ -77,6 +78,7 @@ namespace SHADE std::vector overrideData; std::unique_ptr dataStore; size_t dataStoreSize = 0; + bool dataWasChanged = false; /*-----------------------------------------------------------------------------*/ /* Helper Functions */ diff --git a/SHADE_Engine/src/Graphics/MiddleEnd/Interface/SHMaterialInstance.hpp b/SHADE_Engine/src/Graphics/MiddleEnd/Interface/SHMaterialInstance.hpp index 0aead306..b3dc6c3a 100644 --- a/SHADE_Engine/src/Graphics/MiddleEnd/Interface/SHMaterialInstance.hpp +++ b/SHADE_Engine/src/Graphics/MiddleEnd/Interface/SHMaterialInstance.hpp @@ -53,6 +53,9 @@ namespace SHADE // Save the override data information overrideData.emplace_back(std::move(od)); + + // Flag + dataWasChanged = true; } template T& SHMaterialInstance::GetProperty(const std::string& key) diff --git a/SHADE_Engine/src/Graphics/RenderGraph/SHRenderGraph.cpp b/SHADE_Engine/src/Graphics/RenderGraph/SHRenderGraph.cpp index ecf9059c..6070361f 100644 --- a/SHADE_Engine/src/Graphics/RenderGraph/SHRenderGraph.cpp +++ b/SHADE_Engine/src/Graphics/RenderGraph/SHRenderGraph.cpp @@ -348,8 +348,8 @@ namespace SHADE void SHSubpass::Execute(Handle& commandBuffer, uint32_t frameIndex) noexcept { - // Ensure correct transforms are provided - superBatch->UpdateTransformBuffer(frameIndex); + // Ensure updated transforms and materials are provided + superBatch->UpdateBuffers(frameIndex); // Draw all the batches superBatch->Draw(commandBuffer, frameIndex);