Files
UnrealEngineUWP/Engine/Source/Editor/MainFrame/Private/Frame/MainFrameHandler.h
Robert Manuszewski 8fe5db30e3 Merging UE4-Streaming to UE4
- Linkers are no longer UObjects. Renamed ULinker, ULinkerLoad and ULinkerSave to FLinker, FLinkerLoad, FLinkerSave respectively
- Linkers are now associated with their UPackages
- Linker version is now stored in UPackages
- Async loading is now performed on a separate thread (if platform supports it and only in cooked builds), with the exception of PostLoad which is still done on the game thread
- Added UObject::IsPostLoadThreadSafe() function to determine if PostLoad is thread safe and can be executed on the async loading thread (defaults to false)
- UObject creation is now thread safe and can be performed on any thread
- Move many of the linker/UObject globals into FUObjectThreadContext (TLS)
- GetAsyncLoadPercentage() now takes PostLoad into account
- More async loading stats
- Added AtomicallySetFlags/ClearFlags to UObject
- Made FModuleManager thread safe.
- Added FGCScopeGuard as means of preventing GC from executing from non-game thread
- It's possible to disable async loading thread through ini settings.
- Cancelling async loading will now also trigger GC
- Implemented a basic version of async streaming priorities.

Change 2410813 by Mikolaj Sieluzycki:
	Change Sleep in while loop to ConditionalSleep in FMultiReaderSingleWriterGT
Change 2410734 by Mikolaj Sieluzycki:
	Make FModuleManager thread safe.
Change 2399879 by Mikolaj Sieluzycki:
	Basic version of async streaming priorities.
Change 2410707 by Mikolaj Sieluzycki:
	Implement conditional and no stat versions of sleep.
Change 2371939 by Robert Manuszewski:
	Async Loading Improvements: adding more stats (accumulators)
Change 2372403 by Robert Manuszewski:
	Fixing compile errors when STATs are not enabled
Change 2371526 by Robert Manuszewski:
	AsyncLoading Improvements (WIP)
Change 2407198 by Robert Manuszewski:
	Re-implementing delegate fixes for Async Loading
Change 2407425 by Robert Manuszewski:
	Re-implementing cancelling async loading in the async loading branch.
Change 2484362 by Robert Manuszewski:
	Making it possible to disable async loading thread through ini settings.
Change 2484744 by Robert Manuszewski:
	Minimizing locks in GC and other threads when handling UObjects
Change 2480190 by Robert Manuszewski:
	Fixing infinite stall after canceling async loading in non-cooked builds
Change 2484268 by Robert Manuszewski:
	Fixing crash when allocating permanent object pool.
Change 2489761 by Robert Manuszewski:
	Fixing BulkData using linker archive on the main thread even if the linker was created on the async loading thread.
Change 2493624 by Robert Manuszewski:
	Cancelling async loading will now also trigger GC
Change 2487881 by Robert Manuszewski:
	Making ShaderIdMap operations thread safe.
Change 2488067 by Robert Manuszewski:
	Fixing GetAsyncLoadPercentage. It will now also respect PostLoad.
Change 2458640 by Robert Manuszewski:
	Fixing crash in PIE
Change 2458825 by Robert Manuszewski:
	Fixing a few crashes when streaming and the package is missing.
Change 2476935 by Robert Manuszewski:
	Fixing crash while async loading ANavigationData
Change 2477361 by Robert Manuszewski:
	Fixing crashes in cooked game
Change 2480095 by Robert Manuszewski:
	Making FUObjectArray more thread safe
Change 2475443 by Robert Manuszewski:
	Re-enabling single-threaded async loading path for the editor and platforms that don't support multithreading.
Change 2475458 by Robert Manuszewski:
	Making sure bulk data is only loaded on a separate thread if it's not being loaded on the async loading thread.
Change 2476661 by Robert Manuszewski:
	Fixing FlushAsyncLoading not flushing everything
Change 2401089 by Jaroslaw Surowiec:
	Core - Added AtomicallySetFlags/ClearFlags to UObject, added a comment to ThisThreadAtomicallyClearedRFUnreachable

[CL 2498249 by Robert Manuszewski in Main branch]
2015-04-01 03:03:18 -04:00

247 lines
7.6 KiB
C++

// Copyright 1998-2015 Epic Games, Inc. All Rights Reserved.
#pragma once
/**
* Helper class that handles talking to the Slate App Manager.
*/
class FMainFrameHandler : public TSharedFromThis<FMainFrameHandler>
{
public:
/**
* Shuts down the Editor.
*/
void ShutDownEditor( TSharedRef<SDockTab> TabBeingClosed )
{
ShutDownEditor();
}
/**
* Shuts down the Editor.
*/
void ShutDownEditor( );
/**
* Checks whether the main frame tab can be closed.
*
* @return true if the tab can be closed, false otherwise.
*/
bool CanCloseTab()
{
if ( GIsRequestingExit )
{
UE_LOG(LogMainFrame, Warning, TEXT("MainFrame: Shutdown already in progress when CanCloseTab was queried, approve tab for closure."));
return true;
}
return CanCloseEditor();
}
/**
* Checks whether the Editor tab can be closed.
*
* @return true if the Editor can be closed, false otherwise.
*/
bool CanCloseEditor()
{
if ( FSlateApplication::IsInitialized() && !FSlateApplication::Get().IsNormalExecution() )
{
// DEBUGGER EXIT PATH
// The debugger is running we cannot actually close now.
// We will stop the debugger and enque a request to close the editor on the next frame.
// Stop debugging.
FSlateApplication::Get().LeaveDebuggingMode();
// Defer the call RequestCloseEditor() till next tick.
GEngine->DeferredCommands.Add( TEXT("CLOSE_SLATE_MAINFRAME") );
// Cannot exit right now.
return false;
}
else if (GIsSavingPackage || IsGarbageCollecting())
{
// SAVING/GC PATH
// We're currently saving or garbage collecting and can't close the editor just yet.
// We will have to wait and try to request to close the editor on the next frame.
// Defer the call RequestCloseEditor() till next tick.
GEngine->DeferredCommands.Add( TEXT("CLOSE_SLATE_MAINFRAME") );
// Cannot exit right now.
return false;
}
else
{
// NORMAL EXIT PATH
// Unattented mode can always exit.
if (FApp::IsUnattended())
{
return true;
}
// We can't close if lightmass is currently building
if (GUnrealEd->WarnIfLightingBuildIsCurrentlyRunning()) {return false;}
bool bOkToExit = true;
// Check if level Mode is open this does PostEditMove processing on actors when it closes so need to do this first before save dialog
if( GLevelEditorModeTools().IsModeActive( FBuiltinEditorModes::EM_Level ) ||
GLevelEditorModeTools().IsModeActive( FBuiltinEditorModes::EM_StreamingLevel) )
{
GLevelEditorModeTools().DeactivateMode(FBuiltinEditorModes::EM_Level);
GLevelEditorModeTools().DeactivateMode(FBuiltinEditorModes::EM_StreamingLevel);
bOkToExit = false;
}
// Can we close all the major tabs? They have sub-editors in them that might want to not close
{
// Ignore the LevelEditor tab; it invoked this function in the first place.
TSet< TSharedRef<SDockTab> > TabsToIgnore;
if ( MainTabPtr.IsValid() )
{
TabsToIgnore.Add( MainTabPtr.Pin().ToSharedRef() );
}
bOkToExit = bOkToExit && FGlobalTabmanager::Get()->CanCloseManager(TabsToIgnore);
}
// Prompt for save and quit only if we did not launch a gameless rocket exe or are in demo mode
if ( FApp::HasGameName() && !GIsDemoMode )
{
// Prompt the user to save packages/maps.
bool bHadPackagesToSave = false;
{
const bool bPromptUserToSave = true;
const bool bSaveMapPackages = true;
const bool bSaveContentPackages = true;
const bool bFastSave = false;
const bool bNotifyNoPackagesSaved = false;
const bool bCanBeDeclined = true;
bOkToExit = bOkToExit && FEditorFileUtils::SaveDirtyPackages(bPromptUserToSave, bSaveMapPackages, bSaveContentPackages, bFastSave, bNotifyNoPackagesSaved, bCanBeDeclined, &bHadPackagesToSave);
}
// If there were packages to save, or switching project, then the user already had a chance to bail out of exiting.
if ( !bOkToExit && !bHadPackagesToSave && FUnrealEdMisc::Get().GetPendingProjectName().IsEmpty() )
{
FUnrealEdMisc::Get().ClearPendingProjectName();
FUnrealEdMisc::Get().AllowSavingLayoutOnClose(true);
FUnrealEdMisc::Get().ForceDeletePreferences(false);
FUnrealEdMisc::Get().ClearConfigRestoreFilenames();
}
}
return bOkToExit;
}
}
void CloseRootWindowOverride( const TSharedRef<SWindow>& WindowBeingClosed )
{
if (CanCloseEditor())
{
ShutDownEditor();
}
}
/**
* Method that handles the generation of the mainframe, given the window it resides in,
* and a string which determines the initial layout of its primary dock area.
*/
void OnMainFrameGenerated( const TSharedPtr<SDockTab>& MainTab, const TSharedRef<SWindow>& InRootWindow )
{
TSharedRef<FGlobalTabmanager> GlobalTabManager = FGlobalTabmanager::Get();
if (MainTab.IsValid())
{
GlobalTabManager->SetMainTab(MainTab.ToSharedRef());
}
// Persistent layouts should get stored using the specified method.
GlobalTabManager->SetOnPersistLayout(FTabManager::FOnPersistLayout::CreateRaw(this, &FMainFrameHandler::HandleTabManagerPersistLayout));
const bool bIncludeGameName = true;
GlobalTabManager->SetApplicationTitle( StaticGetApplicationTitle( bIncludeGameName ) );
InRootWindow->SetRequestDestroyWindowOverride( FRequestDestroyWindowOverride::CreateRaw( this, &FMainFrameHandler::CloseRootWindowOverride ) );
MainTabPtr = MainTab;
RootWindowPtr = InRootWindow;
EnableTabClosedDelegate();
}
/**
* Shows the main frame window. Call this after you've setup initial layouts to reveal the window
*
* @param bStartImmersivePIE True to force a main frame viewport into immersive mode PIE session before shown
*/
void ShowMainFrameWindow(TSharedRef<SWindow> Window, const bool bStartImmersivePIE) const
{
// Make sure viewport windows are maximized/immersed if they need to be
FLevelEditorModule& LevelEditor = FModuleManager::GetModuleChecked< FLevelEditorModule >( TEXT( "LevelEditor" ) );
if( bStartImmersivePIE )
{
// Kick off an immersive PIE session immediately!
LevelEditor.StartImmersivePlayInEditorSession();
Window->ShowWindow();
// Ensure the window is at the front or else we could end up capturing and locking the mouse to a window that isnt visible
bool bForceWindowToFront = true;
Window->BringToFront( bForceWindowToFront );
// Need to register after the window is shown or else we cant capture the mouse
TSharedPtr<ILevelViewport> Viewport = LevelEditor.GetFirstActiveViewport();
Viewport->RegisterGameViewportIfPIE();
}
else
{
// Show the window!
Window->ShowWindow();
// Focus the level editor viewport
LevelEditor.FocusViewport();
// Restore any assets we had open. Note we don't do this on immersive PIE as its annoying to the user.
FAssetEditorManager::Get().RequestRestorePreviouslyOpenAssets();
}
}
/** Gets the parent window of the mainframe */
TSharedPtr<SWindow> GetParentWindow() const
{
return RootWindowPtr.Pin();
}
/** Sets the reference to the main tab */
void SetMainTab(const TSharedRef<SDockTab>& MainTab)
{
MainTabPtr = MainTab;
}
/** Enables the delegate responsible for shutting down the editor when the main tab is closed */
void EnableTabClosedDelegate();
/** Disables the delegate responsible for shutting down the editor when the main tab is closed */
void DisableTabClosedDelegate();
private:
// Callback for persisting the Level Editor's layout.
void HandleTabManagerPersistLayout( const TSharedRef<FTabManager::FLayout>& LayoutToSave )
{
FLayoutSaveRestore::SaveToConfig(GEditorLayoutIni, LayoutToSave);
}
private:
/** Editor main frame window */
TWeakPtr<SDockTab> MainTabPtr;
/** The window that all of the editor is parented to. */
TWeakPtr<SWindow> RootWindowPtr;
};