From d7ff9fdadebe2566d23216c30387a88f873865df Mon Sep 17 00:00:00 2001 From: Wojtek Figat Date: Mon, 9 Jun 2025 15:23:31 +0200 Subject: [PATCH] Optimize editor profiler native allocations when capturing data --- Source/Engine/Content/Content.cpp | 17 +++++++++++++++++ Source/Engine/Content/Content.cs | 14 ++++++++++++++ Source/Engine/Content/Content.h | 7 ++++++- Source/Engine/Engine/NativeInterop.cs | 5 ++++- Source/Engine/Graphics/GPUBufferDescription.cs | 18 ++++++++++++++++++ Source/Engine/Graphics/GPUDevice.cpp | 17 +++++++++++++++++ Source/Engine/Graphics/GPUDevice.h | 8 +++++++- 7 files changed, 83 insertions(+), 3 deletions(-) diff --git a/Source/Engine/Content/Content.cpp b/Source/Engine/Content/Content.cpp index 915f48140..4ba6cbc44 100644 --- a/Source/Engine/Content/Content.cpp +++ b/Source/Engine/Content/Content.cpp @@ -800,6 +800,23 @@ void Content::deleteFileSafety(const StringView& path, const Guid& id) #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 bool Content::RenameAsset(const StringView& oldPath, const StringView& newPath) diff --git a/Source/Engine/Content/Content.cs b/Source/Engine/Content/Content.cs index 4fcc0c300..4f07e1dc6 100644 --- a/Source/Engine/Content/Content.cs +++ b/Source/Engine/Content/Content.cs @@ -1,5 +1,6 @@ // Copyright (c) Wojciech Figat. All rights reserved. +using FlaxEngine.Interop; using System; using System.Runtime.CompilerServices; @@ -7,6 +8,19 @@ namespace FlaxEngine { partial class Content { + /// + /// Gets the assets (loaded or during load). + /// + public static Asset[] Assets + { + get + { + IntPtr ptr = Internal_GetAssetsInternal(); + ManagedArray array = Unsafe.As(ManagedHandle.FromIntPtr(ptr).Target); + return NativeInterop.GCHandleArrayToManagedArray(array); + } + } + /// /// 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. /// diff --git a/Source/Engine/Content/Content.h b/Source/Engine/Content/Content.h index c11a9ed11..15ace944a 100644 --- a/Source/Engine/Content/Content.h +++ b/Source/Engine/Content/Content.h @@ -122,7 +122,7 @@ public: /// Gets the assets (loaded or during load). /// /// The collection of assets. - API_PROPERTY() static Array GetAssets(); + static Array GetAssets(); /// /// Gets the raw dictionary of assets (loaded or during load). @@ -368,4 +368,9 @@ private: static void onAssetUnload(Asset* asset); static void onAssetChangeId(Asset* asset, const Guid& oldId, const Guid& newId); static void deleteFileSafety(const StringView& path, const Guid& id); + + // Internal bindings +#if !COMPILE_WITHOUT_CSHARP + API_FUNCTION(NoProxy) static void* GetAssetsInternal(); +#endif }; diff --git a/Source/Engine/Engine/NativeInterop.cs b/Source/Engine/Engine/NativeInterop.cs index 368c67132..8138d3604 100644 --- a/Source/Engine/Engine/NativeInterop.cs +++ b/Source/Engine/Engine/NativeInterop.cs @@ -201,7 +201,10 @@ namespace FlaxEngine.Interop Span span = ptrArray.ToSpan(); T[] managedArray = new T[ptrArray.Length]; for (int i = 0; i < managedArray.Length; i++) - managedArray[i] = span[i] != IntPtr.Zero ? (T)ManagedHandle.FromIntPtr(span[i]).Target : default; + { + IntPtr ptr = span[i]; + managedArray[i] = ptr != IntPtr.Zero ? (T)ManagedHandle.FromIntPtr(ptr).Target : default; + } return managedArray; } diff --git a/Source/Engine/Graphics/GPUBufferDescription.cs b/Source/Engine/Graphics/GPUBufferDescription.cs index 290e43a7a..9e52876fc 100644 --- a/Source/Engine/Graphics/GPUBufferDescription.cs +++ b/Source/Engine/Graphics/GPUBufferDescription.cs @@ -1,9 +1,27 @@ // Copyright (c) Wojciech Figat. All rights reserved. using System; +using System.Runtime.CompilerServices; +using FlaxEngine.Interop; namespace FlaxEngine { + partial class GPUDevice + { + /// + /// Gets the list with all active GPU resources. + /// + public GPUResource[] Resources + { + get + { + IntPtr ptr = Internal_GetResourcesInternal(__unmanagedPtr); + ManagedArray array = Unsafe.As(ManagedHandle.FromIntPtr(ptr).Target); + return NativeInterop.GCHandleArrayToManagedArray(array); + } + } + } + partial struct GPUBufferDescription : IEquatable { /// diff --git a/Source/Engine/Graphics/GPUDevice.cpp b/Source/Engine/Graphics/GPUDevice.cpp index 1ea008913..18b9cdffc 100644 --- a/Source/Engine/Graphics/GPUDevice.cpp +++ b/Source/Engine/Graphics/GPUDevice.cpp @@ -648,6 +648,23 @@ GPUTasksExecutor* GPUDevice::CreateTasksExecutor() return New(); } +#if !COMPILE_WITHOUT_CSHARP + +#include "Engine/Scripting/ManagedCLR/MUtils.h" + +void* GPUDevice::GetResourcesInternal() +{ + _resourcesLock.Lock(); + MArray* result = MCore::Array::New(GPUResource::TypeInitializer.GetClass(), _resources.Count()); + int32 i = 0; + for (const auto& e : _resources) + MCore::GC::WriteArrayRef(result, e->GetOrCreateManagedInstance(), i++); + _resourcesLock.Unlock(); + return result; +} + +#endif + void GPUDevice::Draw() { PROFILE_MEM(Graphics); diff --git a/Source/Engine/Graphics/GPUDevice.h b/Source/Engine/Graphics/GPUDevice.h index c54395df8..8914085eb 100644 --- a/Source/Engine/Graphics/GPUDevice.h +++ b/Source/Engine/Graphics/GPUDevice.h @@ -236,7 +236,7 @@ public: /// /// Gets the list with all active GPU resources. /// - API_PROPERTY() Array GetResources() const; + Array GetResources() const; /// /// Gets the GPU asynchronous work manager. @@ -432,6 +432,12 @@ public: /// /// The GPU tasks executor. virtual GPUTasksExecutor* CreateTasksExecutor(); + +private: + // Internal bindings +#if !COMPILE_WITHOUT_CSHARP + API_FUNCTION(NoProxy) void* GetResourcesInternal(); +#endif }; ///