Merge remote-tracking branch 'origin/master' into sdl_platform
This commit is contained in:
@@ -1,3 +1,3 @@
|
||||
version https://git-lfs.github.com/spec/v1
|
||||
oid sha256:d2b1dc1523cb2140db7ce5fed6e97b09d7fcebbe6cc19fca7708b5b882267040
|
||||
size 4175
|
||||
oid sha256:d3922811f0eb56cbb515c93cd53d80316740ea78219aa81118d2c9dee4a9d230
|
||||
size 4142
|
||||
|
||||
@@ -10,9 +10,10 @@
|
||||
#include "Engine/Serialization/JsonTools.h"
|
||||
#include "Engine/Serialization/JsonWriters.h"
|
||||
#include "Editor/Cooker/PlatformTools.h"
|
||||
#include "Engine/Engine/Globals.h"
|
||||
#include "Editor/Editor.h"
|
||||
#include "Editor/ProjectInfo.h"
|
||||
#include "Engine/Engine/Globals.h"
|
||||
#include "Editor/Utilities/EditorUtilities.h"
|
||||
#if PLATFORM_MAC
|
||||
#include <sys/stat.h>
|
||||
#endif
|
||||
@@ -127,7 +128,7 @@ bool CompileScriptsStep::DeployBinaries(CookingData& data, const String& path, c
|
||||
const String dst = dstPath / StringUtils::GetFileName(file);
|
||||
if (dst == file)
|
||||
continue;
|
||||
if (FileSystem::CopyFile(dst, file))
|
||||
if (EditorUtilities::CopyFileIfNewer(dst, file))
|
||||
{
|
||||
data.Error(String::Format(TEXT("Failed to copy file from {0} to {1}."), file, dst));
|
||||
return true;
|
||||
|
||||
@@ -59,6 +59,7 @@ bool PrecompileAssembliesStep::Perform(CookingData& data)
|
||||
data.StepProgress(infoMsg, 0);
|
||||
|
||||
// Override Newtonsoft.Json with AOT-version (one that doesn't use System.Reflection.Emit)
|
||||
// TODO: remove it since EngineModule does properly reference AOT lib now
|
||||
EditorUtilities::CopyFileIfNewer(data.ManagedCodeOutputPath / TEXT("Newtonsoft.Json.dll"), Globals::StartupFolder / TEXT("Source/Platforms/DotNet/AOT/Newtonsoft.Json.dll"));
|
||||
FileSystem::DeleteFile(data.ManagedCodeOutputPath / TEXT("Newtonsoft.Json.xml"));
|
||||
FileSystem::DeleteFile(data.ManagedCodeOutputPath / TEXT("Newtonsoft.Json.pdb"));
|
||||
|
||||
@@ -30,6 +30,7 @@
|
||||
#include "Engine/Profiler/ProfilerCPU.h"
|
||||
#include "Engine/Profiler/ProfilerMemory.h"
|
||||
#include "Engine/Scripting/ManagedCLR/MClass.h"
|
||||
#include "Engine/Scripting/Internal/InternalCalls.h"
|
||||
#include "Engine/Scripting/Scripting.h"
|
||||
#if USE_EDITOR
|
||||
#include "Editor/Editor.h"
|
||||
@@ -346,17 +347,21 @@ int32 LoadingThread::Run()
|
||||
ContentLoadTask* task;
|
||||
ThisLoadThread = this;
|
||||
|
||||
MONO_THREAD_INFO_TYPE* monoThreadInfo = nullptr;
|
||||
while (Platform::AtomicRead(&_exitFlag) == 0)
|
||||
{
|
||||
if (LoadTasks.try_dequeue(task))
|
||||
{
|
||||
Run(task);
|
||||
MONO_THREAD_INFO_GET(monoThreadInfo);
|
||||
}
|
||||
else
|
||||
{
|
||||
MONO_ENTER_GC_SAFE_WITH_INFO(monoThreadInfo);
|
||||
LoadTasksMutex.Lock();
|
||||
LoadTasksSignal.Wait(LoadTasksMutex);
|
||||
LoadTasksMutex.Unlock();
|
||||
MONO_EXIT_GC_SAFE_WITH_INFO;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -79,10 +79,11 @@ namespace FlaxEngine.Interop
|
||||
NativeLibrary.SetDllImportResolver(Assembly.GetExecutingAssembly(), NativeLibraryImportResolver);
|
||||
|
||||
// Change default culture to match with Mono runtime default culture
|
||||
CultureInfo.DefaultThreadCurrentCulture = CultureInfo.InvariantCulture;
|
||||
CultureInfo.DefaultThreadCurrentUICulture = CultureInfo.InvariantCulture;
|
||||
System.Threading.Thread.CurrentThread.CurrentCulture = CultureInfo.InvariantCulture;
|
||||
System.Threading.Thread.CurrentThread.CurrentUICulture = CultureInfo.InvariantCulture;
|
||||
var culture = CultureInfo.InvariantCulture;
|
||||
CultureInfo.DefaultThreadCurrentCulture = culture;
|
||||
CultureInfo.DefaultThreadCurrentUICulture = culture;
|
||||
System.Threading.Thread.CurrentThread.CurrentCulture = culture;
|
||||
System.Threading.Thread.CurrentThread.CurrentUICulture = culture;
|
||||
|
||||
}
|
||||
|
||||
|
||||
@@ -422,24 +422,8 @@ bool AndroidFileSystem::getFilesFromDirectoryTop(Array<String>& results, const c
|
||||
if (S_ISREG(statEntry.st_mode) != 0)
|
||||
{
|
||||
// Validate with filter
|
||||
const int32 fullPathLength = StringUtils::Length(fullPath);
|
||||
const int32 searchPatternLength = StringUtils::Length(searchPattern);
|
||||
if (searchPatternLength == 0 || StringUtils::Compare(searchPattern, "*") == 0)
|
||||
{
|
||||
// All files
|
||||
}
|
||||
else if (searchPattern[0] == '*' && searchPatternLength < fullPathLength && StringUtils::Compare(fullPath + fullPathLength - searchPatternLength + 1, searchPattern + 1) == 0)
|
||||
{
|
||||
// Path ending
|
||||
}
|
||||
else
|
||||
{
|
||||
// TODO: implement all cases in a generic way
|
||||
continue;
|
||||
}
|
||||
|
||||
// Add file
|
||||
results.Add(String(fullPath));
|
||||
if (FileSystem::PathFilterHelper(fullPath, searchPattern))
|
||||
results.Add(String(fullPath));
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -7,6 +7,7 @@
|
||||
#include "Engine/Core/Types/StringView.h"
|
||||
#include "Engine/Core/Collections/Array.h"
|
||||
#include "Engine/Core/Math/Math.h"
|
||||
#include "Engine/Core/Log.h"
|
||||
#include "Engine/Engine/Globals.h"
|
||||
|
||||
bool FileSystemBase::ShowOpenFileDialog(Window* parentWindow, const StringView& initialDirectory, const StringView& filter, bool multiSelect, const StringView& title, Array<String, HeapAllocation>& filenames)
|
||||
@@ -313,3 +314,39 @@ bool FileSystemBase::DirectoryCopyHelper(const String& dst, const String& src, b
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
bool FileSystemBase::PathFilterHelper(const char* path, const char* searchPattern)
|
||||
{
|
||||
// Validate with filter
|
||||
const int32 pathLength = StringUtils::Length(path);
|
||||
const int32 searchPatternLength = StringUtils::Length(searchPattern);
|
||||
if (searchPatternLength == 0 ||
|
||||
StringUtils::Compare(searchPattern, "*") == 0 ||
|
||||
StringUtils::Compare(searchPattern, "*.*") == 0)
|
||||
{
|
||||
// All files
|
||||
return true;
|
||||
}
|
||||
else if (searchPattern[0] == '*' && StringUtils::Find(searchPattern + 1, "*") == nullptr)
|
||||
{
|
||||
// Path ending
|
||||
return searchPatternLength < pathLength && StringUtils::Compare(path + pathLength - searchPatternLength + 1, searchPattern + 1, searchPatternLength - 1) == 0;
|
||||
}
|
||||
else if (searchPattern[0] == '*' && searchPatternLength > 2 && searchPattern[searchPatternLength - 1] == '*')
|
||||
{
|
||||
// Contains pattern
|
||||
bool match = false;
|
||||
for (int32 i = 0; i < pathLength - searchPatternLength - 1; i++)
|
||||
{
|
||||
int32 len = Math::Min(searchPatternLength - 2, pathLength - i);
|
||||
if (StringUtils::Compare(&path[i], &searchPattern[1], len) == 0)
|
||||
return true;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
// TODO: implement all cases in a generic way
|
||||
LOG(Warning, "DirectoryGetFiles: Wildcard filter is not implemented ({})", String(searchPattern));
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
@@ -284,6 +284,6 @@ public:
|
||||
/// <returns>Relative path</returns>
|
||||
static String ConvertAbsolutePathToRelative(const String& basePath, const String& path);
|
||||
|
||||
private:
|
||||
static bool DirectoryCopyHelper(const String& dst, const String& src, bool withSubDirectories);
|
||||
static bool PathFilterHelper(const char* path, const char* searchPattern);
|
||||
};
|
||||
|
||||
@@ -367,43 +367,8 @@ bool UnixFileSystem::getFilesFromDirectoryTop(Array<String>& results, const char
|
||||
if (S_ISREG(statEntry.st_mode) != 0)
|
||||
{
|
||||
// Validate with filter
|
||||
const int32 fullPathLength = StringUtils::Length(fullPath);
|
||||
const int32 searchPatternLength = StringUtils::Length(searchPattern);
|
||||
if (searchPatternLength == 0 ||
|
||||
StringUtils::Compare(searchPattern, "*") == 0 ||
|
||||
StringUtils::Compare(searchPattern, "*.*") == 0)
|
||||
{
|
||||
// All files
|
||||
}
|
||||
else if (searchPattern[0] == '*' && searchPatternLength < fullPathLength && StringUtils::Compare(fullPath + fullPathLength - searchPatternLength + 1, searchPattern + 1, searchPatternLength - 1) == 0)
|
||||
{
|
||||
// Path ending
|
||||
}
|
||||
else if (searchPattern[0] == '*' && searchPatternLength > 2 && searchPattern[searchPatternLength-1] == '*')
|
||||
{
|
||||
// Contains pattern
|
||||
bool match = false;
|
||||
for (int32 i = 0; i < pathLength - searchPatternLength - 1; i++)
|
||||
{
|
||||
int32 len = Math::Min(searchPatternLength - 2, pathLength - i);
|
||||
if (StringUtils::Compare(&entry->d_name[i], &searchPattern[1], len) == 0)
|
||||
{
|
||||
match = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (!match)
|
||||
continue;
|
||||
}
|
||||
else
|
||||
{
|
||||
// TODO: implement all cases in a generic way
|
||||
LOG(Warning, "DirectoryGetFiles: Wildcard filter is not implemented");
|
||||
continue;
|
||||
}
|
||||
|
||||
// Add file
|
||||
results.Add(String(fullPath));
|
||||
if (FileSystemBase::PathFilterHelper(fullPath, searchPattern))
|
||||
results.Add(String(fullPath));
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -52,9 +52,12 @@ private:
|
||||
void OnShaderReloading(Asset* obj)
|
||||
{
|
||||
_psDofDepthBlurGeneration->ReleaseGPU();
|
||||
_psBokehGeneration->ReleaseGPU();
|
||||
_psBokeh->ReleaseGPU();
|
||||
_psBokehComposite->ReleaseGPU();
|
||||
if (_psBokehGeneration)
|
||||
_psBokehGeneration->ReleaseGPU();
|
||||
if (_psBokeh)
|
||||
_psBokeh->ReleaseGPU();
|
||||
if (_psBokehComposite)
|
||||
_psBokehComposite->ReleaseGPU();
|
||||
invalidateResources();
|
||||
}
|
||||
#endif
|
||||
|
||||
@@ -551,9 +551,6 @@ bool GlobalSurfaceAtlasPass::Init()
|
||||
// Check platform support
|
||||
const auto device = GPUDevice::Instance;
|
||||
_supported = device->GetFeatureLevel() >= FeatureLevel::SM5 && device->Limits.HasCompute && device->Limits.HasTypedUAVLoad;
|
||||
#if PLATFORM_APPLE_FAMILY
|
||||
_supported = false; // Vulkan over Metal has some issues in complex scenes with DDGI
|
||||
#endif
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
@@ -9,7 +9,7 @@
|
||||
|
||||
#if defined(__clang__)
|
||||
// Helper utility to override vtable entry with automatic restore
|
||||
// See BindingsGenerator.Cpp.cs that generates virtuall method wrappers for scripting to properly call overriden base method
|
||||
// See BindingsGenerator.Cpp.cs that generates virtual method wrappers for scripting to properly call overriden base method
|
||||
struct FLAXENGINE_API VTableFunctionInjector
|
||||
{
|
||||
void** VTableAddr;
|
||||
@@ -100,3 +100,50 @@ T& InternalGetReference(T* obj)
|
||||
DebugLog::ThrowNullReference();
|
||||
return *obj;
|
||||
}
|
||||
|
||||
#ifdef USE_MONO_AOT_COOP
|
||||
|
||||
// Cooperative Suspend - where threads suspend themselves when the runtime requests it.
|
||||
// https://www.mono-project.com/docs/advanced/runtime/docs/coop-suspend/
|
||||
typedef struct _MonoStackData {
|
||||
void* stackpointer;
|
||||
const char* function_name;
|
||||
} MonoStackData;
|
||||
#if BUILD_DEBUG
|
||||
#define MONO_STACKDATA(x) MonoStackData x = { &x, __func__ }
|
||||
#else
|
||||
#define MONO_STACKDATA(x) MonoStackData x = { &x, NULL }
|
||||
#endif
|
||||
#define MONO_THREAD_INFO_TYPE struct MonoThreadInfo
|
||||
DLLIMPORT extern "C" MONO_THREAD_INFO_TYPE* mono_thread_info_attach(void);
|
||||
DLLIMPORT extern "C" void* mono_threads_enter_gc_safe_region_with_info(MONO_THREAD_INFO_TYPE* info, MonoStackData* stackdata);
|
||||
DLLIMPORT extern "C" void mono_threads_exit_gc_safe_region_internal(void* cookie, MonoStackData* stackdata);
|
||||
#ifndef _MONO_UTILS_FORWARD_
|
||||
typedef struct _MonoDomain MonoDomain;
|
||||
DLLIMPORT extern "C" MonoDomain* mono_domain_get(void);
|
||||
#endif
|
||||
#define MONO_ENTER_GC_SAFE \
|
||||
do { \
|
||||
MONO_STACKDATA(__gc_safe_dummy); \
|
||||
void* __gc_safe_cookie = mono_threads_enter_gc_safe_region_internal(&__gc_safe_dummy)
|
||||
#define MONO_EXIT_GC_SAFE \
|
||||
mono_threads_exit_gc_safe_region_internal(__gc_safe_cookie, &__gc_safe_dummy); \
|
||||
} while (0)
|
||||
#define MONO_ENTER_GC_SAFE_WITH_INFO(info) \
|
||||
do { \
|
||||
MONO_STACKDATA(__gc_safe_dummy); \
|
||||
void* __gc_safe_cookie = mono_threads_enter_gc_safe_region_with_info((info), &__gc_safe_dummy)
|
||||
#define MONO_EXIT_GC_SAFE_WITH_INFO MONO_EXIT_GC_SAFE
|
||||
#define MONO_THREAD_INFO_GET(info) if (!info && mono_domain_get()) info = mono_thread_info_attach()
|
||||
|
||||
#else
|
||||
|
||||
#define MONO_THREAD_INFO_TYPE void
|
||||
#define MONO_ENTER_GC_SAFE
|
||||
#define MONO_EXIT_GC_SAFE
|
||||
#define MONO_ENTER_GC_SAFE_WITH_INFO(info)
|
||||
#define MONO_EXIT_GC_SAFE_WITH_INFO
|
||||
#define MONO_THREAD_INFO_GET(info)
|
||||
#define mono_thread_info_attach() nullptr
|
||||
|
||||
#endif
|
||||
|
||||
@@ -2147,7 +2147,13 @@ bool InitHostfxr()
|
||||
#endif
|
||||
|
||||
// Adjust GC threads suspending mode to not block attached native threads (eg. Job System)
|
||||
// https://www.mono-project.com/docs/advanced/runtime/docs/coop-suspend/
|
||||
#if USE_MONO_AOT_COOP
|
||||
Platform::SetEnvironmentVariable(TEXT("MONO_THREADS_SUSPEND"), TEXT("coop"));
|
||||
Platform::SetEnvironmentVariable(TEXT("MONO_SLEEP_ABORT_LIMIT"), TEXT("5000")); // in ms
|
||||
#else
|
||||
Platform::SetEnvironmentVariable(TEXT("MONO_THREADS_SUSPEND"), TEXT("preemptive"));
|
||||
#endif
|
||||
|
||||
#if defined(USE_MONO_AOT_MODE)
|
||||
// Enable AOT mode (per-platform)
|
||||
@@ -2155,9 +2161,9 @@ bool InitHostfxr()
|
||||
#endif
|
||||
|
||||
// Platform-specific setup
|
||||
#if PLATFORM_IOS || PLATFORM_SWITCH
|
||||
setenv("MONO_AOT_MODE", "aot", 1);
|
||||
setenv("DOTNET_SYSTEM_GLOBALIZATION_INVARIANT", "1", 1);
|
||||
#if PLATFORM_IOS || PLATFORM_SWITCH || PLATFORM_PS4 || PLATFORM_PS5
|
||||
Platform::SetEnvironmentVariable(TEXT("MONO_AOT_MODE"), TEXT("aot"));
|
||||
Platform::SetEnvironmentVariable(TEXT("DOTNET_SYSTEM_GLOBALIZATION_INVARIANT"), TEXT("1"));
|
||||
#endif
|
||||
|
||||
#ifdef USE_MONO_AOT_MODULE
|
||||
|
||||
@@ -568,10 +568,14 @@ bool Scripting::Load()
|
||||
#endif
|
||||
|
||||
// Load FlaxEngine
|
||||
const String flaxEnginePath = Globals::BinariesFolder / TEXT("FlaxEngine.CSharp.dll");
|
||||
auto* flaxEngineModule = (NativeBinaryModule*)GetBinaryModuleFlaxEngine();
|
||||
if (!flaxEngineModule->Assembly->IsLoaded())
|
||||
{
|
||||
String flaxEnginePath = Globals::BinariesFolder / TEXT("FlaxEngine.CSharp.dll");
|
||||
#if USE_MONO_AOT
|
||||
if (!FileSystem::FileExists(flaxEnginePath))
|
||||
flaxEnginePath = Globals::BinariesFolder / TEXT("Dotnet") / TEXT("FlaxEngine.CSharp.dll");
|
||||
#endif
|
||||
if (flaxEngineModule->Assembly->Load(flaxEnginePath))
|
||||
{
|
||||
LOG(Error, "Failed to load FlaxEngine C# assembly.");
|
||||
|
||||
@@ -198,7 +198,7 @@ namespace FlaxEngine
|
||||
private static void OnLocalizationChanged()
|
||||
{
|
||||
// Invariant-globalization only (see InitHostfxr with Mono)
|
||||
#if !(PLATFORM_IOS || PLATFORM_SWITCH)
|
||||
#if !(PLATFORM_IOS || PLATFORM_SWITCH || PLATFORM_PS4 || PLATFORM_PS5)
|
||||
var currentThread = Thread.CurrentThread;
|
||||
var language = Localization.CurrentLanguage;
|
||||
if (language != null)
|
||||
@@ -261,7 +261,7 @@ namespace FlaxEngine
|
||||
|
||||
internal static ManagedHandle CultureInfoToManaged(int lcid)
|
||||
{
|
||||
#if PLATFORM_IOS || PLATFORM_SWITCH
|
||||
#if PLATFORM_IOS || PLATFORM_SWITCH || PLATFORM_PS4 || PLATFORM_PS5
|
||||
// Invariant-globalization only (see InitHostfxr with Mono)
|
||||
lcid = 0;
|
||||
#endif
|
||||
|
||||
@@ -15,6 +15,7 @@
|
||||
#include "Engine/Profiler/ProfilerMemory.h"
|
||||
#if USE_CSHARP
|
||||
#include "Engine/Scripting/ManagedCLR/MCore.h"
|
||||
#include "Engine/Scripting/Internal/InternalCalls.h"
|
||||
#endif
|
||||
|
||||
#define JOB_SYSTEM_ENABLED 1
|
||||
@@ -184,6 +185,7 @@ int32 JobSystemThread::Run()
|
||||
JobData data;
|
||||
Function<void(int32)> job;
|
||||
bool attachCSharpThread = true;
|
||||
MONO_THREAD_INFO_TYPE* monoThreadInfo = nullptr;
|
||||
while (Platform::AtomicRead(&ExitFlag) == 0)
|
||||
{
|
||||
// Try to get a job
|
||||
@@ -205,6 +207,7 @@ int32 JobSystemThread::Run()
|
||||
{
|
||||
MCore::Thread::Attach();
|
||||
attachCSharpThread = false;
|
||||
monoThreadInfo = mono_thread_info_attach();
|
||||
}
|
||||
#endif
|
||||
|
||||
@@ -244,9 +247,11 @@ int32 JobSystemThread::Run()
|
||||
else
|
||||
{
|
||||
// Wait for signal
|
||||
MONO_ENTER_GC_SAFE_WITH_INFO(monoThreadInfo);
|
||||
JobsMutex.Lock();
|
||||
JobsSignal.Wait(JobsMutex);
|
||||
JobsMutex.Unlock();
|
||||
MONO_EXIT_GC_SAFE_WITH_INFO;
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
|
||||
@@ -15,6 +15,7 @@
|
||||
#include "Engine/Platform/CPUInfo.h"
|
||||
#include "Engine/Platform/Thread.h"
|
||||
#include "Engine/Profiler/ProfilerMemory.h"
|
||||
#include "Engine/Scripting/Internal/InternalCalls.h"
|
||||
|
||||
FLAXENGINE_API bool IsInMainThread()
|
||||
{
|
||||
@@ -117,6 +118,7 @@ int32 ThreadPool::ThreadProc()
|
||||
Platform::SetThreadAffinityMask(THREAD_POOL_AFFINITY_MASK((int32)index));
|
||||
#endif
|
||||
ThreadPoolTask* task;
|
||||
MONO_THREAD_INFO_TYPE* monoThreadInfo = nullptr;
|
||||
|
||||
// Work until end
|
||||
while (Platform::AtomicRead(&ThreadPoolImpl::ExitFlag) == 0)
|
||||
@@ -125,12 +127,15 @@ int32 ThreadPool::ThreadProc()
|
||||
if (ThreadPoolImpl::Jobs.try_dequeue(task))
|
||||
{
|
||||
task->Execute();
|
||||
MONO_THREAD_INFO_GET(monoThreadInfo);
|
||||
}
|
||||
else
|
||||
{
|
||||
MONO_ENTER_GC_SAFE_WITH_INFO(monoThreadInfo);
|
||||
ThreadPoolImpl::JobsMutex.Lock();
|
||||
ThreadPoolImpl::JobsSignal.Wait(ThreadPoolImpl::JobsMutex);
|
||||
ThreadPoolImpl::JobsMutex.Unlock();
|
||||
MONO_EXIT_GC_SAFE_WITH_INFO;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -329,7 +329,7 @@ float3 GetInscatteredLight(AtmosphericFogData atmosphericFog, in float3 viewPosi
|
||||
if (intersectAtmosphere(viewPosition, viewDir, offset, maxPathLength))
|
||||
{
|
||||
return float3(offset / 10, 0, 0);
|
||||
|
||||
#if 0
|
||||
float pathLength = distance(viewPosition, surfacePos);
|
||||
//return pathLength.xxx;
|
||||
|
||||
@@ -413,6 +413,7 @@ float3 GetInscatteredLight(AtmosphericFogData atmosphericFog, in float3 viewPosi
|
||||
float sunIntensity = 10;
|
||||
inscatteredLight *= sunIntensity;
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
return inscatteredLight;
|
||||
@@ -420,8 +421,6 @@ float3 GetInscatteredLight(AtmosphericFogData atmosphericFog, in float3 viewPosi
|
||||
|
||||
float4 GetAtmosphericFog(AtmosphericFogData atmosphericFog, float viewFar, float3 viewPosition, float3 viewVector, float sceneDepth, float3 sceneColor)
|
||||
{
|
||||
float4 result = float4(1, 0, 0, 1);
|
||||
|
||||
#if 0
|
||||
|
||||
float scale = 0.00001f * atmosphericFog.AtmosphericFogDistanceScale;// convert cm to km
|
||||
@@ -536,8 +535,6 @@ float4 GetAtmosphericFog(AtmosphericFogData atmosphericFog, float viewFar, float
|
||||
//return float4(sun + groundColor + inscatterColor, 1);
|
||||
|
||||
#endif
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
float4 GetAtmosphericFog(AtmosphericFogData atmosphericFog, float viewFar, float3 worldPosition, float3 cameraPosition)
|
||||
|
||||
@@ -96,34 +96,9 @@
|
||||
// Compiler support for HLSL 2021 that is stricter (need to use or/and/select for vector-based logical operators)
|
||||
#if !defined(__DXC_VERSION_MAJOR) || (__DXC_VERSION_MAJOR <= 1 && __DXC_VERSION_MINOR < 7)
|
||||
|
||||
bool InternalAnd(bool a, bool b) { return bool(a && b); }
|
||||
bool2 InternalAnd(bool2 a, bool2 b) { return bool2(a.x && b.x, a.y && b.y); }
|
||||
bool3 InternalAnd(bool3 a, bool3 b) { return bool3(a.x && b.x, a.y && b.y, a.z && b.z); }
|
||||
bool4 InternalAnd(bool4 a, bool4 b) { return bool4(a.x && b.x, a.y && b.y, a.z && b.z, a.w && b.w); }
|
||||
|
||||
bool InternalOr(bool a, bool b) { return bool(a || b); }
|
||||
bool2 InternalOr(bool2 a, bool2 b) { return bool2(a.x || b.x, a.y || b.y); }
|
||||
bool3 InternalOr(bool3 a, bool3 b) { return bool3(a.x || b.x, a.y || b.y, a.z || b.z); }
|
||||
bool4 InternalOr(bool4 a, bool4 b) { return bool4(a.x || b.x, a.y || b.y, a.z || b.z, a.w || b.w); }
|
||||
|
||||
#define SELECT_INTERNAL(type) \
|
||||
type InternalSelect(bool c, type a, type b) { return type (c ? a.x : b.x); } \
|
||||
type##2 InternalSelect(bool c, type##2 a, type##2 b) { return type##2(c ? a.x : b.x, c ? a.y : b.y); } \
|
||||
type##2 InternalSelect(bool2 c, type a, type b) { return type##2(c.x ? a : b, c.y ? a : b); } \
|
||||
type##2 InternalSelect(bool2 c, type##2 a, type##2 b) { return type##2(c.x ? a.x : b.x, c.y ? a.y : b.y); } \
|
||||
type##3 InternalSelect(bool c, type##3 a, type##3 b) { return type##3(c ? a.x : b.x, c ? a.y : b.y, c ? a.z : b.z); } \
|
||||
type##3 InternalSelect(bool3 c, type a, type b) { return type##3(c.x ? a : b, c.y ? a : b, c.z ? a : b); } \
|
||||
type##3 InternalSelect(bool3 c, type##3 a, type##3 b) { return type##3(c.x ? a.x : b.x, c.y ? a.y : b.y, c.z ? a.z : b.z); } \
|
||||
type##4 InternalSelect(bool c, type##4 a, type##4 b) { return type##4(c ? a.x : b.x, c ? a.y : b.y, c ? a.z : b.z, c ? a.w : b.w); } \
|
||||
type##4 InternalSelect(bool4 c, type a, type b) { return type##4(c.x ? a : b, c.y ? a : b, c.z ? a : b, c.w ? a : b); } \
|
||||
type##4 InternalSelect(bool4 c, type##4 a, type##4 b) { return type##4(c.x ? a.x : b.x, c.y ? a.y : b.y, c.z ? a.z : b.z, c.w ? a.w : b.w); }
|
||||
SELECT_INTERNAL(uint)
|
||||
SELECT_INTERNAL(float)
|
||||
#undef SELECT_INTERNAL
|
||||
|
||||
#define and(a, b) InternalAnd(a, b)
|
||||
#define or(a, b) InternalOr(a, b)
|
||||
#define select(c, a, b) InternalSelect(c, a, b)
|
||||
#define and(a, b) (a) && (b)
|
||||
#define or(a, b) (a) || (b)
|
||||
#define select(c, a, b) (c) ? (a) : (b)
|
||||
|
||||
#endif
|
||||
|
||||
|
||||
@@ -311,7 +311,7 @@ float3 AOMultiBounce(float visibility, float3 albedo)
|
||||
|
||||
float2 Flipbook(float2 uv, float frame, float2 sizeXY, float2 flipXY = 0.0f)
|
||||
{
|
||||
float tile = (int)fmod(frame, sizeXY.x * sizeXY.y);
|
||||
float tile = (float)(int)fmod(frame, sizeXY.x * sizeXY.y);
|
||||
float2 tileCount = float2(1.0, 1.0) / sizeXY;
|
||||
float tileY = abs(flipXY.y * sizeXY.y - (floor(tile * tileCount.x) + flipXY.y * 1));
|
||||
float tileX = abs(flipXY.x * sizeXY.x - ((tile - sizeXY.x * floor(tile * tileCount.x)) + flipXY.x * 1));
|
||||
|
||||
@@ -16,13 +16,10 @@ struct BVHNode
|
||||
int Count; // Negative for non-leaf nodes
|
||||
};
|
||||
|
||||
struct BVHBuffers
|
||||
{
|
||||
StructuredBuffer<BVHNode> BVHBuffer;
|
||||
ByteAddressBuffer VertexBuffer;
|
||||
ByteAddressBuffer IndexBuffer;
|
||||
uint VertexStride;
|
||||
};
|
||||
// Pass all data via separate params (SPIR-V doesn't support buffers in structures)
|
||||
#define BVHBuffers_Param StructuredBuffer<BVHNode> BVHBuffer, ByteAddressBuffer VertexBuffer, ByteAddressBuffer IndexBuffer, uint VertexStride
|
||||
#define BVHBuffers_Init(BVHBuffer, VertexBuffer, IndexBuffer, VertexStride) BVHBuffer, VertexBuffer, IndexBuffer, VertexStride
|
||||
#define BVHBuffers_Pass BVHBuffers_Init(BVHBuffer, VertexBuffer, IndexBuffer, VertexStride)
|
||||
|
||||
struct BVHHit
|
||||
{
|
||||
@@ -30,11 +27,11 @@ struct BVHHit
|
||||
bool IsBackface;
|
||||
};
|
||||
|
||||
float3 LoadVertexBVH(BVHBuffers bvh, uint index)
|
||||
float3 LoadVertexBVH(BVHBuffers_Param, uint index)
|
||||
{
|
||||
int addr = index << 2u;
|
||||
uint vertexIndex = bvh.IndexBuffer.Load(addr);
|
||||
return asfloat(bvh.VertexBuffer.Load3(vertexIndex * bvh.VertexStride));
|
||||
uint vertexIndex = IndexBuffer.Load(addr);
|
||||
return asfloat(VertexBuffer.Load3(vertexIndex * VertexStride));
|
||||
}
|
||||
|
||||
// [https://tavianator.com/2011/ray_box.html]
|
||||
@@ -52,7 +49,7 @@ float RayTestBoxBVH(float3 rayPos, float3 rayDir, float3 boxMin, float3 boxMax)
|
||||
}
|
||||
|
||||
// Performs raytracing against the BVH acceleration structure to find the closest intersection with a triangle.
|
||||
bool RayCastBVH(BVHBuffers bvh, float3 rayPos, float3 rayDir, out BVHHit hit, float maxDistance = 1000000.0f)
|
||||
bool RayCastBVH(BVHBuffers_Param, float3 rayPos, float3 rayDir, out BVHHit hit, float maxDistance = 1000000.0f)
|
||||
{
|
||||
hit = (BVHHit)0;
|
||||
hit.Distance = maxDistance;
|
||||
@@ -66,7 +63,7 @@ bool RayCastBVH(BVHBuffers bvh, float3 rayPos, float3 rayDir, out BVHHit hit, fl
|
||||
LOOP
|
||||
while (stackCount > 0)
|
||||
{
|
||||
BVHNode node = bvh.BVHBuffer[stack[--stackCount]];
|
||||
BVHNode node = BVHBuffer[stack[--stackCount]];
|
||||
|
||||
// Raytrace bounds
|
||||
float boundsHit = RayTestBoxBVH(rayPos, rayDir, node.BoundsMin, node.BoundsMax);
|
||||
@@ -82,9 +79,9 @@ bool RayCastBVH(BVHBuffers bvh, float3 rayPos, float3 rayDir, out BVHHit hit, fl
|
||||
for (uint i = indexStart; i < indexEnd;)
|
||||
{
|
||||
// Load triangle
|
||||
float3 v0 = LoadVertexBVH(bvh, i++);
|
||||
float3 v1 = LoadVertexBVH(bvh, i++);
|
||||
float3 v2 = LoadVertexBVH(bvh, i++);
|
||||
float3 v0 = LoadVertexBVH(BVHBuffers_Pass, i++);
|
||||
float3 v1 = LoadVertexBVH(BVHBuffers_Pass, i++);
|
||||
float3 v2 = LoadVertexBVH(BVHBuffers_Pass, i++);
|
||||
|
||||
// Raytrace triangle
|
||||
float distance;
|
||||
@@ -109,7 +106,7 @@ bool RayCastBVH(BVHBuffers bvh, float3 rayPos, float3 rayDir, out BVHHit hit, fl
|
||||
}
|
||||
|
||||
// Performs a query against the BVH acceleration structure to find the closest distance to a triangle from a given point.
|
||||
bool PointQueryBVH(BVHBuffers bvh, float3 pos, out BVHHit hit, float maxDistance = 1000000.0f)
|
||||
bool PointQueryBVH(BVHBuffers_Param, float3 pos, out BVHHit hit, float maxDistance = 1000000.0f)
|
||||
{
|
||||
hit = (BVHHit)0;
|
||||
hit.Distance = maxDistance;
|
||||
@@ -123,7 +120,7 @@ bool PointQueryBVH(BVHBuffers bvh, float3 pos, out BVHHit hit, float maxDistance
|
||||
LOOP
|
||||
while (stackCount > 0)
|
||||
{
|
||||
BVHNode node = bvh.BVHBuffer[stack[--stackCount]];
|
||||
BVHNode node = BVHBuffer[stack[--stackCount]];
|
||||
|
||||
// Skip too far nodes
|
||||
if (PointDistanceBox(node.BoundsMin, node.BoundsMax, pos) >= hit.Distance)
|
||||
@@ -138,9 +135,9 @@ bool PointQueryBVH(BVHBuffers bvh, float3 pos, out BVHHit hit, float maxDistance
|
||||
for (uint i = indexStart; i < indexEnd;)
|
||||
{
|
||||
// Load triangle
|
||||
float3 v0 = LoadVertexBVH(bvh, i++);
|
||||
float3 v1 = LoadVertexBVH(bvh, i++);
|
||||
float3 v2 = LoadVertexBVH(bvh, i++);
|
||||
float3 v0 = LoadVertexBVH(BVHBuffers_Pass, i++);
|
||||
float3 v1 = LoadVertexBVH(BVHBuffers_Pass, i++);
|
||||
float3 v2 = LoadVertexBVH(BVHBuffers_Pass, i++);
|
||||
|
||||
// Check triangle
|
||||
float distance = sqrt(DistancePointToTriangle2(pos, v0, v1, v2));
|
||||
|
||||
@@ -77,15 +77,9 @@ void CS_RasterizeTriangles(uint3 GroupId : SV_GroupID, uint3 GroupThreadID : SV_
|
||||
int3 voxelCoord = GetVoxelCoord(voxelIndex);
|
||||
float3 voxelPos = GetVoxelPos(voxelCoord);
|
||||
|
||||
BVHBuffers bvh;
|
||||
bvh.BVHBuffer = BVHBuffer;
|
||||
bvh.VertexBuffer = VertexBuffer;
|
||||
bvh.IndexBuffer = IndexBuffer;
|
||||
bvh.VertexStride = VertexStride;
|
||||
|
||||
// Point query to find the distance to the closest surface
|
||||
BVHHit hit;
|
||||
PointQueryBVH(bvh, voxelPos, hit, MaxDistance);
|
||||
PointQueryBVH(BVHBuffers_Init(BVHBuffer, VertexBuffer, IndexBuffer, VertexStride), voxelPos, hit, MaxDistance);
|
||||
float sdf = hit.Distance;
|
||||
|
||||
// Raycast triangles around voxel to count triangle backfaces hit
|
||||
@@ -104,7 +98,7 @@ void CS_RasterizeTriangles(uint3 GroupId : SV_GroupID, uint3 GroupThreadID : SV_
|
||||
for (uint i = 0; i < CLOSEST_CACHE_SIZE; i++)
|
||||
{
|
||||
float3 rayDir = closestDirections[i];
|
||||
if (RayCastBVH(bvh, voxelPos, rayDir, hit, MaxDistance))
|
||||
if (RayCastBVH(BVHBuffers_Init(BVHBuffer, VertexBuffer, IndexBuffer, VertexStride), voxelPos, rayDir, hit, MaxDistance))
|
||||
{
|
||||
sdf = min(sdf, hit.Distance);
|
||||
if (hit.IsBackface)
|
||||
|
||||
@@ -227,7 +227,8 @@ ShadowSample SampleDirectionalLightShadowCascade(LightData light, Buffer<float4>
|
||||
// Increase the sharpness for higher cascades to match the filter radius
|
||||
const float SharpnessScale[MaxNumCascades] = { 1.0f, 1.5f, 3.0f, 3.5f };
|
||||
shadow.Sharpness *= SharpnessScale[cascadeIndex];
|
||||
|
||||
|
||||
result.TransmissionShadow = 1;
|
||||
#if defined(USE_GBUFFER_CUSTOM_DATA)
|
||||
// Subsurface shadowing
|
||||
BRANCH
|
||||
@@ -239,8 +240,6 @@ ShadowSample SampleDirectionalLightShadowCascade(LightData light, Buffer<float4>
|
||||
result.TransmissionShadow = CalculateSubsurfaceOcclusion(opacity, shadowPosition.z, shadowMapDepth);
|
||||
result.TransmissionShadow = PostProcessShadow(shadow, result.TransmissionShadow);
|
||||
}
|
||||
#else
|
||||
result.TransmissionShadow = 1;
|
||||
#endif
|
||||
|
||||
result.SurfaceShadow = PostProcessShadow(shadow, result.SurfaceShadow);
|
||||
|
||||
@@ -462,7 +462,7 @@ namespace Flax.Build
|
||||
else
|
||||
{
|
||||
// Copy to the destination folder
|
||||
Utilities.FileCopy(assemblyPath, Path.Combine(dotnetOutputPath, assemblyFileName));
|
||||
Utilities.FileCopy(assemblyPath, Path.Combine(dotnetOutputPath, assemblyFileName), Utilities.CopyMode.OverrideIfNewer);
|
||||
}
|
||||
};
|
||||
if (Configuration.MaxConcurrency > 1 && Configuration.ConcurrencyProcessorScale > 0.0f && !dotnetAotDebug)
|
||||
|
||||
@@ -42,7 +42,8 @@ namespace Flax.Build
|
||||
BinaryModuleName = "FlaxEngine";
|
||||
options.ScriptingAPI.Defines.Add("FLAX");
|
||||
options.ScriptingAPI.Defines.Add("FLAX_ASSERTIONS");
|
||||
options.ScriptingAPI.FileReferences.Add(Utilities.RemovePathRelativeParts(Path.Combine(Globals.EngineRoot, "Source", "Platforms", "DotNet", "Newtonsoft.Json.dll")));
|
||||
var newtonsoftJsonPath = options.Platform?.HasDynamicCodeExecutionSupport ?? true ? "Newtonsoft.Json.dll" : "AOT/Newtonsoft.Json.dll";
|
||||
options.ScriptingAPI.FileReferences.Add(Utilities.RemovePathRelativeParts(Path.Combine(Globals.EngineRoot, "Source", "Platforms", "DotNet", newtonsoftJsonPath)));
|
||||
options.ScriptingAPI.SystemReferences.Add("System.ComponentModel.TypeConverter");
|
||||
}
|
||||
}
|
||||
|
||||
@@ -142,7 +142,7 @@ namespace Flax.Build
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Returns true if this build target should use separate (aka main-only) executable file and separate runtime (in shared library). Used on platforms that don't support linking again executable file but only shared library (see HasExecutableFileReferenceSupport).
|
||||
/// Returns true if this build target should use separate (aka main-only) executable file and separate runtime (in shared library). Used on platforms that don't support linking (or symbol lookup) against executable file but only shared library (see HasExecutableFileReferenceSupport).
|
||||
/// </summary>
|
||||
public virtual bool UseSeparateMainExecutable(BuildOptions buildOptions)
|
||||
{
|
||||
|
||||
@@ -320,6 +320,17 @@ namespace Flax.Build.Platforms
|
||||
{
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets linker argument to reference a specific shared library file.
|
||||
/// </summary>
|
||||
/// <param name="graph">The graph.</param>
|
||||
/// <param name="options">The options.</param>
|
||||
/// <param name="library">The shared library file path.</param>
|
||||
protected virtual string GetSharedLibraryLinkArg(TaskGraph graph, BuildOptions options, string library)
|
||||
{
|
||||
return string.Format("\"-l{0}\"", GetLibName(library));
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
public override CompileOutput CompileCppFiles(TaskGraph graph, BuildOptions options, List<string> sourceFiles, string outputPath)
|
||||
{
|
||||
@@ -534,7 +545,8 @@ namespace Flax.Build.Platforms
|
||||
|
||||
// Input libraries
|
||||
var libraryPaths = new HashSet<string>();
|
||||
foreach (var library in linkEnvironment.InputLibraries)
|
||||
var dynamicLibExt = Platform.SharedLibraryFileExtension;
|
||||
foreach (var library in linkEnvironment.InputLibraries.Concat(options.Libraries))
|
||||
{
|
||||
var dir = Path.GetDirectoryName(library);
|
||||
var ext = Path.GetExtension(library);
|
||||
@@ -546,37 +558,12 @@ namespace Flax.Build.Platforms
|
||||
{
|
||||
// Skip executable
|
||||
}
|
||||
else if (ext == ".so")
|
||||
else if (ext == dynamicLibExt)
|
||||
{
|
||||
// Link against dynamic library
|
||||
task.PrerequisiteFiles.Add(library);
|
||||
libraryPaths.Add(dir);
|
||||
args.Add(string.Format("\"-l{0}\"", GetLibName(library)));
|
||||
}
|
||||
else
|
||||
{
|
||||
task.PrerequisiteFiles.Add(library);
|
||||
args.Add(string.Format("\"{0}\"", GetLibName(library)));
|
||||
}
|
||||
}
|
||||
foreach (var library in options.Libraries)
|
||||
{
|
||||
var dir = Path.GetDirectoryName(library);
|
||||
var ext = Path.GetExtension(library);
|
||||
if (string.IsNullOrEmpty(dir))
|
||||
{
|
||||
args.Add(string.Format("\"-l{0}\"", library));
|
||||
}
|
||||
else if (string.IsNullOrEmpty(ext))
|
||||
{
|
||||
// Skip executable
|
||||
}
|
||||
else if (ext == ".so")
|
||||
{
|
||||
// Link against dynamic library
|
||||
task.PrerequisiteFiles.Add(library);
|
||||
libraryPaths.Add(dir);
|
||||
args.Add(string.Format("\"-l{0}\"", GetLibName(library)));
|
||||
args.Add(GetSharedLibraryLinkArg(graph, options, library));
|
||||
}
|
||||
else
|
||||
{
|
||||
@@ -587,8 +574,7 @@ namespace Flax.Build.Platforms
|
||||
|
||||
// Input files (link static libraries last)
|
||||
task.PrerequisiteFiles.AddRange(linkEnvironment.InputFiles);
|
||||
foreach (var file in linkEnvironment.InputFiles.Where(x => !x.EndsWith(".a"))
|
||||
.Concat(linkEnvironment.InputFiles.Where(x => x.EndsWith(".a"))))
|
||||
foreach (var file in linkEnvironment.InputFiles.Where(x => !x.EndsWith(".a")).Concat(linkEnvironment.InputFiles.Where(x => x.EndsWith(".a"))))
|
||||
{
|
||||
args.Add(string.Format("\"{0}\"", file.Replace('\\', '/')));
|
||||
}
|
||||
|
||||
@@ -144,24 +144,51 @@ namespace Flax.Build
|
||||
return new TwoWayEnumerator<T>(source.GetEnumerator());
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// File copy modes.
|
||||
/// </summary>
|
||||
public enum CopyMode
|
||||
{
|
||||
/// <summary>
|
||||
/// Copies the file to the destination, fails if it already exists.
|
||||
/// </summary>
|
||||
New,
|
||||
|
||||
/// <summary>
|
||||
/// If destination file exists, it will be overriden.
|
||||
/// </summary>
|
||||
OverrideIfExists,
|
||||
|
||||
/// <summary>
|
||||
/// If destination file exists, has the same size and is newer than source file, it won't be overriden (avoids unnecessary copies).
|
||||
/// </summary>
|
||||
OverrideIfNewer,
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Copies the file.
|
||||
/// </summary>
|
||||
/// <param name="srcFilePath">The source file path.</param>
|
||||
/// <param name="dstFilePath">The destination file path.</param>
|
||||
/// <param name="overwrite"><see langword="true" /> if the destination file can be overwritten; otherwise, <see langword="false" />.</param>
|
||||
public static void FileCopy(string srcFilePath, string dstFilePath, bool overwrite = true)
|
||||
/// <param name="mode">Copy operation modes.</param>
|
||||
public static void FileCopy(string srcFilePath, string dstFilePath, CopyMode mode = CopyMode.OverrideIfExists)
|
||||
{
|
||||
if (string.IsNullOrEmpty(srcFilePath))
|
||||
throw new ArgumentNullException(nameof(srcFilePath));
|
||||
if (string.IsNullOrEmpty(dstFilePath))
|
||||
throw new ArgumentNullException(nameof(dstFilePath));
|
||||
|
||||
if (mode == CopyMode.OverrideIfNewer &&
|
||||
File.Exists(dstFilePath) &&
|
||||
File.GetLastWriteTime(srcFilePath) <= File.GetLastWriteTime(dstFilePath) &&
|
||||
new FileInfo(dstFilePath).Length == new FileInfo(srcFilePath).Length)
|
||||
return;
|
||||
|
||||
Log.Verbose(srcFilePath + " -> " + dstFilePath);
|
||||
|
||||
try
|
||||
{
|
||||
File.Copy(srcFilePath, dstFilePath, overwrite);
|
||||
File.Copy(srcFilePath, dstFilePath, mode != CopyMode.New);
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
@@ -173,6 +200,17 @@ namespace Flax.Build
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Copies the file.
|
||||
/// </summary>
|
||||
/// <param name="srcFilePath">The source file path.</param>
|
||||
/// <param name="dstFilePath">The destination file path.</param>
|
||||
/// <param name="overwrite"><see langword="true" /> if the destination file can be overwritten; otherwise, <see langword="false" />.</param>
|
||||
public static void FileCopy(string srcFilePath, string dstFilePath, bool overwrite)
|
||||
{
|
||||
FileCopy(srcFilePath, dstFilePath, overwrite ? CopyMode.OverrideIfExists : CopyMode.New);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Copies the directories.
|
||||
/// </summary>
|
||||
|
||||
Reference in New Issue
Block a user