diff --git a/Content/Shaders/SDF.flax b/Content/Shaders/SDF.flax index 5141c14dd..709cc20f2 100644 --- a/Content/Shaders/SDF.flax +++ b/Content/Shaders/SDF.flax @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:d2b1dc1523cb2140db7ce5fed6e97b09d7fcebbe6cc19fca7708b5b882267040 -size 4175 +oid sha256:d3922811f0eb56cbb515c93cd53d80316740ea78219aa81118d2c9dee4a9d230 +size 4142 diff --git a/Source/Editor/Surface/SurfaceNode.cs b/Source/Editor/Surface/SurfaceNode.cs index e1d7c131f..6312bd68d 100644 --- a/Source/Editor/Surface/SurfaceNode.cs +++ b/Source/Editor/Surface/SurfaceNode.cs @@ -431,27 +431,6 @@ namespace FlaxEditor.Surface /// public bool HasIndependentBoxes => Archetype.IndependentBoxes != null; - /// - /// Gets a value indicating whether this node has dependent boxes with assigned valid types. Otherwise any box has no dependent type assigned. - /// - public bool HasDependentBoxesSetup - { - get - { - if (Archetype.DependentBoxes == null || Archetype.IndependentBoxes == null) - return true; - - for (int i = 0; i < Archetype.DependentBoxes.Length; i++) - { - var b = GetBox(Archetype.DependentBoxes[i]); - if (b != null && b.CurrentType == b.DefaultType) - return false; - } - - return true; - } - } - private static readonly List UpdateStack = new List(); /// diff --git a/Source/Editor/Surface/VisjectSurface.Input.cs b/Source/Editor/Surface/VisjectSurface.Input.cs index 51fd96ad6..cbc041c09 100644 --- a/Source/Editor/Surface/VisjectSurface.Input.cs +++ b/Source/Editor/Surface/VisjectSurface.Input.cs @@ -469,7 +469,8 @@ namespace FlaxEditor.Surface bool handled = base.OnMouseDown(location, button); if (!handled) CustomMouseDown?.Invoke(ref location, button, ref handled); - if (handled) + var root = Root; + if (handled || root == null) { // Clear flags _isMovingSelection = false; @@ -523,11 +524,11 @@ namespace FlaxEditor.Surface if (_leftMouseDown && controlUnderMouse.CanSelect(ref cLocation)) { // Check if user is pressing control - if (Root.GetKey(KeyboardKeys.Control)) + if (root.GetKey(KeyboardKeys.Control)) { AddToSelection(controlUnderMouse); } - else if (Root.GetKey(KeyboardKeys.Shift)) + else if (root.GetKey(KeyboardKeys.Shift)) { RemoveFromSelection(controlUnderMouse); } @@ -539,7 +540,7 @@ namespace FlaxEditor.Surface } // Start moving selected nodes - if (!Root.GetKey(KeyboardKeys.Shift)) + if (!root.GetKey(KeyboardKeys.Shift)) { StartMouseCapture(); _movingSelectionViewPos = _rootControl.Location; @@ -559,7 +560,7 @@ namespace FlaxEditor.Surface // Start selecting or commenting StartMouseCapture(); - if (!Root.GetKey(KeyboardKeys.Control) && !Root.GetKey(KeyboardKeys.Shift)) + if (!root.GetKey(KeyboardKeys.Control) && !root.GetKey(KeyboardKeys.Shift)) { ClearSelection(); } diff --git a/Source/Editor/Surface/VisjectSurfaceContext.Serialization.cs b/Source/Editor/Surface/VisjectSurfaceContext.Serialization.cs index a00d37aef..ed19b937f 100644 --- a/Source/Editor/Surface/VisjectSurfaceContext.Serialization.cs +++ b/Source/Editor/Surface/VisjectSurfaceContext.Serialization.cs @@ -178,19 +178,31 @@ namespace FlaxEditor.Surface // Update boxes types for nodes that dependant box types based on incoming connections { - bool keepUpdating = false; - int updateLimit = 100; + bool keepUpdating = true; + int updatesMin = 2, updatesMax = 100; do { + keepUpdating = false; for (int i = 0; i < RootControl.Children.Count; i++) { - if (RootControl.Children[i] is SurfaceNode node && !node.HasDependentBoxesSetup) + if (RootControl.Children[i] is SurfaceNode node) { node.UpdateBoxesTypes(); - keepUpdating = true; + var arch = node.Archetype; + if (arch.DependentBoxes != null && arch.IndependentBoxes != null) + { + foreach (var boxId in arch.DependentBoxes) + { + var b = node.GetBox(boxId); + if (b != null && b.CurrentType == b.DefaultType) + { + keepUpdating = true; + } + } + } } } - } while (keepUpdating && updateLimit-- > 0); + } while ((keepUpdating && --updatesMax > 0) || --updatesMin > 0); } Loaded?.Invoke(this); diff --git a/Source/Editor/Windows/Assets/MaterialInstanceWindow.cs b/Source/Editor/Windows/Assets/MaterialInstanceWindow.cs index 4a896c674..cb39930f9 100644 --- a/Source/Editor/Windows/Assets/MaterialInstanceWindow.cs +++ b/Source/Editor/Windows/Assets/MaterialInstanceWindow.cs @@ -14,7 +14,6 @@ using FlaxEditor.Surface; using FlaxEditor.Viewport.Previews; using FlaxEngine; using FlaxEngine.GUI; -using FlaxEngine.Utilities; namespace FlaxEditor.Windows.Assets { @@ -430,7 +429,7 @@ namespace FlaxEditor.Windows.Assets for (var i = 0; i < parameters.Length; i++) { var p = parameters[i]; - if (p.IsOverride) + if (p.IsOverride && p.IsPublic) { p.IsOverride = false; actions.Add(new EditParamOverrideAction diff --git a/Source/Engine/Animations/Graph/AnimGroup.Animation.cpp b/Source/Engine/Animations/Graph/AnimGroup.Animation.cpp index c76bddf3f..fd62ec537 100644 --- a/Source/Engine/Animations/Graph/AnimGroup.Animation.cpp +++ b/Source/Engine/Animations/Graph/AnimGroup.Animation.cpp @@ -246,11 +246,19 @@ void AnimGraphExecutor::ProcessAnimEvents(AnimGraphNode* node, bool loop, float const float duration = k.Value.Duration > 1 ? k.Value.Duration : 0.0f; #define ADD_OUTGOING_EVENT(type) context.Data->OutgoingEvents.Add({ k.Value.Instance, (AnimatedModel*)context.Data->Object, anim, eventTime, eventDeltaTime, AnimGraphInstanceData::OutgoingEvent::type }) if ((k.Time <= eventTimeMax && eventTimeMin <= k.Time + duration - && (Math::FloorToInt(animPos) != 0 && Math::CeilToInt(animPrevPos) != Math::CeilToInt(anim->GetDuration()) && Math::FloorToInt(animPrevPos) != 0 && Math::CeilToInt(animPos) != Math::CeilToInt(anim->GetDuration()))) + && (Math::FloorToInt(animPos) != 0 && Math::CeilToInt(animPrevPos) != Math::CeilToInt(anim->GetDuration()) + && Math::FloorToInt(animPrevPos) != 0 && Math::CeilToInt(animPos) != Math::CeilToInt(anim->GetDuration()))) // Handle the edge case of an event on 0 or on max animation duration during looping - || (loop && duration == 0.0f && Math::CeilToInt(animPos) == Math::CeilToInt(anim->GetDuration()) && k.Time == anim->GetDuration()) + || (!loop && duration == 0.0f && Math::CeilToInt(animPos) == Math::CeilToInt(anim->GetDuration()) && Math::CeilToInt(animPrevPos) == Math::CeilToInt(anim->GetDuration()) - 1 && Math::NearEqual(k.Time, anim->GetDuration())) || (loop && Math::FloorToInt(animPos) == 0 && Math::CeilToInt(animPrevPos) == Math::CeilToInt(anim->GetDuration()) && k.Time == 0.0f) || (loop && Math::FloorToInt(animPrevPos) == 0 && Math::CeilToInt(animPos) == Math::CeilToInt(anim->GetDuration()) && k.Time == 0.0f) + || (loop && Math::FloorToInt(animPos) == 0 && Math::CeilToInt(animPrevPos) == Math::CeilToInt(anim->GetDuration()) && Math::NearEqual(k.Time, anim->GetDuration())) + || (loop && Math::FloorToInt(animPrevPos) == 0 && Math::CeilToInt(animPos) == Math::CeilToInt(anim->GetDuration()) && Math::NearEqual(k.Time, anim->GetDuration())) + || (Math::FloorToInt(animPos) == 1 && Math::FloorToInt(animPrevPos) == 0 && k.Time == 1.0f) + || (Math::FloorToInt(animPos) == 0 && Math::FloorToInt(animPrevPos) == 1 && k.Time == 1.0f) + || (Math::CeilToInt(animPos) == Math::CeilToInt(anim->GetDuration()) && Math::CeilToInt(animPrevPos) == Math::CeilToInt(anim->GetDuration()) - 1 && Math::NearEqual(k.Time, anim->GetDuration() - 1.0f)) + || (Math::CeilToInt(animPos) == Math::CeilToInt(anim->GetDuration()) - 1 && Math::CeilToInt(animPrevPos) == Math::CeilToInt(anim->GetDuration()) && Math::NearEqual(k.Time, anim->GetDuration() - 1.0f)) + || (Math::FloorToInt(animPos) == 0 && Math::FloorToInt(animPrevPos) == 0 && k.Time == 0.0f) ) { int32 stateIndex = -1; diff --git a/Source/Engine/Content/Assets/MaterialInstance.cpp b/Source/Engine/Content/Assets/MaterialInstance.cpp index 78a276a8a..8d142626e 100644 --- a/Source/Engine/Content/Assets/MaterialInstance.cpp +++ b/Source/Engine/Content/Assets/MaterialInstance.cpp @@ -243,7 +243,8 @@ Asset::LoadResult MaterialInstance::load() ParamsChanged(); } - baseMaterial->RemoveReference(); + if (baseMaterial) + baseMaterial->RemoveReference(); return LoadResult::Ok; } diff --git a/Source/Engine/Content/AssetsContainer.h b/Source/Engine/Content/AssetsContainer.h index aceba1f07..dd9b549b5 100644 --- a/Source/Engine/Content/AssetsContainer.h +++ b/Source/Engine/Content/AssetsContainer.h @@ -18,7 +18,7 @@ public: /// The asset id. /// Loaded asset of null. template - T* LoadAsync(const Guid& id) + T* Load(const Guid& id) { for (auto& e : *this) { @@ -26,8 +26,10 @@ public: return (T*)e.Get(); } auto asset = (T*)::LoadAsset(id, T::TypeInitializer); - if (asset) + if (asset && !asset->WaitForLoaded()) Add(asset); + else + asset = nullptr; return asset; } diff --git a/Source/Engine/Level/Actors/Spline.cpp b/Source/Engine/Level/Actors/Spline.cpp index 25bdc4ce9..d6c2417c8 100644 --- a/Source/Engine/Level/Actors/Spline.cpp +++ b/Source/Engine/Level/Actors/Spline.cpp @@ -518,7 +518,7 @@ namespace Vector3 nextPos = transform.LocalToWorld(next->Value.Translation); DEBUG_DRAW_WIRE_SPHERE(BoundingSphere(nextPos, NodeSizeByDistance(nextPos, scaleByDistance)), color, 0.0f, depthTest); const float d = (next->Time - prev->Time) / 3.0f; - DEBUG_DRAW_BEZIER(prevPos, prevPos + prev->TangentOut.Translation * d, nextPos + next->TangentIn.Translation * d, nextPos, color, 0.0f, depthTest); + DEBUG_DRAW_BEZIER(prevPos, transform.LocalToWorld(prev->Value.Translation + prev->TangentOut.Translation * d), transform.LocalToWorld(next->Value.Translation + next->TangentIn.Translation * d), nextPos, color, 0.0f, depthTest); prev = next; prevPos = nextPos; } diff --git a/Source/Engine/Particles/Graph/GPU/ParticleEmitterGraph.GPU.Particles.cpp b/Source/Engine/Particles/Graph/GPU/ParticleEmitterGraph.GPU.Particles.cpp index 197b53e13..6ae810d82 100644 --- a/Source/Engine/Particles/Graph/GPU/ParticleEmitterGraph.GPU.Particles.cpp +++ b/Source/Engine/Particles/Graph/GPU/ParticleEmitterGraph.GPU.Particles.cpp @@ -425,8 +425,8 @@ void ParticleEmitterGPUGenerator::ProcessGroupParticles(Box* box, Node* node, Va case 300: { // Load function asset - const auto function = Assets.LoadAsync((Guid)node->Values[0]); - if (!function || function->WaitForLoaded()) + const auto function = Assets.Load((Guid)node->Values[0]); + if (!function) { OnError(node, box, TEXT("Missing or invalid function.")); value = Value::Zero; @@ -439,7 +439,7 @@ void ParticleEmitterGPUGenerator::ProcessGroupParticles(Box* box, Node* node, Va { if (_callStack[i]->Type == GRAPH_NODE_MAKE_TYPE(14, 300)) { - const auto callFunc = Assets.LoadAsync((Guid)_callStack[i]->Values[0]); + const auto callFunc = Assets.Load((Guid)_callStack[i]->Values[0]); if (callFunc == function) { OnError(node, box, String::Format(TEXT("Recursive call to function '{0}'!"), function->ToString())); @@ -514,7 +514,7 @@ void ParticleEmitterGPUGenerator::ProcessGroupFunction(Box* box, Node* node, Val value = Value::Zero; break; } - const auto function = Assets.LoadAsync((Guid)functionCallNode->Values[0]); + const auto function = Assets.Load((Guid)functionCallNode->Values[0]); if (!_functions.TryGet(functionCallNode, graph) || !function) { OnError(node, box, TEXT("Missing calling function graph.")); diff --git a/Source/Engine/Renderer/DepthOfFieldPass.h b/Source/Engine/Renderer/DepthOfFieldPass.h index b7351c4b1..098c4061e 100644 --- a/Source/Engine/Renderer/DepthOfFieldPass.h +++ b/Source/Engine/Renderer/DepthOfFieldPass.h @@ -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 diff --git a/Source/Engine/Renderer/GI/GlobalSurfaceAtlasPass.cpp b/Source/Engine/Renderer/GI/GlobalSurfaceAtlasPass.cpp index 1c1b9e4e3..ce0ec1881 100644 --- a/Source/Engine/Renderer/GI/GlobalSurfaceAtlasPass.cpp +++ b/Source/Engine/Renderer/GI/GlobalSurfaceAtlasPass.cpp @@ -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; } diff --git a/Source/Engine/Scripting/ManagedCLR/MCore.cpp b/Source/Engine/Scripting/ManagedCLR/MCore.cpp index 4300434e3..350cc39d2 100644 --- a/Source/Engine/Scripting/ManagedCLR/MCore.cpp +++ b/Source/Engine/Scripting/ManagedCLR/MCore.cpp @@ -21,6 +21,7 @@ MDomain* MRootDomain = nullptr; MDomain* MActiveDomain = nullptr; Array> MDomains; +bool MCore::Ready = false; MClass* MCore::TypeCache::Void = nullptr; MClass* MCore::TypeCache::Object = nullptr; @@ -301,6 +302,11 @@ bool MProperty::IsStatic() const return false; } +void MCore::OnManagedEventAfterShutdown(const char* eventName) +{ + LOG(Error, "Found a binding leak on '{}' event used by C# scripting after shutdown. Ensure to unregister scripting events from objects during disposing.", ::String(eventName)); +} + MDomain* MCore::GetRootDomain() { return MRootDomain; diff --git a/Source/Engine/Scripting/ManagedCLR/MCore.h b/Source/Engine/Scripting/ManagedCLR/MCore.h index cedebe7b8..1f972af0d 100644 --- a/Source/Engine/Scripting/ManagedCLR/MCore.h +++ b/Source/Engine/Scripting/ManagedCLR/MCore.h @@ -57,6 +57,10 @@ public: static void UnloadScriptingAssemblyLoadContext(); #endif + // Utility for guarding against using C# scripting runtime after shutdown (eg. when asset delegate is not properly disposed). + static bool Ready; + static void OnManagedEventAfterShutdown(const char* eventName); + public: /// /// Utilities for C# object management. diff --git a/Source/Engine/Scripting/Runtime/DotNet.cpp b/Source/Engine/Scripting/Runtime/DotNet.cpp index 1b220b017..d8e5acaff 100644 --- a/Source/Engine/Scripting/Runtime/DotNet.cpp +++ b/Source/Engine/Scripting/Runtime/DotNet.cpp @@ -316,7 +316,8 @@ bool MCore::LoadEngine() char* buildInfo = CallStaticMethod(GetStaticMethodPointer(TEXT("GetRuntimeInformation"))); LOG(Info, ".NET runtime version: {0}", ::String(buildInfo)); - MCore::GC::FreeMemory(buildInfo); + GC::FreeMemory(buildInfo); + Ready = true; return false; } @@ -327,6 +328,7 @@ void MCore::UnloadEngine() return; PROFILE_CPU(); CallStaticMethod(GetStaticMethodPointer(TEXT("Exit"))); + Ready = false; MDomains.ClearDelete(); MRootDomain = nullptr; ShutdownHostfxr(); diff --git a/Source/Engine/Tools/MaterialGenerator/MaterialGenerator.Layer.cpp b/Source/Engine/Tools/MaterialGenerator/MaterialGenerator.Layer.cpp index 73b3058a3..c0f1ede7e 100644 --- a/Source/Engine/Tools/MaterialGenerator/MaterialGenerator.Layer.cpp +++ b/Source/Engine/Tools/MaterialGenerator/MaterialGenerator.Layer.cpp @@ -50,8 +50,8 @@ MaterialLayer* MaterialGenerator::GetLayer(const Guid& id, Node* caller) } // Load asset - Asset* asset = Assets.LoadAsync(id); - if (asset == nullptr || asset->WaitForLoaded(10 * 1000)) + Asset* asset = Assets.Load(id); + if (asset == nullptr) { OnError(caller, nullptr, TEXT("Failed to load material asset.")); return nullptr; diff --git a/Source/Engine/Tools/MaterialGenerator/MaterialGenerator.Material.cpp b/Source/Engine/Tools/MaterialGenerator/MaterialGenerator.Material.cpp index 4594446ec..c778c03ee 100644 --- a/Source/Engine/Tools/MaterialGenerator/MaterialGenerator.Material.cpp +++ b/Source/Engine/Tools/MaterialGenerator/MaterialGenerator.Material.cpp @@ -285,8 +285,8 @@ void MaterialGenerator::ProcessGroupMaterial(Box* box, Node* node, Value& value) case 24: { // Load function asset - const auto function = Assets.LoadAsync((Guid)node->Values[0]); - if (!function || function->WaitForLoaded()) + const auto function = Assets.Load((Guid)node->Values[0]); + if (!function) { OnError(node, box, TEXT("Missing or invalid function.")); value = Value::Zero; @@ -299,7 +299,7 @@ void MaterialGenerator::ProcessGroupMaterial(Box* box, Node* node, Value& value) { if (_callStack[i]->Type == GRAPH_NODE_MAKE_TYPE(1, 24)) { - const auto callFunc = Assets.LoadAsync((Guid)_callStack[i]->Values[0]); + const auto callFunc = Assets.Load((Guid)_callStack[i]->Values[0]); if (callFunc == function) { OnError(node, box, String::Format(TEXT("Recursive call to function '{0}'!"), function->ToString())); @@ -808,7 +808,7 @@ void MaterialGenerator::ProcessGroupFunction(Box* box, Node* node, Value& value) value = Value::Zero; break; } - const auto function = Assets.LoadAsync((Guid)functionCallNode->Values[0]); + const auto function = Assets.Load((Guid)functionCallNode->Values[0]); if (!_functions.TryGet(functionCallNode, graph) || !function) { OnError(node, box, TEXT("Missing calling function graph.")); diff --git a/Source/Engine/Visject/ShaderGraph.cpp b/Source/Engine/Visject/ShaderGraph.cpp index b6616d159..688e46382 100644 --- a/Source/Engine/Visject/ShaderGraph.cpp +++ b/Source/Engine/Visject/ShaderGraph.cpp @@ -704,8 +704,8 @@ void ShaderGenerator::ProcessGroupTools(Box* box, Node* node, Value& value) case 16: { // Get the variable type - auto asset = Assets.LoadAsync((Guid)node->Values[0]); - if (!asset || asset->WaitForLoaded()) + auto asset = Assets.Load((Guid)node->Values[0]); + if (!asset) { OnError(node, box, TEXT("Failed to load Gameplay Global asset.")); value = Value::Zero; diff --git a/Source/Shaders/Common.hlsl b/Source/Shaders/Common.hlsl index 10b2855f4..66303546a 100644 --- a/Source/Shaders/Common.hlsl +++ b/Source/Shaders/Common.hlsl @@ -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 diff --git a/Source/Shaders/MeshAccelerationStructure.hlsl b/Source/Shaders/MeshAccelerationStructure.hlsl index d98d25404..0559e5f55 100644 --- a/Source/Shaders/MeshAccelerationStructure.hlsl +++ b/Source/Shaders/MeshAccelerationStructure.hlsl @@ -16,13 +16,10 @@ struct BVHNode int Count; // Negative for non-leaf nodes }; -struct BVHBuffers -{ - StructuredBuffer 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 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)); diff --git a/Source/Shaders/SDF.shader b/Source/Shaders/SDF.shader index b2ae928f7..77e27d8f9 100644 --- a/Source/Shaders/SDF.shader +++ b/Source/Shaders/SDF.shader @@ -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) diff --git a/Source/Tools/Flax.Build/Bindings/BindingsGenerator.Cpp.cs b/Source/Tools/Flax.Build/Bindings/BindingsGenerator.Cpp.cs index 2f251932f..190036af4 100644 --- a/Source/Tools/Flax.Build/Bindings/BindingsGenerator.Cpp.cs +++ b/Source/Tools/Flax.Build/Bindings/BindingsGenerator.Cpp.cs @@ -2043,6 +2043,7 @@ namespace Flax.Build.Bindings contents.Append(')').AppendLine(); contents.Append(" {").AppendLine(); contents.Append(" static MMethod* method = nullptr;").AppendLine(); + contents.AppendFormat(" if (!MCore::Ready) {{ MCore::OnManagedEventAfterShutdown(\"{0}.{1}\"); return; }}", classTypeNameManaged, eventInfo.Name).AppendLine(); contents.AppendFormat(" if (!method) {{ method = {1}::TypeInitializer.GetClass()->GetMethod(\"Internal_{0}_Invoke\", {2}); CHECK(method); }}", eventInfo.Name, classTypeNameNative, paramsCount).AppendLine(); contents.Append(" MObject* exception = nullptr;").AppendLine(); if (paramsCount == 0)