void FEndPhysicsTickFunction::ExecuteTick(float DeltaTime, enum ELevelTick TickType, ENamedThreads::Type CurrentThread, const FGraphEventRef& MyCompletionGraphEvent) { check(Target); FPhysScene* PhysScene = Target->GetPhysicsScene(); if (PhysScene == NULL) { return; } FGraphEventRef PhysicsComplete = PhysScene->GetCompletionEvent(); if (PhysicsComplete.GetReference() && !PhysicsComplete->IsComplete()) { // don't release the next tick group until the physics has completed and we have run FinishPhysicsSim DECLARE_CYCLE_STAT(TEXT("FSimpleDelegateGraphTask.FinishPhysicsSim"), STAT_FSimpleDelegateGraphTask_FinishPhysicsSim, STATGROUP_TaskGraphTasks); MyCompletionGraphEvent->DontCompleteUntil( FSimpleDelegateGraphTask::CreateAndDispatchWhenReady( FSimpleDelegateGraphTask::FDelegate::CreateUObject(Target, &UWorld::FinishPhysicsSim), GET_STATID(STAT_FSimpleDelegateGraphTask_FinishPhysicsSim), PhysicsComplete, ENamedThreads::GameThread ) ); } else { // it was already done, so let just do it. Target->FinishPhysicsSim(); } }
void FEndPhysicsTickFunction::ExecuteTick(float DeltaTime, enum ELevelTick TickType, ENamedThreads::Type CurrentThread, const FGraphEventRef& MyCompletionGraphEvent) { QUICK_SCOPE_CYCLE_COUNTER(FEndPhysicsTickFunction_ExecuteTick); check(Target); FPhysScene* PhysScene = Target->GetPhysicsScene(); if (PhysScene == NULL) { return; } FGraphEventRef PhysicsComplete = PhysScene->GetCompletionEvent(); if (PhysicsComplete.GetReference() && !PhysicsComplete->IsComplete()) { // don't release the next tick group until the physics has completed and we have run FinishPhysicsSim DECLARE_CYCLE_STAT(TEXT("FSimpleDelegateGraphTask.FinishPhysicsSim"), STAT_FSimpleDelegateGraphTask_FinishPhysicsSim, STATGROUP_TaskGraphTasks); MyCompletionGraphEvent->DontCompleteUntil( FSimpleDelegateGraphTask::CreateAndDispatchWhenReady( FSimpleDelegateGraphTask::FDelegate::CreateUObject(Target, &UWorld::FinishPhysicsSim), GET_STATID(STAT_FSimpleDelegateGraphTask_FinishPhysicsSim), PhysicsComplete, ENamedThreads::GameThread ) ); } else { // it was already done, so let just do it. Target->FinishPhysicsSim(); } #if PHYSX_MEMORY_VALIDATION static int32 Frequency = 0; if (Frequency++ > 10) { Frequency = 0; GPhysXAllocator->ValidateHeaders(); } #endif }
/** Exposes ticking of physics-engine scene outside Engine. */ void FPhysScene::TickPhysScene(uint32 SceneType, FGraphEventRef& InOutCompletionEvent) { SCOPE_CYCLE_COUNTER(STAT_TotalPhysicsTime); SCOPE_CYCLE_COUNTER(STAT_PhysicsKickOffDynamicsTime); check(SceneType < NumPhysScenes); if (bPhysXSceneExecuting[SceneType] != 0) { // Already executing this scene, must call WaitPhysScene before calling this function again. UE_LOG(LogPhysics, Log, TEXT("TickPhysScene: Already executing scene (%d) - aborting."), SceneType); return; } #if WITH_SUBSTEPPING if (IsSubstepping(SceneType)) //we don't bother sub-stepping cloth { //We're about to start stepping so swap buffers. Might want to find a better place for this? PhysSubSteppers[SceneType]->SwapBuffers(); } #endif /** * clamp down... if this happens we are simming physics slower than real-time, so be careful with it. * it can improve framerate dramatically (really, it is the same as scaling all velocities down and * enlarging all timesteps) but at the same time, it will screw with networking (client and server will * diverge a lot more.) */ float UseDelta = FMath::Min(UseSyncTime(SceneType) ? SyncDeltaSeconds : DeltaSeconds, MaxPhysicsDeltaTime); // Only simulate a positive time step. if (UseDelta <= 0.f) { if (UseDelta < 0.f) { // only do this if negative. Otherwise, whenever we pause, this will come up UE_LOG(LogPhysics, Warning, TEXT("TickPhysScene: Negative timestep (%f) - aborting."), UseDelta); } return; } #if WITH_PHYSX GatherPhysXStats(GetPhysXScene(SceneType), SceneType); #endif /** * Weight frame time according to PhysScene settings. */ AveragedFrameTime[SceneType] *= FrameTimeSmoothingFactor[SceneType]; AveragedFrameTime[SceneType] += (1.0f - FrameTimeSmoothingFactor[SceneType])*UseDelta; // Set execution flag bPhysXSceneExecuting[SceneType] = true; check(!InOutCompletionEvent.GetReference()); // these should be gone because nothing is outstanding InOutCompletionEvent = FGraphEvent::CreateGraphEvent(); bool bTaskOutstanding = false; #if WITH_PHYSX #if WITH_VEHICLE if (VehicleManager && SceneType == PST_Sync) { float TickTime = AveragedFrameTime[SceneType]; #if WITH_SUBSTEPPING if (IsSubstepping(SceneType)) { TickTime = UseSyncTime(SceneType) ? SyncDeltaSeconds : DeltaSeconds; } #endif VehicleManager->PreTick(TickTime); #if WITH_SUBSTEPPING if (IsSubstepping(SceneType) == false) #endif { VehicleManager->Update(AveragedFrameTime[SceneType]); } } #endif #if !WITH_APEX PxScene* PScene = GetPhysXScene(SceneType); if (PScene && (UseDelta > 0.f)) { PhysXCompletionTask* Task = new PhysXCompletionTask(InOutCompletionEvent, PScene->getTaskManager()); PScene->lockWrite(); PScene->simulate(AveragedFrameTime[SceneType], Task); PScene->unlockWrite(); Task->removeReference(); bTaskOutstanding = true; } #else // #if !WITH_APEX // The APEX scene calls the simulate function for the PhysX scene, so we only call ApexScene->simulate(). NxApexScene* ApexScene = GetApexScene(SceneType); if(ApexScene && UseDelta > 0.f) { #if WITH_SUBSTEPPING if (IsSubstepping(SceneType)) //we don't bother sub-stepping cloth { bTaskOutstanding = SubstepSimulation(SceneType, InOutCompletionEvent); }else #endif { PhysXCompletionTask* Task = new PhysXCompletionTask(InOutCompletionEvent, ApexScene->getTaskManager()); ApexScene->simulate(AveragedFrameTime[SceneType], true, Task); Task->removeReference(); bTaskOutstanding = true; } } #endif // #if !WITH_APEX #endif // WITH_PHYSX if (!bTaskOutstanding) { InOutCompletionEvent->DispatchSubsequents(); // nothing to do, so nothing to wait for } #if WITH_SUBSTEPPING bSubstepping = UPhysicsSettings::Get()->bSubstepping; bSubsteppingAsync = UPhysicsSettings::Get()->bSubsteppingAsync; #endif }