Optimize Animated Model bones matrices buffer update

This commit is contained in:
Wojtek Figat
2021-06-06 23:15:41 +02:00
parent 982b22b4b1
commit 07ad94de13
4 changed files with 33 additions and 25 deletions

View File

@@ -7,7 +7,6 @@
#include "Engine/Engine/EngineService.h" #include "Engine/Engine/EngineService.h"
Array<AnimatedModel*> UpdateList; Array<AnimatedModel*> UpdateList;
Array<Matrix> UpdateBones;
class AnimationsService : public EngineService class AnimationsService : public EngineService
{ {
@@ -81,7 +80,6 @@ void AnimationsService::Update()
void AnimationsService::Dispose() void AnimationsService::Dispose()
{ {
UpdateList.Resize(0); UpdateList.Resize(0);
UpdateBones.Resize(0);
} }
void Animations::AddToUpdate(AnimatedModel* obj) void Animations::AddToUpdate(AnimatedModel* obj)

View File

@@ -41,10 +41,27 @@ void SkinnedMeshDrawData::SetData(const Matrix* bones, bool dropHistory)
{ {
if (!bones) if (!bones)
return; return;
ASSERT(BonesCount > 0);
ANIM_GRAPH_PROFILE_EVENT("SetSkinnedMeshData"); ANIM_GRAPH_PROFILE_EVENT("SetSkinnedMeshData");
// Copy bones to the buffer
const int32 count = BonesCount;
const int32 preFetchStride = 2;
const Matrix* input = bones;
const auto output = (Matrix3x4*)Data.Get();
ASSERT(Data.Count() == count * sizeof(Matrix3x4));
for (int32 i = 0; i < count; i++)
{
Matrix3x4* bone = output + i;
Platform::Prefetch(bone + preFetchStride);
Platform::Prefetch((byte*)(bone + preFetchStride) + PLATFORM_CACHE_LINE_SIZE);
bone->SetMatrixTranspose(input[i]);
}
OnDataChanged(dropHistory);
}
void SkinnedMeshDrawData::OnDataChanged(bool dropHistory)
{
// Setup previous frame bone matrices if needed // Setup previous frame bone matrices if needed
if (_hasValidData && !dropHistory) if (_hasValidData && !dropHistory)
{ {
@@ -64,20 +81,6 @@ void SkinnedMeshDrawData::SetData(const Matrix* bones, bool dropHistory)
SAFE_DELETE_GPU_RESOURCE(PrevBoneMatrices); SAFE_DELETE_GPU_RESOURCE(PrevBoneMatrices);
} }
// Copy bones to the buffer
const int32 count = BonesCount;
const int32 preFetchStride = 2;
const Matrix* input = bones;
const auto output = (Matrix3x4*)Data.Get();
ASSERT(Data.Count() == count * sizeof(Matrix3x4));
for (int32 i = 0; i < count; i++)
{
Matrix3x4* bone = output + i;
Platform::Prefetch(bone + preFetchStride);
Platform::Prefetch((byte*)(bone + preFetchStride) + PLATFORM_CACHE_LINE_SIZE);
bone->SetMatrixTranspose(input[i]);
}
_isDirty = true; _isDirty = true;
_hasValidData = true; _hasValidData = true;
} }

View File

@@ -54,7 +54,6 @@ public:
/// <summary> /// <summary>
/// Determines whether this instance is ready for rendering. /// Determines whether this instance is ready for rendering.
/// </summary> /// </summary>
/// <returns>True if has valid data and can be rendered, otherwise false.</returns>
FORCE_INLINE bool IsReady() const FORCE_INLINE bool IsReady() const
{ {
return BoneMatrices != nullptr && BoneMatrices->IsAllocated(); return BoneMatrices != nullptr && BoneMatrices->IsAllocated();
@@ -73,6 +72,12 @@ public:
/// <param name="dropHistory">True if drop previous update bones used for motion blur, otherwise will keep them and do the update.</param> /// <param name="dropHistory">True if drop previous update bones used for motion blur, otherwise will keep them and do the update.</param>
void SetData(const Matrix* bones, bool dropHistory); void SetData(const Matrix* bones, bool dropHistory);
/// <summary>
/// After bones Data has been modified externally. Updates the bone matrices data for the GPU buffer. Ensure to call Flush before rendering.
/// </summary>
/// <param name="dropHistory">True if drop previous update bones used for motion blur, otherwise will keep them and do the update.</param>
void OnDataChanged(bool dropHistory);
/// <summary> /// <summary>
/// Flushes the bones data buffer with the GPU by sending the data fro the CPU. /// Flushes the bones data buffer with the GPU by sending the data fro the CPU.
/// </summary> /// </summary>

View File

@@ -2,6 +2,7 @@
#include "AnimatedModel.h" #include "AnimatedModel.h"
#include "BoneSocket.h" #include "BoneSocket.h"
#include "Engine/Core/Math/Matrix3x4.h"
#include "Engine/Animations/Animations.h" #include "Engine/Animations/Animations.h"
#include "Engine/Engine/Engine.h" #include "Engine/Engine/Engine.h"
#if USE_EDITOR #if USE_EDITOR
@@ -13,8 +14,6 @@
#include "Engine/Level/SceneObjectsFactory.h" #include "Engine/Level/SceneObjectsFactory.h"
#include "Engine/Serialization/Serialization.h" #include "Engine/Serialization/Serialization.h"
extern Array<Matrix> UpdateBones;
AnimatedModel::AnimatedModel(const SpawnParams& params) AnimatedModel::AnimatedModel(const SpawnParams& params)
: ModelInstanceActor(params) : ModelInstanceActor(params)
, _actualMode(AnimationUpdateMode::Never) , _actualMode(AnimationUpdateMode::Never)
@@ -470,14 +469,17 @@ void AnimatedModel::OnAnimationUpdated()
// Calculate the final bones transformations and update skinning // Calculate the final bones transformations and update skinning
{ {
ANIM_GRAPH_PROFILE_EVENT("Final Pose"); ANIM_GRAPH_PROFILE_EVENT("Final Pose");
UpdateBones.Resize(skeleton.Bones.Count(), false); const int32 bonesCount = skeleton.Bones.Count();
for (int32 boneIndex = 0; boneIndex < skeleton.Bones.Count(); boneIndex++) Matrix3x4* output = (Matrix3x4*)_skinningData.Data.Get();
ASSERT(_skinningData.Data.Count() == bonesCount * sizeof(Matrix3x4));
for (int32 boneIndex = 0; boneIndex < bonesCount; boneIndex++)
{ {
auto& bone = skeleton.Bones[boneIndex]; auto& bone = skeleton.Bones[boneIndex];
UpdateBones[boneIndex] = bone.OffsetMatrix * GraphInstance.NodesPose[bone.NodeIndex]; Matrix matrix = bone.OffsetMatrix * GraphInstance.NodesPose[bone.NodeIndex];
output[boneIndex].SetMatrixTranspose(matrix);
} }
_skinningData.OnDataChanged(!PerBoneMotionBlur);
} }
_skinningData.SetData(UpdateBones.Get(), !PerBoneMotionBlur);
UpdateBounds(); UpdateBounds();
UpdateSockets(); UpdateSockets();