可可西

UE4之LoadingScreen机制

1. 当IsMoviePlayerEnabled()为false或使用nullrhi来运行游戏时,会使用FNullGameMoviePlayer(空MoviePlayer)来跑

2. FDefaultGameMoviePlayer为实现LoadingScreen的核心类,包括视频数据流(IMovieStreamer)、UI界面(SWindow)、多线程更新(SlateLoadingThread)

3. 各个平台(Android、iOS、Windows)实现了自己的IMovieStreamer,用于解码视频文件,一个IMovieStreamer对应一个视频文件。

    各平台上的IMovieStreamer对象伴随FXXXMoviePlayerModule平台模块的加载来创建和注册到FDefaultGameMoviePlayer对象中,卸载来反注册和删除

TSharedPtr<FXXXMediaPlayerStreamer> XXXMovieStreamer; // 全局智能指针对象

class FXXXMoviePlayerModule : public IModuleInterface
{
    /** IModuleInterface implementation */
    virtual void StartupModule() override
    {
        FXXXMediaPlayerStreamer* Streamer = new FXXXMediaPlayerStreamer;
        XXXMovieStreamer = MakeShareable(Streamer);
            
        FCoreDelegates::RegisterMovieStreamerDelegate.Broadcast(XXXMovieStreamer);
    }

    virtual void ShutdownModule() override
    {
        if (XXXMovieStreamer.IsValid())
        {
            FCoreDelegates::UnRegisterMovieStreamerDelegate.Broadcast(XXXMovieStreamer);
        }

        XXXMovieStreamer->Cleanup();
        XXXMovieStreamer.Reset();
    }

};

 

一些MoviePlayer相关的函数:

/*** UnrealEngine\Engine\Source\Runtime\MoviePlayer\Public\MoviePlayer.h ***/
/** Creates the movie player */
MOVIEPLAYER_API void CreateMoviePlayer();

/** Destroys the movie player */
MOVIEPLAYER_API void DestroyMoviePlayer();

/** Gets the movie player singleton for the engine. */
MOVIEPLAYER_API IGameMoviePlayer* GetMoviePlayer();

MOVIEPLAYER_API IGameMoviePlayer& GetMoviePlayerRef();

/** Returns true if the movie player is enabled. */
bool MOVIEPLAYER_API IsMoviePlayerEnabled();

 

FSlateLoadingSynchronizationMechanism::SlateThreadRunMainLoop()

/** UnrealEngine\Engine\Source\Runtime\MoviePlayer\Private\MoviePlayerThreading.cpp **/
void FSlateLoadingSynchronizationMechanism::SlateThreadRunMainLoop()
{
    ThreadSuspendedEvent = FPlatformProcess::GetSynchEventFromPool();
    ThreadResumedEvent = FPlatformProcess::GetSynchEventFromPool();

    double LastTime = FPlatformTime::Seconds();

    bool bWasSuspendedLastFrame = false;

    while (IsSlateMainLoopRunning())
    {
        if (IsSuspended.GetValue() == 0)
        {
            if (bWasSuspendedLastFrame)
            {
                bWasSuspendedLastFrame = false;
                ThreadResumedEvent->Trigger();
            }

            {
                double CurrentTime = FPlatformTime::Seconds();
                double DeltaTime = CurrentTime - LastTime;

                // 60 fps max
                const double MaxTickRate = 1.0 / 60.0f;

                const double TimeToWait = MaxTickRate - DeltaTime;

                if (TimeToWait > 0)
                {
                    FPlatformProcess::Sleep(TimeToWait);
                    CurrentTime = FPlatformTime::Seconds();
                    DeltaTime = CurrentTime - LastTime;
                }

                if (FSlateApplication::IsInitialized() && !IsSlateDrawPassEnqueued())
                {
                    FSlateRenderer* MainSlateRenderer = FSlateApplication::Get().GetRenderer();
                    FScopeLock ScopeLock(MainSlateRenderer->GetResourceCriticalSection());

                    WidgetRenderer->DrawWindow(DeltaTime);

                    SetSlateDrawPassEnqueued();
                }

                LastTime = CurrentTime;
            }
        }
        else if (!bWasSuspendedLastFrame)
        {
            bWasSuspendedLastFrame = true;
            ThreadSuspendedEvent->Trigger();
        }
        else
        {
            FPlatformProcess::SleepNoStats(0.001f);
        }
    }
    
    while (IsSlateDrawPassEnqueued())
    {
        FPlatformProcess::Sleep(1.f / 60.f);
    }
    
    bMainLoopRunning = false;

    FPlatformProcess::ReturnSynchEventToPool(ThreadSuspendedEvent);
    ThreadSuspendedEvent = nullptr;
    FPlatformProcess::ReturnSynchEventToPool(ThreadResumedEvent);
    ThreadResumedEvent = nullptr;
}

 

 

FMoviePlayerWidgetRenderer::DrawWindow()

/** UnrealEngine\Engine\Source\Runtime\MoviePlayer\Private\DefaultGameMoviePlayer.cpp **/
void FMoviePlayerWidgetRenderer::DrawWindow(float DeltaTime)
{
    if (GDynamicRHI && GDynamicRHI->RHIIsRenderingSuspended())
    {
        // This avoids crashes if we Suspend rendering whilst the loading screen is up
        // as we don't want Slate to submit any more draw calls until we Resume.
        return;
    }

    const float Scale = FSlateApplication::Get().GetApplicationScale() * MainWindow->GetDPIScaleFactor();
    FVector2D DrawSize = VirtualRenderWindow->GetClientSizeInScreen() / Scale;

    FSlateApplication::Get().Tick(ESlateTickType::Time);

    FGeometry WindowGeometry = FGeometry::MakeRoot(DrawSize, FSlateLayoutTransform(Scale));

    VirtualRenderWindow->SlatePrepass(WindowGeometry.Scale);

    FSlateRect ClipRect = WindowGeometry.GetLayoutBoundingRect();

    HittestGrid->SetHittestArea(VirtualRenderWindow->GetPositionInScreen(), VirtualRenderWindow->GetViewportSize());
    HittestGrid->Clear();

    // Get the free buffer & add our virtual window
    FSlateDrawBuffer& DrawBuffer = SlateRenderer->GetDrawBuffer();
    FSlateWindowElementList& WindowElementList = DrawBuffer.AddWindowElementList(VirtualRenderWindow);

    WindowElementList.SetRenderTargetWindow(MainWindow);

    int32 MaxLayerId = 0;
    {
        FPaintArgs PaintArgs(nullptr, *HittestGrid, FVector2D::ZeroVector, FSlateApplication::Get().GetCurrentTime(), FSlateApplication::Get().GetDeltaTime());

        // Paint the window
        MaxLayerId = VirtualRenderWindow->Paint(    // TSharedRef<class SVirtualWindow> VirtualRenderWindow  注:SVirtualWindow : public SWindow
            PaintArgs,
            WindowGeometry, ClipRect,
            WindowElementList,
            0,
            FWidgetStyle(),
            VirtualRenderWindow->IsEnabled());
    }

    SlateRenderer->DrawWindows(DrawBuffer);  // 不LoadingScreen时,该逻辑跑在GameThread上

    DrawBuffer.ViewOffset = FVector2D::ZeroVector;
}

 

正常情况下,UI界面的更新是在GameThread中处理的

>    UE4Editor-SlateRHIRenderer.dll!FSlateRHIRenderer::DrawWindows_Private(FSlateDrawBuffer & WindowDrawBuffer={...}) Line 1501    C++
     UE4Editor-Slate.dll!FSlateApplication::PrivateDrawWindows(TSharedPtr<SWindow,0> DrawOnlyThisWindow={...}) Line 1389    C++
     UE4Editor-Slate.dll!FSlateApplication::DrawWindows() Line 1088    C++
     UE4Editor-Slate.dll!FSlateApplication::TickAndDrawWidgets(float DeltaTime) Line 1663    C++
     UE4Editor-Slate.dll!FSlateApplication::Tick(ESlateTickType TickType) Line 1517    C++
     UE4Editor-Win64-DebugGame.exe!FEngineLoop::Tick() Line 5051    C++
     [Inline Frame] UE4Editor-Win64-DebugGame.exe!EngineTick() Line 63    C++
     UE4Editor-Win64-DebugGame.exe!GuardedMain(const wchar_t * CmdLine=0x00000105e0b897c0) Line 174    C++
     UE4Editor-Win64-DebugGame.exe!WinMain(HINSTANCE__ * hInInstance=0x000000000000000a, HINSTANCE__ * hPrevInstance=0x0000000000000000, char * __formal=0x0000000000000000, int nCmdShow=0) Line 275    C++
     [Inline Frame] UE4Editor-Win64-DebugGame.exe!invoke_main() Line 102    C++
     UE4Editor-Win64-DebugGame.exe!__scrt_common_main_seh() Line 288    C++
     kernel32.dll!BaseThreadInitThunk()    Unknown
     ntdll.dll!RtlUserThreadStart()    Unknown

 

当GameThread长时间忙于其他事情时,为了防止UI界面卡死,可以将UI界面的更新切换到LoadingScreen线程来跑

>    UE4Editor-SlateRHIRenderer.dll!FSlateRHIRenderer::DrawWindows_Private(FSlateDrawBuffer & WindowDrawBuffer={...}) Line 1699    C++
     UE4Editor-MoviePlayer.dll!FMoviePlayerWidgetRenderer::DrawWindow(float DeltaTime=-1.78076227e-33) Line 1018    C++
     UE4Editor-MoviePlayer.dll!FSlateLoadingSynchronizationMechanism::SlateThreadRunMainLoop() Line 180    C++
     UE4Editor-MoviePlayer.dll!FSlateLoadingThreadTask::Run() Line 258    C++
     UE4Editor-Core.dll!FRunnableThreadWin::Run() Line 90    C++
     UE4Editor-Core.dll!FRunnableThreadWin::GuardedRun() Line 27    C++
     kernel32.dll!BaseThreadInitThunk()    Unknown
     ntdll.dll!RtlUserThreadStart()    Unknown

 

渲染会切换到FDefaultGameMoviePlayer::Tick中来跑   注:FDefaultGameMoviePlayerFTickableObjectRenderThread上派生

>    UE4Editor-MoviePlayer.dll!FDefaultGameMoviePlayer::Tick(float DeltaTime) Line 658    C++
     UE4Editor-RenderCore.dll!TickHighFrequencyTickables(double CurTime) Line 253    C++
     UE4Editor-RenderCore.dll!TickRenderingTickables() Line 271    C++
     [Inline Frame] UE4Editor-RenderCore.dll!FRenderingThreadTickHeartbeat::Run::__l7::<lambda_bfd1ddcd77fe5e349cdd0178d16972d4>::operator()(FRHICommandList &) Line 605    C++
     UE4Editor-RenderCore.dll!TEnqueueUniqueRenderCommandType<`FRenderingThreadTickHeartbeat::Run'::`7'::HeartbeatTickTickablesName,<lambda_bfd1ddcd77fe5e349cdd0178d16972d4>>::DoTask(ENamedThreads::Type CurrentThread=-1601341044, const TRefCountPtr<FGraphEvent> & MyCompletionGraphEvent={...}) Line 190    C++
     UE4Editor-RenderCore.dll!TGraphTask<TEnqueueUniqueRenderCommandType<`FRenderingThreadTickHeartbeat::Run'::`7'::HeartbeatTickTickablesName,<lambda_bfd1ddcd77fe5e349cdd0178d16972d4>>>::ExecuteTask(TArray<FBaseGraphTask *,TSizedDefaultAllocator<32>> & NewTasks, ENamedThreads::Type CurrentThread=ActualRenderingThread) Line 886    C++
     [Inline Frame] UE4Editor-Core.dll!FBaseGraphTask::Execute(TArray<FBaseGraphTask *,TSizedDefaultAllocator<32>> & CurrentThread=ActualRenderingThread, ENamedThreads::Type) Line 524    C++
     UE4Editor-Core.dll!FNamedTaskThread::ProcessTasksNamedThread(int QueueIndex, bool bAllowStall=true) Line 709    C++
     UE4Editor-Core.dll!FNamedTaskThread::ProcessTasksUntilQuit(int QueueIndex) Line 601    C++
     UE4Editor-RenderCore.dll!RenderingThreadMain(FEvent * TaskGraphBoundSyncEvent=0x000001f4e4c6da80) Line 378    C++
     UE4Editor-RenderCore.dll!FRenderingThread::Run() Line 537    C++
     UE4Editor-Core.dll!FRunnableThreadWin::Run() Line 90    C++
     UE4Editor-Core.dll!FRunnableThreadWin::GuardedRun() Line 27    C++
     kernel32.dll!BaseThreadInitThunk()    Unknown
     ntdll.dll!RtlUserThreadStart()    Unknown

 

游戏启动引擎初始化时

     ntdll.dll!NtCreateSection()    Unknown
     ntdll.dll!LdrpMapDllNtFileName()    Unknown
     ntdll.dll!LdrpMapDllFullPath()    Unknown
     ntdll.dll!LdrpProcessWork()    Unknown
     ntdll.dll!LdrpLoadDllInternal()    Unknown
     ntdll.dll!LdrpLoadDll()    Unknown
     ntdll.dll!LdrLoadDll()    Unknown
     KernelBase.dll!LoadLibraryExW()    Unknown
>    UE4Editor-Core.dll!FWindowsPlatformProcess::LoadLibraryWithSearchPaths(const FString & FileName={...}, const TArray<FString,TSizedDefaultAllocator<32>> & SearchPaths={...}) Line 1889    C++
     UE4Editor-Core.dll!FWindowsPlatformProcess::GetDllHandle(const wchar_t * FileName=0x000001808bb62980) Line 91    C++
     UE4Editor-Core.dll!FModuleManager::LoadModuleWithFailureReason(const FName InModuleName={...}, EModuleLoadResult & OutFailureReason=Success) Line 506    C++
     UE4Editor-Projects.dll!FModuleDescriptor::LoadModulesForPhase(ELoadingPhase::Type LoadingPhase=PreDefault, const TArray<FModuleDescriptor,TSizedDefaultAllocator<32>> & Modules={...}, TMap<FName,enum EModuleLoadResult,FDefaultSetAllocator,TDefaultMapHashableKeyFuncs<FName,enum EModuleLoadResult,0>> & ModuleLoadErrors={...}) Line 561    C++
     UE4Editor-Projects.dll!FPluginManager::TryLoadModulesForPlugin(const FPlugin & Plugin={...}, const ELoadingPhase::Type LoadingPhase) Line 1321    C++
     UE4Editor-Projects.dll!FPluginManager::LoadModulesForEnabledPlugins(const ELoadingPhase::Type LoadingPhase=PreDefault) Line 1395    C++
     UE4Editor-Win64-DebugGame.exe!FEngineLoop::LoadStartupModules() Line 3866    C++
     UE4Editor-Win64-DebugGame.exe!FEngineLoop::PreInitPostStartupScreen(const wchar_t * CmdLine=0x00007ff7e95d2b28) Line 3245    C++
     [Inline Frame] UE4Editor-Win64-DebugGame.exe!FEngineLoop::PreInit(const wchar_t *) Line 3649    C++
     [Inline Frame] UE4Editor-Win64-DebugGame.exe!EnginePreInit(const wchar_t *) Line 43    C++
     UE4Editor-Win64-DebugGame.exe!GuardedMain(const wchar_t * CmdLine=0x00000180d04997c0) Line 128    C++
     UE4Editor-Win64-DebugGame.exe!WinMain(HINSTANCE__ * hInInstance=0x000000000000000a, HINSTANCE__ * hPrevInstance=0x0000000000000000, char * __formal=0x0000000000000000, int nCmdShow=0) Line 275    C++
     [Inline Frame] UE4Editor-Win64-DebugGame.exe!invoke_main() Line 102    C++
     UE4Editor-Win64-DebugGame.exe!__scrt_common_main_seh() Line 288    C++
     kernel32.dll!BaseThreadInitThunk()    Unknown
     ntdll.dll!RtlUserThreadStart()    Unknown

 

FEngineLoop::PreInitPostStartupScreen()函数中主动调用GetMoviePlayer()->PlayMovie()来启动LoadingScreen线程

     UE4Editor-Core.dll!FRunnableThread::Create(FRunnable * InRunnable=0x0000026db4397f00, const wchar_t * ThreadName=0x0000026db441f160, unsigned int InStackSize=0, EThreadPriority InThreadPri=TPri_Normal, unsigned __int64 InThreadAffinityMask=18446744073709551615, EThreadCreateFlags InCreateFlags=None) Line 542    C++
>    [Inline Frame] UE4Editor-MoviePlayer.dll!FSlateLoadingSynchronizationMechanism::Initialize() Line 63    C++
     UE4Editor-MoviePlayer.dll!FDefaultGameMoviePlayer::PlayMovie() Line 386    C++
     UE4Editor-Win64-DebugGame.exe!FEngineLoop::PreInitPostStartupScreen(const wchar_t * CmdLine=0x00007ff7e95d2b28) Line 3212    C++
     [Inline Frame] UE4Editor-Win64-DebugGame.exe!FEngineLoop::PreInit(const wchar_t *) Line 3649    C++
     [Inline Frame] UE4Editor-Win64-DebugGame.exe!EnginePreInit(const wchar_t *) Line 43    C++
     UE4Editor-Win64-DebugGame.exe!GuardedMain(const wchar_t * CmdLine=0x0000026df8c597c0) Line 128    C++
     UE4Editor-Win64-DebugGame.exe!WinMain(HINSTANCE__ * hInInstance=0x000000000000000a, HINSTANCE__ * hPrevInstance=0x0000000000000000, char * __formal=0x0000000000000000, int nCmdShow=0) Line 275    C++
     [Inline Frame] UE4Editor-Win64-DebugGame.exe!invoke_main() Line 102    C++
     UE4Editor-Win64-DebugGame.exe!__scrt_common_main_seh() Line 288    C++
     kernel32.dll!BaseThreadInitThunk()    Unknown
     ntdll.dll!RtlUserThreadStart()    Unknown

 

在后续FEngineLoop::Init()函数中调用GetMoviePlayer()->WaitForMovieToFinish()来结束LoadingScreen线程

>    UE4Editor-MoviePlayer.dll!FSlateLoadingSynchronizationMechanism::DestroySlateThread() Line 81    C++
     UE4Editor-MoviePlayer.dll!FDefaultGameMoviePlayer::WaitForMovieToFinish(bool bAllowEngineTick=false) Line 443    C++
     UE4Editor-Win64-DebugGame.exe!FEngineLoop::Init() Line 4061    C++
     [Inline Frame] UE4Editor-Win64-DebugGame.exe!EngineInit() Line 53    C++
     UE4Editor-Win64-DebugGame.exe!GuardedMain(const wchar_t * CmdLine=0x0000026df8c597c0) Line 156    C++
     UE4Editor-Win64-DebugGame.exe!WinMain(HINSTANCE__ * hInInstance=0x000000000000000a, HINSTANCE__ * hPrevInstance=0x0000000000000000, char * __formal=0x0000000000000000, int nCmdShow=0) Line 275    C++
     [Inline Frame] UE4Editor-Win64-DebugGame.exe!invoke_main() Line 102    C++
     UE4Editor-Win64-DebugGame.exe!__scrt_common_main_seh() Line 288    C++
     kernel32.dll!BaseThreadInitThunk()    Unknown
     ntdll.dll!RtlUserThreadStart()    Unknown

 

LoadMap设置了LoadingScreen时

FDefaultGameMoviePlayer::Initialize()时,会注册PreLoadMap的代理,使得在加载地图之前开始执行PlayMovie()来启动LoadingScreen线程

     UE4Editor-Core.dll!FRunnableThread::Create(FRunnable * InRunnable=0x0000019c2e75edf0, const wchar_t * ThreadName=0x0000019c2e9f4ee0, unsigned int InStackSize=0, EThreadPriority InThreadPri=TPri_Normal, unsigned __int64 InThreadAffinityMask=18446744073709551615, EThreadCreateFlags InCreateFlags=None) Line 551    C++
>    [Inline Frame] UE4Editor-MoviePlayer.dll!FSlateLoadingSynchronizationMechanism::Initialize() Line 63    C++
     UE4Editor-MoviePlayer.dll!FDefaultGameMoviePlayer::PlayMovie() Line 386    C++
     UE4Editor-StreamingPauseRendering.dll!FStreamingPauseRenderingModule::BeginStreamingPause(FViewport * GameViewport=0x0000019c305c4460) Line 160    C++
     [Inline Frame] UE4Editor-Engine.dll!TDelegate<void __cdecl(FViewport *),FDefaultDelegateUserPolicy>::Execute(FViewport * <Params_0>) Line 580    C++
     UE4Editor-Engine.dll!UEngine::BlockTillLevelStreamingCompleted(UWorld * InWorld=0x0000019c32148b80) Line 13969    C++
     UE4Editor-Engine.dll!AGameMode::HandleMatchHasStarted() Line 242    C++
     UE4Editor-Engine.dll!AGameMode::SetMatchState(FName NewState={...}) Line 368    C++
     UE4Editor-Engine.dll!AGameMode::StartMatch() Line 216    C++
     UE4Editor-Engine.dll!UWorld::BeginPlay() Line 4616    C++
     UE4Editor-Engine.dll!UEngine::LoadMap(FWorldContext & WorldContext={...}, FURL URL={...}, UPendingNetGame * Pending=0xffffffffffffffff, FString & Error={...}) Line 13880    C++
     UE4Editor-Engine.dll!UEngine::Browse(FWorldContext & WorldContext={...}, FURL URL={...}, FString & Error={...}) Line 12928    C++
     UE4Editor-Engine.dll!UEngine::TickWorldTravel(FWorldContext & Context={...}, float DeltaSeconds) Line 13126    C++
     UE4Editor-Engine.dll!UGameEngine::Tick(float DeltaSeconds=11.7816048, bool bIdleMode=false) Line 1863    C++
     UE4Editor-Win64-DebugGame.exe!FEngineLoop::Tick() Line 4939    C++
     [Inline Frame] UE4Editor-Win64-DebugGame.exe!EngineTick() Line 63    C++
     UE4Editor-Win64-DebugGame.exe!GuardedMain(const wchar_t * CmdLine=0x0000019bc60d97c0) Line 174    C++
     UE4Editor-Win64-DebugGame.exe!WinMain(HINSTANCE__ * hInInstance=0x000000000000000a, HINSTANCE__ * hPrevInstance=0x0000000000000000, char * __formal=0x0000000000000000, int nCmdShow=0) Line 275    C++
     [Inline Frame] UE4Editor-Win64-DebugGame.exe!invoke_main() Line 102    C++
     UE4Editor-Win64-DebugGame.exe!__scrt_common_main_seh() Line 288    C++
     kernel32.dll!BaseThreadInitThunk()    Unknown
     ntdll.dll!RtlUserThreadStart()    Unknown

 

PostLoadMap时执行WaitForMovieToFinish()来结束LoadingScreen线程

>    UE4Editor-MoviePlayer.dll!FSlateLoadingSynchronizationMechanism::DestroySlateThread() Line 81    C++
     UE4Editor-MoviePlayer.dll!FDefaultGameMoviePlayer::WaitForMovieToFinish(bool bAllowEngineTick=false) Line 443    C++
     [Inline Frame] UE4Editor-MoviePlayer.dll!Invoke(void(FDefaultGameMoviePlayer::*)(UWorld *)) Line 65    C++
     [Inline Frame] UE4Editor-MoviePlayer.dll!UE4Tuple_Private::TTupleBase<TIntegerSequence<unsigned int>>::ApplyAfter(void(FDefaultGameMoviePlayer::*)(UWorld *) &) Line 299    C++
     UE4Editor-MoviePlayer.dll!TBaseRawMethodDelegateInstance<0,FDefaultGameMoviePlayer,void __cdecl(UWorld *),FDefaultDelegateUserPolicy>::ExecuteIfSafe(UWorld * <Params_0>) Line 469    C++
     UE4Editor-Engine.dll!TMulticastDelegate<void __cdecl(UWorld *),FDefaultDelegateUserPolicy>::Broadcast(UWorld * <Params_0>=0x0000019c1d957580) Line 955    C++
     UE4Editor-Engine.dll!UEngine::LoadMap(FWorldContext & WorldContext={...}, FURL URL={...}, UPendingNetGame * Pending=0xffffffffffffffff, FString & Error={...}) Line 13885    C++
     UE4Editor-Engine.dll!UEngine::Browse(FWorldContext & WorldContext={...}, FURL URL={...}, FString & Error={...}) Line 12928    C++
     UE4Editor-Engine.dll!UEngine::TickWorldTravel(FWorldContext & Context={...}, float DeltaSeconds) Line 13126    C++
     UE4Editor-Engine.dll!UGameEngine::Tick(float DeltaSeconds=0.0333334021, bool bIdleMode=false) Line 1863    C++
     UE4Editor-Win64-DebugGame.exe!FEngineLoop::Tick() Line 4939    C++
     [Inline Frame] UE4Editor-Win64-DebugGame.exe!EngineTick() Line 63    C++
     UE4Editor-Win64-DebugGame.exe!GuardedMain(const wchar_t * CmdLine=0x0000019bc60d97c0) Line 174    C++
     UE4Editor-Win64-DebugGame.exe!WinMain(HINSTANCE__ * hInInstance=0x000000000000000a, HINSTANCE__ * hPrevInstance=0x0000000000000000, char * __formal=0x0000000000000000, int nCmdShow=0) Line 275    C++
     [Inline Frame] UE4Editor-Win64-DebugGame.exe!invoke_main() Line 102    C++
     UE4Editor-Win64-DebugGame.exe!__scrt_common_main_seh() Line 288    C++
     kernel32.dll!BaseThreadInitThunk()    Unknown
     ntdll.dll!RtlUserThreadStart()    Unknown

 

FDefaultGameMoviePlayerOnPreLoadMapOnPostLoadMap函数

/** UnrealEngine\Engine\Source\Runtime\MoviePlayer\Private\DefaultGameMoviePlayer.cpp **/
void FDefaultGameMoviePlayer::OnPreLoadMap(const FString& LevelName)
{
    FCoreUObjectDelegates::PostLoadMapWithWorld.RemoveAll(this);

    if( PlayMovie() )
    {
        FCoreUObjectDelegates::PostLoadMapWithWorld.AddRaw(this, &FDefaultGameMoviePlayer::OnPostLoadMap );
    }
}

void FDefaultGameMoviePlayer::OnPostLoadMap(UWorld* LoadedWorld)
{
    if (!LoadingScreenAttributes.bAllowEngineTick)
    {
        // If engine tick is enabled, we don't want to tick here and instead want to run from the WaitForMovieToFinish call in LaunchEngineLoop
        WaitForMovieToFinish();
    }
}

 

LoadMap没有设置LoadingScreen时

LoadMapFStreamingPauseRenderingModule会执行PlayMovie()和WaitForMovieToFinish()

 

右下角会有三个点的UI动画表现(throbber),详见:UnrealEngine\Engine\Source\Runtime\Slate\Private\Widgets\Images\SThrobber.cpp

// FDefaultGameMoviePlayer::PlayMovie()
>    UE4Editor-MoviePlayer.dll!FDefaultGameMoviePlayer::PlayMovie() Line 385    C++
     UE4Editor-StreamingPauseRendering.dll!FStreamingPauseRenderingModule::BeginStreamingPause(FViewport * GameViewport=0x0000026e34448d80) Line 160    C++
     [Inline Frame] UE4Editor-Engine.dll!TDelegate<void __cdecl(FViewport *),FDefaultDelegateUserPolicy>::Execute(FViewport * <Params_0>) Line 580    C++
     UE4Editor-Engine.dll!UEngine::BlockTillLevelStreamingCompleted(UWorld * InWorld=0x0000026e23952080) Line 13969    C++
     UE4Editor-Engine.dll!AGameMode::HandleMatchHasStarted() Line 242    C++
     UE4Editor-Engine.dll!AGameMode::SetMatchState(FName NewState={...}) Line 368    C++
     UE4Editor-Engine.dll!AGameMode::StartMatch() Line 216    C++
     UE4Editor-Engine.dll!UWorld::BeginPlay() Line 4616    C++
     UE4Editor-Engine.dll!UEngine::LoadMap(FWorldContext & WorldContext={...}, FURL URL={...}, UPendingNetGame * Pending=0xffffffffffffffff, FString & Error={...}) Line 13880    C++
     UE4Editor-Engine.dll!UEngine::Browse(FWorldContext & WorldContext={...}, FURL URL={...}, FString & Error={...}) Line 12928    C++
     UE4Editor-Engine.dll!UEngine::TickWorldTravel(FWorldContext & Context={...}, float DeltaSeconds) Line 13126    C++
     UE4Editor-Engine.dll!UGameEngine::Tick(float DeltaSeconds=104.692589, bool bIdleMode=false) Line 1863    C++
     UE4Editor-Win64-DebugGame.exe!FEngineLoop::Tick() Line 4939    C++
     [Inline Frame] UE4Editor-Win64-DebugGame.exe!EngineTick() Line 63    C++
     UE4Editor-Win64-DebugGame.exe!GuardedMain(const wchar_t * CmdLine=0x0000026df8c597c0) Line 174    C++
     UE4Editor-Win64-DebugGame.exe!WinMain(HINSTANCE__ * hInInstance=0x000000000000000a, HINSTANCE__ * hPrevInstance=0x0000000000000000, char * __formal=0x0000000000000000, int nCmdShow=0) Line 275    C++
     [Inline Frame] UE4Editor-Win64-DebugGame.exe!invoke_main() Line 102    C++
     UE4Editor-Win64-DebugGame.exe!__scrt_common_main_seh() Line 288    C++
     kernel32.dll!BaseThreadInitThunk()    Unknown
     ntdll.dll!RtlUserThreadStart()    Unknown


// FDefaultGameMoviePlayer::WaitForMovieToFinish()
>    UE4Editor-MoviePlayer.dll!FDefaultGameMoviePlayer::WaitForMovieToFinish(bool bAllowEngineTick=false) Line 436    C++
     UE4Editor-StreamingPauseRendering.dll!FStreamingPauseRenderingModule::EndStreamingPause() Line 173    C++
     [Inline Frame] UE4Editor-Engine.dll!TDelegate<void __cdecl(void),FDefaultDelegateUserPolicy>::Execute() Line 580    C++
     UE4Editor-Engine.dll!UEngine::BlockTillLevelStreamingCompleted(UWorld * InWorld=0x0000026e23952080) Line 13973    C++
     UE4Editor-Engine.dll!AGameMode::HandleMatchHasStarted() Line 242    C++
     UE4Editor-Engine.dll!AGameMode::SetMatchState(FName NewState={...}) Line 368    C++
     UE4Editor-Engine.dll!AGameMode::StartMatch() Line 216    C++
     UE4Editor-Engine.dll!UWorld::BeginPlay() Line 4616    C++
     UE4Editor-Engine.dll!UEngine::LoadMap(FWorldContext & WorldContext={...}, FURL URL={...}, UPendingNetGame * Pending=0xffffffffffffffff, FString & Error={...}) Line 13880    C++
     UE4Editor-Engine.dll!UEngine::Browse(FWorldContext & WorldContext={...}, FURL URL={...}, FString & Error={...}) Line 12928    C++
     UE4Editor-Engine.dll!UEngine::TickWorldTravel(FWorldContext & Context={...}, float DeltaSeconds) Line 13126    C++
     UE4Editor-Engine.dll!UGameEngine::Tick(float DeltaSeconds=104.692589, bool bIdleMode=false) Line 1863    C++
     UE4Editor-Win64-DebugGame.exe!FEngineLoop::Tick() Line 4939    C++
     [Inline Frame] UE4Editor-Win64-DebugGame.exe!EngineTick() Line 63    C++
     UE4Editor-Win64-DebugGame.exe!GuardedMain(const wchar_t * CmdLine=0x0000026df8c597c0) Line 174    C++
     UE4Editor-Win64-DebugGame.exe!WinMain(HINSTANCE__ * hInInstance=0x000000000000000a, HINSTANCE__ * hPrevInstance=0x0000000000000000, char * __formal=0x0000000000000000, int nCmdShow=0) Line 275    C++
     [Inline Frame] UE4Editor-Win64-DebugGame.exe!invoke_main() Line 102    C++
     UE4Editor-Win64-DebugGame.exe!__scrt_common_main_seh() Line 288    C++
     kernel32.dll!BaseThreadInitThunk()    Unknown
     ntdll.dll!RtlUserThreadStart()    Unknown

 

主循环Tick中调用FDefaultGameMoviePlayer::WaitForMovieToFinish

>    UE4Editor-MoviePlayer.dll!FDefaultGameMoviePlayer::WaitForMovieToFinish(bool bAllowEngineTick=true) Line 436    C++
     UE4Editor-Win64-DebugGame.exe!FEngineLoop::Tick() Line 4963    C++
     [Inline Frame] UE4Editor-Win64-DebugGame.exe!EngineTick() Line 63    C++
     UE4Editor-Win64-DebugGame.exe!GuardedMain(const wchar_t * CmdLine=0x0000026df8c597c0) Line 174    C++
     UE4Editor-Win64-DebugGame.exe!WinMain(HINSTANCE__ * hInInstance=0x000000000000000a, HINSTANCE__ * hPrevInstance=0x0000000000000000, char * __formal=0x0000000000000000, int nCmdShow=0) Line 275    C++
     [Inline Frame] UE4Editor-Win64-DebugGame.exe!invoke_main() Line 102    C++
     UE4Editor-Win64-DebugGame.exe!__scrt_common_main_seh() Line 288    C++
     kernel32.dll!BaseThreadInitThunk()    Unknown
     ntdll.dll!RtlUserThreadStart()    Unknown

 

扩展阅读

LoadingScreen(github)

Async Loading Screens and Transition Levels | Unreal Fest Europe 2019 | Unreal Engine

 

posted on 2024-06-20 23:27  可可西  阅读(205)  评论(0编辑  收藏  举报

导航