Material data on the GPU is now updated when material data changes

This commit is contained in:
Kah Wei 2022-09-24 02:07:47 +08:00
parent 32278e1564
commit 759c87e2a1
10 changed files with 109 additions and 16 deletions

View File

@ -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<uint32_t>(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;
}
/*---------------------------------------------------------------------------------*/

View File

@ -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<SHVkLogicalDevice> device, uint32_t frameIndex);
void Draw(Handle<SHVkCommandBuffer> cmdBuffer, uint32_t frameIndex);
@ -86,8 +88,12 @@ namespace SHADE
/*-----------------------------------------------------------------------------*/
/* Data Members */
/*-----------------------------------------------------------------------------*/
// Resources
Handle<SHVkLogicalDevice> device;
// Batch Properties
Handle<SHVkPipeline> pipeline;
std::unordered_set<Handle<SHMaterialInstance>> referencedMatInstances;
std::array<bool, SHGraphicsConstants::NUM_FRAME_BUFFERS> matBufferDirty;
// Batch Tree
std::vector<SHSubBatch> subBatches;
std::array<bool, SHGraphicsConstants::NUM_FRAME_BUFFERS> isDirty;
@ -96,6 +102,7 @@ namespace SHADE
std::vector<SHMatrix> transformData;
std::unique_ptr<char> matPropsData;
Byte matPropsDataSize = 0;
Byte singleMatPropSize = 0;
bool isCPUBuffersDirty = true;
// GPU Buffers
std::array<Handle<SHVkBuffer>, SHGraphicsConstants::NUM_FRAME_BUFFERS> drawDataBuffer;

View File

@ -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);
}
}

View File

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

View File

@ -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);
}
}

View File

@ -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<SHVkLogicalDevice> device, uint32_t frameIndex) noexcept;
void Draw(Handle<SHVkCommandBuffer> cmdBuffer, uint32_t frameIndex) noexcept;

View File

@ -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<char*>(dest) + DATA_OFFSET, dataStore.get() + data.StoredDataOffset, data.DataSize);
}
// Data was exported so unflag
dataWasChanged = false;
}
/*---------------------------------------------------------------------------------*/

View File

@ -62,12 +62,13 @@ namespace SHADE
template<typename T>
const T& GetProperty(const std::string& key) const;
void ResetProperties() noexcept;
void ExportProperties(void* dest) const;
void ExportProperties(void* dest);
/*-----------------------------------------------------------------------------*/
/* Getter Functions */
/*-----------------------------------------------------------------------------*/
Handle<SHMaterial> GetBaseMaterial() const { return baseMaterial; }
Handle<SHMaterial> GetBaseMaterial() const noexcept { return baseMaterial; }
bool HasChanged() const noexcept { return dataWasChanged; }
private:
/*-----------------------------------------------------------------------------*/
@ -77,6 +78,7 @@ namespace SHADE
std::vector<OverrideData> overrideData;
std::unique_ptr<char> dataStore;
size_t dataStoreSize = 0;
bool dataWasChanged = false;
/*-----------------------------------------------------------------------------*/
/* Helper Functions */

View File

@ -53,6 +53,9 @@ namespace SHADE
// Save the override data information
overrideData.emplace_back(std::move(od));
// Flag
dataWasChanged = true;
}
template<typename T>
T& SHMaterialInstance::GetProperty(const std::string& key)

View File

@ -348,8 +348,8 @@ namespace SHADE
void SHSubpass::Execute(Handle<SHVkCommandBuffer>& 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);