Material data on the GPU is now updated when material data changes
This commit is contained in:
parent
32278e1564
commit
759c87e2a1
|
@ -58,6 +58,9 @@ namespace SHADE
|
||||||
// Add renderable in
|
// Add renderable in
|
||||||
subBatch->Renderables.insert(renderable);
|
subBatch->Renderables.insert(renderable);
|
||||||
|
|
||||||
|
// Also add material instance in
|
||||||
|
referencedMatInstances.insert(renderable->GetMaterial());
|
||||||
|
|
||||||
// Mark all as dirty
|
// Mark all as dirty
|
||||||
setAllDirtyFlags();
|
setAllDirtyFlags();
|
||||||
}
|
}
|
||||||
|
@ -76,6 +79,22 @@ namespace SHADE
|
||||||
|
|
||||||
subBatch->Renderables.erase(renderable);
|
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
|
// Mark all as dirty
|
||||||
for (bool& dirt : isDirty)
|
for (bool& dirt : isDirty)
|
||||||
dirt = true;
|
dirt = true;
|
||||||
|
@ -101,6 +120,62 @@ namespace SHADE
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
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)
|
void SHBatch::UpdateTransformBuffer(uint32_t frameIndex)
|
||||||
{
|
{
|
||||||
if (frameIndex >= SHGraphicsConstants::NUM_FRAME_BUFFERS)
|
if (frameIndex >= SHGraphicsConstants::NUM_FRAME_BUFFERS)
|
||||||
|
@ -169,7 +244,6 @@ namespace SHADE
|
||||||
vk::ShaderStageFlagBits::eFragment
|
vk::ShaderStageFlagBits::eFragment
|
||||||
);
|
);
|
||||||
const bool EMPTY_MAT_PROPS = !SHADER_INFO;
|
const bool EMPTY_MAT_PROPS = !SHADER_INFO;
|
||||||
Byte singleMatPropSize = 0;
|
|
||||||
Byte matPropTotalBytes = 0;
|
Byte matPropTotalBytes = 0;
|
||||||
if (!EMPTY_MAT_PROPS)
|
if (!EMPTY_MAT_PROPS)
|
||||||
{
|
{
|
||||||
|
@ -252,6 +326,9 @@ namespace SHADE
|
||||||
}
|
}
|
||||||
|
|
||||||
isDirty[frameIndex] = false;
|
isDirty[frameIndex] = false;
|
||||||
|
|
||||||
|
// Save logical device
|
||||||
|
this->device = device;
|
||||||
}
|
}
|
||||||
|
|
||||||
/*---------------------------------------------------------------------------------*/
|
/*---------------------------------------------------------------------------------*/
|
||||||
|
|
|
@ -34,6 +34,7 @@ namespace SHADE
|
||||||
class SHMesh;
|
class SHMesh;
|
||||||
class SHRenderable;
|
class SHRenderable;
|
||||||
class SHVkLogicalDevice;
|
class SHVkLogicalDevice;
|
||||||
|
class SHMaterialInstance;
|
||||||
|
|
||||||
/*---------------------------------------------------------------------------------*/
|
/*---------------------------------------------------------------------------------*/
|
||||||
/* Type Definitions */
|
/* Type Definitions */
|
||||||
|
@ -73,6 +74,7 @@ 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 UpdateMaterialBuffer(uint32_t frameIndex);
|
||||||
void UpdateTransformBuffer(uint32_t frameIndex);
|
void UpdateTransformBuffer(uint32_t frameIndex);
|
||||||
void Build(Handle<SHVkLogicalDevice> device, uint32_t frameIndex);
|
void Build(Handle<SHVkLogicalDevice> device, uint32_t frameIndex);
|
||||||
void Draw(Handle<SHVkCommandBuffer> cmdBuffer, uint32_t frameIndex);
|
void Draw(Handle<SHVkCommandBuffer> cmdBuffer, uint32_t frameIndex);
|
||||||
|
@ -86,8 +88,12 @@ namespace SHADE
|
||||||
/*-----------------------------------------------------------------------------*/
|
/*-----------------------------------------------------------------------------*/
|
||||||
/* Data Members */
|
/* Data Members */
|
||||||
/*-----------------------------------------------------------------------------*/
|
/*-----------------------------------------------------------------------------*/
|
||||||
|
// Resources
|
||||||
|
Handle<SHVkLogicalDevice> device;
|
||||||
// Batch Properties
|
// Batch Properties
|
||||||
Handle<SHVkPipeline> pipeline;
|
Handle<SHVkPipeline> pipeline;
|
||||||
|
std::unordered_set<Handle<SHMaterialInstance>> referencedMatInstances;
|
||||||
|
std::array<bool, SHGraphicsConstants::NUM_FRAME_BUFFERS> matBufferDirty;
|
||||||
// Batch Tree
|
// Batch Tree
|
||||||
std::vector<SHSubBatch> subBatches;
|
std::vector<SHSubBatch> subBatches;
|
||||||
std::array<bool, SHGraphicsConstants::NUM_FRAME_BUFFERS> isDirty;
|
std::array<bool, SHGraphicsConstants::NUM_FRAME_BUFFERS> isDirty;
|
||||||
|
@ -96,6 +102,7 @@ namespace SHADE
|
||||||
std::vector<SHMatrix> transformData;
|
std::vector<SHMatrix> transformData;
|
||||||
std::unique_ptr<char> matPropsData;
|
std::unique_ptr<char> matPropsData;
|
||||||
Byte matPropsDataSize = 0;
|
Byte matPropsDataSize = 0;
|
||||||
|
Byte singleMatPropSize = 0;
|
||||||
bool isCPUBuffersDirty = true;
|
bool isCPUBuffersDirty = true;
|
||||||
// GPU Buffers
|
// GPU Buffers
|
||||||
std::array<Handle<SHVkBuffer>, SHGraphicsConstants::NUM_FRAME_BUFFERS> drawDataBuffer;
|
std::array<Handle<SHVkBuffer>, SHGraphicsConstants::NUM_FRAME_BUFFERS> drawDataBuffer;
|
||||||
|
|
|
@ -109,11 +109,11 @@ namespace SHADE
|
||||||
superBatches.clear();
|
superBatches.clear();
|
||||||
}
|
}
|
||||||
|
|
||||||
void SHBatcher::UpdateTransformBuffer(uint32_t frameIndex)
|
void SHBatcher::UpdateBuffers(uint32_t frameIndex)
|
||||||
{
|
{
|
||||||
for (auto& batch : superBatches)
|
for (auto& batch : superBatches)
|
||||||
{
|
{
|
||||||
batch->UpdateTransformBuffer(frameIndex);
|
batch->UpdateBuffers(frameIndex);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -53,7 +53,7 @@ namespace SHADE
|
||||||
void RemoveFromBatch(SHRenderable const* renderable);
|
void RemoveFromBatch(SHRenderable const* renderable);
|
||||||
void FinaliseBatches(Handle<SHVkLogicalDevice> device, uint32_t frameIndex);
|
void FinaliseBatches(Handle<SHVkLogicalDevice> device, uint32_t frameIndex);
|
||||||
void ClearBatches();
|
void ClearBatches();
|
||||||
void UpdateTransformBuffer(uint32_t frameIndex);
|
void UpdateBuffers(uint32_t frameIndex);
|
||||||
void RegisterSuperBatch(Handle<SHSuperBatch> superBatch);
|
void RegisterSuperBatch(Handle<SHSuperBatch> superBatch);
|
||||||
void DeregisterSuperBatch(Handle<SHSuperBatch> superBatch);
|
void DeregisterSuperBatch(Handle<SHSuperBatch> superBatch);
|
||||||
|
|
||||||
|
|
|
@ -78,10 +78,11 @@ namespace SHADE
|
||||||
batches.clear();
|
batches.clear();
|
||||||
}
|
}
|
||||||
|
|
||||||
void SHSuperBatch::UpdateTransformBuffer(uint32_t frameIndex)
|
void SHSuperBatch::UpdateBuffers(uint32_t frameIndex)
|
||||||
{
|
{
|
||||||
for (auto& batch : batches)
|
for (auto& batch : batches)
|
||||||
{
|
{
|
||||||
|
batch.UpdateMaterialBuffer(frameIndex);
|
||||||
batch.UpdateTransformBuffer(frameIndex);
|
batch.UpdateTransformBuffer(frameIndex);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -55,7 +55,7 @@ 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(uint32_t frameIndex);
|
void UpdateBuffers(uint32_t frameIndex);
|
||||||
void Build(Handle<SHVkLogicalDevice> device, uint32_t frameIndex) noexcept;
|
void Build(Handle<SHVkLogicalDevice> device, uint32_t frameIndex) noexcept;
|
||||||
void Draw(Handle<SHVkCommandBuffer> cmdBuffer, uint32_t frameIndex) noexcept;
|
void Draw(Handle<SHVkCommandBuffer> cmdBuffer, uint32_t frameIndex) noexcept;
|
||||||
|
|
||||||
|
|
|
@ -38,7 +38,7 @@ namespace SHADE
|
||||||
dataStore.reset();
|
dataStore.reset();
|
||||||
}
|
}
|
||||||
|
|
||||||
void SHMaterialInstance::ExportProperties(void* dest) const
|
void SHMaterialInstance::ExportProperties(void* dest)
|
||||||
{
|
{
|
||||||
assert(dataStore != nullptr);
|
assert(dataStore != nullptr);
|
||||||
|
|
||||||
|
@ -62,6 +62,9 @@ namespace SHADE
|
||||||
const auto DATA_OFFSET = variable->offset;
|
const auto DATA_OFFSET = variable->offset;
|
||||||
memcpy(static_cast<char*>(dest) + DATA_OFFSET, dataStore.get() + data.StoredDataOffset, data.DataSize);
|
memcpy(static_cast<char*>(dest) + DATA_OFFSET, dataStore.get() + data.StoredDataOffset, data.DataSize);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Data was exported so unflag
|
||||||
|
dataWasChanged = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
/*---------------------------------------------------------------------------------*/
|
/*---------------------------------------------------------------------------------*/
|
||||||
|
|
|
@ -62,12 +62,13 @@ namespace SHADE
|
||||||
template<typename T>
|
template<typename T>
|
||||||
const T& GetProperty(const std::string& key) const;
|
const T& GetProperty(const std::string& key) const;
|
||||||
void ResetProperties() noexcept;
|
void ResetProperties() noexcept;
|
||||||
void ExportProperties(void* dest) const;
|
void ExportProperties(void* dest);
|
||||||
|
|
||||||
/*-----------------------------------------------------------------------------*/
|
/*-----------------------------------------------------------------------------*/
|
||||||
/* Getter Functions */
|
/* Getter Functions */
|
||||||
/*-----------------------------------------------------------------------------*/
|
/*-----------------------------------------------------------------------------*/
|
||||||
Handle<SHMaterial> GetBaseMaterial() const { return baseMaterial; }
|
Handle<SHMaterial> GetBaseMaterial() const noexcept { return baseMaterial; }
|
||||||
|
bool HasChanged() const noexcept { return dataWasChanged; }
|
||||||
|
|
||||||
private:
|
private:
|
||||||
/*-----------------------------------------------------------------------------*/
|
/*-----------------------------------------------------------------------------*/
|
||||||
|
@ -77,6 +78,7 @@ namespace SHADE
|
||||||
std::vector<OverrideData> overrideData;
|
std::vector<OverrideData> overrideData;
|
||||||
std::unique_ptr<char> dataStore;
|
std::unique_ptr<char> dataStore;
|
||||||
size_t dataStoreSize = 0;
|
size_t dataStoreSize = 0;
|
||||||
|
bool dataWasChanged = false;
|
||||||
|
|
||||||
/*-----------------------------------------------------------------------------*/
|
/*-----------------------------------------------------------------------------*/
|
||||||
/* Helper Functions */
|
/* Helper Functions */
|
||||||
|
|
|
@ -53,6 +53,9 @@ namespace SHADE
|
||||||
|
|
||||||
// Save the override data information
|
// Save the override data information
|
||||||
overrideData.emplace_back(std::move(od));
|
overrideData.emplace_back(std::move(od));
|
||||||
|
|
||||||
|
// Flag
|
||||||
|
dataWasChanged = true;
|
||||||
}
|
}
|
||||||
template<typename T>
|
template<typename T>
|
||||||
T& SHMaterialInstance::GetProperty(const std::string& key)
|
T& SHMaterialInstance::GetProperty(const std::string& key)
|
||||||
|
|
|
@ -348,8 +348,8 @@ namespace SHADE
|
||||||
|
|
||||||
void SHSubpass::Execute(Handle<SHVkCommandBuffer>& commandBuffer, uint32_t frameIndex) noexcept
|
void SHSubpass::Execute(Handle<SHVkCommandBuffer>& commandBuffer, uint32_t frameIndex) noexcept
|
||||||
{
|
{
|
||||||
// Ensure correct transforms are provided
|
// Ensure updated transforms and materials are provided
|
||||||
superBatch->UpdateTransformBuffer(frameIndex);
|
superBatch->UpdateBuffers(frameIndex);
|
||||||
|
|
||||||
// Draw all the batches
|
// Draw all the batches
|
||||||
superBatch->Draw(commandBuffer, frameIndex);
|
superBatch->Draw(commandBuffer, frameIndex);
|
||||||
|
|
Loading…
Reference in New Issue