Merge remote-tracking branch 'origin/1.11' into sdl_platform_1.11
# Conflicts: # Source/Engine/Platform/Windows/WindowsPlatform.cpp # Source/Tools/Flax.Build/Build/ProjectTarget.cs # Source/Tools/Flax.Build/Configuration.cs
This commit is contained in:
Binary file not shown.
@@ -28,6 +28,13 @@ TextureCube SkyLightTexture : register(t__SRV__);
|
|||||||
Buffer<float4> ShadowsBuffer : register(t__SRV__);
|
Buffer<float4> ShadowsBuffer : register(t__SRV__);
|
||||||
Texture2D<float> ShadowMap : register(t__SRV__);
|
Texture2D<float> ShadowMap : register(t__SRV__);
|
||||||
@4// Forward Shading: Utilities
|
@4// Forward Shading: Utilities
|
||||||
|
// Public accessors for lighting data, use them as data binding might change but those methods will remain.
|
||||||
|
LightData GetDirectionalLight() { return DirectionalLight; }
|
||||||
|
LightData GetSkyLight() { return SkyLight; }
|
||||||
|
ProbeData GetEnvironmentProbe() { return EnvironmentProbe; }
|
||||||
|
ExponentialHeightFogData GetExponentialHeightFog() { return ExponentialHeightFog; }
|
||||||
|
uint GetLocalLightsCount() { return LocalLightsCount; }
|
||||||
|
LightData GetLocalLight(uint i) { return LocalLights[i]; }
|
||||||
@5// Forward Shading: Shaders
|
@5// Forward Shading: Shaders
|
||||||
|
|
||||||
// Pixel Shader function for Forward Pass
|
// Pixel Shader function for Forward Pass
|
||||||
@@ -76,9 +83,8 @@ void PS_Forward(
|
|||||||
gBuffer.ShadingModel = MATERIAL_SHADING_MODEL;
|
gBuffer.ShadingModel = MATERIAL_SHADING_MODEL;
|
||||||
|
|
||||||
// Calculate lighting from a single directional light
|
// Calculate lighting from a single directional light
|
||||||
float4 shadowMask = 1.0f;
|
|
||||||
ShadowSample shadow = SampleDirectionalLightShadow(DirectionalLight, ShadowsBuffer, ShadowMap, gBuffer);
|
ShadowSample shadow = SampleDirectionalLightShadow(DirectionalLight, ShadowsBuffer, ShadowMap, gBuffer);
|
||||||
shadowMask = GetShadowMask(shadow);
|
float4 shadowMask = GetShadowMask(shadow);
|
||||||
float4 light = GetLighting(ViewPos, DirectionalLight, gBuffer, shadowMask, false, false);
|
float4 light = GetLighting(ViewPos, DirectionalLight, gBuffer, shadowMask, false, false);
|
||||||
|
|
||||||
// Calculate lighting from sky light
|
// Calculate lighting from sky light
|
||||||
|
|||||||
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
+2
-2
@@ -2,9 +2,9 @@
|
|||||||
"Name": "Flax",
|
"Name": "Flax",
|
||||||
"Version": {
|
"Version": {
|
||||||
"Major": 1,
|
"Major": 1,
|
||||||
"Minor": 10,
|
"Minor": 11,
|
||||||
"Revision": 0,
|
"Revision": 0,
|
||||||
"Build": 6705
|
"Build": 6800
|
||||||
},
|
},
|
||||||
"Company": "Flax",
|
"Company": "Flax",
|
||||||
"Copyright": "Copyright (c) 2012-2025 Wojciech Figat. All rights reserved.",
|
"Copyright": "Copyright (c) 2012-2025 Wojciech Figat. All rights reserved.",
|
||||||
|
|||||||
@@ -174,7 +174,9 @@ void EditorAnalytics::StartSession()
|
|||||||
// Bind events
|
// Bind events
|
||||||
GameCooker::OnEvent.Bind<RegisterGameCookingStart>();
|
GameCooker::OnEvent.Bind<RegisterGameCookingStart>();
|
||||||
ShadowsOfMordor::Builder::Instance()->OnBuildStarted.Bind<RegisterLightmapsBuildingStart>();
|
ShadowsOfMordor::Builder::Instance()->OnBuildStarted.Bind<RegisterLightmapsBuildingStart>();
|
||||||
|
#if LOG_ENABLE
|
||||||
Log::Logger::OnError.Bind<RegisterError>();
|
Log::Logger::OnError.Bind<RegisterError>();
|
||||||
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
void EditorAnalytics::EndSession()
|
void EditorAnalytics::EndSession()
|
||||||
@@ -187,7 +189,9 @@ void EditorAnalytics::EndSession()
|
|||||||
// Unbind events
|
// Unbind events
|
||||||
GameCooker::OnEvent.Unbind<RegisterGameCookingStart>();
|
GameCooker::OnEvent.Unbind<RegisterGameCookingStart>();
|
||||||
ShadowsOfMordor::Builder::Instance()->OnBuildStarted.Unbind<RegisterLightmapsBuildingStart>();
|
ShadowsOfMordor::Builder::Instance()->OnBuildStarted.Unbind<RegisterLightmapsBuildingStart>();
|
||||||
|
#if LOG_ENABLE
|
||||||
Log::Logger::OnError.Unbind<RegisterError>();
|
Log::Logger::OnError.Unbind<RegisterError>();
|
||||||
|
#endif
|
||||||
|
|
||||||
// End session
|
// End session
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -20,13 +20,6 @@ class PlatformTools;
|
|||||||
#define GAME_BUILD_DOTNET_RUNTIME_MAX_VER 9
|
#define GAME_BUILD_DOTNET_RUNTIME_MAX_VER 9
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#if OFFICIAL_BUILD
|
|
||||||
// Use the fixed .NET SDK version in packaged builds for compatibility (FlaxGame is precompiled with it)
|
|
||||||
#define GAME_BUILD_DOTNET_VER TEXT("-dotnet=" MACRO_TO_STR(GAME_BUILD_DOTNET_RUNTIME_MIN_VER))
|
|
||||||
#else
|
|
||||||
#define GAME_BUILD_DOTNET_VER TEXT("")
|
|
||||||
#endif
|
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Game building options. Used as flags.
|
/// Game building options. Used as flags.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
@@ -374,6 +367,8 @@ public:
|
|||||||
/// </summary>
|
/// </summary>
|
||||||
void GetBuildPlatformName(const Char*& platform, const Char*& architecture) const;
|
void GetBuildPlatformName(const Char*& platform, const Char*& architecture) const;
|
||||||
|
|
||||||
|
String GetDotnetCommandArg() const;
|
||||||
|
|
||||||
public:
|
public:
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
|
|||||||
@@ -30,6 +30,7 @@
|
|||||||
#include "Engine/Scripting/ManagedCLR/MAssembly.h"
|
#include "Engine/Scripting/ManagedCLR/MAssembly.h"
|
||||||
#include "Engine/Content/JsonAsset.h"
|
#include "Engine/Content/JsonAsset.h"
|
||||||
#include "Engine/Content/AssetReference.h"
|
#include "Engine/Content/AssetReference.h"
|
||||||
|
#include "Engine/Profiler/ProfilerMemory.h"
|
||||||
#if PLATFORM_TOOLS_WINDOWS
|
#if PLATFORM_TOOLS_WINDOWS
|
||||||
#include "Platform/Windows/WindowsPlatformTools.h"
|
#include "Platform/Windows/WindowsPlatformTools.h"
|
||||||
#include "Engine/Platform/Windows/WindowsPlatformSettings.h"
|
#include "Engine/Platform/Windows/WindowsPlatformSettings.h"
|
||||||
@@ -311,6 +312,14 @@ void CookingData::GetBuildPlatformName(const Char*& platform, const Char*& archi
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
String CookingData::GetDotnetCommandArg() const
|
||||||
|
{
|
||||||
|
int32 version = Tools->GetDotnetVersion();
|
||||||
|
if (version == 0)
|
||||||
|
return String::Empty;
|
||||||
|
return String::Format(TEXT("-dotnet={}"), version);
|
||||||
|
}
|
||||||
|
|
||||||
void CookingData::StepProgress(const String& info, const float stepProgress) const
|
void CookingData::StepProgress(const String& info, const float stepProgress) const
|
||||||
{
|
{
|
||||||
const float singleStepProgress = 1.0f / (StepsCount + 1);
|
const float singleStepProgress = 1.0f / (StepsCount + 1);
|
||||||
@@ -380,6 +389,7 @@ bool GameCooker::IsCancelRequested()
|
|||||||
|
|
||||||
PlatformTools* GameCooker::GetTools(BuildPlatform platform)
|
PlatformTools* GameCooker::GetTools(BuildPlatform platform)
|
||||||
{
|
{
|
||||||
|
PROFILE_MEM(Editor);
|
||||||
PlatformTools* result = nullptr;
|
PlatformTools* result = nullptr;
|
||||||
if (!Tools.TryGet(platform, result))
|
if (!Tools.TryGet(platform, result))
|
||||||
{
|
{
|
||||||
@@ -471,6 +481,7 @@ bool GameCooker::Build(BuildPlatform platform, BuildConfiguration configuration,
|
|||||||
LOG(Error, "Build platform {0} is not supported.", ::ToString(platform));
|
LOG(Error, "Build platform {0} is not supported.", ::ToString(platform));
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
PROFILE_MEM(Editor);
|
||||||
|
|
||||||
// Setup
|
// Setup
|
||||||
CancelFlag = 0;
|
CancelFlag = 0;
|
||||||
@@ -624,6 +635,7 @@ void GameCookerImpl::ReportProgress(const String& info, float totalProgress)
|
|||||||
|
|
||||||
void GameCookerImpl::OnCollectAssets(HashSet<Guid>& assets)
|
void GameCookerImpl::OnCollectAssets(HashSet<Guid>& assets)
|
||||||
{
|
{
|
||||||
|
PROFILE_MEM(Editor);
|
||||||
if (Internal_OnCollectAssets == nullptr)
|
if (Internal_OnCollectAssets == nullptr)
|
||||||
{
|
{
|
||||||
auto c = GameCooker::GetStaticClass();
|
auto c = GameCooker::GetStaticClass();
|
||||||
@@ -651,6 +663,7 @@ void GameCookerImpl::OnCollectAssets(HashSet<Guid>& assets)
|
|||||||
|
|
||||||
bool GameCookerImpl::Build()
|
bool GameCookerImpl::Build()
|
||||||
{
|
{
|
||||||
|
PROFILE_MEM(Editor);
|
||||||
CookingData& data = *Data;
|
CookingData& data = *Data;
|
||||||
LOG(Info, "Starting Game Cooker...");
|
LOG(Info, "Starting Game Cooker...");
|
||||||
LOG(Info, "Platform: {0}, Configuration: {2}, Options: {1}", ::ToString(data.Platform), (int32)data.Options, ::ToString(data.Configuration));
|
LOG(Info, "Platform: {0}, Configuration: {2}, Options: {1}", ::ToString(data.Platform), (int32)data.Options, ::ToString(data.Configuration));
|
||||||
@@ -670,8 +683,7 @@ bool GameCookerImpl::Build()
|
|||||||
|
|
||||||
MCore::Thread::Attach();
|
MCore::Thread::Attach();
|
||||||
|
|
||||||
// Build Started
|
// Build start
|
||||||
if (!EnumHasAnyFlags(data.Options, BuildOptions::NoCook))
|
|
||||||
{
|
{
|
||||||
CallEvent(GameCooker::EventType::BuildStarted);
|
CallEvent(GameCooker::EventType::BuildStarted);
|
||||||
data.Tools->OnBuildStarted(data);
|
data.Tools->OnBuildStarted(data);
|
||||||
@@ -744,8 +756,8 @@ bool GameCookerImpl::Build()
|
|||||||
}
|
}
|
||||||
IsRunning = false;
|
IsRunning = false;
|
||||||
CancelFlag = 0;
|
CancelFlag = 0;
|
||||||
if (!EnumHasAnyFlags(data.Options, BuildOptions::NoCook))
|
|
||||||
{
|
{
|
||||||
|
// Build end
|
||||||
for (int32 stepIndex = 0; stepIndex < Steps.Count(); stepIndex++)
|
for (int32 stepIndex = 0; stepIndex < Steps.Count(); stepIndex++)
|
||||||
Steps[stepIndex]->OnBuildEnded(data, failed);
|
Steps[stepIndex]->OnBuildEnded(data, failed);
|
||||||
data.Tools->OnBuildEnded(data, failed);
|
data.Tools->OnBuildEnded(data, failed);
|
||||||
@@ -778,6 +790,8 @@ int32 GameCookerImpl::ThreadFunction()
|
|||||||
|
|
||||||
bool GameCookerService::Init()
|
bool GameCookerService::Init()
|
||||||
{
|
{
|
||||||
|
PROFILE_MEM(Editor);
|
||||||
|
|
||||||
auto editorAssembly = ((NativeBinaryModule*)GetBinaryModuleFlaxEngine())->Assembly;
|
auto editorAssembly = ((NativeBinaryModule*)GetBinaryModuleFlaxEngine())->Assembly;
|
||||||
editorAssembly->Unloading.Bind(OnEditorAssemblyUnloading);
|
editorAssembly->Unloading.Bind(OnEditorAssemblyUnloading);
|
||||||
GameCooker::OnCollectAssets.Bind(OnCollectAssets);
|
GameCooker::OnCollectAssets.Bind(OnCollectAssets);
|
||||||
@@ -789,6 +803,7 @@ void GameCookerService::Update()
|
|||||||
{
|
{
|
||||||
if (IsRunning)
|
if (IsRunning)
|
||||||
{
|
{
|
||||||
|
PROFILE_MEM(Editor);
|
||||||
ScopeLock lock(ProgressLocker);
|
ScopeLock lock(ProgressLocker);
|
||||||
|
|
||||||
if (ProgressMsg.HasChars())
|
if (ProgressMsg.HasChars())
|
||||||
|
|||||||
@@ -195,4 +195,9 @@ bool GDKPlatformTools::OnPostProcess(CookingData& data, GDKPlatformSettings* pla
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
int32 GDKPlatformTools::GetDotnetVersion() const
|
||||||
|
{
|
||||||
|
return GAME_BUILD_DOTNET_RUNTIME_MIN_VER;
|
||||||
|
}
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|||||||
@@ -26,6 +26,7 @@ public:
|
|||||||
public:
|
public:
|
||||||
|
|
||||||
// [PlatformTools]
|
// [PlatformTools]
|
||||||
|
int32 GetDotnetVersion() const override;
|
||||||
DotNetAOTModes UseAOT() const override;
|
DotNetAOTModes UseAOT() const override;
|
||||||
bool OnDeployBinaries(CookingData& data) override;
|
bool OnDeployBinaries(CookingData& data) override;
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -186,7 +186,7 @@ bool MacPlatformTools::OnPostProcess(CookingData& data)
|
|||||||
ADD_ENTRY("CFBundlePackageType", "APPL");
|
ADD_ENTRY("CFBundlePackageType", "APPL");
|
||||||
ADD_ENTRY("NSPrincipalClass", "NSApplication");
|
ADD_ENTRY("NSPrincipalClass", "NSApplication");
|
||||||
ADD_ENTRY("LSApplicationCategoryType", "public.app-category.games");
|
ADD_ENTRY("LSApplicationCategoryType", "public.app-category.games");
|
||||||
ADD_ENTRY("LSMinimumSystemVersion", "10.15");
|
ADD_ENTRY("LSMinimumSystemVersion", "13");
|
||||||
ADD_ENTRY("CFBundleIconFile", "icon.icns");
|
ADD_ENTRY("CFBundleIconFile", "icon.icns");
|
||||||
ADD_ENTRY_STR("CFBundleExecutable", executableName);
|
ADD_ENTRY_STR("CFBundleExecutable", executableName);
|
||||||
ADD_ENTRY_STR("CFBundleIdentifier", appIdentifier);
|
ADD_ENTRY_STR("CFBundleIdentifier", appIdentifier);
|
||||||
@@ -231,6 +231,8 @@ bool MacPlatformTools::OnPostProcess(CookingData& data)
|
|||||||
LOG(Info, "Building app package...");
|
LOG(Info, "Building app package...");
|
||||||
{
|
{
|
||||||
const String dmgPath = data.OriginalOutputPath / appName + TEXT(".dmg");
|
const String dmgPath = data.OriginalOutputPath / appName + TEXT(".dmg");
|
||||||
|
if (FileSystem::FileExists(dmgPath))
|
||||||
|
FileSystem::DeleteFile(dmgPath);
|
||||||
CreateProcessSettings procSettings;
|
CreateProcessSettings procSettings;
|
||||||
procSettings.HiddenWindow = true;
|
procSettings.HiddenWindow = true;
|
||||||
procSettings.WorkingDirectory = data.OriginalOutputPath;
|
procSettings.WorkingDirectory = data.OriginalOutputPath;
|
||||||
|
|||||||
@@ -528,6 +528,9 @@ bool WindowsPlatformTools::OnDeployBinaries(CookingData& data)
|
|||||||
|
|
||||||
void WindowsPlatformTools::OnBuildStarted(CookingData& data)
|
void WindowsPlatformTools::OnBuildStarted(CookingData& data)
|
||||||
{
|
{
|
||||||
|
if (EnumHasAllFlags(data.Options, BuildOptions::NoCook))
|
||||||
|
return;
|
||||||
|
|
||||||
// Remove old executable
|
// Remove old executable
|
||||||
Array<String> files;
|
Array<String> files;
|
||||||
FileSystem::DirectoryGetFiles(files, data.NativeCodeOutputPath, TEXT("*.exe"), DirectorySearchOption::TopDirectoryOnly);
|
FileSystem::DirectoryGetFiles(files, data.NativeCodeOutputPath, TEXT("*.exe"), DirectorySearchOption::TopDirectoryOnly);
|
||||||
|
|||||||
@@ -70,6 +70,20 @@ public:
|
|||||||
/// </summary>
|
/// </summary>
|
||||||
virtual ArchitectureType GetArchitecture() const = 0;
|
virtual ArchitectureType GetArchitecture() const = 0;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Gets the .Net version to use for the cooked game.
|
||||||
|
/// </summary>
|
||||||
|
virtual int32 GetDotnetVersion() const
|
||||||
|
{
|
||||||
|
#if OFFICIAL_BUILD
|
||||||
|
// Use the fixed .NET SDK version in packaged builds for compatibility (FlaxGame is precompiled with it)
|
||||||
|
return GAME_BUILD_DOTNET_RUNTIME_MIN_VER;
|
||||||
|
#else
|
||||||
|
// Use the highest version found on a system (Flax.Build will decide)
|
||||||
|
return 0;
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Gets the value indicating whenever platform requires AOT (needs C# assemblies to be precompiled).
|
/// Gets the value indicating whenever platform requires AOT (needs C# assemblies to be precompiled).
|
||||||
/// </summary>
|
/// </summary>
|
||||||
|
|||||||
@@ -189,7 +189,7 @@ bool CompileScriptsStep::Perform(CookingData& data)
|
|||||||
const String logFile = data.CacheDirectory / TEXT("CompileLog.txt");
|
const String logFile = data.CacheDirectory / TEXT("CompileLog.txt");
|
||||||
auto args = String::Format(
|
auto args = String::Format(
|
||||||
TEXT("-log -logfile=\"{4}\" -build -mutex -buildtargets={0} -platform={1} -arch={2} -configuration={3} -aotMode={5} {6}"),
|
TEXT("-log -logfile=\"{4}\" -build -mutex -buildtargets={0} -platform={1} -arch={2} -configuration={3} -aotMode={5} {6}"),
|
||||||
target, platform, architecture, configuration, logFile, ToString(data.Tools->UseAOT()), GAME_BUILD_DOTNET_VER);
|
target, platform, architecture, configuration, logFile, ToString(data.Tools->UseAOT()), data.GetDotnetCommandArg());
|
||||||
#if PLATFORM_WINDOWS
|
#if PLATFORM_WINDOWS
|
||||||
if (data.Platform == BuildPlatform::LinuxX64)
|
if (data.Platform == BuildPlatform::LinuxX64)
|
||||||
#elif PLATFORM_LINUX
|
#elif PLATFORM_LINUX
|
||||||
|
|||||||
@@ -36,6 +36,7 @@
|
|||||||
#include "Engine/Engine/Base/GameBase.h"
|
#include "Engine/Engine/Base/GameBase.h"
|
||||||
#include "Engine/Engine/Globals.h"
|
#include "Engine/Engine/Globals.h"
|
||||||
#include "Engine/Tools/TextureTool/TextureTool.h"
|
#include "Engine/Tools/TextureTool/TextureTool.h"
|
||||||
|
#include "Engine/Threading/Threading.h"
|
||||||
#include "Engine/Profiler/ProfilerCPU.h"
|
#include "Engine/Profiler/ProfilerCPU.h"
|
||||||
#include "Engine/Scripting/Enums.h"
|
#include "Engine/Scripting/Enums.h"
|
||||||
#if PLATFORM_TOOLS_WINDOWS
|
#if PLATFORM_TOOLS_WINDOWS
|
||||||
|
|||||||
@@ -88,7 +88,7 @@ bool DeployDataStep::Perform(CookingData& data)
|
|||||||
{
|
{
|
||||||
// Ask Flax.Build to provide .NET SDK location for the current platform
|
// Ask Flax.Build to provide .NET SDK location for the current platform
|
||||||
String sdks;
|
String sdks;
|
||||||
bool failed = ScriptsBuilder::RunBuildTool(String::Format(TEXT("-log -logMessagesOnly -logFileWithConsole -logfile=SDKs.txt -printSDKs {}"), GAME_BUILD_DOTNET_VER), data.CacheDirectory);
|
bool failed = ScriptsBuilder::RunBuildTool(String::Format(TEXT("-log -logMessagesOnly -logFileWithConsole -logfile=SDKs.txt -printSDKs {}"), data.GetDotnetCommandArg()), data.CacheDirectory);
|
||||||
failed |= File::ReadAllText(data.CacheDirectory / TEXT("SDKs.txt"), sdks);
|
failed |= File::ReadAllText(data.CacheDirectory / TEXT("SDKs.txt"), sdks);
|
||||||
int32 idx = sdks.Find(TEXT("DotNetSdk, "), StringSearchCase::CaseSensitive);
|
int32 idx = sdks.Find(TEXT("DotNetSdk, "), StringSearchCase::CaseSensitive);
|
||||||
if (idx != -1)
|
if (idx != -1)
|
||||||
@@ -200,7 +200,7 @@ bool DeployDataStep::Perform(CookingData& data)
|
|||||||
String sdks;
|
String sdks;
|
||||||
const Char *platformName, *archName;
|
const Char *platformName, *archName;
|
||||||
data.GetBuildPlatformName(platformName, archName);
|
data.GetBuildPlatformName(platformName, archName);
|
||||||
String args = String::Format(TEXT("-log -logMessagesOnly -logFileWithConsole -logfile=SDKs.txt -printDotNetRuntime -platform={} -arch={} {}"), platformName, archName, GAME_BUILD_DOTNET_VER);
|
String args = String::Format(TEXT("-log -logMessagesOnly -logFileWithConsole -logfile=SDKs.txt -printDotNetRuntime -platform={} -arch={} {}"), platformName, archName, data.GetDotnetCommandArg());
|
||||||
bool failed = ScriptsBuilder::RunBuildTool(args, data.CacheDirectory);
|
bool failed = ScriptsBuilder::RunBuildTool(args, data.CacheDirectory);
|
||||||
failed |= File::ReadAllText(data.CacheDirectory / TEXT("SDKs.txt"), sdks);
|
failed |= File::ReadAllText(data.CacheDirectory / TEXT("SDKs.txt"), sdks);
|
||||||
Array<String> parts;
|
Array<String> parts;
|
||||||
@@ -244,10 +244,13 @@ bool DeployDataStep::Perform(CookingData& data)
|
|||||||
}
|
}
|
||||||
if (version.IsEmpty())
|
if (version.IsEmpty())
|
||||||
{
|
{
|
||||||
|
int32 minVer = GAME_BUILD_DOTNET_RUNTIME_MIN_VER, maxVer = GAME_BUILD_DOTNET_RUNTIME_MAX_VER;
|
||||||
if (srcDotnetFromEngine)
|
if (srcDotnetFromEngine)
|
||||||
{
|
{
|
||||||
// Detect version from runtime files inside Engine Platform folder
|
// Detect version from runtime files inside Engine Platform folder
|
||||||
for (int32 i = GAME_BUILD_DOTNET_RUNTIME_MAX_VER; i >= GAME_BUILD_DOTNET_RUNTIME_MIN_VER; i--)
|
if (data.Tools->GetDotnetVersion() != 0)
|
||||||
|
minVer = maxVer = data.Tools->GetDotnetVersion();
|
||||||
|
for (int32 i = maxVer; i >= minVer; i--)
|
||||||
{
|
{
|
||||||
// Check runtime files inside Engine Platform folder
|
// Check runtime files inside Engine Platform folder
|
||||||
String testPath1 = srcDotnet / String::Format(TEXT("lib/net{}.0"), i);
|
String testPath1 = srcDotnet / String::Format(TEXT("lib/net{}.0"), i);
|
||||||
@@ -262,7 +265,7 @@ bool DeployDataStep::Perform(CookingData& data)
|
|||||||
}
|
}
|
||||||
if (version.IsEmpty())
|
if (version.IsEmpty())
|
||||||
{
|
{
|
||||||
data.Error(String::Format(TEXT("Failed to find supported .NET {} version for the current host platform."), GAME_BUILD_DOTNET_RUNTIME_MIN_VER));
|
data.Error(String::Format(TEXT("Failed to find supported .NET {} version (min {}) for the current host platform."), maxVer, minVer));
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -364,7 +367,7 @@ bool DeployDataStep::Perform(CookingData& data)
|
|||||||
const String logFile = data.CacheDirectory / TEXT("StripDotnetLibs.txt");
|
const String logFile = data.CacheDirectory / TEXT("StripDotnetLibs.txt");
|
||||||
String args = String::Format(
|
String args = String::Format(
|
||||||
TEXT("-log -logfile=\"{}\" -runDotNetClassLibStripping -mutex -binaries=\"{}\" {}"),
|
TEXT("-log -logfile=\"{}\" -runDotNetClassLibStripping -mutex -binaries=\"{}\" {}"),
|
||||||
logFile, data.DataOutputPath, GAME_BUILD_DOTNET_VER);
|
logFile, data.DataOutputPath, data.GetDotnetCommandArg());
|
||||||
for (const String& define : data.CustomDefines)
|
for (const String& define : data.CustomDefines)
|
||||||
{
|
{
|
||||||
args += TEXT(" -D");
|
args += TEXT(" -D");
|
||||||
|
|||||||
@@ -12,7 +12,7 @@
|
|||||||
void PrecompileAssembliesStep::OnBuildStarted(CookingData& data)
|
void PrecompileAssembliesStep::OnBuildStarted(CookingData& data)
|
||||||
{
|
{
|
||||||
const DotNetAOTModes aotMode = data.Tools->UseAOT();
|
const DotNetAOTModes aotMode = data.Tools->UseAOT();
|
||||||
if (aotMode == DotNetAOTModes::None)
|
if (aotMode == DotNetAOTModes::None || EnumHasAllFlags(data.Options, BuildOptions::NoCook))
|
||||||
return;
|
return;
|
||||||
const auto& buildSettings = *BuildSettings::Get();
|
const auto& buildSettings = *BuildSettings::Get();
|
||||||
|
|
||||||
@@ -69,7 +69,7 @@ bool PrecompileAssembliesStep::Perform(CookingData& data)
|
|||||||
const String logFile = data.CacheDirectory / TEXT("AOTLog.txt");
|
const String logFile = data.CacheDirectory / TEXT("AOTLog.txt");
|
||||||
String args = String::Format(
|
String args = String::Format(
|
||||||
TEXT("-log -logfile=\"{}\" -runDotNetAOT -mutex -platform={} -arch={} -configuration={} -aotMode={} -binaries=\"{}\" -intermediate=\"{}\" {}"),
|
TEXT("-log -logfile=\"{}\" -runDotNetAOT -mutex -platform={} -arch={} -configuration={} -aotMode={} -binaries=\"{}\" -intermediate=\"{}\" {}"),
|
||||||
logFile, platform, architecture, configuration, ToString(aotMode), data.DataOutputPath, data.ManagedCodeOutputPath, GAME_BUILD_DOTNET_VER);
|
logFile, platform, architecture, configuration, ToString(aotMode), data.DataOutputPath, data.ManagedCodeOutputPath, data.GetDotnetCommandArg());
|
||||||
if (!buildSettings.SkipUnusedDotnetLibsPackaging)
|
if (!buildSettings.SkipUnusedDotnetLibsPackaging)
|
||||||
args += TEXT(" -skipUnusedDotnetLibs=false"); // Run AOT on whole class library (not just used libs)
|
args += TEXT(" -skipUnusedDotnetLibs=false"); // Run AOT on whole class library (not just used libs)
|
||||||
for (const String& define : data.CustomDefines)
|
for (const String& define : data.CustomDefines)
|
||||||
|
|||||||
@@ -6,6 +6,8 @@
|
|||||||
#include "Engine/Core/Types/TimeSpan.h"
|
#include "Engine/Core/Types/TimeSpan.h"
|
||||||
#include "Engine/Core/Types/Stopwatch.h"
|
#include "Engine/Core/Types/Stopwatch.h"
|
||||||
#include "Engine/Core/Collections/Dictionary.h"
|
#include "Engine/Core/Collections/Dictionary.h"
|
||||||
|
#include "Engine/Profiler/ProfilerCPU.h"
|
||||||
|
#include "Engine/Profiler/ProfilerMemory.h"
|
||||||
#include "Engine/Engine/EngineService.h"
|
#include "Engine/Engine/EngineService.h"
|
||||||
#include "Engine/Scripting/Scripting.h"
|
#include "Engine/Scripting/Scripting.h"
|
||||||
#include "Engine/Scripting/BinaryModule.h"
|
#include "Engine/Scripting/BinaryModule.h"
|
||||||
@@ -69,6 +71,7 @@ MTypeObject* CustomEditorsUtil::GetCustomEditor(MTypeObject* refType)
|
|||||||
|
|
||||||
bool CustomEditorsUtilService::Init()
|
bool CustomEditorsUtilService::Init()
|
||||||
{
|
{
|
||||||
|
PROFILE_MEM(Editor);
|
||||||
TRACK_ASSEMBLY(((NativeBinaryModule*)GetBinaryModuleFlaxEngine())->Assembly);
|
TRACK_ASSEMBLY(((NativeBinaryModule*)GetBinaryModuleFlaxEngine())->Assembly);
|
||||||
Scripting::BinaryModuleLoaded.Bind(&OnBinaryModuleLoaded);
|
Scripting::BinaryModuleLoaded.Bind(&OnBinaryModuleLoaded);
|
||||||
|
|
||||||
@@ -77,6 +80,8 @@ bool CustomEditorsUtilService::Init()
|
|||||||
|
|
||||||
void OnAssemblyLoaded(MAssembly* assembly)
|
void OnAssemblyLoaded(MAssembly* assembly)
|
||||||
{
|
{
|
||||||
|
PROFILE_CPU_NAMED("CustomEditors.OnAssemblyLoaded");
|
||||||
|
PROFILE_MEM(Editor);
|
||||||
Stopwatch stopwatch;
|
Stopwatch stopwatch;
|
||||||
|
|
||||||
// Prepare FlaxEngine
|
// Prepare FlaxEngine
|
||||||
|
|||||||
@@ -22,7 +22,7 @@ internal class UIControlRefPickerControl : FlaxObjectRefPickerControl
|
|||||||
/// <inheritdoc />
|
/// <inheritdoc />
|
||||||
protected override bool IsValid(Object obj)
|
protected override bool IsValid(Object obj)
|
||||||
{
|
{
|
||||||
return obj == null || (obj is UIControl control && control.Control.GetType() == ControlType);
|
return obj == null || (obj is UIControl control && ControlType.IsAssignableFrom(control.Control.GetType()));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -20,6 +20,7 @@
|
|||||||
#include "Engine/Engine/Engine.h"
|
#include "Engine/Engine/Engine.h"
|
||||||
#include "Engine/ShadowsOfMordor/Builder.h"
|
#include "Engine/ShadowsOfMordor/Builder.h"
|
||||||
#include "Engine/Profiler/ProfilerCPU.h"
|
#include "Engine/Profiler/ProfilerCPU.h"
|
||||||
|
#include "Engine/Profiler/ProfilerMemory.h"
|
||||||
#include "FlaxEngine.Gen.h"
|
#include "FlaxEngine.Gen.h"
|
||||||
#if PLATFORM_LINUX
|
#if PLATFORM_LINUX
|
||||||
#include "Engine/Tools/TextureTool/TextureTool.h"
|
#include "Engine/Tools/TextureTool/TextureTool.h"
|
||||||
@@ -47,6 +48,7 @@ void Editor::CloseSplashScreen()
|
|||||||
|
|
||||||
bool Editor::CheckProjectUpgrade()
|
bool Editor::CheckProjectUpgrade()
|
||||||
{
|
{
|
||||||
|
PROFILE_MEM(Editor);
|
||||||
const auto versionFilePath = Globals::ProjectCacheFolder / TEXT("version");
|
const auto versionFilePath = Globals::ProjectCacheFolder / TEXT("version");
|
||||||
|
|
||||||
// Load version cache file
|
// Load version cache file
|
||||||
@@ -366,6 +368,8 @@ bool Editor::BackupProject()
|
|||||||
|
|
||||||
int32 Editor::LoadProduct()
|
int32 Editor::LoadProduct()
|
||||||
{
|
{
|
||||||
|
PROFILE_MEM(Editor);
|
||||||
|
|
||||||
// Flax Editor product
|
// Flax Editor product
|
||||||
Globals::ProductName = TEXT("Flax Editor");
|
Globals::ProductName = TEXT("Flax Editor");
|
||||||
Globals::CompanyName = TEXT("Flax");
|
Globals::CompanyName = TEXT("Flax");
|
||||||
@@ -626,6 +630,7 @@ int32 Editor::LoadProduct()
|
|||||||
|
|
||||||
Window* Editor::CreateMainWindow()
|
Window* Editor::CreateMainWindow()
|
||||||
{
|
{
|
||||||
|
PROFILE_MEM(Editor);
|
||||||
Window* window = Managed->GetMainWindow();
|
Window* window = Managed->GetMainWindow();
|
||||||
|
|
||||||
#if PLATFORM_LINUX
|
#if PLATFORM_LINUX
|
||||||
@@ -662,6 +667,7 @@ bool Editor::Init()
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
PROFILE_CPU();
|
PROFILE_CPU();
|
||||||
|
PROFILE_MEM(Editor);
|
||||||
|
|
||||||
// If during last lightmaps baking engine crashed we could try to restore the progress
|
// If during last lightmaps baking engine crashed we could try to restore the progress
|
||||||
ShadowsOfMordor::Builder::Instance()->CheckIfRestoreState();
|
ShadowsOfMordor::Builder::Instance()->CheckIfRestoreState();
|
||||||
@@ -693,11 +699,13 @@ bool Editor::Init()
|
|||||||
|
|
||||||
void Editor::BeforeRun()
|
void Editor::BeforeRun()
|
||||||
{
|
{
|
||||||
|
PROFILE_MEM(Editor);
|
||||||
Managed->BeforeRun();
|
Managed->BeforeRun();
|
||||||
}
|
}
|
||||||
|
|
||||||
void Editor::BeforeExit()
|
void Editor::BeforeExit()
|
||||||
{
|
{
|
||||||
|
PROFILE_MEM(Editor);
|
||||||
CloseSplashScreen();
|
CloseSplashScreen();
|
||||||
|
|
||||||
Managed->Exit();
|
Managed->Exit();
|
||||||
@@ -708,6 +716,8 @@ void Editor::BeforeExit()
|
|||||||
|
|
||||||
void EditorImpl::OnUpdate()
|
void EditorImpl::OnUpdate()
|
||||||
{
|
{
|
||||||
|
PROFILE_MEM(Editor);
|
||||||
|
|
||||||
// Update c# editor
|
// Update c# editor
|
||||||
Editor::Managed->Update();
|
Editor::Managed->Update();
|
||||||
|
|
||||||
|
|||||||
@@ -51,7 +51,7 @@ namespace FlaxEditor.GUI
|
|||||||
/// <summary>
|
/// <summary>
|
||||||
/// The column title horizontal text alignment
|
/// The column title horizontal text alignment
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public TextAlignment TitleAlignment = TextAlignment.Near;
|
public TextAlignment TitleAlignment = TextAlignment.Center;
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// The column title margin.
|
/// The column title margin.
|
||||||
|
|||||||
@@ -117,9 +117,10 @@ namespace FlaxEditor.GUI.ContextMenu
|
|||||||
public ContextMenuBase()
|
public ContextMenuBase()
|
||||||
: base(0, 0, 120, 32)
|
: base(0, 0, 120, 32)
|
||||||
{
|
{
|
||||||
_direction = ContextMenuDirection.RightDown;
|
|
||||||
Visible = false;
|
Visible = false;
|
||||||
|
AutoFocus = true;
|
||||||
|
|
||||||
|
_direction = ContextMenuDirection.RightDown;
|
||||||
_isSubMenu = true;
|
_isSubMenu = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -76,6 +76,8 @@ namespace FlaxEditor.GUI.Dialogs
|
|||||||
public ColorSelector(float wheelSize)
|
public ColorSelector(float wheelSize)
|
||||||
: base(0, 0, wheelSize, wheelSize)
|
: base(0, 0, wheelSize, wheelSize)
|
||||||
{
|
{
|
||||||
|
AutoFocus = true;
|
||||||
|
|
||||||
_colorWheelSprite = Editor.Instance.Icons.ColorWheel128;
|
_colorWheelSprite = Editor.Instance.Icons.ColorWheel128;
|
||||||
_wheelRect = new Rectangle(0, 0, wheelSize, wheelSize);
|
_wheelRect = new Rectangle(0, 0, wheelSize, wheelSize);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -71,8 +71,6 @@ namespace FlaxEditor.GUI.Docking
|
|||||||
internal DockPanelProxy(DockPanel panel)
|
internal DockPanelProxy(DockPanel panel)
|
||||||
: base(0, 0, 64, 64)
|
: base(0, 0, 64, 64)
|
||||||
{
|
{
|
||||||
AutoFocus = false;
|
|
||||||
|
|
||||||
_panel = panel;
|
_panel = panel;
|
||||||
AnchorPreset = AnchorPresets.StretchAll;
|
AnchorPreset = AnchorPresets.StretchAll;
|
||||||
Offsets = Margin.Zero;
|
Offsets = Margin.Zero;
|
||||||
|
|||||||
@@ -368,6 +368,8 @@ namespace FlaxEditor.GUI.Input
|
|||||||
public SliderControl(float value, float x = 0, float y = 0, float width = 120, float min = float.MinValue, float max = float.MaxValue)
|
public SliderControl(float value, float x = 0, float y = 0, float width = 120, float min = float.MinValue, float max = float.MaxValue)
|
||||||
: base(x, y, width, TextBox.DefaultHeight)
|
: base(x, y, width, TextBox.DefaultHeight)
|
||||||
{
|
{
|
||||||
|
AutoFocus = true;
|
||||||
|
|
||||||
_min = min;
|
_min = min;
|
||||||
_max = max;
|
_max = max;
|
||||||
_value = Mathf.Clamp(value, min, max);
|
_value = Mathf.Clamp(value, min, max);
|
||||||
|
|||||||
@@ -319,6 +319,8 @@ namespace FlaxEditor.GUI.Tree
|
|||||||
public TreeNode(bool canChangeOrder, SpriteHandle iconCollapsed, SpriteHandle iconOpened)
|
public TreeNode(bool canChangeOrder, SpriteHandle iconCollapsed, SpriteHandle iconOpened)
|
||||||
: base(0, 0, 64, 16)
|
: base(0, 0, 64, 16)
|
||||||
{
|
{
|
||||||
|
AutoFocus = true;
|
||||||
|
|
||||||
_canChangeOrder = canChangeOrder;
|
_canChangeOrder = canChangeOrder;
|
||||||
_animationProgress = 1.0f;
|
_animationProgress = 1.0f;
|
||||||
_cachedHeight = _headerHeight;
|
_cachedHeight = _headerHeight;
|
||||||
|
|||||||
@@ -155,6 +155,7 @@ namespace FlaxEditor.Gizmo
|
|||||||
// Ensure player is not moving objects
|
// Ensure player is not moving objects
|
||||||
if (ActiveAxis != Axis.None)
|
if (ActiveAxis != Axis.None)
|
||||||
return;
|
return;
|
||||||
|
Profiler.BeginEvent("Pick");
|
||||||
|
|
||||||
// Get mouse ray and try to hit any object
|
// Get mouse ray and try to hit any object
|
||||||
var ray = Owner.MouseRay;
|
var ray = Owner.MouseRay;
|
||||||
@@ -243,6 +244,8 @@ namespace FlaxEditor.Gizmo
|
|||||||
{
|
{
|
||||||
sceneEditing.Deselect();
|
sceneEditing.Deselect();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Profiler.EndEvent();
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <inheritdoc />
|
/// <inheritdoc />
|
||||||
|
|||||||
@@ -14,6 +14,7 @@
|
|||||||
#include "Engine/Platform/WindowsManager.h"
|
#include "Engine/Platform/WindowsManager.h"
|
||||||
#include "Engine/Content/Assets/VisualScript.h"
|
#include "Engine/Content/Assets/VisualScript.h"
|
||||||
#include "Engine/Content/Content.h"
|
#include "Engine/Content/Content.h"
|
||||||
|
#include "Engine/Level/Actor.h"
|
||||||
#include "Engine/CSG/CSGBuilder.h"
|
#include "Engine/CSG/CSGBuilder.h"
|
||||||
#include "Engine/Engine/CommandLine.h"
|
#include "Engine/Engine/CommandLine.h"
|
||||||
#include "Engine/Renderer/ProbesRenderer.h"
|
#include "Engine/Renderer/ProbesRenderer.h"
|
||||||
@@ -75,7 +76,7 @@ void OnLightmapsBuildFinished(bool failed)
|
|||||||
OnLightmapsBake(ShadowsOfMordor::BuildProgressStep::GenerateLightmapCharts, 0, 0, false);
|
OnLightmapsBake(ShadowsOfMordor::BuildProgressStep::GenerateLightmapCharts, 0, 0, false);
|
||||||
}
|
}
|
||||||
|
|
||||||
void OnBakeEvent(bool started, const ProbesRenderer::Entry& e)
|
void OnBakeEvent(bool started, Actor* e)
|
||||||
{
|
{
|
||||||
if (Internal_EnvProbeBake == nullptr)
|
if (Internal_EnvProbeBake == nullptr)
|
||||||
{
|
{
|
||||||
@@ -83,7 +84,7 @@ void OnBakeEvent(bool started, const ProbesRenderer::Entry& e)
|
|||||||
ASSERT(Internal_EnvProbeBake);
|
ASSERT(Internal_EnvProbeBake);
|
||||||
}
|
}
|
||||||
|
|
||||||
MObject* probeObj = e.Actor ? e.Actor->GetManagedInstance() : nullptr;
|
MObject* probeObj = e ? e->GetManagedInstance() : nullptr;
|
||||||
|
|
||||||
MainThreadManagedInvokeAction::ParamsBuilder params;
|
MainThreadManagedInvokeAction::ParamsBuilder params;
|
||||||
params.AddParam(started);
|
params.AddParam(started);
|
||||||
@@ -91,12 +92,12 @@ void OnBakeEvent(bool started, const ProbesRenderer::Entry& e)
|
|||||||
MainThreadManagedInvokeAction::Invoke(Internal_EnvProbeBake, params);
|
MainThreadManagedInvokeAction::Invoke(Internal_EnvProbeBake, params);
|
||||||
}
|
}
|
||||||
|
|
||||||
void OnRegisterBake(const ProbesRenderer::Entry& e)
|
void OnRegisterBake(Actor* e)
|
||||||
{
|
{
|
||||||
OnBakeEvent(true, e);
|
OnBakeEvent(true, e);
|
||||||
}
|
}
|
||||||
|
|
||||||
void OnFinishBake(const ProbesRenderer::Entry& e)
|
void OnFinishBake(Actor* e)
|
||||||
{
|
{
|
||||||
OnBakeEvent(false, e);
|
OnBakeEvent(false, e);
|
||||||
}
|
}
|
||||||
@@ -157,7 +158,9 @@ ManagedEditor::ManagedEditor()
|
|||||||
lightmapsBuilder->OnBuildProgress.Bind<OnLightmapsBuildProgress>();
|
lightmapsBuilder->OnBuildProgress.Bind<OnLightmapsBuildProgress>();
|
||||||
lightmapsBuilder->OnBuildFinished.Bind<OnLightmapsBuildFinished>();
|
lightmapsBuilder->OnBuildFinished.Bind<OnLightmapsBuildFinished>();
|
||||||
CSG::Builder::OnBrushModified.Bind<OnBrushModified>();
|
CSG::Builder::OnBrushModified.Bind<OnBrushModified>();
|
||||||
|
#if LOG_ENABLE
|
||||||
Log::Logger::OnMessage.Bind<OnLogMessage>();
|
Log::Logger::OnMessage.Bind<OnLogMessage>();
|
||||||
|
#endif
|
||||||
VisualScripting::DebugFlow.Bind<OnVisualScriptingDebugFlow>();
|
VisualScripting::DebugFlow.Bind<OnVisualScriptingDebugFlow>();
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -173,7 +176,9 @@ ManagedEditor::~ManagedEditor()
|
|||||||
lightmapsBuilder->OnBuildProgress.Unbind<OnLightmapsBuildProgress>();
|
lightmapsBuilder->OnBuildProgress.Unbind<OnLightmapsBuildProgress>();
|
||||||
lightmapsBuilder->OnBuildFinished.Unbind<OnLightmapsBuildFinished>();
|
lightmapsBuilder->OnBuildFinished.Unbind<OnLightmapsBuildFinished>();
|
||||||
CSG::Builder::OnBrushModified.Unbind<OnBrushModified>();
|
CSG::Builder::OnBrushModified.Unbind<OnBrushModified>();
|
||||||
|
#if LOG_ENABLE
|
||||||
Log::Logger::OnMessage.Unbind<OnLogMessage>();
|
Log::Logger::OnMessage.Unbind<OnLogMessage>();
|
||||||
|
#endif
|
||||||
VisualScripting::DebugFlow.Unbind<OnVisualScriptingDebugFlow>();
|
VisualScripting::DebugFlow.Unbind<OnVisualScriptingDebugFlow>();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -711,7 +711,11 @@ namespace FlaxEditor.Modules
|
|||||||
|
|
||||||
private void OnActorChildNodesDispose(ActorNode node)
|
private void OnActorChildNodesDispose(ActorNode node)
|
||||||
{
|
{
|
||||||
|
if (Selection.Count == 0)
|
||||||
|
return;
|
||||||
|
|
||||||
// TODO: cache if selection contains any actor child node and skip this loop if no need to iterate
|
// TODO: cache if selection contains any actor child node and skip this loop if no need to iterate
|
||||||
|
// TODO: or build a hash set with selected nodes for quick O(1) checks (cached until selection changes)
|
||||||
|
|
||||||
// Deselect child nodes
|
// Deselect child nodes
|
||||||
for (int i = 0; i < node.ChildNodes.Count; i++)
|
for (int i = 0; i < node.ChildNodes.Count; i++)
|
||||||
|
|||||||
@@ -3,6 +3,7 @@
|
|||||||
using System;
|
using System;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using System.IO;
|
using System.IO;
|
||||||
|
using System.Linq;
|
||||||
using FlaxEditor.SceneGraph;
|
using FlaxEditor.SceneGraph;
|
||||||
using FlaxEditor.SceneGraph.Actors;
|
using FlaxEditor.SceneGraph.Actors;
|
||||||
using FlaxEngine;
|
using FlaxEngine;
|
||||||
@@ -662,6 +663,48 @@ namespace FlaxEditor.Modules
|
|||||||
//node?.TreeNode.OnActiveChanged();
|
//node?.TreeNode.OnActiveChanged();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private void OnActorDestroyChildren(Actor actor)
|
||||||
|
{
|
||||||
|
// Instead of doing OnActorParentChanged for every child lets remove all of them at once from that actor
|
||||||
|
ActorNode node = GetActorNode(actor);
|
||||||
|
if (node != null)
|
||||||
|
{
|
||||||
|
if (Editor.SceneEditing.HasSthSelected)
|
||||||
|
{
|
||||||
|
// Clear selection if one of the removed actors is selected
|
||||||
|
var selection = new HashSet<Actor>();
|
||||||
|
foreach (var e in Editor.SceneEditing.Selection)
|
||||||
|
{
|
||||||
|
if (e is ActorNode q && q.Actor)
|
||||||
|
selection.Add(q.Actor);
|
||||||
|
}
|
||||||
|
var count = actor.ChildrenCount;
|
||||||
|
for (int i = 0; i < count; i++)
|
||||||
|
{
|
||||||
|
var child = actor.GetChild(i);
|
||||||
|
if (selection.Contains(child))
|
||||||
|
{
|
||||||
|
Editor.SceneEditing.Deselect();
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Remove all child nodes (upfront remove all nodes to run faster)
|
||||||
|
for (int i = 0; i < node.ChildNodes.Count; i++)
|
||||||
|
{
|
||||||
|
if (node.ChildNodes[i] is ActorNode child)
|
||||||
|
child.parentNode = null;
|
||||||
|
}
|
||||||
|
node.TreeNode.DisposeChildren();
|
||||||
|
for (int i = 0; i < node.ChildNodes.Count; i++)
|
||||||
|
{
|
||||||
|
node.ChildNodes[i].Dispose();
|
||||||
|
}
|
||||||
|
node.ChildNodes.Clear();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Gets the actor node.
|
/// Gets the actor node.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
@@ -713,6 +756,7 @@ namespace FlaxEditor.Modules
|
|||||||
Level.ActorOrderInParentChanged += OnActorOrderInParentChanged;
|
Level.ActorOrderInParentChanged += OnActorOrderInParentChanged;
|
||||||
Level.ActorNameChanged += OnActorNameChanged;
|
Level.ActorNameChanged += OnActorNameChanged;
|
||||||
Level.ActorActiveChanged += OnActorActiveChanged;
|
Level.ActorActiveChanged += OnActorActiveChanged;
|
||||||
|
Level.ActorDestroyChildren += OnActorDestroyChildren;
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <inheritdoc />
|
/// <inheritdoc />
|
||||||
@@ -730,6 +774,7 @@ namespace FlaxEditor.Modules
|
|||||||
Level.ActorOrderInParentChanged -= OnActorOrderInParentChanged;
|
Level.ActorOrderInParentChanged -= OnActorOrderInParentChanged;
|
||||||
Level.ActorNameChanged -= OnActorNameChanged;
|
Level.ActorNameChanged -= OnActorNameChanged;
|
||||||
Level.ActorActiveChanged -= OnActorActiveChanged;
|
Level.ActorActiveChanged -= OnActorActiveChanged;
|
||||||
|
Level.ActorDestroyChildren -= OnActorDestroyChildren;
|
||||||
|
|
||||||
// Cleanup graph
|
// Cleanup graph
|
||||||
Root.Dispose();
|
Root.Dispose();
|
||||||
|
|||||||
@@ -6,6 +6,7 @@
|
|||||||
#include "Engine/Core/Log.h"
|
#include "Engine/Core/Log.h"
|
||||||
#include "Engine/Engine/Globals.h"
|
#include "Engine/Engine/Globals.h"
|
||||||
#include "Engine/Core/Math/Quaternion.h"
|
#include "Engine/Core/Math/Quaternion.h"
|
||||||
|
#include "Engine/Profiler/ProfilerMemory.h"
|
||||||
#include "Engine/Serialization/JsonWriters.h"
|
#include "Engine/Serialization/JsonWriters.h"
|
||||||
#include "Engine/Serialization/JsonTools.h"
|
#include "Engine/Serialization/JsonTools.h"
|
||||||
#include <ThirdParty/pugixml/pugixml.hpp>
|
#include <ThirdParty/pugixml/pugixml.hpp>
|
||||||
@@ -327,6 +328,7 @@ ProjectInfo* ProjectInfo::Load(const String& path)
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Load
|
// Load
|
||||||
|
PROFILE_MEM(Editor);
|
||||||
auto project = New<ProjectInfo>();
|
auto project = New<ProjectInfo>();
|
||||||
if (project->LoadProject(path))
|
if (project->LoadProject(path))
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -97,13 +97,16 @@ namespace FlaxEditor.SceneGraph
|
|||||||
/// <returns>Hit object or null if there is no intersection at all.</returns>
|
/// <returns>Hit object or null if there is no intersection at all.</returns>
|
||||||
public SceneGraphNode RayCast(ref Ray ray, ref Ray view, out Real distance, RayCastData.FlagTypes flags = RayCastData.FlagTypes.None)
|
public SceneGraphNode RayCast(ref Ray ray, ref Ray view, out Real distance, RayCastData.FlagTypes flags = RayCastData.FlagTypes.None)
|
||||||
{
|
{
|
||||||
|
Profiler.BeginEvent("RayCastScene");
|
||||||
var data = new RayCastData
|
var data = new RayCastData
|
||||||
{
|
{
|
||||||
Ray = ray,
|
Ray = ray,
|
||||||
View = view,
|
View = view,
|
||||||
Flags = flags
|
Flags = flags
|
||||||
};
|
};
|
||||||
return RayCast(ref data, out distance, out _);
|
var result = RayCast(ref data, out distance, out _);
|
||||||
|
Profiler.EndEvent();
|
||||||
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
@@ -117,13 +120,16 @@ namespace FlaxEditor.SceneGraph
|
|||||||
/// <returns>Hit object or null if there is no intersection at all.</returns>
|
/// <returns>Hit object or null if there is no intersection at all.</returns>
|
||||||
public SceneGraphNode RayCast(ref Ray ray, ref Ray view, out Real distance, out Vector3 normal, RayCastData.FlagTypes flags = RayCastData.FlagTypes.None)
|
public SceneGraphNode RayCast(ref Ray ray, ref Ray view, out Real distance, out Vector3 normal, RayCastData.FlagTypes flags = RayCastData.FlagTypes.None)
|
||||||
{
|
{
|
||||||
|
Profiler.BeginEvent("RayCastScene");
|
||||||
var data = new RayCastData
|
var data = new RayCastData
|
||||||
{
|
{
|
||||||
Ray = ray,
|
Ray = ray,
|
||||||
View = view,
|
View = view,
|
||||||
Flags = flags
|
Flags = flags
|
||||||
};
|
};
|
||||||
return RayCast(ref data, out distance, out normal);
|
var result = RayCast(ref data, out distance, out normal);
|
||||||
|
Profiler.EndEvent();
|
||||||
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
internal static Quaternion RaycastNormalRotation(ref Vector3 normal)
|
internal static Quaternion RaycastNormalRotation(ref Vector3 normal)
|
||||||
|
|||||||
@@ -27,7 +27,7 @@ namespace FlaxEditor.SceneGraph
|
|||||||
/// <summary>
|
/// <summary>
|
||||||
/// The parent node.
|
/// The parent node.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
protected SceneGraphNode parentNode;
|
internal SceneGraphNode parentNode;
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Gets the children list.
|
/// Gets the children list.
|
||||||
|
|||||||
@@ -13,6 +13,7 @@
|
|||||||
#include "Engine/Engine/EngineService.h"
|
#include "Engine/Engine/EngineService.h"
|
||||||
#include "Engine/Platform/Thread.h"
|
#include "Engine/Platform/Thread.h"
|
||||||
#include "Engine/Threading/IRunnable.h"
|
#include "Engine/Threading/IRunnable.h"
|
||||||
|
#include "Engine/Profiler/ProfilerMemory.h"
|
||||||
|
|
||||||
void OnAsyncBegin(Thread* thread);
|
void OnAsyncBegin(Thread* thread);
|
||||||
void OnAsyncEnd();
|
void OnAsyncEnd();
|
||||||
@@ -232,6 +233,8 @@ void OnAsyncEnd()
|
|||||||
|
|
||||||
bool CodeEditingManagerService::Init()
|
bool CodeEditingManagerService::Init()
|
||||||
{
|
{
|
||||||
|
PROFILE_MEM(Editor);
|
||||||
|
|
||||||
// Try get editors
|
// Try get editors
|
||||||
#if USE_VISUAL_STUDIO_DTE
|
#if USE_VISUAL_STUDIO_DTE
|
||||||
VisualStudioEditor::FindEditors(&CodeEditors);
|
VisualStudioEditor::FindEditors(&CodeEditors);
|
||||||
|
|||||||
@@ -23,6 +23,7 @@
|
|||||||
#include "Engine/Scripting/Scripting.h"
|
#include "Engine/Scripting/Scripting.h"
|
||||||
#include "Engine/Scripting/Script.h"
|
#include "Engine/Scripting/Script.h"
|
||||||
#include "Engine/Profiler/ProfilerCPU.h"
|
#include "Engine/Profiler/ProfilerCPU.h"
|
||||||
|
#include "Engine/Profiler/ProfilerMemory.h"
|
||||||
#include "Engine/Level/Level.h"
|
#include "Engine/Level/Level.h"
|
||||||
#include "FlaxEngine.Gen.h"
|
#include "FlaxEngine.Gen.h"
|
||||||
|
|
||||||
@@ -77,7 +78,7 @@ namespace ScriptsBuilderImpl
|
|||||||
void onScriptsReloadEnd();
|
void onScriptsReloadEnd();
|
||||||
void onScriptsLoaded();
|
void onScriptsLoaded();
|
||||||
|
|
||||||
void GetClassName(const StringAnsi& fullname, StringAnsi& className);
|
void GetClassName(const StringAnsiView fullname, StringAnsi& className);
|
||||||
|
|
||||||
void onCodeEditorAsyncOpenBegin()
|
void onCodeEditorAsyncOpenBegin()
|
||||||
{
|
{
|
||||||
@@ -276,7 +277,7 @@ bool ScriptsBuilder::GenerateProject(const StringView& customArgs)
|
|||||||
return RunBuildTool(args);
|
return RunBuildTool(args);
|
||||||
}
|
}
|
||||||
|
|
||||||
void ScriptsBuilderImpl::GetClassName(const StringAnsi& fullname, StringAnsi& className)
|
void ScriptsBuilderImpl::GetClassName(const StringAnsiView fullname, StringAnsi& className)
|
||||||
{
|
{
|
||||||
const auto lastDotIndex = fullname.FindLast('.');
|
const auto lastDotIndex = fullname.FindLast('.');
|
||||||
if (lastDotIndex != -1)
|
if (lastDotIndex != -1)
|
||||||
@@ -417,6 +418,7 @@ void ScriptsBuilder::GetBinariesConfiguration(const Char*& target, const Char*&
|
|||||||
|
|
||||||
bool ScriptsBuilderImpl::compileGameScriptsAsyncInner()
|
bool ScriptsBuilderImpl::compileGameScriptsAsyncInner()
|
||||||
{
|
{
|
||||||
|
PROFILE_MEM(Editor);
|
||||||
LOG(Info, "Starting scripts compilation...");
|
LOG(Info, "Starting scripts compilation...");
|
||||||
CallEvent(EventType::CompileStarted);
|
CallEvent(EventType::CompileStarted);
|
||||||
|
|
||||||
@@ -523,6 +525,8 @@ void ScriptsBuilderImpl::onEditorAssemblyUnloading(MAssembly* assembly)
|
|||||||
|
|
||||||
bool ScriptsBuilderImpl::compileGameScriptsAsync()
|
bool ScriptsBuilderImpl::compileGameScriptsAsync()
|
||||||
{
|
{
|
||||||
|
PROFILE_MEM(Editor);
|
||||||
|
|
||||||
// Start
|
// Start
|
||||||
{
|
{
|
||||||
ScopeLock scopeLock(_locker);
|
ScopeLock scopeLock(_locker);
|
||||||
@@ -566,6 +570,7 @@ bool ScriptsBuilderService::Init()
|
|||||||
// Check flag
|
// Check flag
|
||||||
if (_isInited)
|
if (_isInited)
|
||||||
return false;
|
return false;
|
||||||
|
PROFILE_MEM(Editor);
|
||||||
_isInited = true;
|
_isInited = true;
|
||||||
|
|
||||||
// Link for Editor assembly unload event to clear cached Internal_OnCompilationEnd to prevent errors
|
// Link for Editor assembly unload event to clear cached Internal_OnCompilationEnd to prevent errors
|
||||||
@@ -663,6 +668,9 @@ bool ScriptsBuilderService::Init()
|
|||||||
|
|
||||||
void ScriptsBuilderService::Update()
|
void ScriptsBuilderService::Update()
|
||||||
{
|
{
|
||||||
|
PROFILE_CPU();
|
||||||
|
PROFILE_MEM(Editor);
|
||||||
|
|
||||||
// Send compilation events
|
// Send compilation events
|
||||||
{
|
{
|
||||||
ScopeLock scopeLock(_compileEventsLocker);
|
ScopeLock scopeLock(_compileEventsLocker);
|
||||||
|
|||||||
@@ -233,6 +233,8 @@ namespace FlaxEditor.Surface.Archetypes
|
|||||||
public BlendPointsEditor(Animation.MultiBlend node, bool is2D, float x, float y, float width, float height)
|
public BlendPointsEditor(Animation.MultiBlend node, bool is2D, float x, float y, float width, float height)
|
||||||
: base(x, y, width, height)
|
: base(x, y, width, height)
|
||||||
{
|
{
|
||||||
|
AutoFocus = true;
|
||||||
|
|
||||||
_node = node;
|
_node = node;
|
||||||
_is2D = is2D;
|
_is2D = is2D;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -6,6 +6,7 @@ using FlaxEditor.Scripting;
|
|||||||
using FlaxEditor.Surface.Elements;
|
using FlaxEditor.Surface.Elements;
|
||||||
using FlaxEditor.Windows.Assets;
|
using FlaxEditor.Windows.Assets;
|
||||||
using FlaxEngine;
|
using FlaxEngine;
|
||||||
|
using FlaxEngine.GUI;
|
||||||
|
|
||||||
namespace FlaxEditor.Surface.Archetypes
|
namespace FlaxEditor.Surface.Archetypes
|
||||||
{
|
{
|
||||||
@@ -123,7 +124,8 @@ namespace FlaxEditor.Surface.Archetypes
|
|||||||
case MaterialDomain.Particle:
|
case MaterialDomain.Particle:
|
||||||
case MaterialDomain.Deformable:
|
case MaterialDomain.Deformable:
|
||||||
{
|
{
|
||||||
bool isNotUnlit = info.ShadingModel != MaterialShadingModel.Unlit;
|
bool isNotUnlit = info.ShadingModel != MaterialShadingModel.Unlit && info.ShadingModel != MaterialShadingModel.CustomLit;
|
||||||
|
bool isOpaque = info.BlendMode == MaterialBlendMode.Opaque;
|
||||||
bool withTess = info.TessellationMode != TessellationMethod.None;
|
bool withTess = info.TessellationMode != TessellationMethod.None;
|
||||||
|
|
||||||
GetBox(MaterialNodeBoxes.Color).IsActive = isNotUnlit;
|
GetBox(MaterialNodeBoxes.Color).IsActive = isNotUnlit;
|
||||||
@@ -134,8 +136,8 @@ namespace FlaxEditor.Surface.Archetypes
|
|||||||
GetBox(MaterialNodeBoxes.Roughness).IsActive = isNotUnlit;
|
GetBox(MaterialNodeBoxes.Roughness).IsActive = isNotUnlit;
|
||||||
GetBox(MaterialNodeBoxes.AmbientOcclusion).IsActive = isNotUnlit;
|
GetBox(MaterialNodeBoxes.AmbientOcclusion).IsActive = isNotUnlit;
|
||||||
GetBox(MaterialNodeBoxes.Normal).IsActive = isNotUnlit;
|
GetBox(MaterialNodeBoxes.Normal).IsActive = isNotUnlit;
|
||||||
GetBox(MaterialNodeBoxes.Opacity).IsActive = info.ShadingModel == MaterialShadingModel.Subsurface || info.ShadingModel == MaterialShadingModel.Foliage || info.BlendMode != MaterialBlendMode.Opaque;
|
GetBox(MaterialNodeBoxes.Opacity).IsActive = info.ShadingModel == MaterialShadingModel.Subsurface || info.ShadingModel == MaterialShadingModel.Foliage || !isOpaque;
|
||||||
GetBox(MaterialNodeBoxes.Refraction).IsActive = info.BlendMode != MaterialBlendMode.Opaque;
|
GetBox(MaterialNodeBoxes.Refraction).IsActive = !isOpaque;
|
||||||
GetBox(MaterialNodeBoxes.PositionOffset).IsActive = true;
|
GetBox(MaterialNodeBoxes.PositionOffset).IsActive = true;
|
||||||
GetBox(MaterialNodeBoxes.TessellationMultiplier).IsActive = withTess;
|
GetBox(MaterialNodeBoxes.TessellationMultiplier).IsActive = withTess;
|
||||||
GetBox(MaterialNodeBoxes.WorldDisplacement).IsActive = withTess;
|
GetBox(MaterialNodeBoxes.WorldDisplacement).IsActive = withTess;
|
||||||
@@ -260,6 +262,211 @@ namespace FlaxEditor.Surface.Archetypes
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#if false // TODO: finish code editor based on RichTextBoxBase with text block parsing for custom styling
|
||||||
|
internal sealed class CustomCodeTextBox : RichTextBoxBase
|
||||||
|
{
|
||||||
|
protected override void OnParseTextBlocks()
|
||||||
|
{
|
||||||
|
base.OnParseTextBlocks();
|
||||||
|
|
||||||
|
// Single block for a whole text
|
||||||
|
// TODO: implement code parsing with HLSL syntax
|
||||||
|
var font = Style.Current.FontMedium;
|
||||||
|
var style = new TextBlockStyle
|
||||||
|
{
|
||||||
|
Font = new FontReference(font),
|
||||||
|
Color = Style.Current.Foreground,
|
||||||
|
BackgroundSelectedBrush = new SolidColorBrush(Style.Current.BackgroundSelected),
|
||||||
|
};
|
||||||
|
_textBlocks.Clear();
|
||||||
|
_textBlocks.Add(new TextBlock
|
||||||
|
{
|
||||||
|
Range = new TextRange
|
||||||
|
{
|
||||||
|
StartIndex = 0,
|
||||||
|
EndIndex = TextLength,
|
||||||
|
},
|
||||||
|
Style = style,
|
||||||
|
Bounds = new Rectangle(Float2.Zero, font.MeasureText(Text)),
|
||||||
|
});
|
||||||
|
}
|
||||||
|
#else
|
||||||
|
internal sealed class CustomCodeTextBox : TextBox
|
||||||
|
{
|
||||||
|
#endif
|
||||||
|
public override void Draw()
|
||||||
|
{
|
||||||
|
base.Draw();
|
||||||
|
|
||||||
|
// Draw border
|
||||||
|
if (!IsFocused)
|
||||||
|
Render2D.DrawRectangle(new Rectangle(Float2.Zero, Size), Style.Current.BorderNormal);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
internal sealed class CustomCodeNode : SurfaceNode
|
||||||
|
{
|
||||||
|
private Rectangle _resizeButtonRect;
|
||||||
|
private Float2 _startResizingSize;
|
||||||
|
private Float2 _startResizingCornerOffset;
|
||||||
|
private bool _isResizing;
|
||||||
|
private CustomCodeTextBox _textBox;
|
||||||
|
|
||||||
|
private int SizeValueIndex => Archetype.TypeID == 8 ? 1 : 3; // Index of the Size stored in Values array
|
||||||
|
|
||||||
|
private Float2 SizeValue
|
||||||
|
{
|
||||||
|
get => (Float2)Values[SizeValueIndex];
|
||||||
|
set => SetValue(SizeValueIndex, value, false);
|
||||||
|
}
|
||||||
|
|
||||||
|
public CustomCodeNode(uint id, VisjectSurfaceContext context, NodeArchetype nodeArch, GroupArchetype groupArch)
|
||||||
|
: base(id, context, nodeArch, groupArch)
|
||||||
|
{
|
||||||
|
Float2 pos = new Float2(FlaxEditor.Surface.Constants.NodeMarginX, FlaxEditor.Surface.Constants.NodeMarginY + FlaxEditor.Surface.Constants.NodeHeaderSize), size;
|
||||||
|
if (nodeArch.TypeID == 8)
|
||||||
|
{
|
||||||
|
pos += new Float2(60, 0);
|
||||||
|
size = new Float2(172, 200);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
pos += new Float2(0, 40);
|
||||||
|
size = new Float2(300, 200);
|
||||||
|
}
|
||||||
|
_textBox = new CustomCodeTextBox
|
||||||
|
{
|
||||||
|
IsMultiline = true,
|
||||||
|
Location = pos,
|
||||||
|
Size = size,
|
||||||
|
Parent = this,
|
||||||
|
AnchorMax = Float2.One,
|
||||||
|
};
|
||||||
|
_textBox.EditEnd += () => SetValue(0, _textBox.Text);
|
||||||
|
}
|
||||||
|
|
||||||
|
public override bool CanSelect(ref Float2 location)
|
||||||
|
{
|
||||||
|
return base.CanSelect(ref location) && !_resizeButtonRect.MakeOffsetted(Location).Contains(ref location);
|
||||||
|
}
|
||||||
|
|
||||||
|
public override void OnSurfaceLoaded(SurfaceNodeActions action)
|
||||||
|
{
|
||||||
|
base.OnSurfaceLoaded(action);
|
||||||
|
|
||||||
|
_textBox.Text = (string)Values[0];
|
||||||
|
|
||||||
|
var size = SizeValue;
|
||||||
|
if (Surface != null && Surface.GridSnappingEnabled)
|
||||||
|
size = Surface.SnapToGrid(size, true);
|
||||||
|
Resize(size.X, size.Y);
|
||||||
|
}
|
||||||
|
|
||||||
|
public override void OnValuesChanged()
|
||||||
|
{
|
||||||
|
base.OnValuesChanged();
|
||||||
|
|
||||||
|
var size = SizeValue;
|
||||||
|
Resize(size.X, size.Y);
|
||||||
|
_textBox.Text = (string)Values[0];
|
||||||
|
}
|
||||||
|
|
||||||
|
protected override void UpdateRectangles()
|
||||||
|
{
|
||||||
|
base.UpdateRectangles();
|
||||||
|
|
||||||
|
const float buttonMargin = FlaxEditor.Surface.Constants.NodeCloseButtonMargin;
|
||||||
|
const float buttonSize = FlaxEditor.Surface.Constants.NodeCloseButtonSize;
|
||||||
|
_resizeButtonRect = new Rectangle(_closeButtonRect.Left, Height - buttonSize - buttonMargin - 4, buttonSize, buttonSize);
|
||||||
|
}
|
||||||
|
|
||||||
|
public override void Draw()
|
||||||
|
{
|
||||||
|
base.Draw();
|
||||||
|
|
||||||
|
var style = Style.Current;
|
||||||
|
if (_isResizing)
|
||||||
|
{
|
||||||
|
Render2D.FillRectangle(_resizeButtonRect, style.Selection);
|
||||||
|
Render2D.DrawRectangle(_resizeButtonRect, style.SelectionBorder);
|
||||||
|
}
|
||||||
|
Render2D.DrawSprite(style.Scale, _resizeButtonRect, _resizeButtonRect.Contains(_mousePosition) && Surface.CanEdit ? style.Foreground : style.ForegroundGrey);
|
||||||
|
}
|
||||||
|
|
||||||
|
public override void OnLostFocus()
|
||||||
|
{
|
||||||
|
if (_isResizing)
|
||||||
|
EndResizing();
|
||||||
|
|
||||||
|
base.OnLostFocus();
|
||||||
|
}
|
||||||
|
|
||||||
|
public override void OnEndMouseCapture()
|
||||||
|
{
|
||||||
|
if (_isResizing)
|
||||||
|
EndResizing();
|
||||||
|
|
||||||
|
base.OnEndMouseCapture();
|
||||||
|
}
|
||||||
|
|
||||||
|
public override bool OnMouseDown(Float2 location, MouseButton button)
|
||||||
|
{
|
||||||
|
if (base.OnMouseDown(location, button))
|
||||||
|
return true;
|
||||||
|
|
||||||
|
if (button == MouseButton.Left && _resizeButtonRect.Contains(ref location) && Surface.CanEdit)
|
||||||
|
{
|
||||||
|
// Start sliding
|
||||||
|
_isResizing = true;
|
||||||
|
_startResizingSize = Size;
|
||||||
|
_startResizingCornerOffset = Size - location;
|
||||||
|
StartMouseCapture();
|
||||||
|
Cursor = CursorType.SizeNWSE;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
public override void OnMouseMove(Float2 location)
|
||||||
|
{
|
||||||
|
if (_isResizing)
|
||||||
|
{
|
||||||
|
var emptySize = CalculateNodeSize(0, 0);
|
||||||
|
var size = Float2.Max(location - emptySize + _startResizingCornerOffset, new Float2(240, 160));
|
||||||
|
Resize(size.X, size.Y);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
base.OnMouseMove(location);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public override bool OnMouseUp(Float2 location, MouseButton button)
|
||||||
|
{
|
||||||
|
if (button == MouseButton.Left && _isResizing)
|
||||||
|
{
|
||||||
|
EndResizing();
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
return base.OnMouseUp(location, button);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void EndResizing()
|
||||||
|
{
|
||||||
|
Cursor = CursorType.Default;
|
||||||
|
EndMouseCapture();
|
||||||
|
_isResizing = false;
|
||||||
|
if (_startResizingSize != Size)
|
||||||
|
{
|
||||||
|
var emptySize = CalculateNodeSize(0, 0);
|
||||||
|
SizeValue = Size - emptySize;
|
||||||
|
Surface.MarkAsEdited(false);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
internal enum MaterialTemplateInputsMapping
|
internal enum MaterialTemplateInputsMapping
|
||||||
{
|
{
|
||||||
/// <summary>
|
/// <summary>
|
||||||
@@ -410,13 +617,15 @@ namespace FlaxEditor.Surface.Archetypes
|
|||||||
new NodeArchetype
|
new NodeArchetype
|
||||||
{
|
{
|
||||||
TypeID = 8,
|
TypeID = 8,
|
||||||
|
Create = (id, context, arch, groupArch) => new CustomCodeNode(id, context, arch, groupArch),
|
||||||
Title = "Custom Code",
|
Title = "Custom Code",
|
||||||
Description = "Custom HLSL shader code expression",
|
Description = "Custom HLSL shader code expression",
|
||||||
Flags = NodeFlags.MaterialGraph,
|
Flags = NodeFlags.MaterialGraph,
|
||||||
Size = new Float2(300, 200),
|
Size = new Float2(300, 200),
|
||||||
DefaultValues = new object[]
|
DefaultValues = new object[]
|
||||||
{
|
{
|
||||||
"// Here you can add HLSL code\nOutput0 = Input0;"
|
"// Here you can add HLSL code\nOutput0 = Input0;",
|
||||||
|
new Float2(300, 200),
|
||||||
},
|
},
|
||||||
Elements = new[]
|
Elements = new[]
|
||||||
{
|
{
|
||||||
@@ -433,8 +642,6 @@ namespace FlaxEditor.Surface.Archetypes
|
|||||||
NodeElementArchetype.Factory.Output(1, "Output1", typeof(Float4), 9),
|
NodeElementArchetype.Factory.Output(1, "Output1", typeof(Float4), 9),
|
||||||
NodeElementArchetype.Factory.Output(2, "Output2", typeof(Float4), 10),
|
NodeElementArchetype.Factory.Output(2, "Output2", typeof(Float4), 10),
|
||||||
NodeElementArchetype.Factory.Output(3, "Output3", typeof(Float4), 11),
|
NodeElementArchetype.Factory.Output(3, "Output3", typeof(Float4), 11),
|
||||||
|
|
||||||
NodeElementArchetype.Factory.TextBox(60, 0, 175, 200, 0),
|
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
new NodeArchetype
|
new NodeArchetype
|
||||||
@@ -874,6 +1081,7 @@ namespace FlaxEditor.Surface.Archetypes
|
|||||||
new NodeArchetype
|
new NodeArchetype
|
||||||
{
|
{
|
||||||
TypeID = 38,
|
TypeID = 38,
|
||||||
|
Create = (id, context, arch, groupArch) => new CustomCodeNode(id, context, arch, groupArch),
|
||||||
Title = "Custom Global Code",
|
Title = "Custom Global Code",
|
||||||
Description = "Custom global HLSL shader code expression (placed before material shader code). Can contain includes to shader utilities or declare functions to reuse later.",
|
Description = "Custom global HLSL shader code expression (placed before material shader code). Can contain includes to shader utilities or declare functions to reuse later.",
|
||||||
Flags = NodeFlags.MaterialGraph,
|
Flags = NodeFlags.MaterialGraph,
|
||||||
@@ -883,6 +1091,7 @@ namespace FlaxEditor.Surface.Archetypes
|
|||||||
"// Here you can add HLSL code\nfloat4 GetCustomColor()\n{\n\treturn float4(1, 0, 0, 1);\n}",
|
"// Here you can add HLSL code\nfloat4 GetCustomColor()\n{\n\treturn float4(1, 0, 0, 1);\n}",
|
||||||
true,
|
true,
|
||||||
(int)MaterialTemplateInputsMapping.Utilities,
|
(int)MaterialTemplateInputsMapping.Utilities,
|
||||||
|
new Float2(300, 240),
|
||||||
},
|
},
|
||||||
Elements = new[]
|
Elements = new[]
|
||||||
{
|
{
|
||||||
@@ -890,7 +1099,6 @@ namespace FlaxEditor.Surface.Archetypes
|
|||||||
NodeElementArchetype.Factory.Text(20, 0, "Enabled"),
|
NodeElementArchetype.Factory.Text(20, 0, "Enabled"),
|
||||||
NodeElementArchetype.Factory.Text(0, 20, "Location"),
|
NodeElementArchetype.Factory.Text(0, 20, "Location"),
|
||||||
NodeElementArchetype.Factory.Enum(50, 20, 120, 2, typeof(MaterialTemplateInputsMapping)),
|
NodeElementArchetype.Factory.Enum(50, 20, 120, 2, typeof(MaterialTemplateInputsMapping)),
|
||||||
NodeElementArchetype.Factory.TextBox(0, 40, 300, 200, 0),
|
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
new NodeArchetype
|
new NodeArchetype
|
||||||
|
|||||||
@@ -64,6 +64,7 @@ namespace FlaxEditor.Surface.Elements
|
|||||||
{
|
{
|
||||||
ParentNode = parentNode;
|
ParentNode = parentNode;
|
||||||
Archetype = archetype;
|
Archetype = archetype;
|
||||||
|
AutoFocus = true;
|
||||||
|
|
||||||
var back = Style.Current.TextBoxBackground;
|
var back = Style.Current.TextBoxBackground;
|
||||||
var grayOutFactor = 0.6f;
|
var grayOutFactor = 0.6f;
|
||||||
|
|||||||
@@ -59,6 +59,7 @@ namespace FlaxEditor.Surface
|
|||||||
protected SurfaceControl(VisjectSurfaceContext context, float width, float height)
|
protected SurfaceControl(VisjectSurfaceContext context, float width, float height)
|
||||||
: base(0, 0, width, height)
|
: base(0, 0, width, height)
|
||||||
{
|
{
|
||||||
|
AutoFocus = true;
|
||||||
ClipChildren = false;
|
ClipChildren = false;
|
||||||
|
|
||||||
Surface = context.Surface;
|
Surface = context.Surface;
|
||||||
|
|||||||
@@ -120,6 +120,8 @@ namespace FlaxEditor.Surface
|
|||||||
|
|
||||||
private void UpdateSelectionRectangle()
|
private void UpdateSelectionRectangle()
|
||||||
{
|
{
|
||||||
|
if (Root == null)
|
||||||
|
return;
|
||||||
var p1 = _rootControl.PointFromParent(ref _leftMouseDownPos);
|
var p1 = _rootControl.PointFromParent(ref _leftMouseDownPos);
|
||||||
var p2 = _rootControl.PointFromParent(ref _mousePos);
|
var p2 = _rootControl.PointFromParent(ref _mousePos);
|
||||||
var selectionRect = Rectangle.FromPoints(p1, p2);
|
var selectionRect = Rectangle.FromPoints(p1, p2);
|
||||||
|
|||||||
@@ -5,6 +5,7 @@
|
|||||||
#include "Engine/Content/Assets/Model.h"
|
#include "Engine/Content/Assets/Model.h"
|
||||||
#include "Engine/Content/Assets/MaterialInstance.h"
|
#include "Engine/Content/Assets/MaterialInstance.h"
|
||||||
#include "Engine/Content/Content.h"
|
#include "Engine/Content/Content.h"
|
||||||
|
#include "Engine/Profiler/ProfilerMemory.h"
|
||||||
#include "Engine/Level/Level.h"
|
#include "Engine/Level/Level.h"
|
||||||
#include "Engine/Level/Scene/Scene.h"
|
#include "Engine/Level/Scene/Scene.h"
|
||||||
#include "Engine/Level/Actors/PointLight.h"
|
#include "Engine/Level/Actors/PointLight.h"
|
||||||
@@ -263,6 +264,7 @@ void ViewportIconsRendererService::DrawIcons(RenderContext& renderContext, Actor
|
|||||||
|
|
||||||
bool ViewportIconsRendererService::Init()
|
bool ViewportIconsRendererService::Init()
|
||||||
{
|
{
|
||||||
|
PROFILE_MEM(Editor);
|
||||||
QuadModel = Content::LoadAsyncInternal<Model>(TEXT("Engine/Models/Quad"));
|
QuadModel = Content::LoadAsyncInternal<Model>(TEXT("Engine/Models/Quad"));
|
||||||
#define INIT(type, path) \
|
#define INIT(type, path) \
|
||||||
InstanceBuffers[static_cast<int32>(IconTypes::type)].Setup(1); \
|
InstanceBuffers[static_cast<int32>(IconTypes::type)].Setup(1); \
|
||||||
|
|||||||
@@ -340,6 +340,13 @@ namespace FlaxEditor.Viewport
|
|||||||
{
|
{
|
||||||
_debugDrawData.Clear();
|
_debugDrawData.Clear();
|
||||||
|
|
||||||
|
if (task is SceneRenderTask sceneRenderTask)
|
||||||
|
{
|
||||||
|
// Sync debug view to avoid lag on culling/LODing
|
||||||
|
var view = sceneRenderTask.View;
|
||||||
|
DebugDraw.SetView(ref view);
|
||||||
|
}
|
||||||
|
|
||||||
// Collect selected objects debug shapes and visuals
|
// Collect selected objects debug shapes and visuals
|
||||||
var selectedParents = TransformGizmo.SelectedParents;
|
var selectedParents = TransformGizmo.SelectedParents;
|
||||||
if (selectedParents.Count > 0)
|
if (selectedParents.Count > 0)
|
||||||
|
|||||||
@@ -243,7 +243,12 @@ namespace FlaxEditor.Viewport
|
|||||||
_tempDebugDrawContext = DebugDraw.AllocateContext();
|
_tempDebugDrawContext = DebugDraw.AllocateContext();
|
||||||
DebugDraw.SetContext(_tempDebugDrawContext);
|
DebugDraw.SetContext(_tempDebugDrawContext);
|
||||||
DebugDraw.UpdateContext(_tempDebugDrawContext, 1.0f);
|
DebugDraw.UpdateContext(_tempDebugDrawContext, 1.0f);
|
||||||
|
if (task is SceneRenderTask sceneRenderTask)
|
||||||
|
{
|
||||||
|
// Sync debug view to avoid lag on culling/LODing
|
||||||
|
var view = sceneRenderTask.View;
|
||||||
|
DebugDraw.SetView(ref view);
|
||||||
|
}
|
||||||
for (int i = 0; i < selectedParents.Count; i++)
|
for (int i = 0; i < selectedParents.Count; i++)
|
||||||
{
|
{
|
||||||
if (selectedParents[i].IsActiveInHierarchy)
|
if (selectedParents[i].IsActiveInHierarchy)
|
||||||
|
|||||||
@@ -264,6 +264,7 @@ namespace FlaxEditor.Viewport.Previews
|
|||||||
{
|
{
|
||||||
DebugDraw.SetContext(_debugDrawContext);
|
DebugDraw.SetContext(_debugDrawContext);
|
||||||
DebugDraw.UpdateContext(_debugDrawContext, 1.0f / Mathf.Max(Engine.FramesPerSecond, 1));
|
DebugDraw.UpdateContext(_debugDrawContext, 1.0f / Mathf.Max(Engine.FramesPerSecond, 1));
|
||||||
|
DebugDraw.SetView(ref renderContext.View);
|
||||||
CustomDebugDraw?.Invoke(context, ref renderContext);
|
CustomDebugDraw?.Invoke(context, ref renderContext);
|
||||||
OnDebugDraw(context, ref renderContext);
|
OnDebugDraw(context, ref renderContext);
|
||||||
DebugDraw.Draw(ref renderContext, target.View(), targetDepth.View(), true);
|
DebugDraw.Draw(ref renderContext, target.View(), targetDepth.View(), true);
|
||||||
|
|||||||
@@ -181,15 +181,8 @@ namespace FlaxEditor.Windows.Assets
|
|||||||
|
|
||||||
private class CollisionDataPreview : ModelBasePreview
|
private class CollisionDataPreview : ModelBasePreview
|
||||||
{
|
{
|
||||||
public bool ShowCollisionData = false;
|
public bool ShowInfo;
|
||||||
private int _verticesCount = 0;
|
public string Info;
|
||||||
private int _trianglesCount = 0;
|
|
||||||
|
|
||||||
public void SetVerticesAndTriangleCount(int verticesCount, int triangleCount)
|
|
||||||
{
|
|
||||||
_verticesCount = verticesCount;
|
|
||||||
_trianglesCount = triangleCount;
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <inheritdoc />
|
/// <inheritdoc />
|
||||||
public CollisionDataPreview(bool useWidgets)
|
public CollisionDataPreview(bool useWidgets)
|
||||||
@@ -204,13 +197,12 @@ namespace FlaxEditor.Windows.Assets
|
|||||||
{
|
{
|
||||||
base.Draw();
|
base.Draw();
|
||||||
|
|
||||||
if (ShowCollisionData)
|
if (ShowInfo)
|
||||||
{
|
{
|
||||||
var text = string.Format("\nTriangles: {0:N0}\nVertices: {1:N0}\nMemory Size: {2}", _trianglesCount, _verticesCount, Utilities.Utils.FormatBytesCount(Asset.MemoryUsage));
|
|
||||||
var font = Style.Current.FontMedium;
|
var font = Style.Current.FontMedium;
|
||||||
var pos = new Float2(10, 50);
|
var pos = new Float2(10, 50);
|
||||||
Render2D.DrawText(font, text, new Rectangle(pos + Float2.One, Size), Color.Black);
|
Render2D.DrawText(font, Info, new Rectangle(pos + Float2.One, Size), Color.Black);
|
||||||
Render2D.DrawText(font, text, new Rectangle(pos, Size), Color.White);
|
Render2D.DrawText(font, Info, new Rectangle(pos, Size), Color.White);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -222,11 +214,11 @@ namespace FlaxEditor.Windows.Assets
|
|||||||
// Toolstrip
|
// Toolstrip
|
||||||
_toolstrip.AddSeparator();
|
_toolstrip.AddSeparator();
|
||||||
_toolstrip.AddButton(editor.Icons.CenterView64, () => _preview.ResetCamera()).LinkTooltip("Show whole collision");
|
_toolstrip.AddButton(editor.Icons.CenterView64, () => _preview.ResetCamera()).LinkTooltip("Show whole collision");
|
||||||
var infoButton = (ToolStripButton)_toolstrip.AddButton(editor.Icons.Info64).LinkTooltip("Show Collision Data");
|
var infoButton = (ToolStripButton)_toolstrip.AddButton(editor.Icons.Info64).LinkTooltip("Show Collision Data info");
|
||||||
infoButton.Clicked += () =>
|
infoButton.Clicked += () =>
|
||||||
{
|
{
|
||||||
_preview.ShowCollisionData = !_preview.ShowCollisionData;
|
_preview.ShowInfo = !_preview.ShowInfo;
|
||||||
infoButton.Checked = _preview.ShowCollisionData;
|
infoButton.Checked = _preview.ShowInfo;
|
||||||
};
|
};
|
||||||
_toolstrip.AddButton(editor.Icons.Docs64, () => Platform.OpenUrl(Utilities.Constants.DocsUrl + "manual/physics/colliders/collision-data.html")).LinkTooltip("See documentation to learn more");
|
_toolstrip.AddButton(editor.Icons.Docs64, () => Platform.OpenUrl(Utilities.Constants.DocsUrl + "manual/physics/colliders/collision-data.html")).LinkTooltip("See documentation to learn more");
|
||||||
|
|
||||||
@@ -293,7 +285,7 @@ namespace FlaxEditor.Windows.Assets
|
|||||||
}
|
}
|
||||||
_collisionWiresShowActor.Model = _collisionWiresModel;
|
_collisionWiresShowActor.Model = _collisionWiresModel;
|
||||||
_collisionWiresShowActor.SetMaterial(0, FlaxEngine.Content.LoadAsyncInternal<MaterialBase>(EditorAssets.WiresDebugMaterial));
|
_collisionWiresShowActor.SetMaterial(0, FlaxEngine.Content.LoadAsyncInternal<MaterialBase>(EditorAssets.WiresDebugMaterial));
|
||||||
_preview.SetVerticesAndTriangleCount(triangleCount, indicesCount / 3);
|
_preview.Info = string.Format("\nTriangles: {0:N0}\nVertices: {1:N0}\nMemory Size: {2}", triangleCount, indicesCount / 3, Utilities.Utils.FormatBytesCount(Asset.MemoryUsage));
|
||||||
_preview.Asset = FlaxEngine.Content.LoadAsync<ModelBase>(_asset.Options.Model);
|
_preview.Asset = FlaxEngine.Content.LoadAsync<ModelBase>(_asset.Options.Model);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -59,17 +59,11 @@ namespace FlaxEditor.Windows
|
|||||||
GameCookerWin = win;
|
GameCookerWin = win;
|
||||||
Selector = platformSelector;
|
Selector = platformSelector;
|
||||||
|
|
||||||
PerPlatformOptions[PlatformType.Windows].Init("Output/Windows", "Windows");
|
foreach (var e in PerPlatformOptions)
|
||||||
PerPlatformOptions[PlatformType.XboxOne].Init("Output/XboxOne", "XboxOne");
|
{
|
||||||
PerPlatformOptions[PlatformType.UWP].Init("Output/UWP", "UWP");
|
var str = e.Key.ToString();
|
||||||
PerPlatformOptions[PlatformType.Linux].Init("Output/Linux", "Linux");
|
e.Value.Init("Output/" + str, str);
|
||||||
PerPlatformOptions[PlatformType.PS4].Init("Output/PS4", "PS4");
|
}
|
||||||
PerPlatformOptions[PlatformType.XboxScarlett].Init("Output/XboxScarlett", "XboxScarlett");
|
|
||||||
PerPlatformOptions[PlatformType.Android].Init("Output/Android", "Android");
|
|
||||||
PerPlatformOptions[PlatformType.Switch].Init("Output/Switch", "Switch");
|
|
||||||
PerPlatformOptions[PlatformType.PS5].Init("Output/PS5", "PS5");
|
|
||||||
PerPlatformOptions[PlatformType.Mac].Init("Output/Mac", "Mac");
|
|
||||||
PerPlatformOptions[PlatformType.iOS].Init("Output/iOS", "iOS");
|
|
||||||
}
|
}
|
||||||
|
|
||||||
[HideInEditor]
|
[HideInEditor]
|
||||||
@@ -196,12 +190,14 @@ namespace FlaxEditor.Windows
|
|||||||
var label = layout.Label(text, TextAlignment.Center);
|
var label = layout.Label(text, TextAlignment.Center);
|
||||||
label.Label.AutoHeight = true;
|
label.Label.AutoHeight = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Used to add platform specific tools if available.
|
/// Used to add platform specific tools if available.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <param name="layout">The layout to start the tools at.</param>
|
/// <param name="layout">The layout to start the tools at.</param>
|
||||||
public virtual void OnCustomToolsLayout(LayoutElementsContainer layout) { }
|
public virtual void OnCustomToolsLayout(LayoutElementsContainer layout)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
public virtual void Build()
|
public virtual void Build()
|
||||||
{
|
{
|
||||||
@@ -256,7 +252,7 @@ namespace FlaxEditor.Windows
|
|||||||
if (string.IsNullOrEmpty(sdkPath))
|
if (string.IsNullOrEmpty(sdkPath))
|
||||||
sdkPath = Environment.GetEnvironmentVariable("ANDROID_SDK");
|
sdkPath = Environment.GetEnvironmentVariable("ANDROID_SDK");
|
||||||
emulatorGroup.Label($"SDK path: {sdkPath}");
|
emulatorGroup.Label($"SDK path: {sdkPath}");
|
||||||
|
|
||||||
// AVD and starting emulator
|
// AVD and starting emulator
|
||||||
var avdGroup = emulatorGroup.Group("AVD Emulator");
|
var avdGroup = emulatorGroup.Group("AVD Emulator");
|
||||||
avdGroup.Label("Note: Create AVDs using Android Studio.");
|
avdGroup.Label("Note: Create AVDs using Android Studio.");
|
||||||
@@ -273,7 +269,7 @@ namespace FlaxEditor.Windows
|
|||||||
{
|
{
|
||||||
if (avdListTree.Children.Count > 0)
|
if (avdListTree.Children.Count > 0)
|
||||||
avdListTree.DisposeChildren();
|
avdListTree.DisposeChildren();
|
||||||
|
|
||||||
var processStartInfo = new System.Diagnostics.ProcessStartInfo
|
var processStartInfo = new System.Diagnostics.ProcessStartInfo
|
||||||
{
|
{
|
||||||
FileName = Path.Combine(sdkPath, "emulator", "emulator.exe"),
|
FileName = Path.Combine(sdkPath, "emulator", "emulator.exe"),
|
||||||
@@ -299,7 +295,7 @@ namespace FlaxEditor.Windows
|
|||||||
};
|
};
|
||||||
//processSettings.ShellExecute = true;
|
//processSettings.ShellExecute = true;
|
||||||
FlaxEngine.Platform.CreateProcess(ref processSettings);
|
FlaxEngine.Platform.CreateProcess(ref processSettings);
|
||||||
|
|
||||||
var output = new string(processSettings.Output);*/
|
var output = new string(processSettings.Output);*/
|
||||||
if (output.Length == 0)
|
if (output.Length == 0)
|
||||||
{
|
{
|
||||||
@@ -345,9 +341,9 @@ namespace FlaxEditor.Windows
|
|||||||
processSettings.ShellExecute = true;
|
processSettings.ShellExecute = true;
|
||||||
FlaxEngine.Platform.CreateProcess(ref processSettings);
|
FlaxEngine.Platform.CreateProcess(ref processSettings);
|
||||||
};
|
};
|
||||||
|
|
||||||
emulatorGroup.Space(2);
|
emulatorGroup.Space(2);
|
||||||
|
|
||||||
// Device
|
// Device
|
||||||
var installGroup = emulatorGroup.Group("Install");
|
var installGroup = emulatorGroup.Group("Install");
|
||||||
installGroup.Panel.IsClosed = false;
|
installGroup.Panel.IsClosed = false;
|
||||||
@@ -391,10 +387,10 @@ namespace FlaxEditor.Windows
|
|||||||
processSettings.SaveOutput = true;
|
processSettings.SaveOutput = true;
|
||||||
processSettings.ShellExecute = false;
|
processSettings.ShellExecute = false;
|
||||||
FlaxEngine.Platform.CreateProcess(ref processSettings);
|
FlaxEngine.Platform.CreateProcess(ref processSettings);
|
||||||
|
|
||||||
var output = new string(processSettings.Output);
|
var output = new string(processSettings.Output);
|
||||||
*/
|
*/
|
||||||
|
|
||||||
if (output.Length > 0 && !output.Equals("List of devices attached", StringComparison.Ordinal))
|
if (output.Length > 0 && !output.Equals("List of devices attached", StringComparison.Ordinal))
|
||||||
{
|
{
|
||||||
noDevicesLabel.Visible = false;
|
noDevicesLabel.Visible = false;
|
||||||
@@ -403,7 +399,7 @@ namespace FlaxEditor.Windows
|
|||||||
{
|
{
|
||||||
if (line.Trim().Equals("List of devices attached", StringComparison.Ordinal) || string.IsNullOrEmpty(line.Trim()))
|
if (line.Trim().Equals("List of devices attached", StringComparison.Ordinal) || string.IsNullOrEmpty(line.Trim()))
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
var tab = line.Split("device ");
|
var tab = line.Split("device ");
|
||||||
if (tab.Length < 2)
|
if (tab.Length < 2)
|
||||||
continue;
|
continue;
|
||||||
@@ -430,7 +426,7 @@ namespace FlaxEditor.Windows
|
|||||||
{
|
{
|
||||||
if (deviceListTree.Selection.Count == 0)
|
if (deviceListTree.Selection.Count == 0)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
// Get built APK at output path
|
// Get built APK at output path
|
||||||
string output = StringUtils.ConvertRelativePathToAbsolute(Globals.ProjectFolder, StringUtils.NormalizePath(Output));
|
string output = StringUtils.ConvertRelativePathToAbsolute(Globals.ProjectFolder, StringUtils.NormalizePath(Output));
|
||||||
if (!Directory.Exists(output))
|
if (!Directory.Exists(output))
|
||||||
@@ -438,7 +434,7 @@ namespace FlaxEditor.Windows
|
|||||||
FlaxEditor.Editor.LogWarning("Can not copy APK because output folder does not exist.");
|
FlaxEditor.Editor.LogWarning("Can not copy APK because output folder does not exist.");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
var apkFiles = Directory.GetFiles(output, "*.apk");
|
var apkFiles = Directory.GetFiles(output, "*.apk");
|
||||||
if (apkFiles.Length == 0)
|
if (apkFiles.Length == 0)
|
||||||
{
|
{
|
||||||
@@ -457,7 +453,7 @@ namespace FlaxEditor.Windows
|
|||||||
}
|
}
|
||||||
apkFilesString += $" \"{file}\"";
|
apkFilesString += $" \"{file}\"";
|
||||||
}
|
}
|
||||||
|
|
||||||
CreateProcessSettings processSettings = new CreateProcessSettings
|
CreateProcessSettings processSettings = new CreateProcessSettings
|
||||||
{
|
{
|
||||||
FileName = Path.Combine(sdkPath, "platform-tools", "adb.exe"),
|
FileName = Path.Combine(sdkPath, "platform-tools", "adb.exe"),
|
||||||
|
|||||||
@@ -1192,6 +1192,12 @@ namespace FlaxEditor.Windows
|
|||||||
Screen.CursorVisible = true;
|
Screen.CursorVisible = true;
|
||||||
Screen.CursorLock = CursorLockMode.None;
|
Screen.CursorLock = CursorLockMode.None;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (Editor.IsPlayMode && IsDocked && IsSelected && RootWindow.FocusedControl == null)
|
||||||
|
{
|
||||||
|
// Game UI cleared focus so regain it to maintain UI navigation just like game window does
|
||||||
|
FlaxEngine.Scripting.InvokeOnUpdate(Focus);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <inheritdoc />
|
/// <inheritdoc />
|
||||||
|
|||||||
@@ -235,6 +235,8 @@ namespace FlaxEditor.Windows
|
|||||||
|
|
||||||
// Add items
|
// Add items
|
||||||
ItemsListContextMenu.Item lastItem = null;
|
ItemsListContextMenu.Item lastItem = null;
|
||||||
|
var itemFont = Style.Current.FontSmall;
|
||||||
|
var maxWidth = 0.0f;
|
||||||
foreach (var command in commands)
|
foreach (var command in commands)
|
||||||
{
|
{
|
||||||
cm.AddItem(lastItem = new Item
|
cm.AddItem(lastItem = new Item
|
||||||
@@ -252,6 +254,7 @@ namespace FlaxEditor.Windows
|
|||||||
// Set command
|
// Set command
|
||||||
Set(item.Name);
|
Set(item.Name);
|
||||||
};
|
};
|
||||||
|
maxWidth = Mathf.Max(maxWidth, itemFont.MeasureText(command).X);
|
||||||
}
|
}
|
||||||
cm.ItemClicked += item =>
|
cm.ItemClicked += item =>
|
||||||
{
|
{
|
||||||
@@ -265,6 +268,9 @@ namespace FlaxEditor.Windows
|
|||||||
cm.Height = 220;
|
cm.Height = 220;
|
||||||
if (cm.Height > totalHeight)
|
if (cm.Height > totalHeight)
|
||||||
cm.Height = totalHeight; // Limit popup height if list is small
|
cm.Height = totalHeight; // Limit popup height if list is small
|
||||||
|
maxWidth += 8.0f + ScrollBar.DefaultSize; // Margin
|
||||||
|
if (cm.Width < maxWidth)
|
||||||
|
cm.Width = maxWidth;
|
||||||
if (searchText != null)
|
if (searchText != null)
|
||||||
{
|
{
|
||||||
cm.SortItems();
|
cm.SortItems();
|
||||||
@@ -344,8 +350,8 @@ namespace FlaxEditor.Windows
|
|||||||
// Update history buffer
|
// Update history buffer
|
||||||
if (_window._commandHistory == null)
|
if (_window._commandHistory == null)
|
||||||
_window._commandHistory = new List<string>();
|
_window._commandHistory = new List<string>();
|
||||||
else if (_window._commandHistory.Count != 0 && _window._commandHistory.Last() == command)
|
else if (_window._commandHistory.Count != 0 && _window._commandHistory.Contains(command))
|
||||||
_window._commandHistory.RemoveAt(_window._commandHistory.Count - 1);
|
_window._commandHistory.Remove(command);
|
||||||
_window._commandHistory.Add(command);
|
_window._commandHistory.Add(command);
|
||||||
if (_window._commandHistory.Count > CommandHistoryLimit)
|
if (_window._commandHistory.Count > CommandHistoryLimit)
|
||||||
_window._commandHistory.RemoveAt(0);
|
_window._commandHistory.RemoveAt(0);
|
||||||
|
|||||||
@@ -34,6 +34,7 @@ namespace FlaxEditor.Windows.Profiler
|
|||||||
private List<ClickableRow> _tableRowsCache;
|
private List<ClickableRow> _tableRowsCache;
|
||||||
private Dictionary<Guid, Resource> _resourceCache;
|
private Dictionary<Guid, Resource> _resourceCache;
|
||||||
private StringBuilder _stringBuilder;
|
private StringBuilder _stringBuilder;
|
||||||
|
private Asset[] _assetsCache;
|
||||||
|
|
||||||
public Assets()
|
public Assets()
|
||||||
: base("Assets")
|
: base("Assets")
|
||||||
@@ -138,12 +139,12 @@ namespace FlaxEditor.Windows.Profiler
|
|||||||
_stringBuilder = new StringBuilder();
|
_stringBuilder = new StringBuilder();
|
||||||
|
|
||||||
// Capture current assets usage info
|
// Capture current assets usage info
|
||||||
var assets = FlaxEngine.Content.Assets;
|
FlaxEngine.Content.GetAssets(ref _assetsCache, out var count);
|
||||||
var resources = new Resource[assets.Length];
|
var resources = new Resource[count];
|
||||||
ulong totalMemoryUsage = 0;
|
ulong totalMemoryUsage = 0;
|
||||||
for (int i = 0; i < resources.Length; i++)
|
for (int i = 0; i < count; i++)
|
||||||
{
|
{
|
||||||
var asset = assets[i];
|
var asset = _assetsCache[i];
|
||||||
ref var resource = ref resources[i];
|
ref var resource = ref resources[i];
|
||||||
if (!asset)
|
if (!asset)
|
||||||
continue;
|
continue;
|
||||||
@@ -179,6 +180,7 @@ namespace FlaxEditor.Windows.Profiler
|
|||||||
if (_resources == null)
|
if (_resources == null)
|
||||||
_resources = new SamplesBuffer<Resource[]>();
|
_resources = new SamplesBuffer<Resource[]>();
|
||||||
_resources.Add(resources);
|
_resources.Add(resources);
|
||||||
|
Array.Clear(_assetsCache);
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <inheritdoc />
|
/// <inheritdoc />
|
||||||
@@ -200,6 +202,7 @@ namespace FlaxEditor.Windows.Profiler
|
|||||||
_resourceCache?.Clear();
|
_resourceCache?.Clear();
|
||||||
_tableRowsCache?.Clear();
|
_tableRowsCache?.Clear();
|
||||||
_stringBuilder?.Clear();
|
_stringBuilder?.Clear();
|
||||||
|
_assetsCache = null;
|
||||||
|
|
||||||
base.OnDestroy();
|
base.OnDestroy();
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -2,6 +2,8 @@
|
|||||||
|
|
||||||
#if USE_PROFILER
|
#if USE_PROFILER
|
||||||
using System;
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using FlaxEditor.GUI;
|
||||||
using FlaxEngine;
|
using FlaxEngine;
|
||||||
using FlaxEngine.GUI;
|
using FlaxEngine.GUI;
|
||||||
|
|
||||||
@@ -13,9 +15,22 @@ namespace FlaxEditor.Windows.Profiler
|
|||||||
/// <seealso cref="FlaxEditor.Windows.Profiler.ProfilerMode" />
|
/// <seealso cref="FlaxEditor.Windows.Profiler.ProfilerMode" />
|
||||||
internal sealed class Memory : ProfilerMode
|
internal sealed class Memory : ProfilerMode
|
||||||
{
|
{
|
||||||
|
private struct FrameData
|
||||||
|
{
|
||||||
|
public ProfilerMemory.GroupsArray Usage;
|
||||||
|
public ProfilerMemory.GroupsArray Peek;
|
||||||
|
public ProfilerMemory.GroupsArray Count;
|
||||||
|
}
|
||||||
|
|
||||||
private readonly SingleChart _nativeAllocationsChart;
|
private readonly SingleChart _nativeAllocationsChart;
|
||||||
private readonly SingleChart _managedAllocationsChart;
|
private readonly SingleChart _managedAllocationsChart;
|
||||||
|
private readonly Table _table;
|
||||||
|
private SamplesBuffer<FrameData> _frames;
|
||||||
|
private List<Row> _tableRowsCache;
|
||||||
|
private string[] _groupNames;
|
||||||
|
private int[] _groupOrder;
|
||||||
|
private Label _warningText;
|
||||||
|
|
||||||
public Memory()
|
public Memory()
|
||||||
: base("Memory")
|
: base("Memory")
|
||||||
{
|
{
|
||||||
@@ -50,6 +65,70 @@ namespace FlaxEditor.Windows.Profiler
|
|||||||
Parent = layout,
|
Parent = layout,
|
||||||
};
|
};
|
||||||
_managedAllocationsChart.SelectedSampleChanged += OnSelectedSampleChanged;
|
_managedAllocationsChart.SelectedSampleChanged += OnSelectedSampleChanged;
|
||||||
|
|
||||||
|
// Warning text
|
||||||
|
if (!ProfilerMemory.Enabled)
|
||||||
|
{
|
||||||
|
_warningText = new Label
|
||||||
|
{
|
||||||
|
Text = "Detailed memory profiling is disabled. Run with command line '-mem'",
|
||||||
|
TextColor = Color.Red,
|
||||||
|
Visible = false,
|
||||||
|
Parent = layout,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
// Table
|
||||||
|
var style = Style.Current;
|
||||||
|
var headerColor = style.LightBackground;
|
||||||
|
var textColor = style.Foreground;
|
||||||
|
_table = new Table
|
||||||
|
{
|
||||||
|
Columns = new[]
|
||||||
|
{
|
||||||
|
new ColumnDefinition
|
||||||
|
{
|
||||||
|
UseExpandCollapseMode = true,
|
||||||
|
CellAlignment = TextAlignment.Near,
|
||||||
|
Title = "Group",
|
||||||
|
TitleBackgroundColor = headerColor,
|
||||||
|
TitleColor = textColor,
|
||||||
|
},
|
||||||
|
new ColumnDefinition
|
||||||
|
{
|
||||||
|
Title = "Usage",
|
||||||
|
TitleBackgroundColor = headerColor,
|
||||||
|
FormatValue = FormatCellBytes,
|
||||||
|
TitleColor = textColor,
|
||||||
|
},
|
||||||
|
new ColumnDefinition
|
||||||
|
{
|
||||||
|
Title = "Peek",
|
||||||
|
TitleBackgroundColor = headerColor,
|
||||||
|
FormatValue = FormatCellBytes,
|
||||||
|
TitleColor = textColor,
|
||||||
|
},
|
||||||
|
new ColumnDefinition
|
||||||
|
{
|
||||||
|
Title = "Count",
|
||||||
|
TitleBackgroundColor = headerColor,
|
||||||
|
TitleColor = textColor,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
Parent = layout,
|
||||||
|
};
|
||||||
|
_table.Splits = new[]
|
||||||
|
{
|
||||||
|
0.5f,
|
||||||
|
0.2f,
|
||||||
|
0.2f,
|
||||||
|
0.1f,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
private string FormatCellBytes(object x)
|
||||||
|
{
|
||||||
|
return Utilities.Utils.FormatBytesCount(Convert.ToUInt64(x));
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <inheritdoc />
|
/// <inheritdoc />
|
||||||
@@ -57,6 +136,7 @@ namespace FlaxEditor.Windows.Profiler
|
|||||||
{
|
{
|
||||||
_nativeAllocationsChart.Clear();
|
_nativeAllocationsChart.Clear();
|
||||||
_managedAllocationsChart.Clear();
|
_managedAllocationsChart.Clear();
|
||||||
|
_frames?.Clear();
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <inheritdoc />
|
/// <inheritdoc />
|
||||||
@@ -84,6 +164,19 @@ namespace FlaxEditor.Windows.Profiler
|
|||||||
|
|
||||||
_nativeAllocationsChart.AddSample(nativeMemoryAllocation);
|
_nativeAllocationsChart.AddSample(nativeMemoryAllocation);
|
||||||
_managedAllocationsChart.AddSample(managedMemoryAllocation);
|
_managedAllocationsChart.AddSample(managedMemoryAllocation);
|
||||||
|
|
||||||
|
// Gather memory profiler stats for groups
|
||||||
|
var frame = new FrameData
|
||||||
|
{
|
||||||
|
Usage = ProfilerMemory.GetGroups(0),
|
||||||
|
Peek = ProfilerMemory.GetGroups(1),
|
||||||
|
Count = ProfilerMemory.GetGroups(2),
|
||||||
|
};
|
||||||
|
if (_frames == null)
|
||||||
|
_frames = new SamplesBuffer<FrameData>();
|
||||||
|
if (_groupNames == null)
|
||||||
|
_groupNames = ProfilerMemory.GetGroupNames();
|
||||||
|
_frames.Add(frame);
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <inheritdoc />
|
/// <inheritdoc />
|
||||||
@@ -91,6 +184,112 @@ namespace FlaxEditor.Windows.Profiler
|
|||||||
{
|
{
|
||||||
_nativeAllocationsChart.SelectedSampleIndex = selectedFrame;
|
_nativeAllocationsChart.SelectedSampleIndex = selectedFrame;
|
||||||
_managedAllocationsChart.SelectedSampleIndex = selectedFrame;
|
_managedAllocationsChart.SelectedSampleIndex = selectedFrame;
|
||||||
|
|
||||||
|
UpdateTable(selectedFrame);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <inheritdoc />
|
||||||
|
public override void OnDestroy()
|
||||||
|
{
|
||||||
|
_tableRowsCache?.Clear();
|
||||||
|
_groupNames = null;
|
||||||
|
_groupOrder = null;
|
||||||
|
|
||||||
|
base.OnDestroy();
|
||||||
|
}
|
||||||
|
|
||||||
|
private void UpdateTable(int selectedFrame)
|
||||||
|
{
|
||||||
|
if (_frames == null)
|
||||||
|
return;
|
||||||
|
if (_tableRowsCache == null)
|
||||||
|
_tableRowsCache = new List<Row>();
|
||||||
|
_table.IsLayoutLocked = true;
|
||||||
|
|
||||||
|
RecycleTableRows(_table, _tableRowsCache);
|
||||||
|
UpdateTableInner(selectedFrame);
|
||||||
|
|
||||||
|
_table.UnlockChildrenRecursive();
|
||||||
|
_table.PerformLayout();
|
||||||
|
}
|
||||||
|
|
||||||
|
private unsafe void UpdateTableInner(int selectedFrame)
|
||||||
|
{
|
||||||
|
if (_frames.Count == 0)
|
||||||
|
return;
|
||||||
|
if (_warningText != null)
|
||||||
|
_warningText.Visible = true;
|
||||||
|
var frame = _frames.Get(selectedFrame);
|
||||||
|
var totalUage = frame.Usage.Values0[(int)ProfilerMemory.Groups.TotalTracked];
|
||||||
|
var totalPeek = frame.Peek.Values0[(int)ProfilerMemory.Groups.TotalTracked];
|
||||||
|
var totalCount = frame.Count.Values0[(int)ProfilerMemory.Groups.TotalTracked];
|
||||||
|
|
||||||
|
// Sort by memory size
|
||||||
|
if (_groupOrder == null)
|
||||||
|
_groupOrder = new int[(int)ProfilerMemory.Groups.MAX];
|
||||||
|
for (int i = 0; i < (int)ProfilerMemory.Groups.MAX; i++)
|
||||||
|
_groupOrder[i] = i;
|
||||||
|
Array.Sort(_groupOrder, (x, y) =>
|
||||||
|
{
|
||||||
|
var tmp = _frames.Get(selectedFrame);
|
||||||
|
return tmp.Usage.Values0[y].CompareTo(tmp.Usage.Values0[x]);
|
||||||
|
});
|
||||||
|
|
||||||
|
// Add rows
|
||||||
|
var rowColor2 = Style.Current.Background * 1.4f;
|
||||||
|
for (int i = 0; i < (int)ProfilerMemory.Groups.MAX; i++)
|
||||||
|
{
|
||||||
|
var group = _groupOrder[i];
|
||||||
|
var groupUsage = frame.Usage.Values0[group];
|
||||||
|
if (groupUsage <= 0)
|
||||||
|
continue;
|
||||||
|
var groupPeek = frame.Peek.Values0[group];
|
||||||
|
var groupCount = frame.Count.Values0[group];
|
||||||
|
|
||||||
|
Row row;
|
||||||
|
if (_tableRowsCache.Count != 0)
|
||||||
|
{
|
||||||
|
var last = _tableRowsCache.Count - 1;
|
||||||
|
row = _tableRowsCache[last];
|
||||||
|
_tableRowsCache.RemoveAt(last);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
row = new Row
|
||||||
|
{
|
||||||
|
Values = new object[4],
|
||||||
|
BackgroundColors = new Color[4],
|
||||||
|
};
|
||||||
|
}
|
||||||
|
{
|
||||||
|
// Group
|
||||||
|
row.Values[0] = _groupNames[group];
|
||||||
|
|
||||||
|
// Usage
|
||||||
|
row.Values[1] = groupUsage;
|
||||||
|
row.BackgroundColors[1] = Color.Red.AlphaMultiplied(Mathf.Min(1, (float)groupUsage / totalUage) * 0.5f);
|
||||||
|
|
||||||
|
// Peek
|
||||||
|
row.Values[2] = groupPeek;
|
||||||
|
row.BackgroundColors[2] = Color.Red.AlphaMultiplied(Mathf.Min(1, (float)groupPeek / totalPeek) * 0.5f);
|
||||||
|
|
||||||
|
// Count
|
||||||
|
row.Values[3] = groupCount;
|
||||||
|
row.BackgroundColors[3] = Color.Red.AlphaMultiplied(Mathf.Min(1, (float)groupCount / totalCount) * 0.5f);
|
||||||
|
}
|
||||||
|
row.Width = _table.Width;
|
||||||
|
row.BackgroundColor = i % 2 == 1 ? rowColor2 : Color.Transparent;
|
||||||
|
row.Parent = _table;
|
||||||
|
|
||||||
|
var useBackground = group != (int)ProfilerMemory.Groups.Total &&
|
||||||
|
group != (int)ProfilerMemory.Groups.TotalTracked &&
|
||||||
|
group != (int)ProfilerMemory.Groups.Malloc;
|
||||||
|
if (!useBackground)
|
||||||
|
{
|
||||||
|
for (int k = 1; k < row.BackgroundColors.Length; k++)
|
||||||
|
row.BackgroundColors[k] = Color.Transparent;
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -35,6 +35,7 @@ namespace FlaxEditor.Windows.Profiler
|
|||||||
private Dictionary<string, Guid> _assetPathToId;
|
private Dictionary<string, Guid> _assetPathToId;
|
||||||
private Dictionary<Guid, Resource> _resourceCache;
|
private Dictionary<Guid, Resource> _resourceCache;
|
||||||
private StringBuilder _stringBuilder;
|
private StringBuilder _stringBuilder;
|
||||||
|
private GPUResource[] _gpuResourcesCached;
|
||||||
|
|
||||||
public MemoryGPU()
|
public MemoryGPU()
|
||||||
: base("GPU Memory")
|
: base("GPU Memory")
|
||||||
@@ -138,13 +139,15 @@ namespace FlaxEditor.Windows.Profiler
|
|||||||
|
|
||||||
// Capture current GPU resources usage info
|
// Capture current GPU resources usage info
|
||||||
var contentDatabase = Editor.Instance.ContentDatabase;
|
var contentDatabase = Editor.Instance.ContentDatabase;
|
||||||
var gpuResources = GPUDevice.Instance.Resources;
|
GPUDevice.Instance.GetResources(ref _gpuResourcesCached, out var count);
|
||||||
var resources = new Resource[gpuResources.Length];
|
var resources = new Resource[count];
|
||||||
var sb = _stringBuilder;
|
var sb = _stringBuilder;
|
||||||
for (int i = 0; i < resources.Length; i++)
|
for (int i = 0; i < count; i++)
|
||||||
{
|
{
|
||||||
var gpuResource = gpuResources[i];
|
var gpuResource = _gpuResourcesCached[i];
|
||||||
ref var resource = ref resources[i];
|
ref var resource = ref resources[i];
|
||||||
|
if (!gpuResource)
|
||||||
|
continue;
|
||||||
|
|
||||||
// Try to reuse cached resource info
|
// Try to reuse cached resource info
|
||||||
var gpuResourceId = gpuResource.ID;
|
var gpuResourceId = gpuResource.ID;
|
||||||
@@ -219,6 +222,7 @@ namespace FlaxEditor.Windows.Profiler
|
|||||||
if (_resources == null)
|
if (_resources == null)
|
||||||
_resources = new SamplesBuffer<Resource[]>();
|
_resources = new SamplesBuffer<Resource[]>();
|
||||||
_resources.Add(resources);
|
_resources.Add(resources);
|
||||||
|
Array.Clear(_gpuResourcesCached);
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <inheritdoc />
|
/// <inheritdoc />
|
||||||
@@ -255,6 +259,7 @@ namespace FlaxEditor.Windows.Profiler
|
|||||||
_assetPathToId?.Clear();
|
_assetPathToId?.Clear();
|
||||||
_tableRowsCache?.Clear();
|
_tableRowsCache?.Clear();
|
||||||
_stringBuilder?.Clear();
|
_stringBuilder?.Clear();
|
||||||
|
_gpuResourcesCached = null;
|
||||||
|
|
||||||
base.OnDestroy();
|
base.OnDestroy();
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -7,6 +7,7 @@
|
|||||||
#include "Engine/Engine/Time.h"
|
#include "Engine/Engine/Time.h"
|
||||||
#include "Engine/Engine/EngineService.h"
|
#include "Engine/Engine/EngineService.h"
|
||||||
#include "Engine/Profiler/ProfilerCPU.h"
|
#include "Engine/Profiler/ProfilerCPU.h"
|
||||||
|
#include "Engine/Profiler/ProfilerMemory.h"
|
||||||
#include "Engine/Threading/TaskGraph.h"
|
#include "Engine/Threading/TaskGraph.h"
|
||||||
|
|
||||||
class BehaviorSystem : public TaskGraphSystem
|
class BehaviorSystem : public TaskGraphSystem
|
||||||
@@ -38,6 +39,7 @@ TaskGraphSystem* Behavior::System = nullptr;
|
|||||||
void BehaviorSystem::Job(int32 index)
|
void BehaviorSystem::Job(int32 index)
|
||||||
{
|
{
|
||||||
PROFILE_CPU_NAMED("Behavior.Job");
|
PROFILE_CPU_NAMED("Behavior.Job");
|
||||||
|
PROFILE_MEM(AI);
|
||||||
Behaviors[index]->UpdateAsync();
|
Behaviors[index]->UpdateAsync();
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -57,6 +59,7 @@ void BehaviorSystem::Execute(TaskGraph* graph)
|
|||||||
|
|
||||||
bool BehaviorService::Init()
|
bool BehaviorService::Init()
|
||||||
{
|
{
|
||||||
|
PROFILE_MEM(AI);
|
||||||
Behavior::System = New<BehaviorSystem>();
|
Behavior::System = New<BehaviorSystem>();
|
||||||
Engine::UpdateGraph->AddSystem(Behavior::System);
|
Engine::UpdateGraph->AddSystem(Behavior::System);
|
||||||
return false;
|
return false;
|
||||||
@@ -70,9 +73,9 @@ void BehaviorService::Dispose()
|
|||||||
|
|
||||||
Behavior::Behavior(const SpawnParams& params)
|
Behavior::Behavior(const SpawnParams& params)
|
||||||
: Script(params)
|
: Script(params)
|
||||||
|
, Tree(this)
|
||||||
{
|
{
|
||||||
_knowledge.Behavior = this;
|
_knowledge.Behavior = this;
|
||||||
Tree.Changed.Bind<Behavior, &Behavior::ResetLogic>(this);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void Behavior::UpdateAsync()
|
void Behavior::UpdateAsync()
|
||||||
@@ -172,6 +175,19 @@ void Behavior::OnDisable()
|
|||||||
BehaviorServiceInstance.UpdateList.Remove(this);
|
BehaviorServiceInstance.UpdateList.Remove(this);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void Behavior::OnAssetChanged(Asset* asset, void* caller)
|
||||||
|
{
|
||||||
|
ResetLogic();
|
||||||
|
}
|
||||||
|
|
||||||
|
void Behavior::OnAssetLoaded(Asset* asset, void* caller)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
void Behavior::OnAssetUnloaded(Asset* asset, void* caller)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
#if USE_EDITOR
|
#if USE_EDITOR
|
||||||
|
|
||||||
bool Behavior::GetNodeDebugRelevancy(const BehaviorTreeNode* node, const Behavior* behavior)
|
bool Behavior::GetNodeDebugRelevancy(const BehaviorTreeNode* node, const Behavior* behavior)
|
||||||
|
|||||||
@@ -11,7 +11,7 @@
|
|||||||
/// <summary>
|
/// <summary>
|
||||||
/// Behavior instance script that runs Behavior Tree execution.
|
/// Behavior instance script that runs Behavior Tree execution.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
API_CLASS(Attributes="Category(\"Flax Engine\")") class FLAXENGINE_API Behavior : public Script
|
API_CLASS(Attributes="Category(\"Flax Engine\")") class FLAXENGINE_API Behavior : public Script, private IAssetReference
|
||||||
{
|
{
|
||||||
API_AUTO_SERIALIZATION();
|
API_AUTO_SERIALIZATION();
|
||||||
DECLARE_SCRIPTING_TYPE(Behavior);
|
DECLARE_SCRIPTING_TYPE(Behavior);
|
||||||
@@ -92,6 +92,11 @@ public:
|
|||||||
void OnDisable() override;
|
void OnDisable() override;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
// [IAssetReference]
|
||||||
|
void OnAssetChanged(Asset* asset, void* caller) override;
|
||||||
|
void OnAssetLoaded(Asset* asset, void* caller) override;
|
||||||
|
void OnAssetUnloaded(Asset* asset, void* caller) override;
|
||||||
|
|
||||||
#if USE_EDITOR
|
#if USE_EDITOR
|
||||||
// Editor-only utilities to debug nodes state.
|
// Editor-only utilities to debug nodes state.
|
||||||
API_FUNCTION(Internal) static bool GetNodeDebugRelevancy(const BehaviorTreeNode* node, const Behavior* behavior);
|
API_FUNCTION(Internal) static bool GetNodeDebugRelevancy(const BehaviorTreeNode* node, const Behavior* behavior);
|
||||||
|
|||||||
@@ -4,6 +4,7 @@
|
|||||||
#include "BehaviorTree.h"
|
#include "BehaviorTree.h"
|
||||||
#include "BehaviorTreeNodes.h"
|
#include "BehaviorTreeNodes.h"
|
||||||
#include "BehaviorKnowledgeSelector.h"
|
#include "BehaviorKnowledgeSelector.h"
|
||||||
|
#include "Engine/Profiler/ProfilerMemory.h"
|
||||||
#include "Engine/Scripting/Scripting.h"
|
#include "Engine/Scripting/Scripting.h"
|
||||||
#include "Engine/Scripting/BinaryModule.h"
|
#include "Engine/Scripting/BinaryModule.h"
|
||||||
#include "Engine/Scripting/ManagedCLR/MProperty.h"
|
#include "Engine/Scripting/ManagedCLR/MProperty.h"
|
||||||
@@ -144,6 +145,7 @@ BehaviorKnowledge::~BehaviorKnowledge()
|
|||||||
|
|
||||||
void BehaviorKnowledge::InitMemory(BehaviorTree* tree)
|
void BehaviorKnowledge::InitMemory(BehaviorTree* tree)
|
||||||
{
|
{
|
||||||
|
PROFILE_MEM(AI);
|
||||||
if (Tree)
|
if (Tree)
|
||||||
FreeMemory();
|
FreeMemory();
|
||||||
if (!tree)
|
if (!tree)
|
||||||
|
|||||||
@@ -10,6 +10,7 @@
|
|||||||
#include "Engine/Serialization/JsonSerializer.h"
|
#include "Engine/Serialization/JsonSerializer.h"
|
||||||
#include "Engine/Serialization/MemoryReadStream.h"
|
#include "Engine/Serialization/MemoryReadStream.h"
|
||||||
#include "Engine/Threading/Threading.h"
|
#include "Engine/Threading/Threading.h"
|
||||||
|
#include "Engine/Profiler/ProfilerMemory.h"
|
||||||
#include "FlaxEngine.Gen.h"
|
#include "FlaxEngine.Gen.h"
|
||||||
#if USE_EDITOR
|
#if USE_EDITOR
|
||||||
#include "Engine/Level/Level.h"
|
#include "Engine/Level/Level.h"
|
||||||
@@ -275,6 +276,7 @@ Asset::LoadResult BehaviorTree::load()
|
|||||||
if (surfaceChunk == nullptr)
|
if (surfaceChunk == nullptr)
|
||||||
return LoadResult::MissingDataChunk;
|
return LoadResult::MissingDataChunk;
|
||||||
MemoryReadStream surfaceStream(surfaceChunk->Get(), surfaceChunk->Size());
|
MemoryReadStream surfaceStream(surfaceChunk->Get(), surfaceChunk->Size());
|
||||||
|
PROFILE_MEM(AI);
|
||||||
if (Graph.Load(&surfaceStream, true))
|
if (Graph.Load(&surfaceStream, true))
|
||||||
{
|
{
|
||||||
LOG(Warning, "Failed to load graph \'{0}\'", ToString());
|
LOG(Warning, "Failed to load graph \'{0}\'", ToString());
|
||||||
|
|||||||
@@ -4,6 +4,7 @@
|
|||||||
#include "AnimEvent.h"
|
#include "AnimEvent.h"
|
||||||
#include "Engine/Engine/Engine.h"
|
#include "Engine/Engine/Engine.h"
|
||||||
#include "Engine/Profiler/ProfilerCPU.h"
|
#include "Engine/Profiler/ProfilerCPU.h"
|
||||||
|
#include "Engine/Profiler/ProfilerMemory.h"
|
||||||
#include "Engine/Level/Actors/AnimatedModel.h"
|
#include "Engine/Level/Actors/AnimatedModel.h"
|
||||||
#include "Engine/Engine/Time.h"
|
#include "Engine/Engine/Time.h"
|
||||||
#include "Engine/Engine/EngineService.h"
|
#include "Engine/Engine/EngineService.h"
|
||||||
@@ -52,7 +53,7 @@ namespace
|
|||||||
|
|
||||||
AnimationsService AnimationManagerInstance;
|
AnimationsService AnimationManagerInstance;
|
||||||
TaskGraphSystem* Animations::System = nullptr;
|
TaskGraphSystem* Animations::System = nullptr;
|
||||||
ConcurrentSystemLocker Animations::SystemLocker;
|
ReadWriteLock Animations::SystemLocker;
|
||||||
#if USE_EDITOR
|
#if USE_EDITOR
|
||||||
Delegate<Animations::DebugFlowInfo> Animations::DebugFlow;
|
Delegate<Animations::DebugFlowInfo> Animations::DebugFlow;
|
||||||
#endif
|
#endif
|
||||||
@@ -69,6 +70,7 @@ AnimContinuousEvent::AnimContinuousEvent(const SpawnParams& params)
|
|||||||
|
|
||||||
bool AnimationsService::Init()
|
bool AnimationsService::Init()
|
||||||
{
|
{
|
||||||
|
PROFILE_MEM(Animations);
|
||||||
Animations::System = New<AnimationsSystem>();
|
Animations::System = New<AnimationsSystem>();
|
||||||
Engine::UpdateGraph->AddSystem(Animations::System);
|
Engine::UpdateGraph->AddSystem(Animations::System);
|
||||||
return false;
|
return false;
|
||||||
@@ -83,6 +85,7 @@ void AnimationsService::Dispose()
|
|||||||
void AnimationsSystem::Job(int32 index)
|
void AnimationsSystem::Job(int32 index)
|
||||||
{
|
{
|
||||||
PROFILE_CPU_NAMED("Animations.Job");
|
PROFILE_CPU_NAMED("Animations.Job");
|
||||||
|
PROFILE_MEM(Animations);
|
||||||
auto animatedModel = AnimationManagerInstance.UpdateList[index];
|
auto animatedModel = AnimationManagerInstance.UpdateList[index];
|
||||||
if (CanUpdateModel(animatedModel))
|
if (CanUpdateModel(animatedModel))
|
||||||
{
|
{
|
||||||
@@ -121,7 +124,7 @@ void AnimationsSystem::Execute(TaskGraph* graph)
|
|||||||
Active = true;
|
Active = true;
|
||||||
|
|
||||||
// Ensure no animation assets can be reloaded/modified during async update
|
// Ensure no animation assets can be reloaded/modified during async update
|
||||||
Animations::SystemLocker.Begin(false);
|
Animations::SystemLocker.ReadLock();
|
||||||
|
|
||||||
// Setup data for async update
|
// Setup data for async update
|
||||||
const auto& tickData = Time::Update;
|
const auto& tickData = Time::Update;
|
||||||
@@ -147,6 +150,7 @@ void AnimationsSystem::PostExecute(TaskGraph* graph)
|
|||||||
if (!Active)
|
if (!Active)
|
||||||
return;
|
return;
|
||||||
PROFILE_CPU_NAMED("Animations.PostExecute");
|
PROFILE_CPU_NAMED("Animations.PostExecute");
|
||||||
|
PROFILE_MEM(Animations);
|
||||||
|
|
||||||
// Update gameplay
|
// Update gameplay
|
||||||
for (int32 index = 0; index < AnimationManagerInstance.UpdateList.Count(); index++)
|
for (int32 index = 0; index < AnimationManagerInstance.UpdateList.Count(); index++)
|
||||||
@@ -161,16 +165,18 @@ void AnimationsSystem::PostExecute(TaskGraph* graph)
|
|||||||
|
|
||||||
// Cleanup
|
// Cleanup
|
||||||
AnimationManagerInstance.UpdateList.Clear();
|
AnimationManagerInstance.UpdateList.Clear();
|
||||||
Animations::SystemLocker.End(false);
|
Animations::SystemLocker.ReadUnlock();
|
||||||
Active = false;
|
Active = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
void Animations::AddToUpdate(AnimatedModel* obj)
|
void Animations::AddToUpdate(AnimatedModel* obj)
|
||||||
{
|
{
|
||||||
|
ScopeWriteLock lock(SystemLocker);
|
||||||
AnimationManagerInstance.UpdateList.Add(obj);
|
AnimationManagerInstance.UpdateList.Add(obj);
|
||||||
}
|
}
|
||||||
|
|
||||||
void Animations::RemoveFromUpdate(AnimatedModel* obj)
|
void Animations::RemoveFromUpdate(AnimatedModel* obj)
|
||||||
{
|
{
|
||||||
|
ScopeWriteLock lock(SystemLocker);
|
||||||
AnimationManagerInstance.UpdateList.Remove(obj);
|
AnimationManagerInstance.UpdateList.Remove(obj);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -4,7 +4,6 @@
|
|||||||
|
|
||||||
#include "Engine/Scripting/ScriptingType.h"
|
#include "Engine/Scripting/ScriptingType.h"
|
||||||
#include "Engine/Core/Delegate.h"
|
#include "Engine/Core/Delegate.h"
|
||||||
#include "Engine/Threading/ConcurrentSystemLocker.h"
|
|
||||||
|
|
||||||
class TaskGraphSystem;
|
class TaskGraphSystem;
|
||||||
class AnimatedModel;
|
class AnimatedModel;
|
||||||
@@ -23,7 +22,7 @@ API_CLASS(Static) class FLAXENGINE_API Animations
|
|||||||
API_FIELD(ReadOnly) static TaskGraphSystem* System;
|
API_FIELD(ReadOnly) static TaskGraphSystem* System;
|
||||||
|
|
||||||
// Data access locker for animations data.
|
// Data access locker for animations data.
|
||||||
static ConcurrentSystemLocker SystemLocker;
|
static ReadWriteLock SystemLocker;
|
||||||
|
|
||||||
#if USE_EDITOR
|
#if USE_EDITOR
|
||||||
// Data wrapper for the debug flow information.
|
// Data wrapper for the debug flow information.
|
||||||
|
|||||||
@@ -6,6 +6,7 @@
|
|||||||
#include "Engine/Content/Assets/SkinnedModel.h"
|
#include "Engine/Content/Assets/SkinnedModel.h"
|
||||||
#include "Engine/Graphics/Models/SkeletonData.h"
|
#include "Engine/Graphics/Models/SkeletonData.h"
|
||||||
#include "Engine/Scripting/Scripting.h"
|
#include "Engine/Scripting/Scripting.h"
|
||||||
|
#include "Engine/Threading/Threading.h"
|
||||||
|
|
||||||
extern void RetargetSkeletonPose(const SkeletonData& sourceSkeleton, const SkeletonData& targetSkeleton, const SkinnedModel::SkeletonMapping& mapping, const Transform* sourceNodes, Transform* targetNodes);
|
extern void RetargetSkeletonPose(const SkeletonData& sourceSkeleton, const SkeletonData& targetSkeleton, const SkinnedModel::SkeletonMapping& mapping, const Transform* sourceNodes, Transform* targetNodes);
|
||||||
|
|
||||||
|
|||||||
@@ -7,6 +7,7 @@
|
|||||||
#include "Engine/Content/Content.h"
|
#include "Engine/Content/Content.h"
|
||||||
#include "Engine/Content/Deprecated.h"
|
#include "Engine/Content/Deprecated.h"
|
||||||
#include "Engine/Serialization/MemoryReadStream.h"
|
#include "Engine/Serialization/MemoryReadStream.h"
|
||||||
|
#include "Engine/Profiler/ProfilerMemory.h"
|
||||||
#include "Engine/Audio/AudioClip.h"
|
#include "Engine/Audio/AudioClip.h"
|
||||||
#include "Engine/Graphics/PostProcessSettings.h"
|
#include "Engine/Graphics/PostProcessSettings.h"
|
||||||
#if USE_EDITOR
|
#if USE_EDITOR
|
||||||
@@ -249,6 +250,7 @@ bool SceneAnimation::Save(const StringView& path)
|
|||||||
Asset::LoadResult SceneAnimation::load()
|
Asset::LoadResult SceneAnimation::load()
|
||||||
{
|
{
|
||||||
TrackStatesCount = 0;
|
TrackStatesCount = 0;
|
||||||
|
PROFILE_MEM(AnimationsData);
|
||||||
|
|
||||||
// Get the data chunk
|
// Get the data chunk
|
||||||
if (LoadChunk(0))
|
if (LoadChunk(0))
|
||||||
|
|||||||
@@ -12,6 +12,7 @@
|
|||||||
#include "Engine/Audio/AudioSource.h"
|
#include "Engine/Audio/AudioSource.h"
|
||||||
#include "Engine/Graphics/RenderTask.h"
|
#include "Engine/Graphics/RenderTask.h"
|
||||||
#include "Engine/Renderer/RenderList.h"
|
#include "Engine/Renderer/RenderList.h"
|
||||||
|
#include "Engine/Profiler/ProfilerMemory.h"
|
||||||
#include "Engine/Scripting/Scripting.h"
|
#include "Engine/Scripting/Scripting.h"
|
||||||
#include "Engine/Scripting/Script.h"
|
#include "Engine/Scripting/Script.h"
|
||||||
#include "Engine/Scripting/ManagedCLR/MException.h"
|
#include "Engine/Scripting/ManagedCLR/MException.h"
|
||||||
@@ -151,6 +152,7 @@ void SceneAnimationPlayer::Tick(float dt)
|
|||||||
SceneAnimation* anim = Animation.Get();
|
SceneAnimation* anim = Animation.Get();
|
||||||
if (!anim || !anim->IsLoaded())
|
if (!anim || !anim->IsLoaded())
|
||||||
return;
|
return;
|
||||||
|
PROFILE_MEM(Animations);
|
||||||
|
|
||||||
// Setup state
|
// Setup state
|
||||||
if (_tracks.Count() != anim->TrackStatesCount)
|
if (_tracks.Count() != anim->TrackStatesCount)
|
||||||
@@ -229,6 +231,7 @@ void SceneAnimationPlayer::MapTrack(const StringView& from, const Guid& to)
|
|||||||
SceneAnimation* anim = Animation.Get();
|
SceneAnimation* anim = Animation.Get();
|
||||||
if (!anim || !anim->IsLoaded())
|
if (!anim || !anim->IsLoaded())
|
||||||
return;
|
return;
|
||||||
|
PROFILE_MEM(Animations);
|
||||||
for (int32 j = 0; j < anim->Tracks.Count(); j++)
|
for (int32 j = 0; j < anim->Tracks.Count(); j++)
|
||||||
{
|
{
|
||||||
const auto& track = anim->Tracks[j];
|
const auto& track = anim->Tracks[j];
|
||||||
|
|||||||
@@ -8,6 +8,7 @@
|
|||||||
#include "Engine/Scripting/BinaryModule.h"
|
#include "Engine/Scripting/BinaryModule.h"
|
||||||
#include "Engine/Level/Level.h"
|
#include "Engine/Level/Level.h"
|
||||||
#include "Engine/Profiler/ProfilerCPU.h"
|
#include "Engine/Profiler/ProfilerCPU.h"
|
||||||
|
#include "Engine/Profiler/ProfilerMemory.h"
|
||||||
#include "Engine/Engine/Engine.h"
|
#include "Engine/Engine/Engine.h"
|
||||||
#include "Engine/Engine/CommandLine.h"
|
#include "Engine/Engine/CommandLine.h"
|
||||||
#include "Engine/Core/Log.h"
|
#include "Engine/Core/Log.h"
|
||||||
@@ -151,6 +152,7 @@ void Audio::SetEnableHRTF(bool value)
|
|||||||
bool AudioService::Init()
|
bool AudioService::Init()
|
||||||
{
|
{
|
||||||
PROFILE_CPU_NAMED("Audio.Init");
|
PROFILE_CPU_NAMED("Audio.Init");
|
||||||
|
PROFILE_MEM(Audio);
|
||||||
const auto settings = AudioSettings::Get();
|
const auto settings = AudioSettings::Get();
|
||||||
const bool mute = CommandLine::Options.Mute.IsTrue() || settings->DisableAudio;
|
const bool mute = CommandLine::Options.Mute.IsTrue() || settings->DisableAudio;
|
||||||
|
|
||||||
@@ -211,6 +213,7 @@ bool AudioService::Init()
|
|||||||
void AudioService::Update()
|
void AudioService::Update()
|
||||||
{
|
{
|
||||||
PROFILE_CPU_NAMED("Audio.Update");
|
PROFILE_CPU_NAMED("Audio.Update");
|
||||||
|
PROFILE_MEM(Audio);
|
||||||
|
|
||||||
// Update the master volume
|
// Update the master volume
|
||||||
float masterVolume = MasterVolume;
|
float masterVolume = MasterVolume;
|
||||||
|
|||||||
@@ -7,50 +7,67 @@
|
|||||||
#include "Engine/Core/Log.h"
|
#include "Engine/Core/Log.h"
|
||||||
#include "Engine/Content/Upgraders/AudioClipUpgrader.h"
|
#include "Engine/Content/Upgraders/AudioClipUpgrader.h"
|
||||||
#include "Engine/Content/Factories/BinaryAssetFactory.h"
|
#include "Engine/Content/Factories/BinaryAssetFactory.h"
|
||||||
|
#include "Engine/Profiler/ProfilerCPU.h"
|
||||||
#include "Engine/Scripting/ManagedCLR/MUtils.h"
|
#include "Engine/Scripting/ManagedCLR/MUtils.h"
|
||||||
#include "Engine/Streaming/StreamingGroup.h"
|
#include "Engine/Streaming/StreamingGroup.h"
|
||||||
#include "Engine/Serialization/MemoryReadStream.h"
|
#include "Engine/Serialization/MemoryReadStream.h"
|
||||||
|
#include "Engine/Profiler/ProfilerMemory.h"
|
||||||
#include "Engine/Tools/AudioTool/OggVorbisDecoder.h"
|
#include "Engine/Tools/AudioTool/OggVorbisDecoder.h"
|
||||||
#include "Engine/Tools/AudioTool/AudioTool.h"
|
#include "Engine/Tools/AudioTool/AudioTool.h"
|
||||||
#include "Engine/Threading/Threading.h"
|
#include "Engine/Threading/Threading.h"
|
||||||
|
|
||||||
REGISTER_BINARY_ASSET_WITH_UPGRADER(AudioClip, "FlaxEngine.AudioClip", AudioClipUpgrader, false);
|
REGISTER_BINARY_ASSET_WITH_UPGRADER(AudioClip, "FlaxEngine.AudioClip", AudioClipUpgrader, false);
|
||||||
|
|
||||||
|
AudioClip::StreamingTask::StreamingTask(AudioClip* asset)
|
||||||
|
: _asset(asset)
|
||||||
|
, _dataLock(asset->Storage->Lock())
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
bool AudioClip::StreamingTask::HasReference(Object* resource) const
|
||||||
|
{
|
||||||
|
return _asset == resource;
|
||||||
|
}
|
||||||
|
|
||||||
bool AudioClip::StreamingTask::Run()
|
bool AudioClip::StreamingTask::Run()
|
||||||
{
|
{
|
||||||
AssetReference<AudioClip> ref = _asset.Get();
|
PROFILE_CPU_NAMED("AudioStreaming");
|
||||||
if (ref == nullptr || AudioBackend::Instance == nullptr)
|
PROFILE_MEM(Audio);
|
||||||
|
AssetReference<AudioClip> clip = _asset.Get();
|
||||||
|
if (clip == nullptr || AudioBackend::Instance == nullptr)
|
||||||
return true;
|
return true;
|
||||||
ScopeLock lock(ref->Locker);
|
#if TRACY_ENABLE
|
||||||
const auto& queue = ref->StreamingQueue;
|
const StringView name(clip->GetPath());
|
||||||
if (queue.Count() == 0)
|
ZoneName(*name, name.Length());
|
||||||
return false;
|
#endif
|
||||||
auto clip = ref.Get();
|
|
||||||
|
|
||||||
// Update the buffers
|
// Process the loading queue (hold the asset lock)
|
||||||
|
clip->Locker.Lock();
|
||||||
|
const auto& queue = clip->StreamingQueue;
|
||||||
|
Array<int32, FixedAllocation<ASSET_FILE_DATA_CHUNKS>> loadQueue;
|
||||||
for (int32 i = 0; i < queue.Count(); i++)
|
for (int32 i = 0; i < queue.Count(); i++)
|
||||||
{
|
{
|
||||||
const auto idx = queue[i];
|
const int32 idx = queue[i];
|
||||||
uint32& bufferID = clip->Buffers[idx];
|
uint32& bufferID = clip->Buffers[idx];
|
||||||
if (bufferID == 0)
|
if (bufferID == 0)
|
||||||
{
|
{
|
||||||
bufferID = AudioBackend::Buffer::Create();
|
// Load buffers outside the asset lock to prevent lock contention
|
||||||
|
loadQueue.Add(idx);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
// Release unused data
|
// Release unused buffer
|
||||||
AudioBackend::Buffer::Delete(bufferID);
|
AudioBackend::Buffer::Delete(bufferID);
|
||||||
bufferID = 0;
|
bufferID = 0;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
clip->Locker.Unlock();
|
||||||
|
|
||||||
// Load missing buffers data (from asset chunks)
|
// Load missing buffers data (from asset chunks)
|
||||||
for (int32 i = 0; i < queue.Count(); i++)
|
for (int32 i = 0; i < loadQueue.Count(); i++)
|
||||||
{
|
{
|
||||||
if (clip->WriteBuffer(queue[i]))
|
if (clip->WriteBuffer(loadQueue[i]))
|
||||||
{
|
|
||||||
return true;
|
return true;
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Update the sources
|
// Update the sources
|
||||||
@@ -318,6 +335,7 @@ bool AudioClip::init(AssetInitData& initData)
|
|||||||
|
|
||||||
Asset::LoadResult AudioClip::load()
|
Asset::LoadResult AudioClip::load()
|
||||||
{
|
{
|
||||||
|
PROFILE_MEM(Audio);
|
||||||
#if !COMPILE_WITH_OGG_VORBIS
|
#if !COMPILE_WITH_OGG_VORBIS
|
||||||
if (AudioHeader.Format == AudioFormat::Vorbis)
|
if (AudioHeader.Format == AudioFormat::Vorbis)
|
||||||
{
|
{
|
||||||
@@ -410,14 +428,11 @@ void AudioClip::unload(bool isReloading)
|
|||||||
|
|
||||||
bool AudioClip::WriteBuffer(int32 chunkIndex)
|
bool AudioClip::WriteBuffer(int32 chunkIndex)
|
||||||
{
|
{
|
||||||
// Ignore if buffer is not created
|
|
||||||
const uint32 bufferID = Buffers[chunkIndex];
|
|
||||||
if (bufferID == 0)
|
|
||||||
return false;
|
|
||||||
|
|
||||||
// Ensure audio backend exists
|
// Ensure audio backend exists
|
||||||
if (AudioBackend::Instance == nullptr)
|
if (AudioBackend::Instance == nullptr)
|
||||||
return true;
|
return true;
|
||||||
|
PROFILE_CPU();
|
||||||
|
PROFILE_MEM(Audio);
|
||||||
|
|
||||||
const auto chunk = GetChunk(chunkIndex);
|
const auto chunk = GetChunk(chunkIndex);
|
||||||
if (chunk == nullptr || chunk->IsMissing())
|
if (chunk == nullptr || chunk->IsMissing())
|
||||||
@@ -429,6 +444,7 @@ bool AudioClip::WriteBuffer(int32 chunkIndex)
|
|||||||
Array<byte> tmp1, tmp2;
|
Array<byte> tmp1, tmp2;
|
||||||
AudioDataInfo info = AudioHeader.Info;
|
AudioDataInfo info = AudioHeader.Info;
|
||||||
const uint32 bytesPerSample = info.BitDepth / 8;
|
const uint32 bytesPerSample = info.BitDepth / 8;
|
||||||
|
ZoneValue(chunk->Size() / 1024); // Audio data size (in kB)
|
||||||
|
|
||||||
// Get raw data or decompress it
|
// Get raw data or decompress it
|
||||||
switch (Format())
|
switch (Format())
|
||||||
@@ -436,6 +452,7 @@ bool AudioClip::WriteBuffer(int32 chunkIndex)
|
|||||||
case AudioFormat::Vorbis:
|
case AudioFormat::Vorbis:
|
||||||
{
|
{
|
||||||
#if COMPILE_WITH_OGG_VORBIS
|
#if COMPILE_WITH_OGG_VORBIS
|
||||||
|
PROFILE_CPU_NAMED("OggVorbisDecode");
|
||||||
OggVorbisDecoder decoder;
|
OggVorbisDecoder decoder;
|
||||||
MemoryReadStream stream(chunk->Get(), chunk->Size());
|
MemoryReadStream stream(chunk->Get(), chunk->Size());
|
||||||
AudioDataInfo tmpInfo;
|
AudioDataInfo tmpInfo;
|
||||||
@@ -472,7 +489,13 @@ bool AudioClip::WriteBuffer(int32 chunkIndex)
|
|||||||
data = Span<byte>(tmp2.Get(), tmp2.Count());
|
data = Span<byte>(tmp2.Get(), tmp2.Count());
|
||||||
}
|
}
|
||||||
|
|
||||||
// Write samples to the audio buffer
|
// Write samples to the audio buffer (create one if missing)
|
||||||
|
Locker.Lock(); // StreamingTask loads buffers without lock so do it here
|
||||||
|
uint32& bufferID = Buffers[chunkIndex];
|
||||||
|
if (bufferID == 0)
|
||||||
|
bufferID = AudioBackend::Buffer::Create();
|
||||||
AudioBackend::Buffer::Write(bufferID, data.Get(), info);
|
AudioBackend::Buffer::Write(bufferID, data.Get(), info);
|
||||||
|
Locker.Unlock();
|
||||||
|
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -44,22 +44,11 @@ public:
|
|||||||
FlaxStorage::LockData _dataLock;
|
FlaxStorage::LockData _dataLock;
|
||||||
|
|
||||||
public:
|
public:
|
||||||
/// <summary>
|
StreamingTask(AudioClip* asset);
|
||||||
/// Init
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="asset">Parent asset</param>
|
|
||||||
StreamingTask(AudioClip* asset)
|
|
||||||
: _asset(asset)
|
|
||||||
, _dataLock(asset->Storage->Lock())
|
|
||||||
{
|
|
||||||
}
|
|
||||||
|
|
||||||
public:
|
public:
|
||||||
// [ThreadPoolTask]
|
// [ThreadPoolTask]
|
||||||
bool HasReference(Object* resource) const override
|
bool HasReference(Object* resource) const override;
|
||||||
{
|
|
||||||
return _asset == resource;
|
|
||||||
}
|
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
// [ThreadPoolTask]
|
// [ThreadPoolTask]
|
||||||
|
|||||||
@@ -8,6 +8,7 @@
|
|||||||
#include "Engine/Engine/Time.h"
|
#include "Engine/Engine/Time.h"
|
||||||
#include "Engine/Level/Scene/Scene.h"
|
#include "Engine/Level/Scene/Scene.h"
|
||||||
#include "Engine/Profiler/ProfilerCPU.h"
|
#include "Engine/Profiler/ProfilerCPU.h"
|
||||||
|
#include "Engine/Profiler/ProfilerMemory.h"
|
||||||
#include "AudioBackend.h"
|
#include "AudioBackend.h"
|
||||||
#include "Audio.h"
|
#include "Audio.h"
|
||||||
|
|
||||||
@@ -21,9 +22,8 @@ AudioSource::AudioSource(const SpawnParams& params)
|
|||||||
, _playOnStart(false)
|
, _playOnStart(false)
|
||||||
, _startTime(0.0f)
|
, _startTime(0.0f)
|
||||||
, _allowSpatialization(true)
|
, _allowSpatialization(true)
|
||||||
|
, Clip(this)
|
||||||
{
|
{
|
||||||
Clip.Changed.Bind<AudioSource, &AudioSource::OnClipChanged>(this);
|
|
||||||
Clip.Loaded.Bind<AudioSource, &AudioSource::OnClipLoaded>(this);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void AudioSource::SetVolume(float value)
|
void AudioSource::SetVolume(float value)
|
||||||
@@ -121,6 +121,7 @@ void AudioSource::Play()
|
|||||||
auto state = _state;
|
auto state = _state;
|
||||||
if (state == States::Playing)
|
if (state == States::Playing)
|
||||||
return;
|
return;
|
||||||
|
PROFILE_CPU();
|
||||||
if (Clip == nullptr || Clip->WaitForLoaded())
|
if (Clip == nullptr || Clip->WaitForLoaded())
|
||||||
{
|
{
|
||||||
LOG(Warning, "Cannot play audio source without a clip ({0})", GetNamePath());
|
LOG(Warning, "Cannot play audio source without a clip ({0})", GetNamePath());
|
||||||
@@ -189,6 +190,7 @@ void AudioSource::Stop()
|
|||||||
{
|
{
|
||||||
if (_state == States::Stopped)
|
if (_state == States::Stopped)
|
||||||
return;
|
return;
|
||||||
|
PROFILE_CPU();
|
||||||
|
|
||||||
_state = States::Stopped;
|
_state = States::Stopped;
|
||||||
_isActuallyPlayingSth = false;
|
_isActuallyPlayingSth = false;
|
||||||
@@ -264,7 +266,7 @@ void AudioSource::RequestStreamingBuffersUpdate()
|
|||||||
_needToUpdateStreamingBuffers = true;
|
_needToUpdateStreamingBuffers = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
void AudioSource::OnClipChanged()
|
void AudioSource::OnAssetChanged(Asset* asset, void* caller)
|
||||||
{
|
{
|
||||||
Stop();
|
Stop();
|
||||||
|
|
||||||
@@ -276,7 +278,7 @@ void AudioSource::OnClipChanged()
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void AudioSource::OnClipLoaded()
|
void AudioSource::OnAssetLoaded(Asset* asset, void* caller)
|
||||||
{
|
{
|
||||||
if (!SourceID)
|
if (!SourceID)
|
||||||
return;
|
return;
|
||||||
@@ -302,6 +304,10 @@ void AudioSource::OnClipLoaded()
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void AudioSource::OnAssetUnloaded(Asset* asset, void* caller)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
bool AudioSource::UseStreaming() const
|
bool AudioSource::UseStreaming() const
|
||||||
{
|
{
|
||||||
if (Clip == nullptr || Clip->WaitForLoaded())
|
if (Clip == nullptr || Clip->WaitForLoaded())
|
||||||
@@ -383,6 +389,7 @@ bool AudioSource::IntersectsItself(const Ray& ray, Real& distance, Vector3& norm
|
|||||||
void AudioSource::Update()
|
void AudioSource::Update()
|
||||||
{
|
{
|
||||||
PROFILE_CPU();
|
PROFILE_CPU();
|
||||||
|
PROFILE_MEM(Audio);
|
||||||
|
|
||||||
// Update the velocity
|
// Update the velocity
|
||||||
const Vector3 pos = GetPosition();
|
const Vector3 pos = GetPosition();
|
||||||
|
|||||||
@@ -13,7 +13,7 @@
|
|||||||
/// Whether or not an audio source is spatial is controlled by the assigned AudioClip.The volume and the pitch of a spatial audio source is controlled by its position and the AudioListener's position/direction/velocity.
|
/// Whether or not an audio source is spatial is controlled by the assigned AudioClip.The volume and the pitch of a spatial audio source is controlled by its position and the AudioListener's position/direction/velocity.
|
||||||
/// </remarks>
|
/// </remarks>
|
||||||
API_CLASS(Attributes="ActorContextMenu(\"New/Audio/Audio Source\"), ActorToolbox(\"Other\")")
|
API_CLASS(Attributes="ActorContextMenu(\"New/Audio/Audio Source\"), ActorToolbox(\"Other\")")
|
||||||
class FLAXENGINE_API AudioSource : public Actor
|
class FLAXENGINE_API AudioSource : public Actor, IAssetReference
|
||||||
{
|
{
|
||||||
DECLARE_SCENE_OBJECT(AudioSource);
|
DECLARE_SCENE_OBJECT(AudioSource);
|
||||||
friend class AudioStreamingHandler;
|
friend class AudioStreamingHandler;
|
||||||
@@ -293,8 +293,10 @@ public:
|
|||||||
void RequestStreamingBuffersUpdate();
|
void RequestStreamingBuffersUpdate();
|
||||||
|
|
||||||
private:
|
private:
|
||||||
void OnClipChanged();
|
// [IAssetReference]
|
||||||
void OnClipLoaded();
|
void OnAssetChanged(Asset* asset, void* caller) override;
|
||||||
|
void OnAssetLoaded(Asset* asset, void* caller) override;
|
||||||
|
void OnAssetUnloaded(Asset* asset, void* caller) override;
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Plays the audio source. Should have buffer(s) binded before.
|
/// Plays the audio source. Should have buffer(s) binded before.
|
||||||
|
|||||||
@@ -9,6 +9,7 @@
|
|||||||
#include "Engine/Tools/AudioTool/AudioTool.h"
|
#include "Engine/Tools/AudioTool/AudioTool.h"
|
||||||
#include "Engine/Engine/Units.h"
|
#include "Engine/Engine/Units.h"
|
||||||
#include "Engine/Profiler/ProfilerCPU.h"
|
#include "Engine/Profiler/ProfilerCPU.h"
|
||||||
|
#include "Engine/Profiler/ProfilerMemory.h"
|
||||||
#include "Engine/Audio/Audio.h"
|
#include "Engine/Audio/Audio.h"
|
||||||
#include "Engine/Audio/AudioListener.h"
|
#include "Engine/Audio/AudioListener.h"
|
||||||
#include "Engine/Audio/AudioSource.h"
|
#include "Engine/Audio/AudioSource.h"
|
||||||
@@ -321,6 +322,8 @@ void AudioBackendOAL::Listener_ReinitializeAll()
|
|||||||
|
|
||||||
uint32 AudioBackendOAL::Source_Add(const AudioDataInfo& format, const Vector3& position, const Quaternion& orientation, float volume, float pitch, float pan, bool loop, bool spatial, float attenuation, float minDistance, float doppler)
|
uint32 AudioBackendOAL::Source_Add(const AudioDataInfo& format, const Vector3& position, const Quaternion& orientation, float volume, float pitch, float pan, bool loop, bool spatial, float attenuation, float minDistance, float doppler)
|
||||||
{
|
{
|
||||||
|
PROFILE_MEM(Audio);
|
||||||
|
|
||||||
uint32 sourceID = 0;
|
uint32 sourceID = 0;
|
||||||
ALC::Source::Rebuild(sourceID, position, orientation, volume, pitch, pan, loop, spatial, attenuation, minDistance, doppler);
|
ALC::Source::Rebuild(sourceID, position, orientation, volume, pitch, pan, loop, spatial, attenuation, minDistance, doppler);
|
||||||
|
|
||||||
@@ -516,6 +519,7 @@ void AudioBackendOAL::Buffer_Delete(uint32 bufferID)
|
|||||||
void AudioBackendOAL::Buffer_Write(uint32 bufferID, byte* samples, const AudioDataInfo& info)
|
void AudioBackendOAL::Buffer_Write(uint32 bufferID, byte* samples, const AudioDataInfo& info)
|
||||||
{
|
{
|
||||||
PROFILE_CPU();
|
PROFILE_CPU();
|
||||||
|
PROFILE_MEM(Audio);
|
||||||
|
|
||||||
// Pick the format for the audio data (it might not be supported natively)
|
// Pick the format for the audio data (it might not be supported natively)
|
||||||
ALenum format = GetOpenALBufferFormat(info.NumChannels, info.BitDepth);
|
ALenum format = GetOpenALBufferFormat(info.NumChannels, info.BitDepth);
|
||||||
@@ -625,6 +629,8 @@ AudioBackend::FeatureFlags AudioBackendOAL::Base_Features()
|
|||||||
|
|
||||||
void AudioBackendOAL::Base_OnActiveDeviceChanged()
|
void AudioBackendOAL::Base_OnActiveDeviceChanged()
|
||||||
{
|
{
|
||||||
|
PROFILE_MEM(Audio);
|
||||||
|
|
||||||
// Cleanup
|
// Cleanup
|
||||||
Array<ALC::AudioSourceState> states;
|
Array<ALC::AudioSourceState> states;
|
||||||
states.EnsureCapacity(Audio::Sources.Count());
|
states.EnsureCapacity(Audio::Sources.Count());
|
||||||
|
|||||||
@@ -9,6 +9,7 @@
|
|||||||
#include "Engine/Core/Log.h"
|
#include "Engine/Core/Log.h"
|
||||||
#include "Engine/Audio/Audio.h"
|
#include "Engine/Audio/Audio.h"
|
||||||
#include "Engine/Threading/Threading.h"
|
#include "Engine/Threading/Threading.h"
|
||||||
|
#include "Engine/Profiler/ProfilerMemory.h"
|
||||||
|
|
||||||
#if PLATFORM_WINDOWS
|
#if PLATFORM_WINDOWS
|
||||||
// Tweak Win ver
|
// Tweak Win ver
|
||||||
@@ -232,6 +233,7 @@ void AudioBackendXAudio2::Listener_ReinitializeAll()
|
|||||||
|
|
||||||
uint32 AudioBackendXAudio2::Source_Add(const AudioDataInfo& format, const Vector3& position, const Quaternion& orientation, float volume, float pitch, float pan, bool loop, bool spatial, float attenuation, float minDistance, float doppler)
|
uint32 AudioBackendXAudio2::Source_Add(const AudioDataInfo& format, const Vector3& position, const Quaternion& orientation, float volume, float pitch, float pan, bool loop, bool spatial, float attenuation, float minDistance, float doppler)
|
||||||
{
|
{
|
||||||
|
PROFILE_MEM(Audio);
|
||||||
ScopeLock lock(XAudio2::Locker);
|
ScopeLock lock(XAudio2::Locker);
|
||||||
|
|
||||||
// Get first free source
|
// Get first free source
|
||||||
@@ -580,6 +582,7 @@ void AudioBackendXAudio2::Source_DequeueProcessedBuffers(uint32 sourceID)
|
|||||||
|
|
||||||
uint32 AudioBackendXAudio2::Buffer_Create()
|
uint32 AudioBackendXAudio2::Buffer_Create()
|
||||||
{
|
{
|
||||||
|
PROFILE_MEM(Audio);
|
||||||
uint32 bufferID;
|
uint32 bufferID;
|
||||||
ScopeLock lock(XAudio2::Locker);
|
ScopeLock lock(XAudio2::Locker);
|
||||||
|
|
||||||
@@ -618,6 +621,7 @@ void AudioBackendXAudio2::Buffer_Delete(uint32 bufferID)
|
|||||||
|
|
||||||
void AudioBackendXAudio2::Buffer_Write(uint32 bufferID, byte* samples, const AudioDataInfo& info)
|
void AudioBackendXAudio2::Buffer_Write(uint32 bufferID, byte* samples, const AudioDataInfo& info)
|
||||||
{
|
{
|
||||||
|
PROFILE_MEM(Audio);
|
||||||
CHECK(info.NumChannels <= MAX_INPUT_CHANNELS);
|
CHECK(info.NumChannels <= MAX_INPUT_CHANNELS);
|
||||||
|
|
||||||
XAudio2::Locker.Lock();
|
XAudio2::Locker.Lock();
|
||||||
|
|||||||
+128
-70
@@ -9,6 +9,7 @@
|
|||||||
#include "Engine/Core/Log.h"
|
#include "Engine/Core/Log.h"
|
||||||
#include "Engine/Core/LogContext.h"
|
#include "Engine/Core/LogContext.h"
|
||||||
#include "Engine/Profiler/ProfilerCPU.h"
|
#include "Engine/Profiler/ProfilerCPU.h"
|
||||||
|
#include "Engine/Profiler/ProfilerMemory.h"
|
||||||
#include "Engine/Scripting/ManagedCLR/MCore.h"
|
#include "Engine/Scripting/ManagedCLR/MCore.h"
|
||||||
#include "Engine/Threading/MainThreadTask.h"
|
#include "Engine/Threading/MainThreadTask.h"
|
||||||
#include "Engine/Threading/ThreadLocal.h"
|
#include "Engine/Threading/ThreadLocal.h"
|
||||||
@@ -34,15 +35,18 @@ bool ContentDeprecated::Clear(bool newValue)
|
|||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
AssetReferenceBase::AssetReferenceBase(IAssetReference* owner)
|
||||||
|
: _owner(owner)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
AssetReferenceBase::~AssetReferenceBase()
|
AssetReferenceBase::~AssetReferenceBase()
|
||||||
{
|
{
|
||||||
Asset* asset = _asset;
|
Asset* asset = _asset;
|
||||||
if (asset)
|
if (asset)
|
||||||
{
|
{
|
||||||
_asset = nullptr;
|
_asset = nullptr;
|
||||||
asset->OnLoaded.Unbind<AssetReferenceBase, &AssetReferenceBase::OnLoaded>(this);
|
asset->RemoveReference(this);
|
||||||
asset->OnUnloaded.Unbind<AssetReferenceBase, &AssetReferenceBase::OnUnloaded>(this);
|
|
||||||
asset->RemoveReference();
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -51,52 +55,60 @@ String AssetReferenceBase::ToString() const
|
|||||||
return _asset ? _asset->ToString() : TEXT("<null>");
|
return _asset ? _asset->ToString() : TEXT("<null>");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void AssetReferenceBase::OnAssetChanged(Asset* asset, void* caller)
|
||||||
|
{
|
||||||
|
if (_owner)
|
||||||
|
_owner->OnAssetChanged(asset, this);
|
||||||
|
}
|
||||||
|
|
||||||
|
void AssetReferenceBase::OnAssetLoaded(Asset* asset, void* caller)
|
||||||
|
{
|
||||||
|
if (_asset != asset)
|
||||||
|
return;
|
||||||
|
Loaded();
|
||||||
|
if (_owner)
|
||||||
|
_owner->OnAssetLoaded(asset, this);
|
||||||
|
}
|
||||||
|
|
||||||
|
void AssetReferenceBase::OnAssetUnloaded(Asset* asset, void* caller)
|
||||||
|
{
|
||||||
|
if (_asset != asset)
|
||||||
|
return;
|
||||||
|
Unload();
|
||||||
|
OnSet(nullptr);
|
||||||
|
if (_owner)
|
||||||
|
_owner->OnAssetUnloaded(asset, this);
|
||||||
|
}
|
||||||
|
|
||||||
void AssetReferenceBase::OnSet(Asset* asset)
|
void AssetReferenceBase::OnSet(Asset* asset)
|
||||||
{
|
{
|
||||||
auto e = _asset;
|
auto e = _asset;
|
||||||
if (e != asset)
|
if (e != asset)
|
||||||
{
|
{
|
||||||
if (e)
|
if (e)
|
||||||
{
|
e->RemoveReference(this);
|
||||||
e->OnLoaded.Unbind<AssetReferenceBase, &AssetReferenceBase::OnLoaded>(this);
|
|
||||||
e->OnUnloaded.Unbind<AssetReferenceBase, &AssetReferenceBase::OnUnloaded>(this);
|
|
||||||
e->RemoveReference();
|
|
||||||
}
|
|
||||||
_asset = e = asset;
|
_asset = e = asset;
|
||||||
if (e)
|
if (e)
|
||||||
{
|
e->AddReference(this);
|
||||||
e->AddReference();
|
|
||||||
e->OnLoaded.Bind<AssetReferenceBase, &AssetReferenceBase::OnLoaded>(this);
|
|
||||||
e->OnUnloaded.Bind<AssetReferenceBase, &AssetReferenceBase::OnUnloaded>(this);
|
|
||||||
}
|
|
||||||
Changed();
|
Changed();
|
||||||
|
if (_owner)
|
||||||
|
_owner->OnAssetChanged(asset, this);
|
||||||
if (e && e->IsLoaded())
|
if (e && e->IsLoaded())
|
||||||
|
{
|
||||||
Loaded();
|
Loaded();
|
||||||
|
if (_owner)
|
||||||
|
_owner->OnAssetLoaded(asset, this);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void AssetReferenceBase::OnLoaded(Asset* asset)
|
|
||||||
{
|
|
||||||
if (_asset != asset)
|
|
||||||
return;
|
|
||||||
Loaded();
|
|
||||||
}
|
|
||||||
|
|
||||||
void AssetReferenceBase::OnUnloaded(Asset* asset)
|
|
||||||
{
|
|
||||||
if (_asset != asset)
|
|
||||||
return;
|
|
||||||
Unload();
|
|
||||||
OnSet(nullptr);
|
|
||||||
}
|
|
||||||
|
|
||||||
WeakAssetReferenceBase::~WeakAssetReferenceBase()
|
WeakAssetReferenceBase::~WeakAssetReferenceBase()
|
||||||
{
|
{
|
||||||
Asset* asset = _asset;
|
Asset* asset = _asset;
|
||||||
if (asset)
|
if (asset)
|
||||||
{
|
{
|
||||||
_asset = nullptr;
|
_asset = nullptr;
|
||||||
asset->OnUnloaded.Unbind<WeakAssetReferenceBase, &WeakAssetReferenceBase::OnUnloaded>(this);
|
asset->RemoveReference(this, true);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -105,36 +117,43 @@ String WeakAssetReferenceBase::ToString() const
|
|||||||
return _asset ? _asset->ToString() : TEXT("<null>");
|
return _asset ? _asset->ToString() : TEXT("<null>");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void WeakAssetReferenceBase::OnAssetChanged(Asset* asset, void* caller)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
void WeakAssetReferenceBase::OnAssetLoaded(Asset* asset, void* caller)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
void WeakAssetReferenceBase::OnAssetUnloaded(Asset* asset, void* caller)
|
||||||
|
{
|
||||||
|
if (_asset != asset)
|
||||||
|
return;
|
||||||
|
Unload();
|
||||||
|
asset->RemoveReference(this, true);
|
||||||
|
_asset = nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
void WeakAssetReferenceBase::OnSet(Asset* asset)
|
void WeakAssetReferenceBase::OnSet(Asset* asset)
|
||||||
{
|
{
|
||||||
auto e = _asset;
|
auto e = _asset;
|
||||||
if (e != asset)
|
if (e != asset)
|
||||||
{
|
{
|
||||||
if (e)
|
if (e)
|
||||||
e->OnUnloaded.Unbind<WeakAssetReferenceBase, &WeakAssetReferenceBase::OnUnloaded>(this);
|
e->RemoveReference(this, true);
|
||||||
_asset = e = asset;
|
_asset = e = asset;
|
||||||
if (e)
|
if (e)
|
||||||
e->OnUnloaded.Bind<WeakAssetReferenceBase, &WeakAssetReferenceBase::OnUnloaded>(this);
|
e->AddReference(this, true);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void WeakAssetReferenceBase::OnUnloaded(Asset* asset)
|
|
||||||
{
|
|
||||||
if (_asset != asset)
|
|
||||||
return;
|
|
||||||
Unload();
|
|
||||||
asset->OnUnloaded.Unbind<WeakAssetReferenceBase, &WeakAssetReferenceBase::OnUnloaded>(this);
|
|
||||||
_asset = nullptr;
|
|
||||||
}
|
|
||||||
|
|
||||||
SoftAssetReferenceBase::~SoftAssetReferenceBase()
|
SoftAssetReferenceBase::~SoftAssetReferenceBase()
|
||||||
{
|
{
|
||||||
Asset* asset = _asset;
|
Asset* asset = _asset;
|
||||||
if (asset)
|
if (asset)
|
||||||
{
|
{
|
||||||
_asset = nullptr;
|
_asset = nullptr;
|
||||||
asset->OnUnloaded.Unbind<SoftAssetReferenceBase, &SoftAssetReferenceBase::OnUnloaded>(this);
|
asset->RemoveReference(this);
|
||||||
asset->RemoveReference();
|
|
||||||
}
|
}
|
||||||
#if !BUILD_RELEASE
|
#if !BUILD_RELEASE
|
||||||
_id = Guid::Empty;
|
_id = Guid::Empty;
|
||||||
@@ -146,22 +165,34 @@ String SoftAssetReferenceBase::ToString() const
|
|||||||
return _asset ? _asset->ToString() : (_id.IsValid() ? _id.ToString() : TEXT("<null>"));
|
return _asset ? _asset->ToString() : (_id.IsValid() ? _id.ToString() : TEXT("<null>"));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void SoftAssetReferenceBase::OnAssetChanged(Asset* asset, void* caller)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
void SoftAssetReferenceBase::OnAssetLoaded(Asset* asset, void* caller)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
void SoftAssetReferenceBase::OnAssetUnloaded(Asset* asset, void* caller)
|
||||||
|
{
|
||||||
|
if (_asset != asset)
|
||||||
|
return;
|
||||||
|
_asset->RemoveReference(this);
|
||||||
|
_asset = nullptr;
|
||||||
|
_id = Guid::Empty;
|
||||||
|
Changed();
|
||||||
|
}
|
||||||
|
|
||||||
void SoftAssetReferenceBase::OnSet(Asset* asset)
|
void SoftAssetReferenceBase::OnSet(Asset* asset)
|
||||||
{
|
{
|
||||||
if (_asset == asset)
|
if (_asset == asset)
|
||||||
return;
|
return;
|
||||||
if (_asset)
|
if (_asset)
|
||||||
{
|
_asset->RemoveReference(this);
|
||||||
_asset->OnUnloaded.Unbind<SoftAssetReferenceBase, &SoftAssetReferenceBase::OnUnloaded>(this);
|
|
||||||
_asset->RemoveReference();
|
|
||||||
}
|
|
||||||
_asset = asset;
|
_asset = asset;
|
||||||
_id = asset ? asset->GetID() : Guid::Empty;
|
_id = asset ? asset->GetID() : Guid::Empty;
|
||||||
if (asset)
|
if (asset)
|
||||||
{
|
asset->AddReference(this);
|
||||||
asset->AddReference();
|
|
||||||
asset->OnUnloaded.Bind<SoftAssetReferenceBase, &SoftAssetReferenceBase::OnUnloaded>(this);
|
|
||||||
}
|
|
||||||
Changed();
|
Changed();
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -170,10 +201,7 @@ void SoftAssetReferenceBase::OnSet(const Guid& id)
|
|||||||
if (_id == id)
|
if (_id == id)
|
||||||
return;
|
return;
|
||||||
if (_asset)
|
if (_asset)
|
||||||
{
|
_asset->RemoveReference(this);
|
||||||
_asset->OnUnloaded.Unbind<SoftAssetReferenceBase, &SoftAssetReferenceBase::OnUnloaded>(this);
|
|
||||||
_asset->RemoveReference();
|
|
||||||
}
|
|
||||||
_asset = nullptr;
|
_asset = nullptr;
|
||||||
_id = id;
|
_id = id;
|
||||||
Changed();
|
Changed();
|
||||||
@@ -184,21 +212,7 @@ void SoftAssetReferenceBase::OnResolve(const ScriptingTypeHandle& type)
|
|||||||
ASSERT(!_asset);
|
ASSERT(!_asset);
|
||||||
_asset = ::LoadAsset(_id, type);
|
_asset = ::LoadAsset(_id, type);
|
||||||
if (_asset)
|
if (_asset)
|
||||||
{
|
_asset->AddReference(this);
|
||||||
_asset->OnUnloaded.Bind<SoftAssetReferenceBase, &SoftAssetReferenceBase::OnUnloaded>(this);
|
|
||||||
_asset->AddReference();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void SoftAssetReferenceBase::OnUnloaded(Asset* asset)
|
|
||||||
{
|
|
||||||
if (_asset != asset)
|
|
||||||
return;
|
|
||||||
_asset->RemoveReference();
|
|
||||||
_asset->OnUnloaded.Unbind<SoftAssetReferenceBase, &SoftAssetReferenceBase::OnUnloaded>(this);
|
|
||||||
_asset = nullptr;
|
|
||||||
_id = Guid::Empty;
|
|
||||||
Changed();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
Asset::Asset(const SpawnParams& params, const AssetInfo* info)
|
Asset::Asset(const SpawnParams& params, const AssetInfo* info)
|
||||||
@@ -216,6 +230,39 @@ int32 Asset::GetReferencesCount() const
|
|||||||
return (int32)Platform::AtomicRead(const_cast<int64 volatile*>(&_refCount));
|
return (int32)Platform::AtomicRead(const_cast<int64 volatile*>(&_refCount));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void Asset::AddReference()
|
||||||
|
{
|
||||||
|
Platform::InterlockedIncrement(&_refCount);
|
||||||
|
}
|
||||||
|
|
||||||
|
void Asset::AddReference(IAssetReference* ref, bool week)
|
||||||
|
{
|
||||||
|
if (!week)
|
||||||
|
Platform::InterlockedIncrement(&_refCount);
|
||||||
|
if (ref)
|
||||||
|
{
|
||||||
|
//PROFILE_MEM(EngineDelegate); // Include references tracking memory within Delegate memory
|
||||||
|
ScopeLock lock(_referencesLocker);
|
||||||
|
_references.Add(ref);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void Asset::RemoveReference()
|
||||||
|
{
|
||||||
|
Platform::InterlockedDecrement(&_refCount);
|
||||||
|
}
|
||||||
|
|
||||||
|
void Asset::RemoveReference(IAssetReference* ref, bool week)
|
||||||
|
{
|
||||||
|
if (ref)
|
||||||
|
{
|
||||||
|
ScopeLock lock(_referencesLocker);
|
||||||
|
_references.Remove(ref);
|
||||||
|
}
|
||||||
|
if (!week)
|
||||||
|
Platform::InterlockedDecrement(&_refCount);
|
||||||
|
}
|
||||||
|
|
||||||
String Asset::ToString() const
|
String Asset::ToString() const
|
||||||
{
|
{
|
||||||
return String::Format(TEXT("{0}, {1}, {2}"), GetTypeName(), GetID(), GetPath());
|
return String::Format(TEXT("{0}, {1}, {2}"), GetTypeName(), GetID(), GetPath());
|
||||||
@@ -232,7 +279,7 @@ void Asset::OnDeleteObject()
|
|||||||
|
|
||||||
const bool wasMarkedToDelete = _deleteFileOnUnload != 0;
|
const bool wasMarkedToDelete = _deleteFileOnUnload != 0;
|
||||||
#if USE_EDITOR
|
#if USE_EDITOR
|
||||||
const String path = wasMarkedToDelete ? GetPath() : String::Empty;
|
const String path = wasMarkedToDelete ? String(GetPath()) : String::Empty;
|
||||||
#endif
|
#endif
|
||||||
const Guid id = GetID();
|
const Guid id = GetID();
|
||||||
|
|
||||||
@@ -354,6 +401,7 @@ uint64 Asset::GetMemoryUsage() const
|
|||||||
if (Platform::AtomicRead(&_loadingTask))
|
if (Platform::AtomicRead(&_loadingTask))
|
||||||
result += sizeof(ContentLoadTask);
|
result += sizeof(ContentLoadTask);
|
||||||
result += (OnLoaded.Capacity() + OnReloading.Capacity() + OnUnloaded.Capacity()) * sizeof(EventType::FunctionType);
|
result += (OnLoaded.Capacity() + OnReloading.Capacity() + OnUnloaded.Capacity()) * sizeof(EventType::FunctionType);
|
||||||
|
result += _references.Capacity() * sizeof(HashSet<IAssetReference*>::Bucket);
|
||||||
Locker.Unlock();
|
Locker.Unlock();
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
@@ -444,6 +492,9 @@ bool Asset::WaitForLoaded(double timeoutInMilliseconds) const
|
|||||||
}
|
}
|
||||||
|
|
||||||
PROFILE_CPU();
|
PROFILE_CPU();
|
||||||
|
ZoneColor(TracyWaitZoneColor);
|
||||||
|
const StringView path(GetPath());
|
||||||
|
ZoneText(*path, path.Length());
|
||||||
|
|
||||||
Content::WaitForTask(loadingTask, timeoutInMilliseconds);
|
Content::WaitForTask(loadingTask, timeoutInMilliseconds);
|
||||||
|
|
||||||
@@ -528,6 +579,7 @@ ContentLoadTask* Asset::createLoadingTask()
|
|||||||
|
|
||||||
void Asset::startLoading()
|
void Asset::startLoading()
|
||||||
{
|
{
|
||||||
|
PROFILE_MEM(ContentAssets);
|
||||||
ASSERT(!IsLoaded());
|
ASSERT(!IsLoaded());
|
||||||
ASSERT(Platform::AtomicRead(&_loadingTask) == 0);
|
ASSERT(Platform::AtomicRead(&_loadingTask) == 0);
|
||||||
auto loadingTask = createLoadingTask();
|
auto loadingTask = createLoadingTask();
|
||||||
@@ -627,6 +679,9 @@ void Asset::onLoaded_MainThread()
|
|||||||
ASSERT(IsInMainThread());
|
ASSERT(IsInMainThread());
|
||||||
|
|
||||||
// Send event
|
// Send event
|
||||||
|
ScopeLock lock(_referencesLocker);
|
||||||
|
for (const auto& e : _references)
|
||||||
|
e.Item->OnAssetLoaded(this, this);
|
||||||
OnLoaded(this);
|
OnLoaded(this);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -640,6 +695,9 @@ void Asset::onUnload_MainThread()
|
|||||||
CancelStreaming();
|
CancelStreaming();
|
||||||
|
|
||||||
// Send event
|
// Send event
|
||||||
|
ScopeLock lock(_referencesLocker);
|
||||||
|
for (const auto& e : _references)
|
||||||
|
e.Item->OnAssetUnloaded(this, this);
|
||||||
OnUnloaded(this);
|
OnUnloaded(this);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -18,6 +18,20 @@
|
|||||||
public: \
|
public: \
|
||||||
explicit type(const SpawnParams& params, const AssetInfo* info)
|
explicit type(const SpawnParams& params, const AssetInfo* info)
|
||||||
|
|
||||||
|
// Utility interface for objects that reference asset and want to get notified about asset reference changes.
|
||||||
|
class FLAXENGINE_API IAssetReference
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
virtual ~IAssetReference() = default;
|
||||||
|
|
||||||
|
// Asset reference got changed.
|
||||||
|
virtual void OnAssetChanged(Asset* asset, void* caller) = 0;
|
||||||
|
// Asset got loaded.
|
||||||
|
virtual void OnAssetLoaded(Asset* asset, void* caller) = 0;
|
||||||
|
// Asset gets unloaded.
|
||||||
|
virtual void OnAssetUnloaded(Asset* asset, void* caller) = 0;
|
||||||
|
};
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Asset objects base class.
|
/// Asset objects base class.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
@@ -48,6 +62,9 @@ protected:
|
|||||||
int8 _deleteFileOnUnload : 1; // Indicates that asset source file should be removed on asset unload
|
int8 _deleteFileOnUnload : 1; // Indicates that asset source file should be removed on asset unload
|
||||||
int8 _isVirtual : 1; // Indicates that asset is pure virtual (generated or temporary, has no storage so won't be saved)
|
int8 _isVirtual : 1; // Indicates that asset is pure virtual (generated or temporary, has no storage so won't be saved)
|
||||||
|
|
||||||
|
HashSet<IAssetReference*> _references;
|
||||||
|
CriticalSection _referencesLocker; // TODO: convert into a single interlocked exchange for the current thread owning lock
|
||||||
|
|
||||||
public:
|
public:
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Initializes a new instance of the <see cref="Asset"/> class.
|
/// Initializes a new instance of the <see cref="Asset"/> class.
|
||||||
@@ -88,24 +105,28 @@ public:
|
|||||||
/// <summary>
|
/// <summary>
|
||||||
/// Adds reference to that asset.
|
/// Adds reference to that asset.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
FORCE_INLINE void AddReference()
|
void AddReference();
|
||||||
{
|
|
||||||
Platform::InterlockedIncrement(&_refCount);
|
/// <summary>
|
||||||
}
|
/// Adds reference to that asset.
|
||||||
|
/// </summary>
|
||||||
|
void AddReference(IAssetReference* ref, bool week = false);
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Removes reference from that asset.
|
/// Removes reference from that asset.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
FORCE_INLINE void RemoveReference()
|
void RemoveReference();
|
||||||
{
|
|
||||||
Platform::InterlockedDecrement(&_refCount);
|
/// <summary>
|
||||||
}
|
/// Removes reference from that asset.
|
||||||
|
/// </summary>
|
||||||
|
void RemoveReference(IAssetReference* ref, bool week = false);
|
||||||
|
|
||||||
public:
|
public:
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Gets the path to the asset storage file. In Editor, it reflects the actual file, in cooked Game, it fakes the Editor path to be informative for developers.
|
/// Gets the path to the asset storage file. In Editor, it reflects the actual file, in cooked Game, it fakes the Editor path to be informative for developers.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
API_PROPERTY() virtual const String& GetPath() const = 0;
|
API_PROPERTY() virtual StringView GetPath() const = 0;
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Gets the asset type name.
|
/// Gets the asset type name.
|
||||||
|
|||||||
@@ -7,10 +7,11 @@
|
|||||||
/// <summary>
|
/// <summary>
|
||||||
/// Asset reference utility. Keeps reference to the linked asset object and handles load/unload events.
|
/// Asset reference utility. Keeps reference to the linked asset object and handles load/unload events.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
class FLAXENGINE_API AssetReferenceBase
|
class FLAXENGINE_API AssetReferenceBase : public IAssetReference
|
||||||
{
|
{
|
||||||
protected:
|
protected:
|
||||||
Asset* _asset = nullptr;
|
Asset* _asset = nullptr;
|
||||||
|
IAssetReference* _owner = nullptr;
|
||||||
|
|
||||||
public:
|
public:
|
||||||
/// <summary>
|
/// <summary>
|
||||||
@@ -36,6 +37,12 @@ public:
|
|||||||
/// </summary>
|
/// </summary>
|
||||||
AssetReferenceBase() = default;
|
AssetReferenceBase() = default;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Initializes a new instance of the <see cref="AssetReferenceBase"/> class.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="owner">The reference owner to keep notified about asset changes.</param>
|
||||||
|
AssetReferenceBase(IAssetReference* owner);
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Finalizes an instance of the <see cref="AssetReferenceBase"/> class.
|
/// Finalizes an instance of the <see cref="AssetReferenceBase"/> class.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
@@ -63,10 +70,14 @@ public:
|
|||||||
/// </summary>
|
/// </summary>
|
||||||
String ToString() const;
|
String ToString() const;
|
||||||
|
|
||||||
|
public:
|
||||||
|
// [IAssetReference]
|
||||||
|
void OnAssetChanged(Asset* asset, void* caller) override;
|
||||||
|
void OnAssetLoaded(Asset* asset, void* caller) override;
|
||||||
|
void OnAssetUnloaded(Asset* asset, void* caller) override;
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
void OnSet(Asset* asset);
|
void OnSet(Asset* asset);
|
||||||
void OnLoaded(Asset* asset);
|
|
||||||
void OnUnloaded(Asset* asset);
|
|
||||||
};
|
};
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
@@ -87,6 +98,13 @@ public:
|
|||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Initializes a new instance of the <see cref="AssetReference"/> class.
|
||||||
|
/// </summary>
|
||||||
|
explicit AssetReference(decltype(__nullptr))
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Initializes a new instance of the <see cref="AssetReference"/> class.
|
/// Initializes a new instance of the <see cref="AssetReference"/> class.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
@@ -96,6 +114,15 @@ public:
|
|||||||
OnSet((Asset*)asset);
|
OnSet((Asset*)asset);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Initializes a new instance of the <see cref="AssetReference"/> class.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="owner">The reference owner to keep notified about asset changes.</param>
|
||||||
|
explicit AssetReference(IAssetReference* owner)
|
||||||
|
: AssetReferenceBase(owner)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Initializes a new instance of the <see cref="AssetReference"/> class.
|
/// Initializes a new instance of the <see cref="AssetReference"/> class.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
|
|||||||
@@ -9,6 +9,7 @@
|
|||||||
#include "Engine/Animations/Animations.h"
|
#include "Engine/Animations/Animations.h"
|
||||||
#include "Engine/Animations/SceneAnimations/SceneAnimation.h"
|
#include "Engine/Animations/SceneAnimations/SceneAnimation.h"
|
||||||
#include "Engine/Scripting/Scripting.h"
|
#include "Engine/Scripting/Scripting.h"
|
||||||
|
#include "Engine/Profiler/ProfilerMemory.h"
|
||||||
#include "Engine/Threading/Threading.h"
|
#include "Engine/Threading/Threading.h"
|
||||||
#include "Engine/Serialization/MemoryReadStream.h"
|
#include "Engine/Serialization/MemoryReadStream.h"
|
||||||
#if USE_EDITOR
|
#if USE_EDITOR
|
||||||
@@ -598,7 +599,8 @@ void Animation::OnScriptingDispose()
|
|||||||
|
|
||||||
Asset::LoadResult Animation::load()
|
Asset::LoadResult Animation::load()
|
||||||
{
|
{
|
||||||
ConcurrentSystemLocker::WriteScope systemScope(Animations::SystemLocker);
|
PROFILE_MEM(AnimationsData);
|
||||||
|
ScopeWriteLock systemScope(Animations::SystemLocker);
|
||||||
|
|
||||||
// Get stream with animations data
|
// Get stream with animations data
|
||||||
const auto dataChunk = GetChunk(0);
|
const auto dataChunk = GetChunk(0);
|
||||||
@@ -730,7 +732,7 @@ Asset::LoadResult Animation::load()
|
|||||||
|
|
||||||
void Animation::unload(bool isReloading)
|
void Animation::unload(bool isReloading)
|
||||||
{
|
{
|
||||||
ConcurrentSystemLocker::WriteScope systemScope(Animations::SystemLocker);
|
ScopeWriteLock systemScope(Animations::SystemLocker);
|
||||||
#if USE_EDITOR
|
#if USE_EDITOR
|
||||||
if (_registeredForScriptingReload)
|
if (_registeredForScriptingReload)
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -9,6 +9,7 @@
|
|||||||
#include "Engine/Core/Types/DataContainer.h"
|
#include "Engine/Core/Types/DataContainer.h"
|
||||||
#include "Engine/Serialization/MemoryReadStream.h"
|
#include "Engine/Serialization/MemoryReadStream.h"
|
||||||
#include "Engine/Serialization/MemoryWriteStream.h"
|
#include "Engine/Serialization/MemoryWriteStream.h"
|
||||||
|
#include "Engine/Profiler/ProfilerMemory.h"
|
||||||
#include "Engine/Content/Factories/BinaryAssetFactory.h"
|
#include "Engine/Content/Factories/BinaryAssetFactory.h"
|
||||||
#include "Engine/Animations/Animations.h"
|
#include "Engine/Animations/Animations.h"
|
||||||
#include "Engine/Threading/Threading.h"
|
#include "Engine/Threading/Threading.h"
|
||||||
@@ -25,7 +26,8 @@ AnimationGraph::AnimationGraph(const SpawnParams& params, const AssetInfo* info)
|
|||||||
|
|
||||||
Asset::LoadResult AnimationGraph::load()
|
Asset::LoadResult AnimationGraph::load()
|
||||||
{
|
{
|
||||||
ConcurrentSystemLocker::WriteScope systemScope(Animations::SystemLocker);
|
PROFILE_MEM(AnimationsData);
|
||||||
|
ScopeWriteLock systemScope(Animations::SystemLocker);
|
||||||
|
|
||||||
// Get stream with graph data
|
// Get stream with graph data
|
||||||
const auto surfaceChunk = GetChunk(0);
|
const auto surfaceChunk = GetChunk(0);
|
||||||
@@ -51,7 +53,7 @@ Asset::LoadResult AnimationGraph::load()
|
|||||||
|
|
||||||
void AnimationGraph::unload(bool isReloading)
|
void AnimationGraph::unload(bool isReloading)
|
||||||
{
|
{
|
||||||
ConcurrentSystemLocker::WriteScope systemScope(Animations::SystemLocker);
|
ScopeWriteLock systemScope(Animations::SystemLocker);
|
||||||
Graph.Clear();
|
Graph.Clear();
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -83,7 +85,8 @@ bool AnimationGraph::InitAsAnimation(SkinnedModel* baseModel, Animation* anim, b
|
|||||||
Log::ArgumentNullException();
|
Log::ArgumentNullException();
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
ConcurrentSystemLocker::WriteScope systemScope(Animations::SystemLocker);
|
PROFILE_MEM(AnimationsData);
|
||||||
|
ScopeWriteLock systemScope(Animations::SystemLocker);
|
||||||
|
|
||||||
// Create Graph data
|
// Create Graph data
|
||||||
MemoryWriteStream writeStream(512);
|
MemoryWriteStream writeStream(512);
|
||||||
@@ -169,7 +172,7 @@ bool AnimationGraph::SaveSurface(const BytesContainer& data)
|
|||||||
{
|
{
|
||||||
if (OnCheckSave())
|
if (OnCheckSave())
|
||||||
return true;
|
return true;
|
||||||
ConcurrentSystemLocker::WriteScope systemScope(Animations::SystemLocker);
|
ScopeWriteLock systemScope(Animations::SystemLocker);
|
||||||
ScopeLock lock(Locker);
|
ScopeLock lock(Locker);
|
||||||
|
|
||||||
if (IsVirtual())
|
if (IsVirtual())
|
||||||
|
|||||||
@@ -8,6 +8,7 @@
|
|||||||
#include "Engine/Serialization/MemoryWriteStream.h"
|
#include "Engine/Serialization/MemoryWriteStream.h"
|
||||||
#endif
|
#endif
|
||||||
#include "Engine/Animations/Animations.h"
|
#include "Engine/Animations/Animations.h"
|
||||||
|
#include "Engine/Profiler/ProfilerMemory.h"
|
||||||
#include "Engine/Content/Factories/BinaryAssetFactory.h"
|
#include "Engine/Content/Factories/BinaryAssetFactory.h"
|
||||||
#include "Engine/Threading/Threading.h"
|
#include "Engine/Threading/Threading.h"
|
||||||
|
|
||||||
@@ -20,7 +21,8 @@ AnimationGraphFunction::AnimationGraphFunction(const SpawnParams& params, const
|
|||||||
|
|
||||||
Asset::LoadResult AnimationGraphFunction::load()
|
Asset::LoadResult AnimationGraphFunction::load()
|
||||||
{
|
{
|
||||||
ConcurrentSystemLocker::WriteScope systemScope(Animations::SystemLocker);
|
PROFILE_MEM(AnimationsData);
|
||||||
|
ScopeWriteLock systemScope(Animations::SystemLocker);
|
||||||
|
|
||||||
// Get graph data from chunk
|
// Get graph data from chunk
|
||||||
const auto surfaceChunk = GetChunk(0);
|
const auto surfaceChunk = GetChunk(0);
|
||||||
@@ -47,7 +49,7 @@ Asset::LoadResult AnimationGraphFunction::load()
|
|||||||
|
|
||||||
void AnimationGraphFunction::unload(bool isReloading)
|
void AnimationGraphFunction::unload(bool isReloading)
|
||||||
{
|
{
|
||||||
ConcurrentSystemLocker::WriteScope systemScope(Animations::SystemLocker);
|
ScopeWriteLock systemScope(Animations::SystemLocker);
|
||||||
GraphData.Release();
|
GraphData.Release();
|
||||||
Inputs.Clear();
|
Inputs.Clear();
|
||||||
Outputs.Clear();
|
Outputs.Clear();
|
||||||
@@ -96,7 +98,7 @@ bool AnimationGraphFunction::SaveSurface(const BytesContainer& data) const
|
|||||||
{
|
{
|
||||||
if (OnCheckSave())
|
if (OnCheckSave())
|
||||||
return true;
|
return true;
|
||||||
ConcurrentSystemLocker::WriteScope systemScope(Animations::SystemLocker);
|
ScopeWriteLock systemScope(Animations::SystemLocker);
|
||||||
ScopeLock lock(Locker);
|
ScopeLock lock(Locker);
|
||||||
|
|
||||||
// Set Visject Surface data
|
// Set Visject Surface data
|
||||||
|
|||||||
@@ -165,9 +165,13 @@ Asset::LoadResult Material::load()
|
|||||||
MaterialGenerator generator;
|
MaterialGenerator generator;
|
||||||
generator.Error.Bind(&OnGeneratorError);
|
generator.Error.Bind(&OnGeneratorError);
|
||||||
if (_shaderHeader.Material.GraphVersion != MATERIAL_GRAPH_VERSION)
|
if (_shaderHeader.Material.GraphVersion != MATERIAL_GRAPH_VERSION)
|
||||||
|
{
|
||||||
LOG(Info, "Converting material \'{0}\', from version {1} to {2}...", name, _shaderHeader.Material.GraphVersion, MATERIAL_GRAPH_VERSION);
|
LOG(Info, "Converting material \'{0}\', from version {1} to {2}...", name, _shaderHeader.Material.GraphVersion, MATERIAL_GRAPH_VERSION);
|
||||||
|
}
|
||||||
else
|
else
|
||||||
|
{
|
||||||
LOG(Info, "Updating material \'{0}\'...", name);
|
LOG(Info, "Updating material \'{0}\'...", name);
|
||||||
|
}
|
||||||
|
|
||||||
// Load or create material surface
|
// Load or create material surface
|
||||||
MaterialLayer* layer;
|
MaterialLayer* layer;
|
||||||
@@ -410,16 +414,18 @@ void Material::InitCompilationOptions(ShaderCompilationOptions& options)
|
|||||||
// Prepare
|
// Prepare
|
||||||
auto& info = _shaderHeader.Material.Info;
|
auto& info = _shaderHeader.Material.Info;
|
||||||
const bool isSurfaceOrTerrainOrDeformable = info.Domain == MaterialDomain::Surface || info.Domain == MaterialDomain::Terrain || info.Domain == MaterialDomain::Deformable;
|
const bool isSurfaceOrTerrainOrDeformable = info.Domain == MaterialDomain::Surface || info.Domain == MaterialDomain::Terrain || info.Domain == MaterialDomain::Deformable;
|
||||||
|
const bool isOpaque = info.BlendMode == MaterialBlendMode::Opaque;
|
||||||
const bool useCustomData = info.ShadingModel == MaterialShadingModel::Subsurface || info.ShadingModel == MaterialShadingModel::Foliage;
|
const bool useCustomData = info.ShadingModel == MaterialShadingModel::Subsurface || info.ShadingModel == MaterialShadingModel::Foliage;
|
||||||
const bool useForward = ((info.Domain == MaterialDomain::Surface || info.Domain == MaterialDomain::Deformable) && info.BlendMode != MaterialBlendMode::Opaque) || info.Domain == MaterialDomain::Particle;
|
const bool useForward = ((info.Domain == MaterialDomain::Surface || info.Domain == MaterialDomain::Deformable) && !isOpaque) || info.Domain == MaterialDomain::Particle;
|
||||||
const bool useTess =
|
const bool useTess =
|
||||||
info.TessellationMode != TessellationMethod::None &&
|
info.TessellationMode != TessellationMethod::None &&
|
||||||
RenderTools::CanSupportTessellation(options.Profile) && isSurfaceOrTerrainOrDeformable;
|
RenderTools::CanSupportTessellation(options.Profile) && isSurfaceOrTerrainOrDeformable;
|
||||||
const bool useDistortion =
|
const bool useDistortion =
|
||||||
(info.Domain == MaterialDomain::Surface || info.Domain == MaterialDomain::Deformable || info.Domain == MaterialDomain::Particle) &&
|
(info.Domain == MaterialDomain::Surface || info.Domain == MaterialDomain::Deformable || info.Domain == MaterialDomain::Particle) &&
|
||||||
info.BlendMode != MaterialBlendMode::Opaque &&
|
!isOpaque &&
|
||||||
EnumHasAnyFlags(info.UsageFlags, MaterialUsageFlags::UseRefraction) &&
|
EnumHasAnyFlags(info.UsageFlags, MaterialUsageFlags::UseRefraction) &&
|
||||||
(info.FeaturesFlags & MaterialFeaturesFlags::DisableDistortion) == MaterialFeaturesFlags::None;
|
(info.FeaturesFlags & MaterialFeaturesFlags::DisableDistortion) == MaterialFeaturesFlags::None;
|
||||||
|
const MaterialShadingModel shadingModel = info.ShadingModel == MaterialShadingModel::CustomLit ? MaterialShadingModel::Unlit : info.ShadingModel;
|
||||||
|
|
||||||
// @formatter:off
|
// @formatter:off
|
||||||
static const char* Numbers[] =
|
static const char* Numbers[] =
|
||||||
@@ -431,7 +437,7 @@ void Material::InitCompilationOptions(ShaderCompilationOptions& options)
|
|||||||
// Setup shader macros
|
// Setup shader macros
|
||||||
options.Macros.Add({ "MATERIAL_DOMAIN", Numbers[(int32)info.Domain] });
|
options.Macros.Add({ "MATERIAL_DOMAIN", Numbers[(int32)info.Domain] });
|
||||||
options.Macros.Add({ "MATERIAL_BLEND", Numbers[(int32)info.BlendMode] });
|
options.Macros.Add({ "MATERIAL_BLEND", Numbers[(int32)info.BlendMode] });
|
||||||
options.Macros.Add({ "MATERIAL_SHADING_MODEL", Numbers[(int32)info.ShadingModel] });
|
options.Macros.Add({ "MATERIAL_SHADING_MODEL", Numbers[(int32)shadingModel] });
|
||||||
options.Macros.Add({ "MATERIAL_MASKED", Numbers[EnumHasAnyFlags(info.UsageFlags, MaterialUsageFlags::UseMask) ? 1 : 0] });
|
options.Macros.Add({ "MATERIAL_MASKED", Numbers[EnumHasAnyFlags(info.UsageFlags, MaterialUsageFlags::UseMask) ? 1 : 0] });
|
||||||
options.Macros.Add({ "DECAL_BLEND_MODE", Numbers[(int32)info.DecalBlendingMode] });
|
options.Macros.Add({ "DECAL_BLEND_MODE", Numbers[(int32)info.DecalBlendingMode] });
|
||||||
options.Macros.Add({ "USE_EMISSIVE", Numbers[EnumHasAnyFlags(info.UsageFlags, MaterialUsageFlags::UseEmissive) ? 1 : 0] });
|
options.Macros.Add({ "USE_EMISSIVE", Numbers[EnumHasAnyFlags(info.UsageFlags, MaterialUsageFlags::UseEmissive) ? 1 : 0] });
|
||||||
@@ -488,7 +494,7 @@ void Material::InitCompilationOptions(ShaderCompilationOptions& options)
|
|||||||
options.Macros.Add({ "IS_PARTICLE", Numbers[info.Domain == MaterialDomain::Particle ? 1 : 0] });
|
options.Macros.Add({ "IS_PARTICLE", Numbers[info.Domain == MaterialDomain::Particle ? 1 : 0] });
|
||||||
options.Macros.Add({ "IS_DEFORMABLE", Numbers[info.Domain == MaterialDomain::Deformable ? 1 : 0] });
|
options.Macros.Add({ "IS_DEFORMABLE", Numbers[info.Domain == MaterialDomain::Deformable ? 1 : 0] });
|
||||||
options.Macros.Add({ "USE_FORWARD", Numbers[useForward ? 1 : 0] });
|
options.Macros.Add({ "USE_FORWARD", Numbers[useForward ? 1 : 0] });
|
||||||
options.Macros.Add({ "USE_DEFERRED", Numbers[isSurfaceOrTerrainOrDeformable && info.BlendMode == MaterialBlendMode::Opaque ? 1 : 0] });
|
options.Macros.Add({ "USE_DEFERRED", Numbers[isSurfaceOrTerrainOrDeformable && isOpaque ? 1 : 0] });
|
||||||
options.Macros.Add({ "USE_DISTORTION", Numbers[useDistortion ? 1 : 0] });
|
options.Macros.Add({ "USE_DISTORTION", Numbers[useDistortion ? 1 : 0] });
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -18,6 +18,7 @@
|
|||||||
#include "Engine/Graphics/Models/MeshDeformation.h"
|
#include "Engine/Graphics/Models/MeshDeformation.h"
|
||||||
#include "Engine/Graphics/Textures/GPUTexture.h"
|
#include "Engine/Graphics/Textures/GPUTexture.h"
|
||||||
#include "Engine/Profiler/ProfilerCPU.h"
|
#include "Engine/Profiler/ProfilerCPU.h"
|
||||||
|
#include "Engine/Profiler/ProfilerMemory.h"
|
||||||
#include "Engine/Renderer/DrawCall.h"
|
#include "Engine/Renderer/DrawCall.h"
|
||||||
#include "Engine/Threading/Threading.h"
|
#include "Engine/Threading/Threading.h"
|
||||||
#include "Engine/Tools/ModelTool/ModelTool.h"
|
#include "Engine/Tools/ModelTool/ModelTool.h"
|
||||||
@@ -304,6 +305,7 @@ bool Model::Init(const Span<int32>& meshesCountPerLod)
|
|||||||
Log::ArgumentOutOfRangeException();
|
Log::ArgumentOutOfRangeException();
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
PROFILE_MEM(GraphicsMeshes);
|
||||||
|
|
||||||
// Dispose previous data and disable streaming (will start data uploading tasks manually)
|
// Dispose previous data and disable streaming (will start data uploading tasks manually)
|
||||||
StopStreaming();
|
StopStreaming();
|
||||||
@@ -343,6 +345,7 @@ bool Model::Init(const Span<int32>& meshesCountPerLod)
|
|||||||
|
|
||||||
bool Model::LoadHeader(ReadStream& stream, byte& headerVersion)
|
bool Model::LoadHeader(ReadStream& stream, byte& headerVersion)
|
||||||
{
|
{
|
||||||
|
PROFILE_MEM(GraphicsMeshes);
|
||||||
if (ModelBase::LoadHeader(stream, headerVersion))
|
if (ModelBase::LoadHeader(stream, headerVersion))
|
||||||
return true;
|
return true;
|
||||||
|
|
||||||
@@ -509,6 +512,7 @@ bool Model::Save(bool withMeshDataFromGpu, Function<FlaxChunk*(int32)>& getChunk
|
|||||||
|
|
||||||
void Model::SetupMaterialSlots(int32 slotsCount)
|
void Model::SetupMaterialSlots(int32 slotsCount)
|
||||||
{
|
{
|
||||||
|
PROFILE_MEM(GraphicsMeshes);
|
||||||
ModelBase::SetupMaterialSlots(slotsCount);
|
ModelBase::SetupMaterialSlots(slotsCount);
|
||||||
|
|
||||||
// Adjust meshes indices for slots
|
// Adjust meshes indices for slots
|
||||||
@@ -584,6 +588,8 @@ int32 Model::GetAllocatedResidency() const
|
|||||||
|
|
||||||
Asset::LoadResult Model::load()
|
Asset::LoadResult Model::load()
|
||||||
{
|
{
|
||||||
|
PROFILE_MEM(GraphicsMeshes);
|
||||||
|
|
||||||
// Get header chunk
|
// Get header chunk
|
||||||
auto chunk0 = GetChunk(0);
|
auto chunk0 = GetChunk(0);
|
||||||
if (chunk0 == nullptr || chunk0->IsMissing())
|
if (chunk0 == nullptr || chunk0->IsMissing())
|
||||||
@@ -613,7 +619,7 @@ Asset::LoadResult Model::load()
|
|||||||
{
|
{
|
||||||
String name;
|
String name;
|
||||||
#if !BUILD_RELEASE
|
#if !BUILD_RELEASE
|
||||||
name = GetPath() + TEXT(".SDF");
|
name = String(GetPath()) + TEXT(".SDF");
|
||||||
#endif
|
#endif
|
||||||
SDF.Texture = GPUDevice::Instance->CreateTexture(name);
|
SDF.Texture = GPUDevice::Instance->CreateTexture(name);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -5,10 +5,12 @@
|
|||||||
#include "Engine/Core/Math/Transform.h"
|
#include "Engine/Core/Math/Transform.h"
|
||||||
#include "Engine/Content/WeakAssetReference.h"
|
#include "Engine/Content/WeakAssetReference.h"
|
||||||
#include "Engine/Serialization/MemoryReadStream.h"
|
#include "Engine/Serialization/MemoryReadStream.h"
|
||||||
|
#include "Engine/Profiler/ProfilerMemory.h"
|
||||||
#include "Engine/Graphics/Config.h"
|
#include "Engine/Graphics/Config.h"
|
||||||
#include "Engine/Graphics/Models/MeshBase.h"
|
#include "Engine/Graphics/Models/MeshBase.h"
|
||||||
#include "Engine/Graphics/Models/MeshDeformation.h"
|
#include "Engine/Graphics/Models/MeshDeformation.h"
|
||||||
#include "Engine/Graphics/Shaders/GPUVertexLayout.h"
|
#include "Engine/Graphics/Shaders/GPUVertexLayout.h"
|
||||||
|
#include "Engine/Threading/Threading.h"
|
||||||
#if GPU_ENABLE_ASYNC_RESOURCES_CREATION
|
#if GPU_ENABLE_ASYNC_RESOURCES_CREATION
|
||||||
#include "Engine/Threading/ThreadPoolTask.h"
|
#include "Engine/Threading/ThreadPoolTask.h"
|
||||||
#define STREAM_TASK_BASE ThreadPoolTask
|
#define STREAM_TASK_BASE ThreadPoolTask
|
||||||
@@ -51,6 +53,7 @@ public:
|
|||||||
AssetReference<ModelBase> model = _model.Get();
|
AssetReference<ModelBase> model = _model.Get();
|
||||||
if (model == nullptr)
|
if (model == nullptr)
|
||||||
return true;
|
return true;
|
||||||
|
PROFILE_MEM(GraphicsMeshes);
|
||||||
|
|
||||||
// Get data
|
// Get data
|
||||||
BytesContainer data;
|
BytesContainer data;
|
||||||
@@ -334,6 +337,8 @@ bool ModelBase::LoadHeader(ReadStream& stream, byte& headerVersion)
|
|||||||
|
|
||||||
bool ModelBase::LoadMesh(MemoryReadStream& stream, byte meshVersion, MeshBase* mesh, MeshData* dataIfReadOnly)
|
bool ModelBase::LoadMesh(MemoryReadStream& stream, byte meshVersion, MeshBase* mesh, MeshData* dataIfReadOnly)
|
||||||
{
|
{
|
||||||
|
PROFILE_MEM(GraphicsMeshes);
|
||||||
|
|
||||||
// Load descriptor
|
// Load descriptor
|
||||||
static_assert(MODEL_MESH_VERSION == 2, "Update code");
|
static_assert(MODEL_MESH_VERSION == 2, "Update code");
|
||||||
uint32 vertices, triangles;
|
uint32 vertices, triangles;
|
||||||
|
|||||||
@@ -4,6 +4,10 @@
|
|||||||
#include "Engine/Core/Log.h"
|
#include "Engine/Core/Log.h"
|
||||||
#include "Engine/Graphics/GPUDevice.h"
|
#include "Engine/Graphics/GPUDevice.h"
|
||||||
#include "Engine/Graphics/Shaders/GPUShader.h"
|
#include "Engine/Graphics/Shaders/GPUShader.h"
|
||||||
|
#if GPU_ENABLE_RESOURCE_NAMING && !USE_EDITOR
|
||||||
|
#include "Engine/Content/Content.h"
|
||||||
|
#include "Engine/Content/Cache/AssetsCache.h"
|
||||||
|
#endif
|
||||||
#include "Engine/Content/Upgraders/ShaderAssetUpgrader.h"
|
#include "Engine/Content/Upgraders/ShaderAssetUpgrader.h"
|
||||||
#include "Engine/Content/Factories/BinaryAssetFactory.h"
|
#include "Engine/Content/Factories/BinaryAssetFactory.h"
|
||||||
#include "Engine/Serialization/MemoryReadStream.h"
|
#include "Engine/Serialization/MemoryReadStream.h"
|
||||||
@@ -14,7 +18,11 @@ Shader::Shader(const SpawnParams& params, const AssetInfo* info)
|
|||||||
: ShaderAssetTypeBase<BinaryAsset>(params, info)
|
: ShaderAssetTypeBase<BinaryAsset>(params, info)
|
||||||
{
|
{
|
||||||
ASSERT(GPUDevice::Instance);
|
ASSERT(GPUDevice::Instance);
|
||||||
_shader = GPUDevice::Instance->CreateShader(info->Path);
|
StringView name = info->Path;
|
||||||
|
#if GPU_ENABLE_RESOURCE_NAMING && !USE_EDITOR
|
||||||
|
name = Content::GetRegistry()->GetEditorAssetPath(info->ID);
|
||||||
|
#endif
|
||||||
|
_shader = GPUDevice::Instance->CreateShader(name);
|
||||||
ASSERT(_shader);
|
ASSERT(_shader);
|
||||||
GPU = _shader;
|
GPU = _shader;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -6,6 +6,7 @@
|
|||||||
#include "Engine/Serialization/MemoryWriteStream.h"
|
#include "Engine/Serialization/MemoryWriteStream.h"
|
||||||
#include "Engine/Content/Factories/BinaryAssetFactory.h"
|
#include "Engine/Content/Factories/BinaryAssetFactory.h"
|
||||||
#include "Engine/Content/Upgraders/SkeletonMaskUpgrader.h"
|
#include "Engine/Content/Upgraders/SkeletonMaskUpgrader.h"
|
||||||
|
#include "Engine/Threading/Threading.h"
|
||||||
|
|
||||||
REGISTER_BINARY_ASSET_WITH_UPGRADER(SkeletonMask, "FlaxEngine.SkeletonMask", SkeletonMaskUpgrader, true);
|
REGISTER_BINARY_ASSET_WITH_UPGRADER(SkeletonMask, "FlaxEngine.SkeletonMask", SkeletonMaskUpgrader, true);
|
||||||
|
|
||||||
|
|||||||
@@ -18,6 +18,7 @@
|
|||||||
#include "Engine/Content/Upgraders/SkinnedModelAssetUpgrader.h"
|
#include "Engine/Content/Upgraders/SkinnedModelAssetUpgrader.h"
|
||||||
#include "Engine/Debug/Exceptions/ArgumentOutOfRangeException.h"
|
#include "Engine/Debug/Exceptions/ArgumentOutOfRangeException.h"
|
||||||
#include "Engine/Profiler/ProfilerCPU.h"
|
#include "Engine/Profiler/ProfilerCPU.h"
|
||||||
|
#include "Engine/Profiler/ProfilerMemory.h"
|
||||||
#include "Engine/Renderer/DrawCall.h"
|
#include "Engine/Renderer/DrawCall.h"
|
||||||
#if USE_EDITOR
|
#if USE_EDITOR
|
||||||
#include "Engine/Graphics/Models/ModelData.h"
|
#include "Engine/Graphics/Models/ModelData.h"
|
||||||
@@ -458,6 +459,7 @@ bool SkinnedModel::Init(const Span<int32>& meshesCountPerLod)
|
|||||||
Log::ArgumentOutOfRangeException();
|
Log::ArgumentOutOfRangeException();
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
PROFILE_MEM(GraphicsMeshes);
|
||||||
|
|
||||||
// Dispose previous data and disable streaming (will start data uploading tasks manually)
|
// Dispose previous data and disable streaming (will start data uploading tasks manually)
|
||||||
StopStreaming();
|
StopStreaming();
|
||||||
@@ -501,6 +503,7 @@ void BlendShape::LoadHeader(ReadStream& stream, byte headerVersion)
|
|||||||
|
|
||||||
void BlendShape::Load(ReadStream& stream, byte meshVersion)
|
void BlendShape::Load(ReadStream& stream, byte meshVersion)
|
||||||
{
|
{
|
||||||
|
PROFILE_MEM(GraphicsMeshes);
|
||||||
UseNormals = stream.ReadBool();
|
UseNormals = stream.ReadBool();
|
||||||
stream.ReadUint32(&MinVertexIndex);
|
stream.ReadUint32(&MinVertexIndex);
|
||||||
stream.ReadUint32(&MaxVertexIndex);
|
stream.ReadUint32(&MaxVertexIndex);
|
||||||
@@ -531,6 +534,7 @@ void BlendShape::Save(WriteStream& stream) const
|
|||||||
|
|
||||||
bool SkinnedModel::LoadMesh(MemoryReadStream& stream, byte meshVersion, MeshBase* mesh, MeshData* dataIfReadOnly)
|
bool SkinnedModel::LoadMesh(MemoryReadStream& stream, byte meshVersion, MeshBase* mesh, MeshData* dataIfReadOnly)
|
||||||
{
|
{
|
||||||
|
PROFILE_MEM(GraphicsMeshes);
|
||||||
if (ModelBase::LoadMesh(stream, meshVersion, mesh, dataIfReadOnly))
|
if (ModelBase::LoadMesh(stream, meshVersion, mesh, dataIfReadOnly))
|
||||||
return true;
|
return true;
|
||||||
static_assert(MODEL_MESH_VERSION == 2, "Update code");
|
static_assert(MODEL_MESH_VERSION == 2, "Update code");
|
||||||
@@ -560,6 +564,7 @@ bool SkinnedModel::LoadMesh(MemoryReadStream& stream, byte meshVersion, MeshBase
|
|||||||
|
|
||||||
bool SkinnedModel::LoadHeader(ReadStream& stream, byte& headerVersion)
|
bool SkinnedModel::LoadHeader(ReadStream& stream, byte& headerVersion)
|
||||||
{
|
{
|
||||||
|
PROFILE_MEM(GraphicsMeshes);
|
||||||
if (ModelBase::LoadHeader(stream, headerVersion))
|
if (ModelBase::LoadHeader(stream, headerVersion))
|
||||||
return true;
|
return true;
|
||||||
static_assert(MODEL_HEADER_VERSION == 2, "Update code");
|
static_assert(MODEL_HEADER_VERSION == 2, "Update code");
|
||||||
@@ -861,6 +866,7 @@ uint64 SkinnedModel::GetMemoryUsage() const
|
|||||||
|
|
||||||
void SkinnedModel::SetupMaterialSlots(int32 slotsCount)
|
void SkinnedModel::SetupMaterialSlots(int32 slotsCount)
|
||||||
{
|
{
|
||||||
|
PROFILE_MEM(GraphicsMeshes);
|
||||||
ModelBase::SetupMaterialSlots(slotsCount);
|
ModelBase::SetupMaterialSlots(slotsCount);
|
||||||
|
|
||||||
// Adjust meshes indices for slots
|
// Adjust meshes indices for slots
|
||||||
@@ -954,6 +960,7 @@ Asset::LoadResult SkinnedModel::load()
|
|||||||
if (chunk0 == nullptr || chunk0->IsMissing())
|
if (chunk0 == nullptr || chunk0->IsMissing())
|
||||||
return LoadResult::MissingDataChunk;
|
return LoadResult::MissingDataChunk;
|
||||||
MemoryReadStream headerStream(chunk0->Get(), chunk0->Size());
|
MemoryReadStream headerStream(chunk0->Get(), chunk0->Size());
|
||||||
|
PROFILE_MEM(GraphicsMeshes);
|
||||||
|
|
||||||
// Load asset data (anything but mesh contents that use streaming)
|
// Load asset data (anything but mesh contents that use streaming)
|
||||||
byte headerVersion;
|
byte headerVersion;
|
||||||
|
|||||||
@@ -18,6 +18,7 @@
|
|||||||
#include "Engine/Serialization/Serialization.h"
|
#include "Engine/Serialization/Serialization.h"
|
||||||
#include "Engine/Serialization/JsonWriter.h"
|
#include "Engine/Serialization/JsonWriter.h"
|
||||||
#include "Engine/Profiler/ProfilerCPU.h"
|
#include "Engine/Profiler/ProfilerCPU.h"
|
||||||
|
#include "Engine/Profiler/ProfilerMemory.h"
|
||||||
#include "Engine/Utilities/StringConverter.h"
|
#include "Engine/Utilities/StringConverter.h"
|
||||||
#include "Engine/Threading/MainThreadTask.h"
|
#include "Engine/Threading/MainThreadTask.h"
|
||||||
#include "Engine/Level/SceneObject.h"
|
#include "Engine/Level/SceneObject.h"
|
||||||
@@ -37,10 +38,12 @@ namespace
|
|||||||
|
|
||||||
void PrintStack(LogType type)
|
void PrintStack(LogType type)
|
||||||
{
|
{
|
||||||
|
#if LOG_ENABLE
|
||||||
const String stack = VisualScripting::GetStackTrace();
|
const String stack = VisualScripting::GetStackTrace();
|
||||||
Log::Logger::Write(type, TEXT("Visual Script stack trace:"));
|
Log::Logger::Write(type, TEXT("Visual Script stack trace:"));
|
||||||
Log::Logger::Write(type, stack);
|
Log::Logger::Write(type, stack);
|
||||||
Log::Logger::Write(type, TEXT(""));
|
Log::Logger::Write(type, TEXT(""));
|
||||||
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
bool SerializeValue(const Variant& a, const Variant& b)
|
bool SerializeValue(const Variant& a, const Variant& b)
|
||||||
@@ -1340,6 +1343,8 @@ bool VisualScript::Save(const StringView& path)
|
|||||||
|
|
||||||
Asset::LoadResult VisualScript::load()
|
Asset::LoadResult VisualScript::load()
|
||||||
{
|
{
|
||||||
|
PROFILE_MEM(ScriptingVisual);
|
||||||
|
|
||||||
// Build Visual Script typename that is based on asset id
|
// Build Visual Script typename that is based on asset id
|
||||||
String typeName = _id.ToString();
|
String typeName = _id.ToString();
|
||||||
StringUtils::ConvertUTF162ANSI(typeName.Get(), _typenameChars, 32);
|
StringUtils::ConvertUTF162ANSI(typeName.Get(), _typenameChars, 32);
|
||||||
@@ -1532,6 +1537,7 @@ Asset::LoadResult VisualScript::load()
|
|||||||
|
|
||||||
void VisualScript::unload(bool isReloading)
|
void VisualScript::unload(bool isReloading)
|
||||||
{
|
{
|
||||||
|
PROFILE_MEM(ScriptingVisual);
|
||||||
#if USE_EDITOR
|
#if USE_EDITOR
|
||||||
if (isReloading)
|
if (isReloading)
|
||||||
{
|
{
|
||||||
@@ -1588,6 +1594,7 @@ AssetChunksFlag VisualScript::getChunksToPreload() const
|
|||||||
|
|
||||||
void VisualScript::CacheScriptingType()
|
void VisualScript::CacheScriptingType()
|
||||||
{
|
{
|
||||||
|
PROFILE_MEM(ScriptingVisual);
|
||||||
ScopeLock lock(VisualScriptingBinaryModule::Locker);
|
ScopeLock lock(VisualScriptingBinaryModule::Locker);
|
||||||
auto& binaryModule = VisualScriptingModule;
|
auto& binaryModule = VisualScriptingModule;
|
||||||
|
|
||||||
@@ -1723,6 +1730,7 @@ ScriptingObject* VisualScriptingBinaryModule::VisualScriptObjectSpawn(const Scri
|
|||||||
VisualScript* visualScript = VisualScriptingModule.Scripts[params.Type.TypeIndex];
|
VisualScript* visualScript = VisualScriptingModule.Scripts[params.Type.TypeIndex];
|
||||||
|
|
||||||
// Initialize instance data
|
// Initialize instance data
|
||||||
|
PROFILE_MEM(ScriptingVisual);
|
||||||
ScopeLock lock(visualScript->Locker);
|
ScopeLock lock(visualScript->Locker);
|
||||||
auto& instanceParams = visualScript->_instances[object->GetID()].Params;
|
auto& instanceParams = visualScript->_instances[object->GetID()].Params;
|
||||||
instanceParams.Resize(visualScript->Graph.Parameters.Count());
|
instanceParams.Resize(visualScript->Graph.Parameters.Count());
|
||||||
@@ -1747,6 +1755,8 @@ ScriptingObject* VisualScriptingBinaryModule::VisualScriptObjectSpawn(const Scri
|
|||||||
|
|
||||||
void VisualScriptingBinaryModule::OnScriptsReloading()
|
void VisualScriptingBinaryModule::OnScriptsReloading()
|
||||||
{
|
{
|
||||||
|
PROFILE_MEM(ScriptingVisual);
|
||||||
|
|
||||||
// Clear any cached types from that module across all loaded Visual Scripts
|
// Clear any cached types from that module across all loaded Visual Scripts
|
||||||
for (auto& script : Scripts)
|
for (auto& script : Scripts)
|
||||||
{
|
{
|
||||||
@@ -1795,6 +1805,7 @@ void VisualScriptingBinaryModule::OnScriptsReloading()
|
|||||||
|
|
||||||
void VisualScriptingBinaryModule::OnEvent(ScriptingObject* object, Span<Variant> parameters, ScriptingTypeHandle eventType, StringView eventName)
|
void VisualScriptingBinaryModule::OnEvent(ScriptingObject* object, Span<Variant> parameters, ScriptingTypeHandle eventType, StringView eventName)
|
||||||
{
|
{
|
||||||
|
PROFILE_MEM(ScriptingVisual);
|
||||||
if (object)
|
if (object)
|
||||||
{
|
{
|
||||||
// Object event
|
// Object event
|
||||||
@@ -1900,9 +1911,13 @@ bool VisualScriptingBinaryModule::InvokeMethod(void* method, const Variant& inst
|
|||||||
if (!instanceObject || instanceObject->GetTypeHandle() != vsMethod->Script->GetScriptingType())
|
if (!instanceObject || instanceObject->GetTypeHandle() != vsMethod->Script->GetScriptingType())
|
||||||
{
|
{
|
||||||
if (!instanceObject)
|
if (!instanceObject)
|
||||||
|
{
|
||||||
LOG(Error, "Failed to call method '{0}.{1}' (args count: {2}) without object instance", String(vsMethod->Script->GetScriptTypeName()), String(vsMethod->Name), vsMethod->ParamNames.Count());
|
LOG(Error, "Failed to call method '{0}.{1}' (args count: {2}) without object instance", String(vsMethod->Script->GetScriptTypeName()), String(vsMethod->Name), vsMethod->ParamNames.Count());
|
||||||
|
}
|
||||||
else
|
else
|
||||||
|
{
|
||||||
LOG(Error, "Failed to call method '{0}.{1}' (args count: {2}) with invalid object instance of type '{3}'", String(vsMethod->Script->GetScriptTypeName()), String(vsMethod->Name), vsMethod->ParamNames.Count(), String(instanceObject->GetType().Fullname));
|
LOG(Error, "Failed to call method '{0}.{1}' (args count: {2}) with invalid object instance of type '{3}'", String(vsMethod->Script->GetScriptTypeName()), String(vsMethod->Name), vsMethod->ParamNames.Count(), String(instanceObject->GetType().Fullname));
|
||||||
|
}
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -1952,6 +1967,7 @@ bool VisualScriptingBinaryModule::GetFieldValue(void* field, const Variant& inst
|
|||||||
|
|
||||||
bool VisualScriptingBinaryModule::SetFieldValue(void* field, const Variant& instance, Variant& value)
|
bool VisualScriptingBinaryModule::SetFieldValue(void* field, const Variant& instance, Variant& value)
|
||||||
{
|
{
|
||||||
|
PROFILE_MEM(ScriptingVisual);
|
||||||
const auto vsFiled = (VisualScript::Field*)field;
|
const auto vsFiled = (VisualScript::Field*)field;
|
||||||
const auto instanceObject = (ScriptingObject*)instance;
|
const auto instanceObject = (ScriptingObject*)instance;
|
||||||
if (!instanceObject)
|
if (!instanceObject)
|
||||||
@@ -2038,6 +2054,7 @@ void VisualScriptingBinaryModule::SerializeObject(JsonWriter& stream, ScriptingO
|
|||||||
|
|
||||||
void VisualScriptingBinaryModule::DeserializeObject(ISerializable::DeserializeStream& stream, ScriptingObject* object, ISerializeModifier* modifier)
|
void VisualScriptingBinaryModule::DeserializeObject(ISerializable::DeserializeStream& stream, ScriptingObject* object, ISerializeModifier* modifier)
|
||||||
{
|
{
|
||||||
|
PROFILE_MEM(ScriptingVisual);
|
||||||
ASSERT(stream.IsObject());
|
ASSERT(stream.IsObject());
|
||||||
Locker.Lock();
|
Locker.Lock();
|
||||||
const auto asset = Scripts[object->GetTypeHandle().TypeIndex].Get();
|
const auto asset = Scripts[object->GetTypeHandle().TypeIndex].Get();
|
||||||
@@ -2161,6 +2178,7 @@ const Variant& VisualScript::GetScriptInstanceParameterValue(const StringView& n
|
|||||||
|
|
||||||
void VisualScript::SetScriptInstanceParameterValue(const StringView& name, ScriptingObject* instance, const Variant& value)
|
void VisualScript::SetScriptInstanceParameterValue(const StringView& name, ScriptingObject* instance, const Variant& value)
|
||||||
{
|
{
|
||||||
|
PROFILE_MEM(ScriptingVisual);
|
||||||
CHECK(instance);
|
CHECK(instance);
|
||||||
for (int32 paramIndex = 0; paramIndex < Graph.Parameters.Count(); paramIndex++)
|
for (int32 paramIndex = 0; paramIndex < Graph.Parameters.Count(); paramIndex++)
|
||||||
{
|
{
|
||||||
@@ -2182,6 +2200,7 @@ void VisualScript::SetScriptInstanceParameterValue(const StringView& name, Scrip
|
|||||||
|
|
||||||
void VisualScript::SetScriptInstanceParameterValue(const StringView& name, ScriptingObject* instance, Variant&& value)
|
void VisualScript::SetScriptInstanceParameterValue(const StringView& name, ScriptingObject* instance, Variant&& value)
|
||||||
{
|
{
|
||||||
|
PROFILE_MEM(ScriptingVisual);
|
||||||
CHECK(instance);
|
CHECK(instance);
|
||||||
for (int32 paramIndex = 0; paramIndex < Graph.Parameters.Count(); paramIndex++)
|
for (int32 paramIndex = 0; paramIndex < Graph.Parameters.Count(); paramIndex++)
|
||||||
{
|
{
|
||||||
@@ -2379,6 +2398,7 @@ VisualScriptingBinaryModule* VisualScripting::GetBinaryModule()
|
|||||||
|
|
||||||
Variant VisualScripting::Invoke(VisualScript::Method* method, ScriptingObject* instance, Span<Variant> parameters)
|
Variant VisualScripting::Invoke(VisualScript::Method* method, ScriptingObject* instance, Span<Variant> parameters)
|
||||||
{
|
{
|
||||||
|
PROFILE_MEM(ScriptingVisual);
|
||||||
CHECK_RETURN(method && method->Script->IsLoaded(), Variant::Zero);
|
CHECK_RETURN(method && method->Script->IsLoaded(), Variant::Zero);
|
||||||
PROFILE_CPU_SRC_LOC(method->ProfilerData);
|
PROFILE_CPU_SRC_LOC(method->ProfilerData);
|
||||||
|
|
||||||
@@ -2419,6 +2439,7 @@ bool VisualScripting::Evaluate(VisualScript* script, ScriptingObject* instance,
|
|||||||
const auto box = node->GetBox(boxId);
|
const auto box = node->GetBox(boxId);
|
||||||
if (!box)
|
if (!box)
|
||||||
return false;
|
return false;
|
||||||
|
PROFILE_MEM(ScriptingVisual);
|
||||||
|
|
||||||
// Add to the calling stack
|
// Add to the calling stack
|
||||||
ScopeContext scope;
|
ScopeContext scope;
|
||||||
|
|||||||
@@ -10,6 +10,7 @@
|
|||||||
#include "Engine/Serialization/JsonTools.h"
|
#include "Engine/Serialization/JsonTools.h"
|
||||||
#include "Engine/Debug/Exceptions/JsonParseException.h"
|
#include "Engine/Debug/Exceptions/JsonParseException.h"
|
||||||
#include "Engine/Threading/ThreadPoolTask.h"
|
#include "Engine/Threading/ThreadPoolTask.h"
|
||||||
|
#include "Engine/Profiler/ProfilerMemory.h"
|
||||||
#if USE_EDITOR
|
#if USE_EDITOR
|
||||||
#include "Engine/Platform/FileSystem.h"
|
#include "Engine/Platform/FileSystem.h"
|
||||||
#include "Engine/Threading/Threading.h"
|
#include "Engine/Threading/Threading.h"
|
||||||
@@ -463,10 +464,10 @@ void BinaryAsset::OnDeleteObject()
|
|||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
const String& BinaryAsset::GetPath() const
|
StringView BinaryAsset::GetPath() const
|
||||||
{
|
{
|
||||||
#if USE_EDITOR
|
#if USE_EDITOR
|
||||||
return Storage ? Storage->GetPath() : String::Empty;
|
return Storage ? StringView(Storage->GetPath()) : StringView::Empty;
|
||||||
#else
|
#else
|
||||||
// In build all assets are packed into packages so use ID for original path lookup
|
// In build all assets are packed into packages so use ID for original path lookup
|
||||||
return Content::GetRegistry()->GetEditorAssetPath(_id);
|
return Content::GetRegistry()->GetEditorAssetPath(_id);
|
||||||
@@ -527,6 +528,7 @@ protected:
|
|||||||
auto storage = ref->Storage;
|
auto storage = ref->Storage;
|
||||||
auto factory = (BinaryAssetFactoryBase*)Content::GetAssetFactory(ref->GetTypeName());
|
auto factory = (BinaryAssetFactoryBase*)Content::GetAssetFactory(ref->GetTypeName());
|
||||||
ASSERT(factory);
|
ASSERT(factory);
|
||||||
|
PROFILE_MEM(ContentAssets);
|
||||||
|
|
||||||
// Here we should open storage and extract AssetInitData
|
// Here we should open storage and extract AssetInitData
|
||||||
// This would also allow to convert/upgrade data
|
// This would also allow to convert/upgrade data
|
||||||
|
|||||||
@@ -292,7 +292,7 @@ public:
|
|||||||
#if USE_EDITOR
|
#if USE_EDITOR
|
||||||
void OnDeleteObject() override;
|
void OnDeleteObject() override;
|
||||||
#endif
|
#endif
|
||||||
const String& GetPath() const final override;
|
StringView GetPath() const final override;
|
||||||
uint64 GetMemoryUsage() const override;
|
uint64 GetMemoryUsage() const override;
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
|
|||||||
@@ -10,15 +10,28 @@
|
|||||||
#include "Engine/Serialization/FileWriteStream.h"
|
#include "Engine/Serialization/FileWriteStream.h"
|
||||||
#include "Engine/Serialization/FileReadStream.h"
|
#include "Engine/Serialization/FileReadStream.h"
|
||||||
#include "Engine/Content/Content.h"
|
#include "Engine/Content/Content.h"
|
||||||
#include "Engine/Content/Storage/ContentStorageManager.h"
|
|
||||||
#include "Engine/Content/Storage/JsonStorageProxy.h"
|
|
||||||
#include "Engine/Profiler/ProfilerCPU.h"
|
#include "Engine/Profiler/ProfilerCPU.h"
|
||||||
#include "Engine/Threading/Threading.h"
|
|
||||||
#include "Engine/Engine/Globals.h"
|
#include "Engine/Engine/Globals.h"
|
||||||
#include "FlaxEngine.Gen.h"
|
#include "FlaxEngine.Gen.h"
|
||||||
|
#if ASSETS_CACHE_EDITABLE
|
||||||
|
#include "Engine/Content/Storage/ContentStorageManager.h"
|
||||||
|
#include "Engine/Content/Storage/JsonStorageProxy.h"
|
||||||
|
#include "Engine/Threading/Threading.h"
|
||||||
|
#define ASSETS_CACHE_LOCK() ScopeLock lock(_locker)
|
||||||
|
#else
|
||||||
|
#define ASSETS_CACHE_LOCK()
|
||||||
|
#endif
|
||||||
|
|
||||||
|
int32 AssetsCache::Size() const
|
||||||
|
{
|
||||||
|
ASSETS_CACHE_LOCK();
|
||||||
|
const int32 result = _registry.Count();
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
void AssetsCache::Init()
|
void AssetsCache::Init()
|
||||||
{
|
{
|
||||||
|
PROFILE_CPU();
|
||||||
Entry e;
|
Entry e;
|
||||||
int32 count;
|
int32 count;
|
||||||
Stopwatch stopwatch;
|
Stopwatch stopwatch;
|
||||||
@@ -71,7 +84,7 @@ void AssetsCache::Init()
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
ScopeLock lock(_locker);
|
ASSETS_CACHE_LOCK();
|
||||||
_isDirty = false;
|
_isDirty = false;
|
||||||
|
|
||||||
// Load elements count
|
// Load elements count
|
||||||
@@ -126,6 +139,16 @@ void AssetsCache::Init()
|
|||||||
_pathsMapping.Add(mappedPath, id);
|
_pathsMapping.Add(mappedPath, id);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#if !USE_EDITOR && !BUILD_RELEASE
|
||||||
|
// Build inverse path mapping in development builds for faster GetEditorAssetPath (eg. used by PROFILE_CPU_ASSET)
|
||||||
|
_pathsMappingInv.Clear();
|
||||||
|
_pathsMappingInv.EnsureCapacity(count);
|
||||||
|
for (auto& mapping : _pathsMapping)
|
||||||
|
{
|
||||||
|
_pathsMappingInv.Add(mapping.Value, StringView(mapping.Key));
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
// Check errors
|
// Check errors
|
||||||
const bool hasError = stream->HasError();
|
const bool hasError = stream->HasError();
|
||||||
deleteStream.Delete();
|
deleteStream.Delete();
|
||||||
@@ -153,7 +176,7 @@ bool AssetsCache::Save()
|
|||||||
if (!_isDirty && FileSystem::FileExists(_path))
|
if (!_isDirty && FileSystem::FileExists(_path))
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
ScopeLock lock(_locker);
|
ASSETS_CACHE_LOCK();
|
||||||
|
|
||||||
if (Save(_path, _registry, _pathsMapping))
|
if (Save(_path, _registry, _pathsMapping))
|
||||||
return true;
|
return true;
|
||||||
@@ -222,12 +245,16 @@ bool AssetsCache::Save(const StringView& path, const Registry& entries, const Pa
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
const String& AssetsCache::GetEditorAssetPath(const Guid& id) const
|
StringView AssetsCache::GetEditorAssetPath(const Guid& id) const
|
||||||
{
|
{
|
||||||
ScopeLock lock(_locker);
|
ASSETS_CACHE_LOCK();
|
||||||
#if USE_EDITOR
|
#if USE_EDITOR
|
||||||
auto e = _registry.TryGet(id);
|
auto e = _registry.TryGet(id);
|
||||||
return e ? e->Info.Path : String::Empty;
|
return e ? e->Info.Path : String::Empty;
|
||||||
|
#elif !BUILD_RELEASE
|
||||||
|
StringView result;
|
||||||
|
_pathsMappingInv.TryGet(id, result);
|
||||||
|
return result;
|
||||||
#else
|
#else
|
||||||
for (auto& e : _pathsMapping)
|
for (auto& e : _pathsMapping)
|
||||||
{
|
{
|
||||||
@@ -241,10 +268,8 @@ const String& AssetsCache::GetEditorAssetPath(const Guid& id) const
|
|||||||
bool AssetsCache::FindAsset(const StringView& path, AssetInfo& info)
|
bool AssetsCache::FindAsset(const StringView& path, AssetInfo& info)
|
||||||
{
|
{
|
||||||
PROFILE_CPU();
|
PROFILE_CPU();
|
||||||
|
|
||||||
bool result = false;
|
bool result = false;
|
||||||
|
ASSETS_CACHE_LOCK();
|
||||||
ScopeLock lock(_locker);
|
|
||||||
|
|
||||||
// Check if asset has direct mapping to id (used for some cooked assets)
|
// Check if asset has direct mapping to id (used for some cooked assets)
|
||||||
Guid id;
|
Guid id;
|
||||||
@@ -293,7 +318,7 @@ bool AssetsCache::FindAsset(const Guid& id, AssetInfo& info)
|
|||||||
{
|
{
|
||||||
PROFILE_CPU();
|
PROFILE_CPU();
|
||||||
bool result = false;
|
bool result = false;
|
||||||
ScopeLock lock(_locker);
|
ASSETS_CACHE_LOCK();
|
||||||
auto e = _registry.TryGet(id);
|
auto e = _registry.TryGet(id);
|
||||||
if (e != nullptr)
|
if (e != nullptr)
|
||||||
{
|
{
|
||||||
@@ -315,14 +340,14 @@ bool AssetsCache::FindAsset(const Guid& id, AssetInfo& info)
|
|||||||
void AssetsCache::GetAll(Array<Guid>& result) const
|
void AssetsCache::GetAll(Array<Guid>& result) const
|
||||||
{
|
{
|
||||||
PROFILE_CPU();
|
PROFILE_CPU();
|
||||||
ScopeLock lock(_locker);
|
ASSETS_CACHE_LOCK();
|
||||||
_registry.GetKeys(result);
|
_registry.GetKeys(result);
|
||||||
}
|
}
|
||||||
|
|
||||||
void AssetsCache::GetAllByTypeName(const StringView& typeName, Array<Guid>& result) const
|
void AssetsCache::GetAllByTypeName(const StringView& typeName, Array<Guid>& result) const
|
||||||
{
|
{
|
||||||
PROFILE_CPU();
|
PROFILE_CPU();
|
||||||
ScopeLock lock(_locker);
|
ASSETS_CACHE_LOCK();
|
||||||
for (auto i = _registry.Begin(); i.IsNotEnd(); ++i)
|
for (auto i = _registry.Begin(); i.IsNotEnd(); ++i)
|
||||||
{
|
{
|
||||||
if (i->Value.Info.TypeName == typeName)
|
if (i->Value.Info.TypeName == typeName)
|
||||||
@@ -330,6 +355,8 @@ void AssetsCache::GetAllByTypeName(const StringView& typeName, Array<Guid>& resu
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#if ASSETS_CACHE_EDITABLE
|
||||||
|
|
||||||
void AssetsCache::RegisterAssets(FlaxStorage* storage)
|
void AssetsCache::RegisterAssets(FlaxStorage* storage)
|
||||||
{
|
{
|
||||||
PROFILE_CPU();
|
PROFILE_CPU();
|
||||||
@@ -341,7 +368,7 @@ void AssetsCache::RegisterAssets(FlaxStorage* storage)
|
|||||||
storage->GetEntries(entries);
|
storage->GetEntries(entries);
|
||||||
ASSERT(entries.HasItems());
|
ASSERT(entries.HasItems());
|
||||||
|
|
||||||
ScopeLock lock(_locker);
|
ASSETS_CACHE_LOCK();
|
||||||
auto storagePath = storage->GetPath();
|
auto storagePath = storage->GetPath();
|
||||||
|
|
||||||
// Remove all old entries from that location
|
// Remove all old entries from that location
|
||||||
@@ -439,7 +466,7 @@ void AssetsCache::RegisterAssets(const FlaxStorageReference& storage)
|
|||||||
void AssetsCache::RegisterAsset(const Guid& id, const String& typeName, const StringView& path)
|
void AssetsCache::RegisterAsset(const Guid& id, const String& typeName, const StringView& path)
|
||||||
{
|
{
|
||||||
PROFILE_CPU();
|
PROFILE_CPU();
|
||||||
ScopeLock lock(_locker);
|
ASSETS_CACHE_LOCK();
|
||||||
|
|
||||||
// Check if asset has been already added to the registry
|
// Check if asset has been already added to the registry
|
||||||
bool isMissing = true;
|
bool isMissing = true;
|
||||||
@@ -491,8 +518,7 @@ void AssetsCache::RegisterAsset(const Guid& id, const String& typeName, const St
|
|||||||
bool AssetsCache::DeleteAsset(const StringView& path, AssetInfo* info)
|
bool AssetsCache::DeleteAsset(const StringView& path, AssetInfo* info)
|
||||||
{
|
{
|
||||||
bool result = false;
|
bool result = false;
|
||||||
_locker.Lock();
|
ASSETS_CACHE_LOCK();
|
||||||
|
|
||||||
for (auto i = _registry.Begin(); i.IsNotEnd(); ++i)
|
for (auto i = _registry.Begin(); i.IsNotEnd(); ++i)
|
||||||
{
|
{
|
||||||
if (i->Value.Info.Path == path)
|
if (i->Value.Info.Path == path)
|
||||||
@@ -505,16 +531,13 @@ bool AssetsCache::DeleteAsset(const StringView& path, AssetInfo* info)
|
|||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
_locker.Unlock();
|
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool AssetsCache::DeleteAsset(const Guid& id, AssetInfo* info)
|
bool AssetsCache::DeleteAsset(const Guid& id, AssetInfo* info)
|
||||||
{
|
{
|
||||||
bool result = false;
|
bool result = false;
|
||||||
_locker.Lock();
|
ASSETS_CACHE_LOCK();
|
||||||
|
|
||||||
const auto e = _registry.TryGet(id);
|
const auto e = _registry.TryGet(id);
|
||||||
if (e != nullptr)
|
if (e != nullptr)
|
||||||
{
|
{
|
||||||
@@ -524,16 +547,13 @@ bool AssetsCache::DeleteAsset(const Guid& id, AssetInfo* info)
|
|||||||
_isDirty = true;
|
_isDirty = true;
|
||||||
result = true;
|
result = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
_locker.Unlock();
|
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool AssetsCache::RenameAsset(const StringView& oldPath, const StringView& newPath)
|
bool AssetsCache::RenameAsset(const StringView& oldPath, const StringView& newPath)
|
||||||
{
|
{
|
||||||
bool result = false;
|
bool result = false;
|
||||||
_locker.Lock();
|
ASSETS_CACHE_LOCK();
|
||||||
|
|
||||||
for (auto i = _registry.Begin(); i.IsNotEnd(); ++i)
|
for (auto i = _registry.Begin(); i.IsNotEnd(); ++i)
|
||||||
{
|
{
|
||||||
if (i->Value.Info.Path == oldPath)
|
if (i->Value.Info.Path == oldPath)
|
||||||
@@ -544,11 +564,11 @@ bool AssetsCache::RenameAsset(const StringView& oldPath, const StringView& newPa
|
|||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
_locker.Unlock();
|
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#endif
|
||||||
|
|
||||||
bool AssetsCache::IsEntryValid(Entry& e)
|
bool AssetsCache::IsEntryValid(Entry& e)
|
||||||
{
|
{
|
||||||
#if ENABLE_ASSETS_DISCOVERY
|
#if ENABLE_ASSETS_DISCOVERY
|
||||||
|
|||||||
@@ -16,6 +16,9 @@ struct AssetHeader;
|
|||||||
struct FlaxStorageReference;
|
struct FlaxStorageReference;
|
||||||
class FlaxStorage;
|
class FlaxStorage;
|
||||||
|
|
||||||
|
// In cooked game all assets are there and all access to registry is read-only so can be multithreaded
|
||||||
|
#define ASSETS_CACHE_EDITABLE (USE_EDITOR)
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Assets cache flags.
|
/// Assets cache flags.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
@@ -75,22 +78,21 @@ public:
|
|||||||
|
|
||||||
private:
|
private:
|
||||||
bool _isDirty = false;
|
bool _isDirty = false;
|
||||||
|
#if ASSETS_CACHE_EDITABLE
|
||||||
CriticalSection _locker;
|
CriticalSection _locker;
|
||||||
|
#endif
|
||||||
Registry _registry;
|
Registry _registry;
|
||||||
PathsMapping _pathsMapping;
|
PathsMapping _pathsMapping;
|
||||||
|
#if !USE_EDITOR && !BUILD_RELEASE
|
||||||
|
Dictionary<Guid, StringView> _pathsMappingInv;
|
||||||
|
#endif
|
||||||
String _path;
|
String _path;
|
||||||
|
|
||||||
public:
|
public:
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Gets amount of registered assets.
|
/// Gets amount of registered assets.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
int32 Size() const
|
int32 Size() const;
|
||||||
{
|
|
||||||
_locker.Lock();
|
|
||||||
const int32 result = _registry.Count();
|
|
||||||
_locker.Unlock();
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
|
|
||||||
public:
|
public:
|
||||||
/// <summary>
|
/// <summary>
|
||||||
@@ -116,11 +118,11 @@ public:
|
|||||||
|
|
||||||
public:
|
public:
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Finds the asset path by id. In editor it returns the actual asset path, at runtime it returns the mapped asset path.
|
/// Finds the asset path by id. In editor, it returns the actual asset path, at runtime it returns the mapped asset path.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <param name="id">The asset id.</param>
|
/// <param name="id">The asset id.</param>
|
||||||
/// <returns>The asset path, or empty if failed to find.</returns>
|
/// <returns>The asset path, or empty if failed to find.</returns>
|
||||||
const String& GetEditorAssetPath(const Guid& id) const;
|
StringView GetEditorAssetPath(const Guid& id) const;
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Finds the asset info by path.
|
/// Finds the asset info by path.
|
||||||
@@ -173,6 +175,7 @@ public:
|
|||||||
/// <param name="result">The result array.</param>
|
/// <param name="result">The result array.</param>
|
||||||
void GetAllByTypeName(const StringView& typeName, Array<Guid, HeapAllocation>& result) const;
|
void GetAllByTypeName(const StringView& typeName, Array<Guid, HeapAllocation>& result) const;
|
||||||
|
|
||||||
|
#if ASSETS_CACHE_EDITABLE
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Register assets in the cache
|
/// Register assets in the cache
|
||||||
/// </summary>
|
/// </summary>
|
||||||
@@ -223,6 +226,7 @@ public:
|
|||||||
/// <param name="newPath">New path</param>
|
/// <param name="newPath">New path</param>
|
||||||
/// <returns>True if has been deleted, otherwise false</returns>
|
/// <returns>True if has been deleted, otherwise false</returns>
|
||||||
bool RenameAsset(const StringView& oldPath, const StringView& newPath);
|
bool RenameAsset(const StringView& oldPath, const StringView& newPath);
|
||||||
|
#endif
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Determines whether cached asset entry is valid.
|
/// Determines whether cached asset entry is valid.
|
||||||
|
|||||||
@@ -4,8 +4,13 @@
|
|||||||
|
|
||||||
#include "Engine/Core/Config.h"
|
#include "Engine/Core/Config.h"
|
||||||
|
|
||||||
// Amount of content loading threads per single physical CPU core
|
// Amount of content loading threads per single logical CPU core
|
||||||
|
#ifndef LOADING_THREAD_PER_LOGICAL_CORE
|
||||||
#define LOADING_THREAD_PER_LOGICAL_CORE 0.5f
|
#define LOADING_THREAD_PER_LOGICAL_CORE 0.5f
|
||||||
|
#endif
|
||||||
|
|
||||||
|
// Enables pinning loading threads to the logical CPU cores with affinity mask
|
||||||
|
//#define LOADING_THREAD_AFFINITY_MASK(thread) (1 << (thread + 1))
|
||||||
|
|
||||||
// Enables additional assets metadata verification
|
// Enables additional assets metadata verification
|
||||||
#define ASSETS_LOADING_EXTRA_VERIFICATION (BUILD_DEBUG || USE_EDITOR)
|
#define ASSETS_LOADING_EXTRA_VERIFICATION (BUILD_DEBUG || USE_EDITOR)
|
||||||
|
|||||||
@@ -28,6 +28,7 @@
|
|||||||
#include "Engine/Engine/Globals.h"
|
#include "Engine/Engine/Globals.h"
|
||||||
#include "Engine/Level/Types.h"
|
#include "Engine/Level/Types.h"
|
||||||
#include "Engine/Profiler/ProfilerCPU.h"
|
#include "Engine/Profiler/ProfilerCPU.h"
|
||||||
|
#include "Engine/Profiler/ProfilerMemory.h"
|
||||||
#include "Engine/Scripting/ManagedCLR/MClass.h"
|
#include "Engine/Scripting/ManagedCLR/MClass.h"
|
||||||
#include "Engine/Scripting/Scripting.h"
|
#include "Engine/Scripting/Scripting.h"
|
||||||
#if USE_EDITOR
|
#if USE_EDITOR
|
||||||
@@ -117,6 +118,8 @@ ContentService ContentServiceInstance;
|
|||||||
|
|
||||||
bool ContentService::Init()
|
bool ContentService::Init()
|
||||||
{
|
{
|
||||||
|
PROFILE_MEM(Content);
|
||||||
|
|
||||||
// Load assets registry
|
// Load assets registry
|
||||||
Cache.Init();
|
Cache.Init();
|
||||||
|
|
||||||
@@ -126,17 +129,17 @@ bool ContentService::Init()
|
|||||||
LOG(Info, "Creating {0} content loading threads...", count);
|
LOG(Info, "Creating {0} content loading threads...", count);
|
||||||
MainLoadThread = New<LoadingThread>();
|
MainLoadThread = New<LoadingThread>();
|
||||||
ThisLoadThread = MainLoadThread;
|
ThisLoadThread = MainLoadThread;
|
||||||
LoadThreads.EnsureCapacity(count);
|
LoadThreads.Resize(count);
|
||||||
for (int32 i = 0; i < count; i++)
|
for (int32 i = 0; i < count; i++)
|
||||||
{
|
{
|
||||||
auto thread = New<LoadingThread>();
|
auto thread = New<LoadingThread>();
|
||||||
|
LoadThreads[i] = thread;
|
||||||
if (thread->Start(String::Format(TEXT("Load Thread {0}"), i)))
|
if (thread->Start(String::Format(TEXT("Load Thread {0}"), i)))
|
||||||
{
|
{
|
||||||
LOG(Fatal, "Cannot spawn content thread {0}/{1}", i, count);
|
LOG(Fatal, "Cannot spawn content thread {0}/{1}", i, count);
|
||||||
Delete(thread);
|
Delete(thread);
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
LoadThreads.Add(thread);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return false;
|
return false;
|
||||||
@@ -159,6 +162,7 @@ void ContentService::Update()
|
|||||||
void ContentService::LateUpdate()
|
void ContentService::LateUpdate()
|
||||||
{
|
{
|
||||||
PROFILE_CPU();
|
PROFILE_CPU();
|
||||||
|
PROFILE_MEM(Content);
|
||||||
|
|
||||||
// Check if need to perform an update of unloading assets
|
// Check if need to perform an update of unloading assets
|
||||||
const TimeSpan timeNow = Time::Update.UnscaledTime;
|
const TimeSpan timeNow = Time::Update.UnscaledTime;
|
||||||
@@ -324,6 +328,7 @@ String LoadingThread::ToString() const
|
|||||||
|
|
||||||
int32 LoadingThread::Run()
|
int32 LoadingThread::Run()
|
||||||
{
|
{
|
||||||
|
PROFILE_MEM(Content);
|
||||||
#if USE_EDITOR && PLATFORM_WINDOWS
|
#if USE_EDITOR && PLATFORM_WINDOWS
|
||||||
// Initialize COM
|
// Initialize COM
|
||||||
// TODO: maybe add sth to Thread::Create to indicate that thread will use COM stuff
|
// TODO: maybe add sth to Thread::Create to indicate that thread will use COM stuff
|
||||||
@@ -334,6 +339,9 @@ int32 LoadingThread::Run()
|
|||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
#ifdef LOADING_THREAD_AFFINITY_MASK
|
||||||
|
Platform::SetThreadAffinityMask(LOADING_THREAD_AFFINITY_MASK(LoadThreads.Find(this)));
|
||||||
|
#endif
|
||||||
|
|
||||||
ContentLoadTask* task;
|
ContentLoadTask* task;
|
||||||
ThisLoadThread = this;
|
ThisLoadThread = this;
|
||||||
@@ -416,6 +424,7 @@ bool Content::GetAssetInfo(const Guid& id, AssetInfo& info)
|
|||||||
if (Cache.FindAsset(id, info))
|
if (Cache.FindAsset(id, info))
|
||||||
return true;
|
return true;
|
||||||
PROFILE_CPU();
|
PROFILE_CPU();
|
||||||
|
PROFILE_MEM(Content);
|
||||||
|
|
||||||
// Locking injects some stalls but we need to make it safe (only one thread can pass though it at once)
|
// Locking injects some stalls but we need to make it safe (only one thread can pass though it at once)
|
||||||
ScopeLock lock(WorkspaceDiscoveryLocker);
|
ScopeLock lock(WorkspaceDiscoveryLocker);
|
||||||
@@ -465,6 +474,7 @@ bool Content::GetAssetInfo(const StringView& path, AssetInfo& info)
|
|||||||
if (!FileSystem::FileExists(path))
|
if (!FileSystem::FileExists(path))
|
||||||
return false;
|
return false;
|
||||||
PROFILE_CPU();
|
PROFILE_CPU();
|
||||||
|
PROFILE_MEM(Content);
|
||||||
|
|
||||||
const auto extension = FileSystem::GetExtension(path).ToLower();
|
const auto extension = FileSystem::GetExtension(path).ToLower();
|
||||||
|
|
||||||
@@ -511,7 +521,7 @@ bool Content::GetAssetInfo(const StringView& path, AssetInfo& info)
|
|||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
String Content::GetEditorAssetPath(const Guid& id)
|
StringView Content::GetEditorAssetPath(const Guid& id)
|
||||||
{
|
{
|
||||||
return Cache.GetEditorAssetPath(id);
|
return Cache.GetEditorAssetPath(id);
|
||||||
}
|
}
|
||||||
@@ -593,6 +603,7 @@ Asset* Content::LoadAsyncInternal(const StringView& internalPath, const MClass*
|
|||||||
|
|
||||||
Asset* Content::LoadAsyncInternal(const StringView& internalPath, const ScriptingTypeHandle& type)
|
Asset* Content::LoadAsyncInternal(const StringView& internalPath, const ScriptingTypeHandle& type)
|
||||||
{
|
{
|
||||||
|
PROFILE_MEM(Content);
|
||||||
#if USE_EDITOR
|
#if USE_EDITOR
|
||||||
const String path = Globals::EngineContentFolder / internalPath + ASSET_FILES_EXTENSION_WITH_DOT;
|
const String path = Globals::EngineContentFolder / internalPath + ASSET_FILES_EXTENSION_WITH_DOT;
|
||||||
if (!FileSystem::FileExists(path))
|
if (!FileSystem::FileExists(path))
|
||||||
@@ -635,6 +646,8 @@ Asset* Content::LoadAsync(const StringView& path, const MClass* type)
|
|||||||
|
|
||||||
Asset* Content::LoadAsync(const StringView& path, const ScriptingTypeHandle& type)
|
Asset* Content::LoadAsync(const StringView& path, const ScriptingTypeHandle& type)
|
||||||
{
|
{
|
||||||
|
PROFILE_MEM(Content);
|
||||||
|
|
||||||
// Ensure path is in a valid format
|
// Ensure path is in a valid format
|
||||||
String pathNorm(path);
|
String pathNorm(path);
|
||||||
ContentStorageManager::FormatPath(pathNorm);
|
ContentStorageManager::FormatPath(pathNorm);
|
||||||
@@ -687,7 +700,6 @@ Asset* Content::GetAsset(const StringView& outputPath)
|
|||||||
{
|
{
|
||||||
if (outputPath.IsEmpty())
|
if (outputPath.IsEmpty())
|
||||||
return nullptr;
|
return nullptr;
|
||||||
|
|
||||||
ScopeLock lock(AssetsLocker);
|
ScopeLock lock(AssetsLocker);
|
||||||
for (auto i = Assets.Begin(); i.IsNotEnd(); ++i)
|
for (auto i = Assets.Begin(); i.IsNotEnd(); ++i)
|
||||||
{
|
{
|
||||||
@@ -737,6 +749,7 @@ void Content::DeleteAsset(const StringView& path)
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#if USE_EDITOR
|
||||||
ScopeLock locker(AssetsLocker);
|
ScopeLock locker(AssetsLocker);
|
||||||
|
|
||||||
// Remove from registry
|
// Remove from registry
|
||||||
@@ -753,6 +766,7 @@ void Content::DeleteAsset(const StringView& path)
|
|||||||
|
|
||||||
// Delete file
|
// Delete file
|
||||||
deleteFileSafety(path, info.ID);
|
deleteFileSafety(path, info.ID);
|
||||||
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
void Content::deleteFileSafety(const StringView& path, const Guid& id)
|
void Content::deleteFileSafety(const StringView& path, const Guid& id)
|
||||||
@@ -791,6 +805,23 @@ void Content::deleteFileSafety(const StringView& path, const Guid& id)
|
|||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#if !COMPILE_WITHOUT_CSHARP
|
||||||
|
|
||||||
|
#include "Engine/Scripting/ManagedCLR/MUtils.h"
|
||||||
|
|
||||||
|
void* Content::GetAssetsInternal()
|
||||||
|
{
|
||||||
|
AssetsLocker.Lock();
|
||||||
|
MArray* result = MCore::Array::New(Asset::TypeInitializer.GetClass(), Assets.Count());
|
||||||
|
int32 i = 0;
|
||||||
|
for (const auto& e : Assets)
|
||||||
|
MCore::GC::WriteArrayRef(result, e.Value->GetOrCreateManagedInstance(), i++);
|
||||||
|
AssetsLocker.Unlock();
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif
|
||||||
|
|
||||||
#if USE_EDITOR
|
#if USE_EDITOR
|
||||||
|
|
||||||
bool Content::RenameAsset(const StringView& oldPath, const StringView& newPath)
|
bool Content::RenameAsset(const StringView& oldPath, const StringView& newPath)
|
||||||
@@ -977,7 +1008,7 @@ bool Content::CloneAssetFile(const StringView& dstPath, const StringView& srcPat
|
|||||||
FileSystem::DeleteFile(tmpPath);
|
FileSystem::DeleteFile(tmpPath);
|
||||||
|
|
||||||
// Reload storage
|
// Reload storage
|
||||||
if (auto storage = ContentStorageManager::GetStorage(dstPath))
|
if (auto storage = ContentStorageManager::GetStorage(dstPath, false))
|
||||||
{
|
{
|
||||||
storage->Reload();
|
storage->Reload();
|
||||||
}
|
}
|
||||||
@@ -1023,6 +1054,7 @@ Asset* Content::CreateVirtualAsset(const MClass* type)
|
|||||||
Asset* Content::CreateVirtualAsset(const ScriptingTypeHandle& type)
|
Asset* Content::CreateVirtualAsset(const ScriptingTypeHandle& type)
|
||||||
{
|
{
|
||||||
PROFILE_CPU();
|
PROFILE_CPU();
|
||||||
|
PROFILE_MEM(Content);
|
||||||
auto& assetType = type.GetType();
|
auto& assetType = type.GetType();
|
||||||
|
|
||||||
// Init mock asset info
|
// Init mock asset info
|
||||||
@@ -1045,7 +1077,9 @@ Asset* Content::CreateVirtualAsset(const ScriptingTypeHandle& type)
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Create asset object
|
// Create asset object
|
||||||
|
PROFILE_MEM_BEGIN(ContentAssets);
|
||||||
auto asset = factory->NewVirtual(info);
|
auto asset = factory->NewVirtual(info);
|
||||||
|
PROFILE_MEM_END();
|
||||||
if (asset == nullptr)
|
if (asset == nullptr)
|
||||||
{
|
{
|
||||||
LOG(Error, "Cannot create virtual asset object.");
|
LOG(Error, "Cannot create virtual asset object.");
|
||||||
@@ -1054,7 +1088,9 @@ Asset* Content::CreateVirtualAsset(const ScriptingTypeHandle& type)
|
|||||||
asset->RegisterObject();
|
asset->RegisterObject();
|
||||||
|
|
||||||
// Call initializer function
|
// Call initializer function
|
||||||
|
PROFILE_MEM_BEGIN(ContentAssets);
|
||||||
asset->InitAsVirtual();
|
asset->InitAsVirtual();
|
||||||
|
PROFILE_MEM_END();
|
||||||
|
|
||||||
// Register asset
|
// Register asset
|
||||||
AssetsLocker.Lock();
|
AssetsLocker.Lock();
|
||||||
@@ -1076,11 +1112,21 @@ void Content::WaitForTask(ContentLoadTask* loadingTask, double timeoutInMillisec
|
|||||||
|
|
||||||
const double timeoutInSeconds = timeoutInMilliseconds * 0.001;
|
const double timeoutInSeconds = timeoutInMilliseconds * 0.001;
|
||||||
const double startTime = Platform::GetTimeSeconds();
|
const double startTime = Platform::GetTimeSeconds();
|
||||||
|
int32 loopCounter = 0;
|
||||||
Task* task = loadingTask;
|
Task* task = loadingTask;
|
||||||
Array<ContentLoadTask*, InlinedAllocation<64>> localQueue;
|
Array<ContentLoadTask*, InlinedAllocation<64>> localQueue;
|
||||||
#define CHECK_CONDITIONS() (!Engine::ShouldExit() && (timeoutInSeconds <= 0.0 || Platform::GetTimeSeconds() - startTime < timeoutInSeconds))
|
#define CHECK_CONDITIONS() (!Engine::ShouldExit() && (timeoutInSeconds <= 0.0 || Platform::GetTimeSeconds() - startTime < timeoutInSeconds))
|
||||||
do
|
do
|
||||||
{
|
{
|
||||||
|
// Give opportunity for other threads to use the current core
|
||||||
|
if (loopCounter == 0)
|
||||||
|
; // First run is fast
|
||||||
|
else if (loopCounter < 10)
|
||||||
|
Platform::Yield();
|
||||||
|
else
|
||||||
|
Platform::Sleep(1);
|
||||||
|
loopCounter++;
|
||||||
|
|
||||||
// Try to execute content tasks
|
// Try to execute content tasks
|
||||||
while (task->IsQueued() && CHECK_CONDITIONS())
|
while (task->IsQueued() && CHECK_CONDITIONS())
|
||||||
{
|
{
|
||||||
@@ -1097,6 +1143,8 @@ void Content::WaitForTask(ContentLoadTask* loadingTask, double timeoutInMillisec
|
|||||||
localQueue.Clear();
|
localQueue.Clear();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
PROFILE_CPU_NAMED("Inline");
|
||||||
|
ZoneColor(0xffaaaaaa);
|
||||||
thread->Run(tmp);
|
thread->Run(tmp);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
@@ -1209,6 +1257,7 @@ Asset* Content::LoadAsync(const Guid& id, const ScriptingTypeHandle& type)
|
|||||||
{
|
{
|
||||||
if (!id.IsValid())
|
if (!id.IsValid())
|
||||||
return nullptr;
|
return nullptr;
|
||||||
|
PROFILE_MEM(Content);
|
||||||
|
|
||||||
// Check if asset has been already loaded
|
// Check if asset has been already loaded
|
||||||
Asset* result = nullptr;
|
Asset* result = nullptr;
|
||||||
@@ -1277,7 +1326,9 @@ Asset* Content::LoadAsync(const Guid& id, const ScriptingTypeHandle& type)
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Create asset object
|
// Create asset object
|
||||||
|
PROFILE_MEM_BEGIN(ContentAssets);
|
||||||
result = factory->New(assetInfo);
|
result = factory->New(assetInfo);
|
||||||
|
PROFILE_MEM_END();
|
||||||
if (result == nullptr)
|
if (result == nullptr)
|
||||||
{
|
{
|
||||||
LOG(Error, "Cannot create asset object. Info: {0}", assetInfo.ToString());
|
LOG(Error, "Cannot create asset object. Info: {0}", assetInfo.ToString());
|
||||||
|
|||||||
@@ -1,5 +1,6 @@
|
|||||||
// Copyright (c) Wojciech Figat. All rights reserved.
|
// Copyright (c) Wojciech Figat. All rights reserved.
|
||||||
|
|
||||||
|
using FlaxEngine.Interop;
|
||||||
using System;
|
using System;
|
||||||
using System.Runtime.CompilerServices;
|
using System.Runtime.CompilerServices;
|
||||||
|
|
||||||
@@ -7,6 +8,33 @@ namespace FlaxEngine
|
|||||||
{
|
{
|
||||||
partial class Content
|
partial class Content
|
||||||
{
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Gets the assets (loaded or during load).
|
||||||
|
/// </summary>
|
||||||
|
public static Asset[] Assets
|
||||||
|
{
|
||||||
|
get
|
||||||
|
{
|
||||||
|
IntPtr ptr = Internal_GetAssetsInternal();
|
||||||
|
ManagedArray array = Unsafe.As<ManagedArray>(ManagedHandle.FromIntPtr(ptr).Target);
|
||||||
|
return NativeInterop.GCHandleArrayToManagedArray<Asset>(array);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Gets the assets (loaded or during load).
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="buffer">Output buffer to fill with asset pointers. Can be provided by a user to avoid memory allocation. Buffer might be larger than actual list size. Use <paramref name="count"/> for actual item count.></param>
|
||||||
|
/// <param name="count">Amount of valid items inside <paramref name="buffer"/>.</param>
|
||||||
|
public static void GetAssets(ref Asset[] buffer, out int count)
|
||||||
|
{
|
||||||
|
count = 0;
|
||||||
|
IntPtr ptr = Internal_GetAssetsInternal();
|
||||||
|
ManagedArray array = Unsafe.As<ManagedArray>(ManagedHandle.FromIntPtr(ptr).Target);
|
||||||
|
buffer = NativeInterop.GCHandleArrayToManagedArray<Asset>(array, buffer);
|
||||||
|
count = buffer.Length;
|
||||||
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Loads asset to the Content Pool and holds it until it won't be referenced by any object. Returns null if asset is missing. Actual asset data loading is performed on a other thread in async.
|
/// Loads asset to the Content Pool and holds it until it won't be referenced by any object. Returns null if asset is missing. Actual asset data loading is performed on a other thread in async.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
|
|||||||
@@ -75,7 +75,7 @@ public:
|
|||||||
/// </summary>
|
/// </summary>
|
||||||
/// <param name="id">The asset id.</param>
|
/// <param name="id">The asset id.</param>
|
||||||
/// <returns>The asset path, or empty if failed to find.</returns>
|
/// <returns>The asset path, or empty if failed to find.</returns>
|
||||||
API_FUNCTION() static String GetEditorAssetPath(const Guid& id);
|
API_FUNCTION() static StringView GetEditorAssetPath(const Guid& id);
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Finds all the asset IDs. Uses asset registry.
|
/// Finds all the asset IDs. Uses asset registry.
|
||||||
@@ -122,7 +122,7 @@ public:
|
|||||||
/// Gets the assets (loaded or during load).
|
/// Gets the assets (loaded or during load).
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <returns>The collection of assets.</returns>
|
/// <returns>The collection of assets.</returns>
|
||||||
API_PROPERTY() static Array<Asset*, HeapAllocation> GetAssets();
|
static Array<Asset*, HeapAllocation> GetAssets();
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Gets the raw dictionary of assets (loaded or during load).
|
/// Gets the raw dictionary of assets (loaded or during load).
|
||||||
@@ -368,4 +368,9 @@ private:
|
|||||||
static void onAssetUnload(Asset* asset);
|
static void onAssetUnload(Asset* asset);
|
||||||
static void onAssetChangeId(Asset* asset, const Guid& oldId, const Guid& newId);
|
static void onAssetChangeId(Asset* asset, const Guid& oldId, const Guid& newId);
|
||||||
static void deleteFileSafety(const StringView& path, const Guid& id);
|
static void deleteFileSafety(const StringView& path, const Guid& id);
|
||||||
|
|
||||||
|
// Internal bindings
|
||||||
|
#if !COMPILE_WITHOUT_CSHARP
|
||||||
|
API_FUNCTION(NoProxy) static void* GetAssetsInternal();
|
||||||
|
#endif
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -20,6 +20,7 @@
|
|||||||
#include "Engine/Core/Cache.h"
|
#include "Engine/Core/Cache.h"
|
||||||
#include "Engine/Debug/Exceptions/JsonParseException.h"
|
#include "Engine/Debug/Exceptions/JsonParseException.h"
|
||||||
#include "Engine/Profiler/ProfilerCPU.h"
|
#include "Engine/Profiler/ProfilerCPU.h"
|
||||||
|
#include "Engine/Profiler/ProfilerMemory.h"
|
||||||
#include "Engine/Scripting/Scripting.h"
|
#include "Engine/Scripting/Scripting.h"
|
||||||
#include "Engine/Scripting/ManagedCLR/MClass.h"
|
#include "Engine/Scripting/ManagedCLR/MClass.h"
|
||||||
#include "Engine/Scripting/ManagedCLR/MField.h"
|
#include "Engine/Scripting/ManagedCLR/MField.h"
|
||||||
@@ -39,6 +40,7 @@ String JsonAssetBase::GetData() const
|
|||||||
if (Data == nullptr)
|
if (Data == nullptr)
|
||||||
return String::Empty;
|
return String::Empty;
|
||||||
PROFILE_CPU_NAMED("JsonAsset.GetData");
|
PROFILE_CPU_NAMED("JsonAsset.GetData");
|
||||||
|
PROFILE_MEM(ContentAssets);
|
||||||
rapidjson_flax::StringBuffer buffer;
|
rapidjson_flax::StringBuffer buffer;
|
||||||
OnGetData(buffer);
|
OnGetData(buffer);
|
||||||
return String((const char*)buffer.GetString(), (int32)buffer.GetSize());
|
return String((const char*)buffer.GetString(), (int32)buffer.GetSize());
|
||||||
@@ -49,6 +51,7 @@ void JsonAssetBase::SetData(const StringView& value)
|
|||||||
if (!IsLoaded())
|
if (!IsLoaded())
|
||||||
return;
|
return;
|
||||||
PROFILE_CPU_NAMED("JsonAsset.SetData");
|
PROFILE_CPU_NAMED("JsonAsset.SetData");
|
||||||
|
PROFILE_MEM(ContentAssets);
|
||||||
const StringAnsi dataJson(value);
|
const StringAnsi dataJson(value);
|
||||||
ScopeLock lock(Locker);
|
ScopeLock lock(Locker);
|
||||||
const StringView dataTypeName = DataTypeName;
|
const StringView dataTypeName = DataTypeName;
|
||||||
@@ -60,6 +63,7 @@ void JsonAssetBase::SetData(const StringView& value)
|
|||||||
|
|
||||||
bool JsonAssetBase::Init(const StringView& dataTypeName, const StringAnsiView& dataJson)
|
bool JsonAssetBase::Init(const StringView& dataTypeName, const StringAnsiView& dataJson)
|
||||||
{
|
{
|
||||||
|
PROFILE_MEM(ContentAssets);
|
||||||
unload(true);
|
unload(true);
|
||||||
DataTypeName = dataTypeName;
|
DataTypeName = dataTypeName;
|
||||||
DataEngineBuild = FLAXENGINE_VERSION_BUILD;
|
DataEngineBuild = FLAXENGINE_VERSION_BUILD;
|
||||||
@@ -87,7 +91,7 @@ void JsonAssetBase::OnGetData(rapidjson_flax::StringBuffer& buffer) const
|
|||||||
Data->Accept(writerObj.GetWriter());
|
Data->Accept(writerObj.GetWriter());
|
||||||
}
|
}
|
||||||
|
|
||||||
const String& JsonAssetBase::GetPath() const
|
StringView JsonAssetBase::GetPath() const
|
||||||
{
|
{
|
||||||
#if USE_EDITOR
|
#if USE_EDITOR
|
||||||
return _path;
|
return _path;
|
||||||
@@ -176,7 +180,7 @@ bool JsonAssetBase::Save(const StringView& path)
|
|||||||
_isResaving = false;
|
_isResaving = false;
|
||||||
|
|
||||||
// Save json to file
|
// Save json to file
|
||||||
if (File::WriteAllBytes(path.HasChars() ? path : StringView(GetPath()), (byte*)buffer.GetString(), (int32)buffer.GetSize()))
|
if (File::WriteAllBytes(path.HasChars() ? path : GetPath(), (byte*)buffer.GetString(), (int32)buffer.GetSize()))
|
||||||
{
|
{
|
||||||
LOG(Error, "Cannot save \'{0}\'", ToString());
|
LOG(Error, "Cannot save \'{0}\'", ToString());
|
||||||
return true;
|
return true;
|
||||||
@@ -239,6 +243,7 @@ Asset::LoadResult JsonAssetBase::loadAsset()
|
|||||||
{
|
{
|
||||||
if (IsVirtual() || _isVirtualDocument)
|
if (IsVirtual() || _isVirtualDocument)
|
||||||
return LoadResult::Ok;
|
return LoadResult::Ok;
|
||||||
|
PROFILE_MEM(ContentAssets);
|
||||||
|
|
||||||
// Load data (raw json file in editor, cooked asset in build game)
|
// Load data (raw json file in editor, cooked asset in build game)
|
||||||
#if USE_EDITOR
|
#if USE_EDITOR
|
||||||
@@ -305,6 +310,7 @@ Asset::LoadResult JsonAssetBase::loadAsset()
|
|||||||
|
|
||||||
void JsonAssetBase::unload(bool isReloading)
|
void JsonAssetBase::unload(bool isReloading)
|
||||||
{
|
{
|
||||||
|
PROFILE_MEM(ContentAssets);
|
||||||
ISerializable::SerializeDocument tmp;
|
ISerializable::SerializeDocument tmp;
|
||||||
Document.Swap(tmp);
|
Document.Swap(tmp);
|
||||||
Data = nullptr;
|
Data = nullptr;
|
||||||
@@ -453,6 +459,7 @@ bool JsonAsset::CreateInstance()
|
|||||||
ScopeLock lock(Locker);
|
ScopeLock lock(Locker);
|
||||||
if (Instance)
|
if (Instance)
|
||||||
return false;
|
return false;
|
||||||
|
PROFILE_MEM(ContentAssets);
|
||||||
|
|
||||||
// Try to scripting type for this data
|
// Try to scripting type for this data
|
||||||
const StringAsANSI<> dataTypeNameAnsi(DataTypeName.Get(), DataTypeName.Length());
|
const StringAsANSI<> dataTypeNameAnsi(DataTypeName.Get(), DataTypeName.Length());
|
||||||
|
|||||||
@@ -88,7 +88,7 @@ protected:
|
|||||||
|
|
||||||
public:
|
public:
|
||||||
// [Asset]
|
// [Asset]
|
||||||
const String& GetPath() const override;
|
StringView GetPath() const override;
|
||||||
uint64 GetMemoryUsage() const override;
|
uint64 GetMemoryUsage() const override;
|
||||||
#if USE_EDITOR
|
#if USE_EDITOR
|
||||||
void GetReferences(Array<Guid, HeapAllocation>& assets, Array<String, HeapAllocation>& files) const override;
|
void GetReferences(Array<Guid, HeapAllocation>& assets, Array<String, HeapAllocation>& files) const override;
|
||||||
|
|||||||
@@ -19,6 +19,15 @@ API_STRUCT(NoDefault, Template, MarshalAs=JsonAsset*) struct JsonAssetReference
|
|||||||
OnSet(asset);
|
OnSet(asset);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
explicit JsonAssetReference(decltype(__nullptr))
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
explicit JsonAssetReference(IAssetReference* owner)
|
||||||
|
: AssetReference<JsonAsset>(owner)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Gets the deserialized native object instance of the given type. Returns null if asset is not loaded or loaded object has different type.
|
/// Gets the deserialized native object instance of the given type. Returns null if asset is not loaded or loaded object has different type.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
|
|||||||
@@ -36,7 +36,7 @@ public:
|
|||||||
// [ContentLoadTask]
|
// [ContentLoadTask]
|
||||||
String ToString() const override
|
String ToString() const override
|
||||||
{
|
{
|
||||||
return String::Format(TEXT("Load Asset Data Task ({}, {}, {})"), (int32)GetState(), _chunks, _asset ? _asset->GetPath() : String::Empty);
|
return String::Format(TEXT("Load Asset Data Task ({}, {}, {})"), (int32)GetState(), _chunks, _asset ? _asset->GetPath() : StringView::Empty);
|
||||||
}
|
}
|
||||||
bool HasReference(Object* obj) const override
|
bool HasReference(Object* obj) const override
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -8,6 +8,7 @@
|
|||||||
#include "Engine/Content/WeakAssetReference.h"
|
#include "Engine/Content/WeakAssetReference.h"
|
||||||
#include "Engine/Core/Log.h"
|
#include "Engine/Core/Log.h"
|
||||||
#include "Engine/Profiler/ProfilerCPU.h"
|
#include "Engine/Profiler/ProfilerCPU.h"
|
||||||
|
#include "Engine/Profiler/ProfilerMemory.h"
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Asset loading task object.
|
/// Asset loading task object.
|
||||||
@@ -44,6 +45,7 @@ protected:
|
|||||||
Result run() override
|
Result run() override
|
||||||
{
|
{
|
||||||
PROFILE_CPU();
|
PROFILE_CPU();
|
||||||
|
PROFILE_MEM(ContentAssets);
|
||||||
|
|
||||||
// Keep valid ref to the asset
|
// Keep valid ref to the asset
|
||||||
AssetReference<::Asset> ref = Asset.Get();
|
AssetReference<::Asset> ref = Asset.Get();
|
||||||
|
|||||||
@@ -7,7 +7,7 @@
|
|||||||
/// <summary>
|
/// <summary>
|
||||||
/// The asset soft reference. Asset gets referenced (loaded) on actual use (ID reference is resolving it).
|
/// The asset soft reference. Asset gets referenced (loaded) on actual use (ID reference is resolving it).
|
||||||
/// </summary>
|
/// </summary>
|
||||||
class FLAXENGINE_API SoftAssetReferenceBase
|
class FLAXENGINE_API SoftAssetReferenceBase : public IAssetReference
|
||||||
{
|
{
|
||||||
protected:
|
protected:
|
||||||
Asset* _asset = nullptr;
|
Asset* _asset = nullptr;
|
||||||
@@ -46,11 +46,16 @@ public:
|
|||||||
/// </summary>
|
/// </summary>
|
||||||
String ToString() const;
|
String ToString() const;
|
||||||
|
|
||||||
|
public:
|
||||||
|
// [IAssetReference]
|
||||||
|
void OnAssetChanged(Asset* asset, void* caller) override;
|
||||||
|
void OnAssetLoaded(Asset* asset, void* caller) override;
|
||||||
|
void OnAssetUnloaded(Asset* asset, void* caller) override;
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
void OnSet(Asset* asset);
|
void OnSet(Asset* asset);
|
||||||
void OnSet(const Guid& id);
|
void OnSet(const Guid& id);
|
||||||
void OnResolve(const ScriptingTypeHandle& type);
|
void OnResolve(const ScriptingTypeHandle& type);
|
||||||
void OnUnloaded(Asset* asset);
|
|
||||||
};
|
};
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
@@ -71,6 +76,13 @@ public:
|
|||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Initializes a new instance of the <see cref="SoftAssetReference"/> class.
|
||||||
|
/// </summary>
|
||||||
|
explicit SoftAssetReference(decltype(__nullptr))
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Initializes a new instance of the <see cref="SoftAssetReference"/> class.
|
/// Initializes a new instance of the <see cref="SoftAssetReference"/> class.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
|
|||||||
@@ -15,14 +15,9 @@
|
|||||||
namespace
|
namespace
|
||||||
{
|
{
|
||||||
CriticalSection Locker;
|
CriticalSection Locker;
|
||||||
#if USE_EDITOR
|
|
||||||
Array<FlaxFile*> Files(1024);
|
|
||||||
Array<FlaxPackage*> Packages;
|
|
||||||
#else
|
|
||||||
Array<FlaxFile*> Files;
|
Array<FlaxFile*> Files;
|
||||||
Array<FlaxPackage*> Packages(64);
|
Array<FlaxPackage*> Packages;
|
||||||
#endif
|
Dictionary<String, FlaxStorage*> StorageMap;
|
||||||
Dictionary<String, FlaxStorage*> StorageMap(2048);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
class ContentStorageService : public EngineService
|
class ContentStorageService : public EngineService
|
||||||
@@ -231,6 +226,12 @@ void ContentStorageManager::GetStorage(Array<FlaxStorage*>& result)
|
|||||||
|
|
||||||
bool ContentStorageService::Init()
|
bool ContentStorageService::Init()
|
||||||
{
|
{
|
||||||
|
#if USE_EDITOR
|
||||||
|
Files.EnsureCapacity(1024);
|
||||||
|
#else
|
||||||
|
Packages.EnsureCapacity(64);
|
||||||
|
#endif
|
||||||
|
StorageMap.EnsureCapacity(2048);
|
||||||
System = New<ContentStorageSystem>();
|
System = New<ContentStorageSystem>();
|
||||||
Engine::UpdateGraph->AddSystem(System);
|
Engine::UpdateGraph->AddSystem(System);
|
||||||
return false;
|
return false;
|
||||||
|
|||||||
@@ -182,10 +182,5 @@ public:
|
|||||||
/// Clones this chunk data (doesn't copy location in file).
|
/// Clones this chunk data (doesn't copy location in file).
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <returns>The cloned chunk.</returns>
|
/// <returns>The cloned chunk.</returns>
|
||||||
FlaxChunk* Clone() const
|
FlaxChunk* Clone() const;
|
||||||
{
|
|
||||||
auto chunk = New<FlaxChunk>();
|
|
||||||
chunk->Data.Copy(Data);
|
|
||||||
return chunk;
|
|
||||||
}
|
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -8,6 +8,7 @@
|
|||||||
#include "Engine/Core/Types/TimeSpan.h"
|
#include "Engine/Core/Types/TimeSpan.h"
|
||||||
#include "Engine/Platform/File.h"
|
#include "Engine/Platform/File.h"
|
||||||
#include "Engine/Profiler/ProfilerCPU.h"
|
#include "Engine/Profiler/ProfilerCPU.h"
|
||||||
|
#include "Engine/Profiler/ProfilerMemory.h"
|
||||||
#include "Engine/Serialization/FileWriteStream.h"
|
#include "Engine/Serialization/FileWriteStream.h"
|
||||||
#include "Engine/Content/Asset.h"
|
#include "Engine/Content/Asset.h"
|
||||||
#include "Engine/Content/Content.h"
|
#include "Engine/Content/Content.h"
|
||||||
@@ -63,6 +64,14 @@ void FlaxChunk::RegisterUsage()
|
|||||||
LastAccessTime = Platform::GetTimeSeconds();
|
LastAccessTime = Platform::GetTimeSeconds();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
FlaxChunk* FlaxChunk::Clone() const
|
||||||
|
{
|
||||||
|
PROFILE_MEM(ContentFiles);
|
||||||
|
auto chunk = New<FlaxChunk>();
|
||||||
|
chunk->Data.Copy(Data);
|
||||||
|
return chunk;
|
||||||
|
}
|
||||||
|
|
||||||
const int32 FlaxStorage::MagicCode = 1180124739;
|
const int32 FlaxStorage::MagicCode = 1180124739;
|
||||||
|
|
||||||
FlaxStorage::LockData FlaxStorage::LockData::Invalid(nullptr);
|
FlaxStorage::LockData FlaxStorage::LockData::Invalid(nullptr);
|
||||||
@@ -281,19 +290,12 @@ uint32 FlaxStorage::GetMemoryUsage() const
|
|||||||
|
|
||||||
bool FlaxStorage::Load()
|
bool FlaxStorage::Load()
|
||||||
{
|
{
|
||||||
// Check if was already loaded
|
|
||||||
if (IsLoaded())
|
if (IsLoaded())
|
||||||
{
|
|
||||||
return false;
|
return false;
|
||||||
}
|
PROFILE_MEM(ContentFiles);
|
||||||
|
|
||||||
// Prevent loading by more than one thread
|
|
||||||
ScopeLock lock(_loadLocker);
|
ScopeLock lock(_loadLocker);
|
||||||
if (IsLoaded())
|
if (IsLoaded())
|
||||||
{
|
|
||||||
// Other thread loaded it
|
|
||||||
return false;
|
return false;
|
||||||
}
|
|
||||||
ASSERT(GetEntriesCount() == 0);
|
ASSERT(GetEntriesCount() == 0);
|
||||||
|
|
||||||
// Open file
|
// Open file
|
||||||
@@ -693,6 +695,7 @@ bool FlaxStorage::LoadAssetHeader(const Guid& id, AssetInitData& data)
|
|||||||
|
|
||||||
bool FlaxStorage::LoadAssetChunk(FlaxChunk* chunk)
|
bool FlaxStorage::LoadAssetChunk(FlaxChunk* chunk)
|
||||||
{
|
{
|
||||||
|
PROFILE_MEM(ContentFiles);
|
||||||
ASSERT(IsLoaded());
|
ASSERT(IsLoaded());
|
||||||
ASSERT(chunk != nullptr && _chunks.Contains(chunk));
|
ASSERT(chunk != nullptr && _chunks.Contains(chunk));
|
||||||
|
|
||||||
@@ -866,6 +869,7 @@ FlaxChunk* FlaxStorage::AllocateChunk()
|
|||||||
{
|
{
|
||||||
if (AllowDataModifications())
|
if (AllowDataModifications())
|
||||||
{
|
{
|
||||||
|
PROFILE_MEM(ContentFiles);
|
||||||
auto chunk = New<FlaxChunk>();
|
auto chunk = New<FlaxChunk>();
|
||||||
_chunks.Add(chunk);
|
_chunks.Add(chunk);
|
||||||
return chunk;
|
return chunk;
|
||||||
@@ -1125,6 +1129,7 @@ bool FlaxStorage::Save(const AssetInitData& data, bool silentMode)
|
|||||||
|
|
||||||
bool FlaxStorage::LoadAssetHeader(const Entry& e, AssetInitData& data)
|
bool FlaxStorage::LoadAssetHeader(const Entry& e, AssetInitData& data)
|
||||||
{
|
{
|
||||||
|
PROFILE_MEM(ContentFiles);
|
||||||
ASSERT(IsLoaded());
|
ASSERT(IsLoaded());
|
||||||
|
|
||||||
auto lock = Lock();
|
auto lock = Lock();
|
||||||
@@ -1396,6 +1401,8 @@ FileReadStream* FlaxStorage::OpenFile()
|
|||||||
auto& stream = _file.Get();
|
auto& stream = _file.Get();
|
||||||
if (stream == nullptr)
|
if (stream == nullptr)
|
||||||
{
|
{
|
||||||
|
PROFILE_MEM(ContentFiles);
|
||||||
|
|
||||||
// Open file
|
// Open file
|
||||||
auto file = File::Open(_path, FileMode::OpenExisting, FileAccess::Read, FileShare::Read);
|
auto file = File::Open(_path, FileMode::OpenExisting, FileAccess::Read, FileShare::Read);
|
||||||
if (file == nullptr)
|
if (file == nullptr)
|
||||||
@@ -1418,6 +1425,7 @@ bool FlaxStorage::CloseFileHandles()
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
PROFILE_CPU();
|
PROFILE_CPU();
|
||||||
|
PROFILE_MEM(ContentFiles);
|
||||||
|
|
||||||
// Note: this is usually called by the content manager when this file is not used or on exit
|
// Note: this is usually called by the content manager when this file is not used or on exit
|
||||||
// In those situations all the async tasks using this storage should be cancelled externally
|
// In those situations all the async tasks using this storage should be cancelled externally
|
||||||
|
|||||||
@@ -7,7 +7,7 @@
|
|||||||
/// <summary>
|
/// <summary>
|
||||||
/// Asset reference utility that doesn't add reference to that asset. Handles asset unload event.
|
/// Asset reference utility that doesn't add reference to that asset. Handles asset unload event.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
API_CLASS(InBuild) class WeakAssetReferenceBase
|
API_CLASS(InBuild) class WeakAssetReferenceBase : public IAssetReference
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
typedef Delegate<> EventType;
|
typedef Delegate<> EventType;
|
||||||
@@ -56,9 +56,14 @@ public:
|
|||||||
/// </summary>
|
/// </summary>
|
||||||
String ToString() const;
|
String ToString() const;
|
||||||
|
|
||||||
|
public:
|
||||||
|
// [IAssetReference]
|
||||||
|
void OnAssetChanged(Asset* asset, void* caller) override;
|
||||||
|
void OnAssetLoaded(Asset* asset, void* caller) override;
|
||||||
|
void OnAssetUnloaded(Asset* asset, void* caller) override;
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
void OnSet(Asset* asset);
|
void OnSet(Asset* asset);
|
||||||
void OnUnloaded(Asset* asset);
|
|
||||||
};
|
};
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
@@ -72,7 +77,13 @@ public:
|
|||||||
/// Initializes a new instance of the <see cref="WeakAssetReference"/> class.
|
/// Initializes a new instance of the <see cref="WeakAssetReference"/> class.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
WeakAssetReference()
|
WeakAssetReference()
|
||||||
: WeakAssetReferenceBase()
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Initializes a new instance of the <see cref="WeakAssetReference"/> class.
|
||||||
|
/// </summary>
|
||||||
|
explicit WeakAssetReference(decltype(__nullptr))
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -81,7 +92,6 @@ public:
|
|||||||
/// </summary>
|
/// </summary>
|
||||||
/// <param name="asset">The asset to set.</param>
|
/// <param name="asset">The asset to set.</param>
|
||||||
WeakAssetReference(T* asset)
|
WeakAssetReference(T* asset)
|
||||||
: WeakAssetReferenceBase()
|
|
||||||
{
|
{
|
||||||
OnSet(asset);
|
OnSet(asset);
|
||||||
}
|
}
|
||||||
|
|||||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user