fix the MarkRenderStateDirty data race condition by gathering as much as data only on the game thread

This commit is contained in:
Mamadou Babaei
2024-08-16 18:02:06 +02:00
parent 276c1f98aa
commit c3bde75b1a
6 changed files with 134 additions and 50 deletions
@@ -51,6 +51,13 @@
FSGVirtualHandAnimInstanceProxy::FSGVirtualHandAnimInstanceProxy()
: FAnimInstanceProxy()
{
bIsVirtualHandVisible = false;
VirtualHand = nullptr;
HandMeshAsset = nullptr;
HandSkeleton = nullptr;
bMarkRenderStateDirty = false;
bShouldAnimationApplyBoneLocation = false;
}
FSGVirtualHandAnimInstanceProxy::FSGVirtualHandAnimInstanceProxy(UAnimInstance* Instance)
@@ -67,41 +74,54 @@ void FSGVirtualHandAnimInstanceProxy::PreEvaluateAnimation(UAnimInstance* InAnim
return;
}
USGVirtualHandComponent* VirtualHand{Cast<USGVirtualHandComponent>(GetSkelMeshComponent())};
VirtualHand = Cast<USGVirtualHandComponent>(GetSkelMeshComponent());
if (!IsValid(VirtualHand))
{
return;
}
HandMeshAsset = VirtualHand->GetSkeletalMeshAsset();
if (!IsValid(HandMeshAsset))
{
return;
}
HandSkeleton = HandMeshAsset->GetSkeleton();
if (!IsValid(HandSkeleton))
{
return;
}
bIsVirtualHandVisible = VirtualHand->IsVisible() && VirtualHand->GetVisibleFlag();
if (!bIsVirtualHandVisible)
{
return;
}
const bool bGotMotionControllerData = VirtualHand->GetMotionControllerData(MotionControllerData);
if (!bGotMotionControllerData || !MotionControllerData.bValid)
{
return;
}
ensureAlwaysMsgf(MotionControllerData.HandKeyPositions.Num() == MotionControllerData.HandKeyRotations.Num(),
TEXT("Mismatched motion controller data positions and rotations!"));
BoneNamesMap.Empty();
for (TArray<FQuat>::SizeType HandKeyIndex = 0;
HandKeyIndex < MotionControllerData.HandKeyRotations.Num(); ++HandKeyIndex)
{
const FName& BoneName{VirtualHand->GetHandBoneName(HandKeyIndex)};
BoneNamesMap.Add(HandKeyIndex, BoneName);
}
const FRotator& AnimationBoneRotationCorrectionOffset{VirtualHand->GetAnimationBoneRotationCorrectionOffset()};
AnimationBoneCorrectionOffsetTransform = FTransform{AnimationBoneRotationCorrectionOffset};
bShouldAnimationApplyBoneLocation = VirtualHand->ShouldAnimationApplyBoneLocation();
}
bool FSGVirtualHandAnimInstanceProxy::Evaluate(FPoseContext& Output)
{
USGVirtualHandComponent* VirtualHand{Cast<USGVirtualHandComponent>(GetSkelMeshComponent())};
if (!IsValid(VirtualHand))
{
return FAnimInstanceProxy::Evaluate(Output);
}
const bool bIsVisible = VirtualHand->IsVisible() && VirtualHand->GetVisibleFlag();
if (!bIsVisible)
{
return FAnimInstanceProxy::Evaluate(Output);
}
const USkeletalMesh* HandMesh{VirtualHand->GetSkeletalMeshAsset()};
if (!IsValid(HandMesh))
{
return FAnimInstanceProxy::Evaluate(Output);
}
const USkeleton* HandSkeleton{HandMesh->GetSkeleton()};
if (!IsValid(HandSkeleton))
if (!bIsVirtualHandVisible)
{
return FAnimInstanceProxy::Evaluate(Output);
}
@@ -111,20 +131,13 @@ bool FSGVirtualHandAnimInstanceProxy::Evaluate(FPoseContext& Output)
return FAnimInstanceProxy::Evaluate(Output);
}
ensureAlwaysMsgf(MotionControllerData.HandKeyPositions.Num() == MotionControllerData.HandKeyRotations.Num(),
TEXT("Mismatched motion controller data positions and rotations!"));
const FRotator& AnimationBoneRotationCorrectionOffset{VirtualHand->GetAnimationBoneRotationCorrectionOffset()};
const FTransform AnimationBoneCorrectionOffsetTransform{AnimationBoneRotationCorrectionOffset};
const bool bAnimationShouldApplyBoneLocation = VirtualHand->AnimationShouldApplyBoneLocation();
FComponentSpacePoseContext PoseContext{Output.AnimInstanceProxy};
PoseContext.Pose.InitPose(Output.Pose);
for (TArray<FQuat>::SizeType HandKeyIndex = 0;
HandKeyIndex < MotionControllerData.HandKeyRotations.Num(); ++HandKeyIndex)
for (const TTuple<TArray<FQuat>::SizeType, FName>& Bone: BoneNamesMap)
{
FName BoneName{VirtualHand->GetHandBoneName(HandKeyIndex)};
const TArray<FQuat>::SizeType HandKeyIndex = Bone.Key;
const FName& BoneName{Bone.Value};
if (BoneName == NAME_None)
{
continue;
@@ -137,7 +150,7 @@ bool FSGVirtualHandAnimInstanceProxy::Evaluate(FPoseContext& Output)
}
FBoneReference BoneReference;
BoneReference.BoneName = MoveTemp(BoneName);
BoneReference.BoneName = BoneName;
BoneReference.BoneIndex = BoneIndex;
BoneReference.bUseSkeletonIndex = true;
@@ -154,7 +167,7 @@ bool FSGVirtualHandAnimInstanceProxy::Evaluate(FPoseContext& Output)
BoneController.RotationSpace = EBoneControlSpace::BCS_WorldSpace;
BoneController.ScaleMode = EBoneModificationMode::BMM_Ignore;
if (bAnimationShouldApplyBoneLocation)
if (bShouldAnimationApplyBoneLocation)
{
FVector BoneTranslation{BoneTransform.GetLocation()};
BoneController.TranslationMode = EBoneModificationMode::BMM_Replace;
@@ -182,11 +195,27 @@ bool FSGVirtualHandAnimInstanceProxy::Evaluate(FPoseContext& Output)
PoseContext.Pose.LocalBlendCSBoneTransforms(BoneTransforms, 1.0f);
PoseContext.Pose.ConvertComponentPosesToLocalPoses(PoseContext.Pose, Output.Pose);
/// FIXME
// This causes a data race in the refactored code!
//VirtualHand->MarkRenderStateDirty();
bMarkRenderStateDirty = true;
}
}
return true;
}
void FSGVirtualHandAnimInstanceProxy::PostEvaluate(UAnimInstance* InAnimInstance)
{
FAnimInstanceProxy::PostEvaluate(InAnimInstance);
if (!bMarkRenderStateDirty)
{
return;
}
if (!IsValid(VirtualHand))
{
return;
}
VirtualHand->MarkRenderStateDirty();
}
@@ -215,7 +215,7 @@ USGVirtualHandComponent::USGVirtualHandComponent(const FObjectInitializer& Objec
bVisibleWhenHandDataUnavailable = false;
AnimationBoneRotationCorrectionOffset = FRotator{0.0f, 90.0f, 90.0f};
bAnimationShouldApplyBoneLocation = true;
bShouldAnimationApplyBoneLocation = true;
bAutoStopAllHapticsOnEndPlay = true;
@@ -36,7 +36,10 @@
#pragma once
#include "Animation/AnimInstanceProxy.h"
#include "Containers/Array.h"
#include "HeadMountedDisplayTypes.h"
#include "Math/Quat.h"
#include "Math/Transform.h"
#include "Templates/UniquePtr.h"
#include "UObject/NameTypes.h"
@@ -48,20 +51,72 @@ struct SENSEGLOVE_API FSGVirtualHandAnimInstanceProxy : public FAnimInstanceProx
GENERATED_USTRUCT_BODY()
private:
bool bIsVirtualHandVisible;
USGVirtualHandComponent* VirtualHand;
USkeletalMesh* HandMeshAsset;
USkeleton* HandSkeleton;
bool bMarkRenderStateDirty;
FXRMotionControllerData MotionControllerData;
TMap<TArray<FQuat>::SizeType, FName> BoneNamesMap;
FTransform AnimationBoneCorrectionOffsetTransform;
bool bShouldAnimationApplyBoneLocation;
public:
FSGVirtualHandAnimInstanceProxy();
FSGVirtualHandAnimInstanceProxy(UAnimInstance* Instance);
protected:
FORCEINLINE bool IsVirtualHandVisible() const
{
return bIsVirtualHandVisible;
}
FORCEINLINE USGVirtualHandComponent* GetVirtualHand() const
{
return VirtualHand;
}
FORCEINLINE USkeletalMesh* GetHandMeshAsset() const
{
return HandMeshAsset;
}
FORCEINLINE USkeleton* GetHandSkeleton() const
{
return HandSkeleton;
}
FORCEINLINE bool IsRenderStateDirty() const
{
return bMarkRenderStateDirty;
}
FORCEINLINE const FXRMotionControllerData& GetMotionControllerData() const
{
return MotionControllerData;
}
FORCEINLINE const TMap<TArray<FQuat>::SizeType, FName>& GetBoneNamesMap() const
{
return BoneNamesMap;
}
FORCEINLINE const FTransform& GetAnimationBoneCorrectionOffsetTransform() const
{
return AnimationBoneCorrectionOffsetTransform;
}
FORCEINLINE bool ShouldAnimationApplyBoneLocation() const
{
return bShouldAnimationApplyBoneLocation;
}
protected:
virtual void PreEvaluateAnimation(UAnimInstance* InAnimInstance) override;
virtual bool Evaluate(FPoseContext& Output) override;
virtual void PostEvaluate(UAnimInstance* InAnimInstance) override;
};
@@ -102,7 +102,7 @@ private:
FRotator AnimationBoneRotationCorrectionOffset;
UPROPERTY(EditAnywhere, Category="SenseGlove | Animation", meta=(AllowPrivateAccess="false"))
uint8 bAnimationShouldApplyBoneLocation : 1;
uint8 bShouldAnimationApplyBoneLocation : 1;
UPROPERTY(EditAnywhere, Category="SenseGlove | Haptics", meta=(AllowPrivateAccess="false"))
uint8 bAutoStopAllHapticsOnEndPlay : 1;
@@ -185,14 +185,14 @@ public:
AnimationBoneRotationCorrectionOffset = InAnimationBoneRotationCorrectionOffset;
}
FORCEINLINE bool AnimationShouldApplyBoneLocation() const
FORCEINLINE bool ShouldAnimationApplyBoneLocation() const
{
return !!bAnimationShouldApplyBoneLocation;
return !!bShouldAnimationApplyBoneLocation;
}
FORCEINLINE void SetAnimationShouldApplyBoneLocation(const bool bInAnimationShouldApplyBoneLocation)
FORCEINLINE void SetShouldAnimationApplyBoneLocation(const bool bInShouldAnimationApplyBoneLocation)
{
bAnimationShouldApplyBoneLocation = bInAnimationShouldApplyBoneLocation;
bShouldAnimationApplyBoneLocation = bInShouldAnimationApplyBoneLocation;
}
FORCEINLINE bool AutoStopsAllHapticsOnEndPlay() const
@@ -98,16 +98,16 @@ void UVirtualHandComponentKismetLibrary::SetAnimationBoneRotationCorrectionOffse
VirtualHandComponent->SetAnimationBoneRotationCorrectionOffset(InAnimationBoneRotationCorrectionOffset);
}
bool UVirtualHandComponentKismetLibrary::AnimationShouldApplyBoneLocation(
bool UVirtualHandComponentKismetLibrary::ShouldAnimationApplyBoneLocation(
const USGVirtualHandComponent* VirtualHandComponent)
{
return VirtualHandComponent->AnimationShouldApplyBoneLocation();
return VirtualHandComponent->ShouldAnimationApplyBoneLocation();
}
void UVirtualHandComponentKismetLibrary::SetAnimationShouldApplyBoneLocation(
USGVirtualHandComponent* VirtualHandComponent, const bool bInAnimationShouldApplyBoneLocation)
void UVirtualHandComponentKismetLibrary::SetShouldAnimationApplyBoneLocation(
USGVirtualHandComponent* VirtualHandComponent, const bool bInShouldAnimationApplyBoneLocation)
{
VirtualHandComponent->SetAnimationShouldApplyBoneLocation(bInAnimationShouldApplyBoneLocation);
VirtualHandComponent->SetShouldAnimationApplyBoneLocation(bInShouldAnimationApplyBoneLocation);
}
bool UVirtualHandComponentKismetLibrary::AutoStopsAllHapticsOnEndPlay(
@@ -97,13 +97,13 @@ public:
const FRotator& InAnimationBoneRotationCorrectionOffset);
UFUNCTION(BlueprintPure, Category="SenseGlove | Components | Virtual Hand Component")
static bool AnimationShouldApplyBoneLocation(
static bool ShouldAnimationApplyBoneLocation(
const USGVirtualHandComponent* VirtualHandComponent);
UFUNCTION(BlueprintCallable, Category="SenseGlove | Components | Virtual Hand Component")
static void SetAnimationShouldApplyBoneLocation(
static void SetShouldAnimationApplyBoneLocation(
UPARAM(ref) USGVirtualHandComponent* VirtualHandComponent,
bool bInAnimationShouldApplyBoneLocation);
bool bInShouldAnimationApplyBoneLocation);
UFUNCTION(BlueprintPure, Category="SenseGlove | Components | Virtual Hand Component")
static bool AutoStopsAllHapticsOnEndPlay(const USGVirtualHandComponent* VirtualHandComponent);