diff --git a/SHADE_Engine/src/Graphics/MiddleEnd/Batching/SHBatch.cpp b/SHADE_Engine/src/Graphics/MiddleEnd/Batching/SHBatch.cpp index fdbbad24..14f29b33 100644 --- a/SHADE_Engine/src/Graphics/MiddleEnd/Batching/SHBatch.cpp +++ b/SHADE_Engine/src/Graphics/MiddleEnd/Batching/SHBatch.cpp @@ -37,40 +37,50 @@ namespace SHADE /* SHBatch - Constructors/Destructors */ /*-----------------------------------------------------------------------------------*/ SHBatch::SHBatch(Handle pipeline) - : pipeline{ pipeline } + : pipeline{ pipeline } { if (!pipeline) throw std::invalid_argument("Attempted to create a SHBatch with an invalid SHPipeline!"); + // Check the pipeline and flag it depending on whether or not it is animated + isAnimated = checkIfIsAnimatedPipeline(pipeline); + // Mark all as dirty setAllDirtyFlags(); } SHBatch::SHBatch(SHBatch&& rhs) - : device { rhs.device } - , pipeline { rhs.pipeline } - , referencedMatInstances { std::move(rhs.referencedMatInstances) } - , matBufferDirty { std::move(rhs.matBufferDirty) } - , subBatches { std::move(rhs.subBatches) } - , isDirty { std::move(rhs.isDirty) } - , drawData { std::move(rhs.drawData) } - , transformData { std::move(rhs.transformData) } - , instancedIntegerData { std::move(rhs.instancedIntegerData) } - , matPropsData { std::move(rhs.matPropsData) } - , matPropsDataSize { rhs.matPropsDataSize } - , singleMatPropAlignedSize { rhs.singleMatPropAlignedSize } - , singleMatPropSize { rhs.singleMatPropSize } - , isCPUBuffersDirty { rhs.isCPUBuffersDirty } - , drawDataBuffer { rhs.drawDataBuffer } - , transformDataBuffer { rhs.transformDataBuffer } - , instancedIntegerBuffer { rhs.instancedIntegerBuffer } - , matPropsBuffer { rhs.matPropsBuffer } - , instanceDataDescSet { rhs.instanceDataDescSet } + : device { rhs.device } + , isAnimated { rhs.isAnimated } + , pipeline { rhs.pipeline } + , referencedMatInstances { std::move(rhs.referencedMatInstances) } + , matBufferDirty { std::move(rhs.matBufferDirty) } + , subBatches { std::move(rhs.subBatches) } + , isDirty { std::move(rhs.isDirty) } + , drawData { std::move(rhs.drawData) } + , transformData { std::move(rhs.transformData) } + , instancedIntegerData { std::move(rhs.instancedIntegerData) } + , matPropsData { std::move(rhs.matPropsData) } + , matPropsDataSize { rhs.matPropsDataSize } + , singleMatPropAlignedSize { rhs.singleMatPropAlignedSize } + , singleMatPropSize { rhs.singleMatPropSize } + , boneMatrixData { std::move(rhs.boneMatrixData) } + , boneMatrixIndices { std::move(rhs.boneMatrixIndices) } + , isCPUBuffersDirty { rhs.isCPUBuffersDirty } + , drawDataBuffer { rhs.drawDataBuffer } + , transformDataBuffer { rhs.transformDataBuffer } + , instancedIntegerBuffer { rhs.instancedIntegerBuffer } + , matPropsBuffer { rhs.matPropsBuffer } + , boneMatrixBuffer { rhs.boneMatrixBuffer } + , boneMatrixFirstIndexBuffer { rhs.boneMatrixFirstIndexBuffer } + , instanceDataDescSet { rhs.instanceDataDescSet } { - rhs.drawDataBuffer = {}; - rhs.transformDataBuffer = {}; - rhs.instancedIntegerBuffer = {}; - rhs.matPropsBuffer = {}; + rhs.drawDataBuffer = {}; + rhs.transformDataBuffer = {}; + rhs.instancedIntegerBuffer = {}; + rhs.matPropsBuffer = {}; + rhs.boneMatrixBuffer = {}; + rhs.boneMatrixFirstIndexBuffer = {}; rhs.instanceDataDescSet = {}; } @@ -79,31 +89,38 @@ namespace SHADE if (this == &rhs) return *this; - device = rhs.device ; - pipeline = rhs.pipeline ; - referencedMatInstances = std::move(rhs.referencedMatInstances); - matBufferDirty = std::move(rhs.matBufferDirty) ; - subBatches = std::move(rhs.subBatches) ; - isDirty = std::move(rhs.isDirty) ; - drawData = std::move(rhs.drawData) ; - transformData = std::move(rhs.transformData) ; - instancedIntegerData = std::move(rhs.instancedIntegerData) ; - matPropsData = std::move(rhs.matPropsData) ; - matPropsDataSize = rhs.matPropsDataSize ; - singleMatPropAlignedSize = rhs.singleMatPropAlignedSize ; - singleMatPropSize = rhs.singleMatPropSize ; - isCPUBuffersDirty = rhs.isCPUBuffersDirty ; - drawDataBuffer = rhs.drawDataBuffer ; - transformDataBuffer = rhs.transformDataBuffer ; - instancedIntegerBuffer = rhs.instancedIntegerBuffer ; - matPropsBuffer = rhs.matPropsBuffer ; - instanceDataDescSet = rhs.instanceDataDescSet ; + device = rhs.device ; + isAnimated = rhs.isAnimated ; + pipeline = rhs.pipeline ; + referencedMatInstances = std::move(rhs.referencedMatInstances); + matBufferDirty = std::move(rhs.matBufferDirty) ; + subBatches = std::move(rhs.subBatches) ; + isDirty = std::move(rhs.isDirty) ; + drawData = std::move(rhs.drawData) ; + transformData = std::move(rhs.transformData) ; + instancedIntegerData = std::move(rhs.instancedIntegerData) ; + matPropsData = std::move(rhs.matPropsData) ; + matPropsDataSize = rhs.matPropsDataSize ; + singleMatPropAlignedSize = rhs.singleMatPropAlignedSize ; + singleMatPropSize = rhs.singleMatPropSize ; + boneMatrixData = std::move(rhs.boneMatrixData) ; + boneMatrixIndices = std::move(rhs.boneMatrixIndices) ; + isCPUBuffersDirty = rhs.isCPUBuffersDirty ; + drawDataBuffer = rhs.drawDataBuffer ; + transformDataBuffer = rhs.transformDataBuffer ; + instancedIntegerBuffer = rhs.instancedIntegerBuffer ; + matPropsBuffer = rhs.matPropsBuffer ; + boneMatrixBuffer = rhs.boneMatrixBuffer ; + boneMatrixFirstIndexBuffer = rhs.boneMatrixFirstIndexBuffer ; + instanceDataDescSet = rhs.instanceDataDescSet ; // Unset values - rhs.drawDataBuffer = {}; - rhs.transformDataBuffer = {}; - rhs.instancedIntegerBuffer = {}; - rhs.matPropsBuffer = {}; + rhs.drawDataBuffer = {}; + rhs.transformDataBuffer = {}; + rhs.instancedIntegerBuffer = {}; + rhs.matPropsBuffer = {}; + rhs.boneMatrixBuffer = {}; + rhs.boneMatrixFirstIndexBuffer = {}; rhs.instanceDataDescSet = {}; return *this; @@ -382,6 +399,10 @@ namespace SHADE void SHBatch::UpdateAnimationBuffer(uint32_t frameIndex) { + // Not animated pipeline, we skip + if (!isAnimated) + return; + // Frame Index check if (frameIndex >= SHGraphicsConstants::NUM_FRAME_BUFFERS) { @@ -392,6 +413,9 @@ namespace SHADE // Reset Animation Matrix Data boneMatrixData.clear(); + // Add the first identity matrix into the bone matrix data + boneMatrixData.emplace_back(SHMatrix::Identity); + // Populate on the CPU for (auto& subBatch : subBatches) for (auto rendId : subBatch.Renderables) @@ -402,6 +426,7 @@ namespace SHADE const auto& MATRICES = animator->GetBoneMatrices(); boneMatrixData.insert(boneMatrixData.end(), MATRICES.cbegin(), MATRICES.cend()); } + // We don't have to account for missing animators or reset indices as the renderable list are not updated at this point } // Update GPU Buffers @@ -446,13 +471,21 @@ namespace SHADE // - EID data instancedIntegerData.reserve(numTotalElements); instancedIntegerData.clear(); + if (isAnimated) + { + // - Bone Data + boneMatrixData.clear(); + boneMatrixIndices.clear(); - auto const& descMappings = SHGraphicsPredefinedData::GetMappings(SHGraphicsPredefinedData::SystemType::BATCHING); + // Add the first identity matrix into the bone matrix data + boneMatrixData.emplace_back(SHMatrix::Identity); + } // - Material Properties Data + auto const& DESC_MAPPINGS = SHGraphicsPredefinedData::GetMappings(SHGraphicsPredefinedData::SystemType::BATCHING); const Handle SHADER_INFO = pipeline->GetPipelineLayout()->GetShaderBlockInterface ( - descMappings.at(SHPredefinedDescriptorTypes::PER_INSTANCE_BATCH), + DESC_MAPPINGS.at(SHPredefinedDescriptorTypes::PER_INSTANCE_BATCH), SHGraphicsConstants::DescriptorSetBindings::PER_INST_MATERIAL_DATA, vk::ShaderStageFlagBits::eFragment ); @@ -470,9 +503,12 @@ namespace SHADE } } // - Bone Data - boneMatrixData.clear(); - boneMatrixIndices.clear(); - boneMatrixIndices.reserve(numTotalElements); + if (isAnimated) + { + boneMatrixData.clear(); + boneMatrixIndices.clear(); + boneMatrixIndices.reserve(numTotalElements); + } // Build Sub Batches uint32_t nextInstanceIndex = 0; @@ -548,12 +584,20 @@ namespace SHADE } // Bone Data - auto animator = SHComponentManager::GetComponent_s(rendId); - if (animator) + if (isAnimated) { - boneMatrixIndices.emplace_back(static_cast(boneMatrixData.size())); - const auto& BONE_MATRICES = animator->GetBoneMatrices(); - boneMatrixData.insert(boneMatrixData.end(), BONE_MATRICES.cbegin(), BONE_MATRICES.cend()); + auto animator = SHComponentManager::GetComponent_s(rendId); + if (animator) + { + boneMatrixIndices.emplace_back(static_cast(boneMatrixData.size())); + const auto& BONE_MATRICES = animator->GetBoneMatrices(); + boneMatrixData.insert(boneMatrixData.end(), BONE_MATRICES.cbegin(), BONE_MATRICES.cend()); + } + else + { + // Take the first matrix which is always identity + boneMatrixIndices.emplace_back(static_cast(0)); + } } } } @@ -590,7 +634,7 @@ namespace SHADE "Batch Instance Data Buffer" ); // - Bone Matrix Indices - if (!boneMatrixIndices.empty()) + if (isAnimated) { const uint32_t BMI_DATA_BYTES = static_cast(boneMatrixIndices.size() * sizeof(uint32_t)); SHVkUtil::EnsureBufferAndCopyHostVisibleData @@ -625,7 +669,7 @@ namespace SHADE // Bind all required objects before drawing std::vector dynamicOffset{ 0 }; - if (!boneMatrixData.empty()) + if (isAnimated) { dynamicOffset.emplace_back(0); } @@ -633,7 +677,7 @@ namespace SHADE cmdBuffer->BindPipeline(pipeline); cmdBuffer->BindVertexBuffer(SHGraphicsConstants::VertexBufferBindings::TRANSFORM, transformDataBuffer[frameIndex], 0); cmdBuffer->BindVertexBuffer(SHGraphicsConstants::VertexBufferBindings::INTEGER_DATA, instancedIntegerBuffer[frameIndex], 0); - if (boneMatrixFirstIndexBuffer[frameIndex]) + if (isAnimated && boneMatrixFirstIndexBuffer[frameIndex]) { cmdBuffer->BindVertexBuffer(SHGraphicsConstants::VertexBufferBindings::BONE_MATRIX_FIRST_INDEX, boneMatrixFirstIndexBuffer[frameIndex], 0); } @@ -701,12 +745,14 @@ namespace SHADE { layoutTypes = PreDefDescLayoutType::MATERIALS; } - if (!boneMatrixData.empty()) + if (isAnimated) { layoutTypes = PreDefDescLayoutType::MATERIAL_AND_BONES; } - if (matPropsData || !boneMatrixData.empty()) + const bool MUST_BUILD_ANIM_BUFFER = isAnimated && !boneMatrixData.empty(); + + if (matPropsData || MUST_BUILD_ANIM_BUFFER) { // Make sure that we have a descriptor set if we don't already have one if (!instanceDataDescSet[frameIndex]) @@ -756,7 +802,7 @@ namespace SHADE } /* Animation Bone Data */ - if (!boneMatrixData.empty()) + if (MUST_BUILD_ANIM_BUFFER) { // Update GPU Buffers const uint32_t BONE_MTX_DATA_BYTES = static_cast(boneMatrixData.size() * sizeof(SHMatrix)); @@ -786,4 +832,21 @@ namespace SHADE ); } } + + bool SHBatch::checkIfIsAnimatedPipeline(Handle pipeline) + { + if (!pipeline || !pipeline->GetPipelineLayout()) + return false; + + // Grab the pipeline descriptor set layouts + auto pipelineDescLayouts = pipeline->GetPipelineLayout()->GetDescriptorSetLayoutsPipeline(); + + // Check if they contain the material and bones layout, that indicates it is + using GfxPreDefType = SHGraphicsPredefinedData::PredefinedDescSetLayoutTypes; + const Handle BONE_DESC_SET_LAYOUT = SHGraphicsPredefinedData::GetPredefinedDescSetLayouts(GfxPreDefType::MATERIAL_AND_BONES)[0]; + return std::find_if(pipelineDescLayouts.begin(), pipelineDescLayouts.end(), [BONE_DESC_SET_LAYOUT](Handle layout) + { + return BONE_DESC_SET_LAYOUT == layout; + }) != pipelineDescLayouts.end(); + } } diff --git a/SHADE_Engine/src/Graphics/MiddleEnd/Batching/SHBatch.h b/SHADE_Engine/src/Graphics/MiddleEnd/Batching/SHBatch.h index 913a7a04..ee7ae90f 100644 --- a/SHADE_Engine/src/Graphics/MiddleEnd/Batching/SHBatch.h +++ b/SHADE_Engine/src/Graphics/MiddleEnd/Batching/SHBatch.h @@ -111,6 +111,8 @@ namespace SHADE /*---------------------------------------------------------------------------------*/ // Resources Handle device; + // Config + bool isAnimated; // Whether the material supports animation // Batch Properties Handle pipeline; std::unordered_set> referencedMatInstances; @@ -126,7 +128,7 @@ namespace SHADE Byte matPropsDataSize = 0; Byte singleMatPropAlignedSize = 0; Byte singleMatPropSize = 0; - std::vector boneMatrixData; + std::vector boneMatrixData; // 0th element is always an identity matrix std::vector boneMatrixIndices; bool isCPUBuffersDirty = true; // GPU Buffers @@ -143,5 +145,6 @@ namespace SHADE /*-----------------------------------------------------------------------------*/ void setAllDirtyFlags(); void rebuildDescriptorSetBuffers(uint32_t frameIndex, Handle descPool); + static bool checkIfIsAnimatedPipeline(Handle pipeline); }; } diff --git a/SHADE_Engine/src/Graphics/MiddleEnd/Interface/SHMeshLibrary.cpp b/SHADE_Engine/src/Graphics/MiddleEnd/Interface/SHMeshLibrary.cpp index 658cc5fe..e950025f 100644 --- a/SHADE_Engine/src/Graphics/MiddleEnd/Interface/SHMeshLibrary.cpp +++ b/SHADE_Engine/src/Graphics/MiddleEnd/Interface/SHMeshLibrary.cpp @@ -173,6 +173,7 @@ namespace SHADE } else { + // Automatically set to index 0, which will be an identity matrix vertBoneIdxStorage.resize(vertBoneIdxStorage.size() + addJob.VertexCount); } if (addJob.VertexBoneWeights)