Add time slicing to Deserialization stage of async scenes loading to avoid hitching
#3261
This commit is contained in:
@@ -114,6 +114,19 @@ struct ScriptsReloadObject
|
|||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
// Small utility for dividing the iterative work over data set that can run in equal slicer limited by time.
|
||||||
|
struct TimeSlicer
|
||||||
|
{
|
||||||
|
int32 Index = -1;
|
||||||
|
int32 Count = 0;
|
||||||
|
double TimeBudget;
|
||||||
|
double StartTime;
|
||||||
|
|
||||||
|
void BeginSync(float timeBudget, int32 count, int32 startIndex = 0);
|
||||||
|
bool StepSync();
|
||||||
|
SceneResult End();
|
||||||
|
};
|
||||||
|
|
||||||
// Async map loading utility for state tracking and synchronization of various load stages.
|
// Async map loading utility for state tracking and synchronization of various load stages.
|
||||||
class SceneLoader
|
class SceneLoader
|
||||||
{
|
{
|
||||||
@@ -154,6 +167,7 @@ public:
|
|||||||
Array<Actor*> InjectedSceneChildren;
|
Array<Actor*> InjectedSceneChildren;
|
||||||
SceneObjectsFactory::Context Context;
|
SceneObjectsFactory::Context Context;
|
||||||
SceneObjectsFactory::PrefabSyncData* PrefabSyncData = nullptr;
|
SceneObjectsFactory::PrefabSyncData* PrefabSyncData = nullptr;
|
||||||
|
TimeSlicer StageSlicer;
|
||||||
|
|
||||||
SceneLoader(bool asyncLoad = false)
|
SceneLoader(bool asyncLoad = false)
|
||||||
: AsyncLoad(asyncLoad)
|
: AsyncLoad(asyncLoad)
|
||||||
@@ -1002,6 +1016,38 @@ SceneResult LevelImpl::loadScene(SceneLoader& loader, rapidjson_flax::Value& dat
|
|||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void TimeSlicer::BeginSync(float timeBudget, int32 count, int32 startIndex)
|
||||||
|
{
|
||||||
|
if (Index == -1)
|
||||||
|
{
|
||||||
|
// Starting
|
||||||
|
Index = startIndex;
|
||||||
|
Count = count;
|
||||||
|
}
|
||||||
|
TimeBudget = (double)timeBudget;
|
||||||
|
StartTime = Platform::GetTimeSeconds();
|
||||||
|
}
|
||||||
|
|
||||||
|
bool TimeSlicer::StepSync()
|
||||||
|
{
|
||||||
|
Index++;
|
||||||
|
double time = Platform::GetTimeSeconds();
|
||||||
|
double dt = time - StartTime;
|
||||||
|
return dt >= TimeBudget;
|
||||||
|
}
|
||||||
|
|
||||||
|
SceneResult TimeSlicer::End()
|
||||||
|
{
|
||||||
|
if (Index >= Count)
|
||||||
|
{
|
||||||
|
// Finished
|
||||||
|
*this = TimeSlicer();
|
||||||
|
return SceneResult::Success;
|
||||||
|
}
|
||||||
|
|
||||||
|
return SceneResult::Wait;
|
||||||
|
}
|
||||||
|
|
||||||
SceneResult SceneLoader::Tick(Args& args)
|
SceneResult SceneLoader::Tick(Args& args)
|
||||||
{
|
{
|
||||||
switch (Stage)
|
switch (Stage)
|
||||||
@@ -1216,19 +1262,24 @@ SceneResult SceneLoader::OnDeserialize(Args& args)
|
|||||||
else
|
else
|
||||||
{
|
{
|
||||||
Scripting::ObjectsLookupIdMapping.Set(&Modifier->IdsMapping);
|
Scripting::ObjectsLookupIdMapping.Set(&Modifier->IdsMapping);
|
||||||
for (int32 i = 1; i < dataCount; i++) // start from 1. at index [0] was scene
|
StageSlicer.BeginSync(args.TimeBudget, dataCount, 1); // start from 1. at index [0] was scene
|
||||||
|
while (StageSlicer.Index < StageSlicer.Count)
|
||||||
{
|
{
|
||||||
auto& objData = args.Data[i];
|
auto& objData = args.Data[StageSlicer.Index];
|
||||||
auto obj = objects[i];
|
auto obj = objects[StageSlicer.Index];
|
||||||
if (obj)
|
if (obj)
|
||||||
SceneObjectsFactory::Deserialize(Context, obj, objData);
|
SceneObjectsFactory::Deserialize(Context, obj, objData);
|
||||||
|
if (StageSlicer.StepSync())
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
Scripting::ObjectsLookupIdMapping.Set(nullptr);
|
Scripting::ObjectsLookupIdMapping.Set(nullptr);
|
||||||
}
|
}
|
||||||
Context.Async = wasAsync;
|
Context.Async = wasAsync;
|
||||||
|
|
||||||
|
auto result = StageSlicer.End();
|
||||||
|
if (result != SceneResult::Wait)
|
||||||
NextStage();
|
NextStage();
|
||||||
return SceneResult::Success;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
SceneResult SceneLoader::OnSyncPrefabs(Args& args)
|
SceneResult SceneLoader::OnSyncPrefabs(Args& args)
|
||||||
|
|||||||
Reference in New Issue
Block a user