You've already forked UnrealEngineUWP
mirror of
https://github.com/izzy2lost/UnrealEngineUWP.git
synced 2026-03-26 18:15:20 -07:00
#lockdown Nick.Penwarden #rb none ========================== MAJOR FEATURES + CHANGES ========================== Change 3250856 on 2017/01/09 by Daniel.Wright Only showing instruction count for 'Base pass shader' now Change 3250943 on 2017/01/09 by Rolando.Caloca DR - Async Compute PSO creation Change 3251036 on 2017/01/09 by Rolando.Caloca DR - Add r.AsyncPipelineCompile - Dispatch on any thread - Wait for completion event Change 3251058 on 2017/01/09 by Ben.Woodhouse Fix for PSO creation D3D error with NumRenderTargets. Add code to compute the correct number of valid rendertargets to prevent an issue during PSO creation when NumRenderTargets is >0, but none of the formats are valid (all formats are DXGI_UNKNOWN) #jira UE-40332 Change 3251141 on 2017/01/09 by Ben.Woodhouse Duplicated from Fortnite CL 3243458: D3D12 memory optimization - The d3d12 buddy suballocator is very wasteful for allocations above 4KB, but the vast majority of allocations are smaller . In the default buffer allocator this was causing 149MB of waste in 340MB of allocations. Moving the max allocation size threshold down to 4KB from 512KB saved 100MB of memory wastage memory. On PC, buffers are 64KB aligned, so we need the threshold to be higher to avoid additional wastage. Add PIX memory tracking instrumentation for buddy allocators so we can track the memory properly in PIX Change 3251142 on 2017/01/09 by Ben.Woodhouse Duplicated from Fortnite 3243496 memory optimisation: use NULL-terminated ansi strings instead of unicode FStrings for symbols, saving 118MB. Previously the strings were loaded from disk as ansi and then converted to FStrings (slowly), before finally being converted them back to ansi strings before being used. In addition to reducing memory overhead, this change reduces complexity and improves startup time. Change 3252323 on 2017/01/10 by Rolando.Caloca DR - Gfx async PSO creation prep Change 3252474 on 2017/01/10 by Daniel.Wright Added 'Compile Unreal Lightmass' to error message Change 3252589 on 2017/01/10 by Daniel.Wright Back out bulk data for distance fields from cl 3241990 which causes distance fields to be corrupt in Fortnite Change 3252790 on 2017/01/10 by Daniel.Wright Added InscatteringColorCubemapAngle to exponential height fog Change 3252843 on 2017/01/10 by Uriel.Doyon Propper fix for UE-40211, where texture streaming bound defrag and async tasks could interact in coherent ways. The bound defrag is now done outside of the async work logic. Change 3252866 on 2017/01/10 by Mark.Satterthwaite Fix Metal shader pipeline hash collisions caused by deferring MTLFunction construction until PrepareToDraw so that we may use Function-Constants to specialise the shader source without generating additional permutations. This is required to generate proper tessellation shaders which are specialised against the index-buffer usage & type (none, uint16, uint32). While we're here amend the hash functions to make better use of the existing hash functions to improve the distribution and hopefully reduce the possibility of collisions in future. #jira UE-40357 Change 3254511 on 2017/01/11 by Rolando.Caloca DR - PSO stats Change 3255958 on 2017/01/12 by Mark.Satterthwaite Reimplement RQT_AbsoluteTime for Metal - pretty sure I did this before, but somehow it got lost. When a RQT_AbsoluteTime is inserted into the command-stream, insert a command-buffer completion handler to record the time of completion & submit the command-buffer immediately. This breaks command-buffers so is noticeably slower and if inserted in a pass that can't be restarted will fail but is currently the only option available. This is sufficient to support the GPUBenchmark used by Scalability. To make this more efficient I've refactored the FMetalCommandBufferFence implementation so that we use a single shared-ptr object containing the command-buffer and a dispatch semaphore, rather than allocating one for each query. The semaphore allows for timed-waits where previously we'd block until completion, unlike the other APIs that report failure after a fixed interval (2s for RQT_AbsoluteTime, otherwise 0.5s). Sadly not all drivers support this abuse of the Metal API, so replace the GL-based workaround for not having time queries with one that just guesses based on RHI device details. Radars will be filed. #jira UE-40554 Change 3256329 on 2017/01/12 by Olaf.Piesche #jira UE-38615 Assert shouldn't be necessary; in fact, it causes a crash when exporting emitters, since in that case we're changing the template at runtime. Change 3256371 on 2017/01/12 by Uriel.Doyon Reenabled texture streaming bound defrag as the fix is in CL 3252843 Change 3257032 on 2017/01/13 by Daniel.Wright Added fastClamp to fastmath.usf Change 3257111 on 2017/01/13 by Daniel.Wright Disabled bAffectDistanceFieldLighting on DefaultPawn, fixes VisualizeMeshDistanceFields in game Change 3257112 on 2017/01/13 by Daniel.Wright DFAO optimizations * Changed the culling algorithm to produce a list of intersecting screen tiles for each object, instead of the other way around. Each tile / object intersection gets its own cone tracing thread group so wavefronts are much smaller and scheduled better. 3.63ms -> 3.48ms (.15ms) * Replace slow instructions in inner loop with fast approximations (exp2 -> sqr + 1, rcpFast, lengthFast) 3.25ms -> 3.09ms (.16ms) * Moved transform from world to local space out of the inner loop (sample position constructed from local space position + direction) 3.09ms -> 3.04ms * Compute shader for ClearUAV 3.04ms -> 2.62ms (.42ms) Change 3257113 on 2017/01/13 by Daniel.Wright Better distance field memory stats Change 3257326 on 2017/01/13 by Uriel.Doyon Workaround to support cases where several textures have the same lighting GUID. Change 3257448 on 2017/01/13 by Daniel.Wright Removed legacy features Distance Field Specular Occlusion, Distance Field Surface Cache AO, PreCullTriangles Change 3257616 on 2017/01/13 by Daniel.Wright Distance field mesh visualization now uses a cone containing the entire tile to cull objects with, making the results stable Change 3257657 on 2017/01/13 by Daniel.Wright Mesh distance fields are stored zlib compressed in memory until needed for uploading to GPU * 81Mb of backing memory -> 32Mb in GPUPerfTest, atlas upload time 29ms -> 893ms Change 3258063 on 2017/01/14 by Rolando.Caloca DR - vk - Refactor descriptor set reuse in prep for more changes Change 3258715 on 2017/01/16 by Daniel.Wright Added VisualizeGlobalDistanceField show flag Change 3258827 on 2017/01/16 by Daniel.Wright Global distance field update regions are clipped against others to reduce redundant updates. Change 3258959 on 2017/01/16 by Benjamin.Hyder Updating Planar Reflection example material in TM-Shadermodels Change3259270on 2017/01/16 by Daniel.Wright [Copy] 'r.MSAACount 1' now produces no MSAA or TAA. 'r.MSAACount 0' can be used to toggle TAA on for comparisons. Change 3259652 on 2017/01/16 by Uriel.Doyon Better support for static primitive becoming dynamic. Change 3260107 on 2017/01/17 by Ben.Woodhouse Fix FMonitoredProcess to prevent infinite loop in -nothreading mode #jira UE-40717 Change 3260594 on 2017/01/17 by Daniel.Wright Added a new global distance field (4x 128^3 clipmaps) which caches mostly static primitives (Mobility set to Static or Stationary) * The full global distance field inherits from the mostly static cache, so when a Movable primitive is modified, only other movable primitives in the vicinity need to be re-composited into the global distance field * Global distance field update cost with one large rotating object went from 2.5ms -> .2ms on 970GTX and 4.6ms -> .3ms. Worst case full volume update is mostly the same. * Adds 12Mb for the new volume textures Change 3260956 on 2017/01/17 by Daniel.Wright Structured buffers for DF object data * Full global distance field clipmap composite 3.0ms -> 2.0ms due to scalarized loads Change 3261296 on 2017/01/17 by Daniel.Wright Exposed MaxObjectsPerTile with 'r.AOMaxObjectsPerCullTile' and lowered the default from 512 to 256, saves 17Mb of object tile culling data structures Removed unnecessary UAV transitions preventing object and global cone tracing from overlapping, saves ~.1ms Change 3262036 on 2017/01/18 by Ben.Salem V0 of Perf monitor plugin for easily consumable stat csvs. With plugin enabled, enter PerformanceMonitor help into the console to get usage details. Change 3262056 on 2017/01/18 by Chris.Bunner Remove inverse tonemapping when rendering HDR output. #jira UE-40728 Change 3262661 on 2017/01/18 by Rolando.Caloca DR - Add missing SetStencilRef() and SetBlendFactor() on most RHIs - Fix hash for PSOs Change 3263674 on 2017/01/19 by Chris.Bunner PR #3144: Improved error messages (Contributed by DarkSlot) #jira UE-40835 Change 3264150 on 2017/01/19 by Ben.Woodhouse Add support for single threaded in FMonitoredProcess. Deprecated IsRunning() in favour of a new Update() method because polling IsRunning is not compatible with -nothreading mode #jira UE-40841 Change 3264153 on 2017/01/19 by Ben.Woodhouse Integrate latest changes from MS-DX12 CLs 3231395-3262526 - Added WinPixEventRuntime.tps - Includes PIX support, various optimizations (saved 1.3ms in testbed scene) CL 3262343: Fix depth testing on translucency not working correctly after cl 3231395. This change reapplies the D3D12RHI changes from CL 3231395 because those changes were lost when integrating from //Dev-Rendering/ but also includes the depth fixes: - Fix depth state not being in DEPTH_READ for use as depth read. The issue was HasDepthBits and HasStencilBits wern't intended for SRV formats and always returned false in the SRV case. CL 3231395: Update D3D12 RHI: - Fix deferred MSAA path in RHI - Add Pix3.h support - Cleanup SetName usage and remove it from shipping builds. - Fix fence reuse bug. We were signaling MAX UINT (-1) and then waiting for 0, which was always signaled. This change also removes the fence value reset code, there is no need to reset a fence to a previous value. - Use FPlatformAtomics::InterlockedIncrement instead of InterlockedIncrement64 - Use InterlockedIncrement() instead of _InterlockedIncrement() and use the FPlatformAtomics:: version. - Fix possible readback heap being evicted while in use. GetQueryData happens on the render thread and isn't tied to a command list so we should always have readback heaps resident. Change 3264251 on 2017/01/19 by Mark.Satterthwaite Modify some asserts in MetalRHI - technically using a store-action of ENoAction on Stencil buffers should make it invalid to restart a render-pass but on Mac it will work because ENoAction won't invalidate anything written. In future we need to use deferred store-actions in Metal so that we can "restart" passes while enforcing correct Load/Store actions. #jira UE-40803 Change 3264642 on 2017/01/19 by Daniel.Wright Raised GMaxShadowDepthBufferSizeX to max texture resolution on most platforms, was previously 4096. Change 3265330 on 2017/01/20 by Ben.Salem Stop performance plugin from building in Win32. #tests recompiled and preflighted Change 3265678 on 2017/01/20 by Marcus.Wassmer Fix bad declaration. #3055 Change 3266656 on 2017/01/20 by Mark.Satterthwaite Changes to the FShaderCache to restore it and extend it to optionally report on shader de-duplication when generating a binary shader cache (Console Variable: r.BinaryShaderCacheLogging). Duplicate & amend CL #3266053 from Trepka: Fixed issues with shader cache not working properly with Mac Metal (but it still requires -norhithread to work at all). Enabled the shader cache by default if RHI thread is disabled. Amend & integrate RCO's CL #3197085. Change 3267741 on 2017/01/23 by Rolando.Caloca DR - Detect duplicated shader and pipeline types Change 3268600 on 2017/01/23 by Uriel.Doyon Added missing r.Streaming.MaxEffectiveScreenSize config to base texture scability settings. Integrated CL 3227368 from Orion stream Enabled r.Streaming.UsePerTextureBias by default as this has been tested in Orion for several months. Fixed issue with the InvestigateTexture command which could return invalid reference depending on the timing, Added th MaxEffectiveScreenSize settings in the investigate texture command. Change3269512on 2017/01/24 by Richard.Wallis Fix for shader binary cache uncompress data size during internal shader log. Change 3271237 on 2017/01/25 by Ben.Woodhouse D3D12 updateTexture2D crash fix #jira UE-41059 Change 3271564 on 2017/01/25 by Olaf.Piesche #jira UE-40980 #udn 325525 Fix uniform buffers for mesh particles; these should really be on the mesh collector, so allocating them as a one frame resource is safe Change 3271594 on 2017/01/25 by Ben.Woodhouse ESRAM support stage 1: Implemented noncontiguous ESRAM page allocator replacing XgMemoryLayout API. The allocator allocates non-contiguous ranges of pages and maps them onto a contiguous virtual address range. Unlike the previous implementation, this allocator frees pages for reuse when resources are destroyed Note: issues with deferred deallocation may prevent reuse in many cases - that will be addressed in the next stage Support for the old allocator is still available (for now) via the define NEW_ESRAM_ALLOCATOR #fyi rolando.caloca Change 3272616 on 2017/01/25 by Rolando.Caloca DR - Update shader version Change 3273138 on 2017/01/26 by Ben.Woodhouse Fix merge issue with MonitoredProcess.cpp (this arose from an integration made as an edit in dev-rendering, which confused perforce when the change was subsequently integrated from main) [CL 3274498 by Rolando Caloca in Main branch]
1037 lines
30 KiB
C++
1037 lines
30 KiB
C++
// Copyright 1998-2017 Epic Games, Inc. All Rights Reserved.
|
|
|
|
#include "CoreMinimal.h"
|
|
#include "HAL/FileManager.h"
|
|
#include "Misc/CommandLine.h"
|
|
#include "Misc/Paths.h"
|
|
#include "Misc/OutputDeviceRedirector.h"
|
|
#include "Templates/ScopedPointer.h"
|
|
#include "Stats/Stats.h"
|
|
#include "Misc/ScopedSlowTask.h"
|
|
#include "Misc/MonitoredProcess.h"
|
|
#include "Modules/ModuleManager.h"
|
|
#include "Interfaces/ITargetPlatform.h"
|
|
#include "Interfaces/ITargetPlatformModule.h"
|
|
#include "Interfaces/ITargetPlatformManagerModule.h"
|
|
#include "Interfaces/IAudioFormat.h"
|
|
#include "Interfaces/IAudioFormatModule.h"
|
|
#include "Interfaces/IShaderFormat.h"
|
|
#include "Interfaces/IShaderFormatModule.h"
|
|
#include "Interfaces/ITextureFormat.h"
|
|
#include "Interfaces/ITextureFormatModule.h"
|
|
#include "PlatformInfo.h"
|
|
#include "DesktopPlatformModule.h"
|
|
#include "IPhysXFormat.h"
|
|
#include "IPhysXFormatModule.h"
|
|
|
|
|
|
DEFINE_LOG_CATEGORY_STATIC(LogTargetPlatformManager, Log, All);
|
|
|
|
|
|
// autosdks only function properly on windows right now.
|
|
#if !IS_MONOLITHIC && (PLATFORM_WINDOWS)
|
|
#define AUTOSDKS_ENABLED 1
|
|
#else
|
|
#define AUTOSDKS_ENABLED 0
|
|
#endif
|
|
|
|
|
|
/**
|
|
* Module for the target platform manager
|
|
*/
|
|
class FTargetPlatformManagerModule
|
|
: public ITargetPlatformManagerModule
|
|
{
|
|
public:
|
|
|
|
/** Default constructor. */
|
|
FTargetPlatformManagerModule()
|
|
: bRestrictFormatsToRuntimeOnly(false)
|
|
, bForceCacheUpdate(true)
|
|
, bIgnoreFirstDelegateCall(true)
|
|
{
|
|
#if AUTOSDKS_ENABLED
|
|
|
|
// AutoSDKs only enabled if UE_SDKS_ROOT is set.
|
|
if (IsAutoSDKsEnabled())
|
|
{
|
|
DECLARE_SCOPE_CYCLE_COUNTER( TEXT( "FTargetPlatformManagerModule.StartAutoSDK" ), STAT_FTargetPlatformManagerModule_StartAutoSDK, STATGROUP_TargetPlatform );
|
|
|
|
// amortize UBT cost by calling it once for all platforms, rather than once per platform.
|
|
if (FParse::Param(FCommandLine::Get(), TEXT("Multiprocess"))==false)
|
|
{
|
|
FString UBTParams(TEXT("-autosdkonly"));
|
|
int32 UBTReturnCode = -1;
|
|
FString UBTOutput;
|
|
if (!FDesktopPlatformModule::Get()->InvokeUnrealBuildToolSync(UBTParams, *GLog, true, UBTReturnCode, UBTOutput))
|
|
{
|
|
UE_LOG(LogTargetPlatformManager, Fatal, TEXT("Failed to run UBT to check SDK status!"));
|
|
}
|
|
}
|
|
|
|
// we have to setup our local environment according to AutoSDKs or the ITargetPlatform's IsSDkInstalled calls may fail
|
|
// before we get a change to setup for a given platform. Use the platforminfo list to avoid any kind of interdependency.
|
|
int32 NumPlatforms;
|
|
const PlatformInfo::FPlatformInfo* PlatformInfoArray = PlatformInfo::GetPlatformInfoArray(NumPlatforms);
|
|
for (int32 i = 0; i < NumPlatforms; ++i)
|
|
{
|
|
const PlatformInfo::FPlatformInfo& PlatformInfo = PlatformInfoArray[i];
|
|
if (PlatformInfo.AutoSDKPath.Len() > 0)
|
|
{
|
|
SetupAndValidateAutoSDK(PlatformInfo.AutoSDKPath);
|
|
}
|
|
}
|
|
}
|
|
#endif
|
|
|
|
SetupSDKStatus();
|
|
//GetTargetPlatforms(); redudant with next call
|
|
GetActiveTargetPlatforms();
|
|
GetAudioFormats();
|
|
GetTextureFormats();
|
|
GetShaderFormats();
|
|
|
|
bForceCacheUpdate = false;
|
|
|
|
FModuleManager::Get().OnModulesChanged().AddRaw(this, &FTargetPlatformManagerModule::ModulesChangesCallback);
|
|
}
|
|
|
|
/** Destructor. */
|
|
virtual ~FTargetPlatformManagerModule()
|
|
{
|
|
FModuleManager::Get().OnModulesChanged().RemoveAll(this);
|
|
}
|
|
|
|
public:
|
|
|
|
// ITargetPlatformManagerModule interface
|
|
|
|
virtual void Invalidate() override
|
|
{
|
|
bForceCacheUpdate = true;
|
|
|
|
SetupSDKStatus();
|
|
//GetTargetPlatforms(); redudant with next call
|
|
GetActiveTargetPlatforms();
|
|
GetAudioFormats();
|
|
GetTextureFormats();
|
|
GetShaderFormats();
|
|
|
|
bForceCacheUpdate = false;
|
|
}
|
|
|
|
virtual const TArray<ITargetPlatform*>& GetTargetPlatforms() override
|
|
{
|
|
if (Platforms.Num() == 0 || bForceCacheUpdate)
|
|
{
|
|
DiscoverAvailablePlatforms();
|
|
}
|
|
|
|
return Platforms;
|
|
}
|
|
|
|
virtual ITargetDevicePtr FindTargetDevice(const FTargetDeviceId& DeviceId) override
|
|
{
|
|
ITargetPlatform* Platform = FindTargetPlatform(DeviceId.GetPlatformName());
|
|
|
|
if (Platform != nullptr)
|
|
{
|
|
return Platform->GetDevice(DeviceId);
|
|
}
|
|
|
|
return nullptr;
|
|
}
|
|
|
|
virtual ITargetPlatform* FindTargetPlatform(FString Name) override
|
|
{
|
|
const TArray<ITargetPlatform*>& TargetPlatforms = GetTargetPlatforms();
|
|
|
|
for (int32 Index = 0; Index < TargetPlatforms.Num(); Index++)
|
|
{
|
|
if (TargetPlatforms[Index]->PlatformName() == Name)
|
|
{
|
|
return TargetPlatforms[Index];
|
|
}
|
|
}
|
|
|
|
return nullptr;
|
|
}
|
|
|
|
virtual const TArray<ITargetPlatform*>& GetCookingTargetPlatforms() override
|
|
{
|
|
static bool bInitialized = false;
|
|
static TArray<ITargetPlatform*> Results;
|
|
|
|
if ( !bInitialized || bForceCacheUpdate )
|
|
{
|
|
Results = GetActiveTargetPlatforms();
|
|
|
|
FString PlatformStr;
|
|
if (FParse::Value(FCommandLine::Get(), TEXT("TARGETPLATFORM="), PlatformStr))
|
|
{
|
|
if (PlatformStr == TEXT("None"))
|
|
{
|
|
Results = Platforms;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
Results = Platforms;
|
|
}
|
|
}
|
|
|
|
return Results;
|
|
}
|
|
|
|
virtual const TArray<ITargetPlatform*>& GetActiveTargetPlatforms() override
|
|
{
|
|
static bool bInitialized = false;
|
|
static TArray<ITargetPlatform*> Results;
|
|
|
|
if (!bInitialized || bForceCacheUpdate)
|
|
{
|
|
bInitialized = true;
|
|
|
|
Results.Empty(Results.Num());
|
|
|
|
const TArray<ITargetPlatform*>& TargetPlatforms = GetTargetPlatforms();
|
|
|
|
FString PlatformStr;
|
|
|
|
if (FParse::Value(FCommandLine::Get(), TEXT("TARGETPLATFORM="), PlatformStr))
|
|
{
|
|
if (PlatformStr == TEXT("None"))
|
|
{
|
|
}
|
|
else if (PlatformStr == TEXT("All"))
|
|
{
|
|
Results = TargetPlatforms;
|
|
}
|
|
else
|
|
{
|
|
TArray<FString> PlatformNames;
|
|
|
|
PlatformStr.ParseIntoArray(PlatformNames, TEXT("+"), true);
|
|
|
|
// for nicer user response
|
|
FString AvailablePlatforms;
|
|
|
|
for (int32 Index = 0; Index < TargetPlatforms.Num(); Index++)
|
|
{
|
|
if (PlatformNames.Contains(TargetPlatforms[Index]->PlatformName()))
|
|
{
|
|
Results.Add(TargetPlatforms[Index]);
|
|
}
|
|
|
|
if(!AvailablePlatforms.IsEmpty())
|
|
{
|
|
AvailablePlatforms += TEXT(", ");
|
|
}
|
|
AvailablePlatforms += TargetPlatforms[Index]->PlatformName();
|
|
}
|
|
|
|
if (Results.Num() == 0)
|
|
{
|
|
// An invalid platform was specified...
|
|
// Inform the user and exit.
|
|
UE_LOG(LogTargetPlatformManager, Error, TEXT("Invalid target platform specified (%s). Available = { %s } "), *PlatformStr, *AvailablePlatforms);
|
|
UE_LOG(LogTargetPlatformManager, Fatal, TEXT("Invalid target platform specified (%s). Available = { %s } "), *PlatformStr, *AvailablePlatforms);
|
|
}
|
|
}
|
|
}
|
|
else
|
|
{
|
|
// if there is no argument, use the current platform and only build formats that are actually needed to run.
|
|
bRestrictFormatsToRuntimeOnly = true;
|
|
|
|
for (int32 Index = 0; Index < TargetPlatforms.Num(); Index++)
|
|
{
|
|
if (TargetPlatforms[Index]->IsRunningPlatform())
|
|
{
|
|
Results.Add(TargetPlatforms[Index]);
|
|
}
|
|
}
|
|
}
|
|
|
|
if (!Results.Num())
|
|
{
|
|
UE_LOG(LogTargetPlatformManager, Display, TEXT("Not building assets for any platform."));
|
|
}
|
|
else
|
|
{
|
|
for (int32 Index = 0; Index < Results.Num(); Index++)
|
|
{
|
|
UE_LOG(LogTargetPlatformManager, Display, TEXT("Building Assets For %s"), *Results[Index]->PlatformName());
|
|
}
|
|
}
|
|
}
|
|
|
|
return Results;
|
|
}
|
|
|
|
virtual bool RestrictFormatsToRuntimeOnly() override
|
|
{
|
|
GetActiveTargetPlatforms(); // make sure this is initialized
|
|
|
|
return bRestrictFormatsToRuntimeOnly;
|
|
}
|
|
|
|
virtual ITargetPlatform* GetRunningTargetPlatform() override
|
|
{
|
|
static bool bInitialized = false;
|
|
static ITargetPlatform* Result = nullptr;
|
|
|
|
if (!bInitialized || bForceCacheUpdate)
|
|
{
|
|
bInitialized = true;
|
|
Result = nullptr;
|
|
|
|
const TArray<ITargetPlatform*>& TargetPlatforms = GetTargetPlatforms();
|
|
|
|
for (int32 Index = 0; Index < TargetPlatforms.Num(); Index++)
|
|
{
|
|
if (TargetPlatforms[Index]->IsRunningPlatform())
|
|
{
|
|
// we should not have two running platforms
|
|
checkf((Result == nullptr),
|
|
TEXT("Found multiple running platforms.\n\t%s\nand\n\t%s"),
|
|
*Result->PlatformName(),
|
|
*TargetPlatforms[Index]->PlatformName()
|
|
);
|
|
Result = TargetPlatforms[Index];
|
|
}
|
|
}
|
|
}
|
|
|
|
return Result;
|
|
}
|
|
|
|
virtual const TArray<const IAudioFormat*>& GetAudioFormats() override
|
|
{
|
|
static bool bInitialized = false;
|
|
static TArray<const IAudioFormat*> Results;
|
|
|
|
if (!bInitialized || bForceCacheUpdate)
|
|
{
|
|
bInitialized = true;
|
|
Results.Empty(Results.Num());
|
|
|
|
TArray<FName> Modules;
|
|
|
|
FModuleManager::Get().FindModules(TEXT("*AudioFormat*"), Modules);
|
|
|
|
if (!Modules.Num())
|
|
{
|
|
UE_LOG(LogTargetPlatformManager, Error, TEXT("No target audio formats found!"));
|
|
}
|
|
|
|
for (int32 Index = 0; Index < Modules.Num(); Index++)
|
|
{
|
|
IAudioFormatModule* Module = FModuleManager::LoadModulePtr<IAudioFormatModule>(Modules[Index]);
|
|
if (Module)
|
|
{
|
|
IAudioFormat* Format = Module->GetAudioFormat();
|
|
if (Format != nullptr)
|
|
{
|
|
Results.Add(Format);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
return Results;
|
|
}
|
|
|
|
virtual const IAudioFormat* FindAudioFormat(FName Name) override
|
|
{
|
|
const TArray<const IAudioFormat*>& AudioFormats = GetAudioFormats();
|
|
|
|
for (int32 Index = 0; Index < AudioFormats.Num(); Index++)
|
|
{
|
|
TArray<FName> Formats;
|
|
|
|
AudioFormats[Index]->GetSupportedFormats(Formats);
|
|
|
|
for (int32 FormatIndex = 0; FormatIndex < Formats.Num(); FormatIndex++)
|
|
{
|
|
if (Formats[FormatIndex] == Name)
|
|
{
|
|
return AudioFormats[Index];
|
|
}
|
|
}
|
|
}
|
|
|
|
return nullptr;
|
|
}
|
|
|
|
virtual const TArray<const ITextureFormat*>& GetTextureFormats() override
|
|
{
|
|
static bool bInitialized = false;
|
|
static TArray<const ITextureFormat*> Results;
|
|
|
|
if (!bInitialized || bForceCacheUpdate)
|
|
{
|
|
bInitialized = true;
|
|
Results.Empty(Results.Num());
|
|
|
|
TArray<FName> Modules;
|
|
|
|
FModuleManager::Get().FindModules(TEXT("*TextureFormat*"), Modules);
|
|
|
|
if (!Modules.Num())
|
|
{
|
|
UE_LOG(LogTargetPlatformManager, Error, TEXT("No target texture formats found!"));
|
|
}
|
|
|
|
for (int32 Index = 0; Index < Modules.Num(); Index++)
|
|
{
|
|
ITextureFormatModule* Module = FModuleManager::LoadModulePtr<ITextureFormatModule>(Modules[Index]);
|
|
if (Module)
|
|
{
|
|
ITextureFormat* Format = Module->GetTextureFormat();
|
|
if (Format != nullptr)
|
|
{
|
|
Results.Add(Format);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
return Results;
|
|
}
|
|
|
|
virtual const ITextureFormat* FindTextureFormat(FName Name) override
|
|
{
|
|
const TArray<const ITextureFormat*>& TextureFormats = GetTextureFormats();
|
|
|
|
for (int32 Index = 0; Index < TextureFormats.Num(); Index++)
|
|
{
|
|
TArray<FName> Formats;
|
|
|
|
TextureFormats[Index]->GetSupportedFormats(Formats);
|
|
|
|
for (int32 FormatIndex = 0; FormatIndex < Formats.Num(); FormatIndex++)
|
|
{
|
|
if (Formats[FormatIndex] == Name)
|
|
{
|
|
return TextureFormats[Index];
|
|
}
|
|
}
|
|
}
|
|
|
|
return nullptr;
|
|
}
|
|
|
|
virtual const TArray<const IShaderFormat*>& GetShaderFormats() override
|
|
{
|
|
static bool bInitialized = false;
|
|
static TArray<const IShaderFormat*> Results;
|
|
|
|
if (!bInitialized || bForceCacheUpdate)
|
|
{
|
|
bInitialized = true;
|
|
Results.Empty(Results.Num());
|
|
|
|
TArray<FName> Modules;
|
|
|
|
FModuleManager::Get().FindModules(SHADERFORMAT_MODULE_WILDCARD, Modules);
|
|
|
|
if (!Modules.Num())
|
|
{
|
|
UE_LOG(LogTargetPlatformManager, Error, TEXT("No target shader formats found!"));
|
|
}
|
|
|
|
for (int32 Index = 0; Index < Modules.Num(); Index++)
|
|
{
|
|
IShaderFormatModule* Module = FModuleManager::LoadModulePtr<IShaderFormatModule>(Modules[Index]);
|
|
if (Module)
|
|
{
|
|
IShaderFormat* Format = Module->GetShaderFormat();
|
|
if (Format != nullptr)
|
|
{
|
|
Results.Add(Format);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
return Results;
|
|
}
|
|
|
|
virtual const IShaderFormat* FindShaderFormat(FName Name) override
|
|
{
|
|
const TArray<const IShaderFormat*>& ShaderFormats = GetShaderFormats();
|
|
|
|
for (int32 Index = 0; Index < ShaderFormats.Num(); Index++)
|
|
{
|
|
TArray<FName> Formats;
|
|
|
|
ShaderFormats[Index]->GetSupportedFormats(Formats);
|
|
|
|
for (int32 FormatIndex = 0; FormatIndex < Formats.Num(); FormatIndex++)
|
|
{
|
|
if (Formats[FormatIndex] == Name)
|
|
{
|
|
return ShaderFormats[Index];
|
|
}
|
|
}
|
|
}
|
|
|
|
return nullptr;
|
|
}
|
|
|
|
virtual uint16 ShaderFormatVersion(FName Name) override
|
|
{
|
|
static TMap<FName, uint16> AlreadyFound;
|
|
uint16* Result = AlreadyFound.Find(Name);
|
|
|
|
if (!Result)
|
|
{
|
|
const IShaderFormat* SF = FindShaderFormat(Name);
|
|
|
|
if (SF)
|
|
{
|
|
Result = &AlreadyFound.Add(Name, SF->GetVersion(Name));
|
|
}
|
|
}
|
|
|
|
check(Result);
|
|
|
|
return *Result;
|
|
}
|
|
|
|
virtual const TArray<const IPhysXFormat*>& GetPhysXFormats() override
|
|
{
|
|
static bool bInitialized = false;
|
|
static TArray<const IPhysXFormat*> Results;
|
|
|
|
if (!bInitialized || bForceCacheUpdate)
|
|
{
|
|
bInitialized = true;
|
|
Results.Empty(Results.Num());
|
|
|
|
TArray<FName> Modules;
|
|
FModuleManager::Get().FindModules(TEXT("PhysXFormat*"), Modules);
|
|
|
|
if (!Modules.Num())
|
|
{
|
|
UE_LOG(LogTargetPlatformManager, Error, TEXT("No target PhysX formats found!"));
|
|
}
|
|
|
|
for (int32 Index = 0; Index < Modules.Num(); Index++)
|
|
{
|
|
IPhysXFormatModule* Module = FModuleManager::LoadModulePtr<IPhysXFormatModule>(Modules[Index]);
|
|
if (Module)
|
|
{
|
|
IPhysXFormat* Format = Module->GetPhysXFormat();
|
|
if (Format != nullptr)
|
|
{
|
|
Results.Add(Format);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
return Results;
|
|
}
|
|
|
|
virtual const IPhysXFormat* FindPhysXFormat(FName Name) override
|
|
{
|
|
const TArray<const IPhysXFormat*>& PhysXFormats = GetPhysXFormats();
|
|
|
|
for (int32 Index = 0; Index < PhysXFormats.Num(); Index++)
|
|
{
|
|
TArray<FName> Formats;
|
|
|
|
PhysXFormats[Index]->GetSupportedFormats(Formats);
|
|
|
|
for (int32 FormatIndex = 0; FormatIndex < Formats.Num(); FormatIndex++)
|
|
{
|
|
if (Formats[FormatIndex] == Name)
|
|
{
|
|
return PhysXFormats[Index];
|
|
}
|
|
}
|
|
}
|
|
|
|
return nullptr;
|
|
}
|
|
|
|
protected:
|
|
|
|
/**
|
|
* Checks whether the AutoDesk software development kit (SDK) is enabled.
|
|
*
|
|
* @return true if the SDK is enabled, false otherwise.
|
|
*/
|
|
bool IsAutoSDKsEnabled()
|
|
{
|
|
static const FString SDKRootEnvFar(TEXT("UE_SDKS_ROOT"));
|
|
const int32 MaxPathSize = 16384;
|
|
TCHAR SDKPath[MaxPathSize] = { 0 };
|
|
FPlatformMisc::GetEnvironmentVariable(*SDKRootEnvFar, SDKPath, MaxPathSize);
|
|
|
|
// AutoSDKs only enabled if UE_SDKS_ROOT is set.
|
|
if (SDKPath[0] != 0)
|
|
{
|
|
return true;
|
|
}
|
|
return false;
|
|
}
|
|
|
|
/** Discovers the available target platforms. */
|
|
void DiscoverAvailablePlatforms()
|
|
{
|
|
DECLARE_SCOPE_CYCLE_COUNTER( TEXT( "FTargetPlatformManagerModule::DiscoverAvailablePlatforms" ), STAT_FTargetPlatformManagerModule_DiscoverAvailablePlatforms, STATGROUP_TargetPlatform );
|
|
|
|
Platforms.Empty(Platforms.Num());
|
|
|
|
TArray<FName> Modules;
|
|
|
|
FString ModuleWildCard = TEXT("*TargetPlatform");
|
|
|
|
#if WITH_EDITOR
|
|
// if we have the editor and we are using -game
|
|
// only need to instantiate the current platform
|
|
#if PLATFORM_WINDOWS
|
|
if (IsRunningGame())
|
|
{
|
|
ModuleWildCard = TEXT("Windows*TargetPlatform");
|
|
}
|
|
#endif
|
|
#endif
|
|
FModuleManager::Get().FindModules(*ModuleWildCard, Modules);
|
|
|
|
// remove this module from the list
|
|
Modules.Remove(FName(TEXT("TargetPlatform")));
|
|
|
|
if (!Modules.Num())
|
|
{
|
|
UE_LOG(LogTargetPlatformManager, Error, TEXT("No target platforms found!"));
|
|
}
|
|
|
|
FScopedSlowTask SlowTask(Modules.Num());
|
|
for (int32 Index = 0; Index < Modules.Num(); Index++)
|
|
{
|
|
SlowTask.EnterProgressFrame(1);
|
|
ITargetPlatformModule* Module = FModuleManager::LoadModulePtr<ITargetPlatformModule>(Modules[Index]);
|
|
if (Module)
|
|
{
|
|
ITargetPlatform* Platform = Module->GetTargetPlatform();
|
|
if (Platform != nullptr)
|
|
{
|
|
// would like to move this check to GetActiveTargetPlatforms, but too many things cache this result
|
|
// this setup will become faster after TTP 341897 is complete.
|
|
RETRY_SETUPANDVALIDATE:
|
|
if (SetupAndValidateAutoSDK(Platform->GetPlatformInfo().AutoSDKPath))
|
|
{
|
|
UE_LOG(LogTemp, Display, TEXT("Loaded TP %s"), *Modules[Index].ToString());
|
|
Platforms.Add(Platform);
|
|
}
|
|
else
|
|
{
|
|
// this hack is here because if you try and setup and validate autosdk some times it will fail because shared files are in use by another child cooker
|
|
static bool bIsChildCooker = FParse::Param(FCommandLine::Get(), TEXT("cookchild"));
|
|
if (bIsChildCooker)
|
|
{
|
|
static int Counter = 0;
|
|
++Counter;
|
|
if (Counter < 10)
|
|
{
|
|
goto RETRY_SETUPANDVALIDATE;
|
|
}
|
|
}
|
|
UE_LOG(LogTemp, Display, TEXT("Failed to SetupAndValidateAutoSDK for platform %s"), *Modules[Index].ToString());
|
|
}
|
|
}
|
|
else
|
|
{
|
|
UE_LOG(LogTemp, Display, TEXT("Failed to get target platform %s"), *Modules[Index].ToString());
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
bool UpdatePlatformEnvironment(FString PlatformName, TArray<FString> &Keys, TArray<FString> &Values) override
|
|
{
|
|
SetupEnvironmentVariables(Keys, Values);
|
|
return SetupSDKStatus(PlatformName);
|
|
}
|
|
|
|
bool SetupAndValidateAutoSDK(const FString& AutoSDKPath)
|
|
{
|
|
#if AUTOSDKS_ENABLED
|
|
bool bValidSDK = false;
|
|
if (AutoSDKPath.Len() > 0)
|
|
{
|
|
FName PlatformFName(*AutoSDKPath);
|
|
|
|
// cache result of the last setup attempt to avoid calling UBT all the time.
|
|
bool* bPreviousSetupSuccessful = PlatformsSetup.Find(PlatformFName);
|
|
if (bPreviousSetupSuccessful)
|
|
{
|
|
bValidSDK = *bPreviousSetupSuccessful;
|
|
}
|
|
else
|
|
{
|
|
bValidSDK = SetupEnvironmentFromAutoSDK(AutoSDKPath);
|
|
PlatformsSetup.Add(PlatformFName, bValidSDK);
|
|
}
|
|
}
|
|
else
|
|
{
|
|
// if a platform has no AutoSDKPath, then just assume the SDK is installed, we have no basis for determining it.
|
|
bValidSDK = true;
|
|
}
|
|
return bValidSDK;
|
|
#else
|
|
return true;
|
|
#endif // AUTOSDKS_ENABLED
|
|
}
|
|
|
|
bool SetupEnvironmentFromAutoSDK(const FString& AutoSDKPath)
|
|
{
|
|
#if AUTOSDKS_ENABLED
|
|
|
|
if (!IsAutoSDKsEnabled())
|
|
{
|
|
return true;
|
|
}
|
|
|
|
// Invoke UBT to perform SDK switching, or detect that a proper manual SDK is already setup.
|
|
#if PLATFORM_WINDOWS
|
|
FString HostPlatform(TEXT("HostWin64"));
|
|
#else
|
|
#error Fill in your host platform directory
|
|
#endif
|
|
|
|
static const FString SDKRootEnvFar(TEXT("UE_SDKS_ROOT"));
|
|
const int32 MaxPathSize = 16384;
|
|
FString SDKPath = FString::ChrN(16384, TEXT('\0'));
|
|
FPlatformMisc::GetEnvironmentVariable(*SDKRootEnvFar, SDKPath.GetCharArray().GetData(), MaxPathSize);
|
|
|
|
FString TargetSDKRoot = FPaths::Combine(*SDKPath, *HostPlatform, *AutoSDKPath);
|
|
static const FString SDKInstallManifestFileName(TEXT("CurrentlyInstalled.txt"));
|
|
FString SDKInstallManifestFilePath = FPaths::Combine(*TargetSDKRoot, *SDKInstallManifestFileName);
|
|
|
|
// If we are using a manual install, then it is valid for there to be no OutputEnvVars file.
|
|
TUniquePtr<FArchive> InstallManifestFile(IFileManager::Get().CreateFileReader(*SDKInstallManifestFilePath));
|
|
if (InstallManifestFile)
|
|
{
|
|
TArray<FString> FileLines;
|
|
int64 FileSize = InstallManifestFile->TotalSize();
|
|
int64 MemSize = FileSize + 1;
|
|
void* FileMem = FMemory::Malloc(MemSize);
|
|
FMemory::Memset(FileMem, 0, MemSize);
|
|
|
|
InstallManifestFile->Serialize(FileMem, FileSize);
|
|
|
|
FString FileAsString(ANSI_TO_TCHAR(FileMem));
|
|
FileAsString.ParseIntoArrayLines(FileLines);
|
|
|
|
FMemory::Free(FileMem);
|
|
InstallManifestFile->Close();
|
|
|
|
|
|
if (FileLines.Num() != 2)
|
|
{
|
|
UE_LOG(LogTargetPlatformManager, Warning, TEXT("Malformed install manifest file for Platform %s"), *AutoSDKPath);
|
|
return false;
|
|
}
|
|
|
|
static const FString ManualSDKString(TEXT("ManualSDK"));
|
|
if (FileLines[1].Compare(ManualSDKString, ESearchCase::IgnoreCase) == 0)
|
|
{
|
|
UE_LOG(LogTargetPlatformManager, Verbose, TEXT("Platform %s has manual sdk install"), *AutoSDKPath);
|
|
return true;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
UE_LOG(LogTargetPlatformManager, Log, TEXT("Install manifest file for Platform %s not found. Platform not set up."), *AutoSDKPath);
|
|
return false;
|
|
}
|
|
|
|
static const FString SDKEnvironmentVarsFile(TEXT("OutputEnvVars.txt"));
|
|
FString EnvVarFileName = FPaths::Combine(*TargetSDKRoot, *SDKEnvironmentVarsFile);
|
|
|
|
// If we are using a manual install, then it is valid for there to be no OutputEnvVars file.
|
|
TUniquePtr<FArchive> EnvVarFile(IFileManager::Get().CreateFileReader(*EnvVarFileName));
|
|
if (EnvVarFile)
|
|
{
|
|
TArray<FString> FileLines;
|
|
{
|
|
int64 FileSize = EnvVarFile->TotalSize();
|
|
int64 MemSize = FileSize + 1;
|
|
void* FileMem = FMemory::Malloc(MemSize);
|
|
FMemory::Memset(FileMem, 0, MemSize);
|
|
|
|
EnvVarFile->Serialize(FileMem, FileSize);
|
|
|
|
FString FileAsString(ANSI_TO_TCHAR(FileMem));
|
|
FileAsString.ParseIntoArrayLines(FileLines);
|
|
|
|
FMemory::Free(FileMem);
|
|
EnvVarFile->Close();
|
|
}
|
|
|
|
TArray<FString> PathAdds;
|
|
TArray<FString> PathRemoves;
|
|
TArray<FString> EnvVarNames;
|
|
TArray<FString> EnvVarValues;
|
|
|
|
const FString VariableSplit(TEXT("="));
|
|
for (int32 i = 0; i < FileLines.Num(); ++i)
|
|
{
|
|
const FString& VariableString = FileLines[i];
|
|
|
|
FString Left;
|
|
FString Right;
|
|
VariableString.Split(VariableSplit, &Left, &Right);
|
|
|
|
if (Left.Compare(TEXT("strippath"), ESearchCase::IgnoreCase) == 0)
|
|
{
|
|
PathRemoves.Add(Right);
|
|
}
|
|
else if (Left.Compare(TEXT("addpath"), ESearchCase::IgnoreCase) == 0)
|
|
{
|
|
PathAdds.Add(Right);
|
|
}
|
|
else
|
|
{
|
|
// convenience for setup.bat writers. Trim any accidental whitespace from var names/values.
|
|
EnvVarNames.Add(Left.Trim().TrimTrailing());
|
|
EnvVarValues.Add(Right.Trim().TrimTrailing());
|
|
}
|
|
}
|
|
|
|
// don't actually set anything until we successfully validate and read all values in.
|
|
// we don't want to set a few vars, return a failure, and then have a platform try to
|
|
// build against a manually installed SDK with half-set env vars.
|
|
SetupEnvironmentVariables(EnvVarNames, EnvVarValues);
|
|
|
|
|
|
const int32 MaxPathVarLen = 32768;
|
|
FString OrigPathVar = FString::ChrN(MaxPathVarLen, TEXT('\0'));
|
|
FPlatformMisc::GetEnvironmentVariable(TEXT("PATH"), OrigPathVar.GetCharArray().GetData(), MaxPathVarLen);
|
|
|
|
// actually perform the PATH stripping / adding.
|
|
const TCHAR* PathDelimiter = FPlatformMisc::GetPathVarDelimiter();
|
|
TArray<FString> PathVars;
|
|
OrigPathVar.ParseIntoArray(PathVars, PathDelimiter, true);
|
|
|
|
TArray<FString> ModifiedPathVars;
|
|
ModifiedPathVars = PathVars;
|
|
|
|
// perform removes first, in case they overlap with any adds.
|
|
for (int32 PathRemoveIndex = 0; PathRemoveIndex < PathRemoves.Num(); ++PathRemoveIndex)
|
|
{
|
|
const FString& PathRemove = PathRemoves[PathRemoveIndex];
|
|
for (int32 PathVarIndex = 0; PathVarIndex < PathVars.Num(); ++PathVarIndex)
|
|
{
|
|
const FString& PathVar = PathVars[PathVarIndex];
|
|
if (PathVar.Find(PathRemove, ESearchCase::IgnoreCase) >= 0)
|
|
{
|
|
UE_LOG(LogTargetPlatformManager, Verbose, TEXT("Removing Path: '%s'"), *PathVar);
|
|
ModifiedPathVars.Remove(PathVar);
|
|
}
|
|
}
|
|
}
|
|
|
|
// remove all the of ADDs so that if this function is executed multiple times, the paths will be guarateed to be in the same order after each run.
|
|
// If we did not do this, a 'remove' that matched some, but not all, of our 'adds' would cause the order to change.
|
|
for (int32 PathAddIndex = 0; PathAddIndex < PathAdds.Num(); ++PathAddIndex)
|
|
{
|
|
const FString& PathAdd = PathAdds[PathAddIndex];
|
|
for (int32 PathVarIndex = 0; PathVarIndex < PathVars.Num(); ++PathVarIndex)
|
|
{
|
|
const FString& PathVar = PathVars[PathVarIndex];
|
|
if (PathVar.Find(PathAdd, ESearchCase::IgnoreCase) >= 0)
|
|
{
|
|
UE_LOG(LogTargetPlatformManager, Verbose, TEXT("Removing Path: '%s'"), *PathVar);
|
|
ModifiedPathVars.Remove(PathVar);
|
|
}
|
|
}
|
|
}
|
|
|
|
// perform adds, but don't add duplicates
|
|
for (int32 PathAddIndex = 0; PathAddIndex < PathAdds.Num(); ++PathAddIndex)
|
|
{
|
|
const FString& PathAdd = PathAdds[PathAddIndex];
|
|
if (!ModifiedPathVars.Contains(PathAdd))
|
|
{
|
|
UE_LOG(LogTargetPlatformManager, Verbose, TEXT("Adding Path: '%s'"), *PathAdd);
|
|
ModifiedPathVars.Add(PathAdd);
|
|
}
|
|
}
|
|
|
|
FString ModifiedPath = FString::Join(ModifiedPathVars, PathDelimiter);
|
|
FPlatformMisc::SetEnvironmentVar(TEXT("PATH"), *ModifiedPath);
|
|
}
|
|
else
|
|
{
|
|
UE_LOG(LogTargetPlatformManager, Warning, TEXT("OutputEnvVars.txt not found for platform: '%s'"), *AutoSDKPath);
|
|
return false;
|
|
}
|
|
|
|
UE_LOG(LogTargetPlatformManager, Verbose, TEXT("Platform %s has auto sdk install"), *AutoSDKPath);
|
|
return true;
|
|
#else
|
|
return true;
|
|
#endif
|
|
}
|
|
|
|
bool SetupSDKStatus()
|
|
{
|
|
return SetupSDKStatus(TEXT(""));
|
|
}
|
|
|
|
bool SetupSDKStatus(FString TargetPlatforms)
|
|
{
|
|
DECLARE_SCOPE_CYCLE_COUNTER( TEXT( "FTargetPlatformManagerModule::SetupSDKStatus" ), STAT_FTargetPlatformManagerModule_SetupSDKStatus, STATGROUP_TargetPlatform );
|
|
|
|
// run UBT with -validate -allplatforms and read the output
|
|
FString CmdExe, CommandLine;
|
|
|
|
if (PLATFORM_MAC)
|
|
{
|
|
CmdExe = TEXT("/bin/sh");
|
|
FString ScriptPath = FPaths::ConvertRelativePathToFull(FPaths::EngineDir() / TEXT("Build/BatchFiles/Mac/RunMono.sh"));
|
|
CommandLine = TEXT("\"") + ScriptPath + TEXT("\" \"") + FPaths::ConvertRelativePathToFull(FPaths::EngineDir() / TEXT("Binaries/DotNET/UnrealBuildTool.exe")) + TEXT("\" -validateplatform");
|
|
}
|
|
else if (PLATFORM_WINDOWS)
|
|
{
|
|
CmdExe = FPaths::ConvertRelativePathToFull(FPaths::EngineDir() / TEXT("Binaries/DotNet/UnrealBuildTool.exe"));
|
|
CommandLine = TEXT("-validateplatform");
|
|
}
|
|
else if (PLATFORM_LINUX)
|
|
{
|
|
CmdExe = TEXT("/bin/bash"); // bash and not sh because of pushd
|
|
FString ScriptPath = FPaths::ConvertRelativePathToFull(FPaths::EngineDir() / TEXT("Build/BatchFiles/Linux/RunMono.sh"));
|
|
CommandLine = TEXT("\"") + ScriptPath + TEXT("\" \"") + FPaths::ConvertRelativePathToFull(FPaths::EngineDir() / TEXT("Binaries/DotNET/UnrealBuildTool.exe")) + TEXT("\" -validateplatform");
|
|
}
|
|
else
|
|
{
|
|
checkf(false, TEXT("FTargetPlatformManagerModule::SetupSDKStatus(): Unsupported platform!"));
|
|
}
|
|
|
|
// Allow for only a subset of platforms to be reparsed - needed when kicking a change from the UI
|
|
CommandLine += TargetPlatforms.IsEmpty() ? TEXT(" -allplatforms") : (TEXT(" -platforms=") + TargetPlatforms);
|
|
|
|
TSharedPtr<FMonitoredProcess> UBTProcess = MakeShareable(new FMonitoredProcess(CmdExe, CommandLine, true));
|
|
UBTProcess->OnOutput().BindStatic(&FTargetPlatformManagerModule::OnStatusOutput);
|
|
SDKStatusMessage = TEXT("");
|
|
UBTProcess->Launch();
|
|
while(UBTProcess->Update())
|
|
{
|
|
FPlatformProcess::Sleep(0.01f);
|
|
}
|
|
|
|
TArray<FString> PlatArray;
|
|
SDKStatusMessage.ParseIntoArrayWS(PlatArray);
|
|
for (int Index = 0; Index < PlatArray.Num()-2; ++Index)
|
|
{
|
|
FString Item = PlatArray[Index];
|
|
if (PlatArray[Index].Contains(TEXT("##PlatformValidate:")))
|
|
{
|
|
PlatformInfo::EPlatformSDKStatus Status = PlatArray[Index+2].Contains(TEXT("INVALID")) ? PlatformInfo::EPlatformSDKStatus::NotInstalled : PlatformInfo::EPlatformSDKStatus::Installed;
|
|
FString PlatformName = PlatArray[Index+1];
|
|
if (PlatformName == TEXT("Win32") || PlatformName == TEXT("Win64"))
|
|
{
|
|
PlatformName = TEXT("Windows");
|
|
PlatformInfo::UpdatePlatformSDKStatus(PlatformName, Status);
|
|
PlatformName = TEXT("WindowsNoEditor");
|
|
PlatformInfo::UpdatePlatformSDKStatus(PlatformName, Status);
|
|
PlatformName = TEXT("WindowsClient");
|
|
PlatformInfo::UpdatePlatformSDKStatus(PlatformName, Status);
|
|
PlatformName = TEXT("WindowsServer");
|
|
PlatformInfo::UpdatePlatformSDKStatus(PlatformName, Status);
|
|
}
|
|
else if (PlatformName == TEXT("Mac"))
|
|
{
|
|
PlatformInfo::UpdatePlatformSDKStatus(PlatformName, Status);
|
|
PlatformName = TEXT("MacNoEditor");
|
|
PlatformInfo::UpdatePlatformSDKStatus(PlatformName, Status);
|
|
PlatformName = TEXT("MacClient");
|
|
PlatformInfo::UpdatePlatformSDKStatus(PlatformName, Status);
|
|
PlatformName = TEXT("MacServer");
|
|
PlatformInfo::UpdatePlatformSDKStatus(PlatformName, Status);
|
|
}
|
|
else if (PlatformName == TEXT("Linux"))
|
|
{
|
|
PlatformInfo::UpdatePlatformSDKStatus(PlatformName, Status);
|
|
PlatformName = TEXT("LinuxNoEditor");
|
|
PlatformInfo::UpdatePlatformSDKStatus(PlatformName, Status);
|
|
PlatformName = TEXT("LinuxClient");
|
|
PlatformInfo::UpdatePlatformSDKStatus(PlatformName, Status);
|
|
PlatformName = TEXT("LinuxServer");
|
|
PlatformInfo::UpdatePlatformSDKStatus(PlatformName, Status);
|
|
}
|
|
else if (PlatformName == TEXT("Desktop"))
|
|
{
|
|
// since Desktop is just packaging, we don't need an SDK, and UBT will return INVALID, since it doesn't build for it
|
|
PlatformInfo::UpdatePlatformSDKStatus(PlatformName, PlatformInfo::EPlatformSDKStatus::Installed);
|
|
}
|
|
else
|
|
{
|
|
PlatformInfo::UpdatePlatformSDKStatus(PlatformName, Status);
|
|
}
|
|
}
|
|
}
|
|
return true;
|
|
}
|
|
|
|
private:
|
|
|
|
void SetupEnvironmentVariables(TArray<FString> &EnvVarNames, const TArray<FString>& EnvVarValues)
|
|
{
|
|
for (int i = 0; i < EnvVarNames.Num(); ++i)
|
|
{
|
|
const FString& EnvVarName = EnvVarNames[i];
|
|
const FString& EnvVarValue = EnvVarValues[i];
|
|
UE_LOG(LogTargetPlatformManager, Verbose, TEXT("Setting variable '%s' to '%s'."), *EnvVarName, *EnvVarValue);
|
|
FPlatformMisc::SetEnvironmentVar(*EnvVarName, *EnvVarValue);
|
|
}
|
|
}
|
|
|
|
void ModulesChangesCallback(FName ModuleName, EModuleChangeReason ReasonForChange)
|
|
{
|
|
if (!bIgnoreFirstDelegateCall && ModuleName.ToString().Contains(TEXT("TargetPlatform")) && !ModuleName.ToString().Contains(TEXT("ProjectTargetPlatformEditor")))
|
|
{
|
|
Invalidate();
|
|
}
|
|
bIgnoreFirstDelegateCall = false;
|
|
}
|
|
|
|
static FString SDKStatusMessage;
|
|
static void OnStatusOutput(FString Message)
|
|
{
|
|
SDKStatusMessage += Message;
|
|
}
|
|
|
|
// If true we should build formats that are actually required for use by the runtime.
|
|
// This happens for an ordinary editor run and more specifically whenever there is no
|
|
// TargetPlatform= on the command line.
|
|
bool bRestrictFormatsToRuntimeOnly;
|
|
|
|
// Flag to force reinitialization of all cached data. This is needed to have up-to-date caches
|
|
// in case of a module reload of a TargetPlatform-Module.
|
|
bool bForceCacheUpdate;
|
|
|
|
// Flag to avoid redunant reloads
|
|
bool bIgnoreFirstDelegateCall;
|
|
|
|
// Holds the list of discovered platforms.
|
|
TArray<ITargetPlatform*> Platforms;
|
|
|
|
#if AUTOSDKS_ENABLED
|
|
// holds the list of Platforms that have attempted setup.
|
|
TMap<FName, bool> PlatformsSetup;
|
|
#endif
|
|
};
|
|
|
|
|
|
FString FTargetPlatformManagerModule::SDKStatusMessage = TEXT("");
|
|
|
|
|
|
IMPLEMENT_MODULE(FTargetPlatformManagerModule, TargetPlatform);
|