refactor(core): asset pipeline overhaul & dock removal
- Introduced IAsset interface and refactored asset loading/saving. - Migrated TextureContentHeader to Ghost.Engine; updated usage. - Rewrote AssetRegistry, AssetCatalog, ImportCoordinator for new asset flow. - Added thread-safe ConcurrentHashSet utility. - Improved EditorApplication folder management/init. - Updated TextureAssetHandler/TextureProcessor for new import/export. - Added EditorContentProvider for asset access. - Updated AssetManager to use new AssetType enum; removed GCHandle. - Removed all custom docking controls and templates. - Deleted obsolete ViewModels/Pages (Console, Hierarchy, Inspector, Project). - Renamed ProjectBrowser to ContentBrowser; updated references. - Updated NuGet packages, Result conversions, and commit instructions. - General cleanup: namespaces, dead code, structure.
This commit is contained in:
@@ -1,47 +1,7 @@
|
||||
using Ghost.Core;
|
||||
using Ghost.Graphics.RHI;
|
||||
using Misaki.HighPerformance.LowLevel;
|
||||
using Misaki.HighPerformance.LowLevel.Buffer;
|
||||
using System.Runtime.InteropServices;
|
||||
|
||||
namespace Ghost.Engine.AssetLoader;
|
||||
|
||||
public abstract class Asset : IResourceReleasable
|
||||
{
|
||||
private bool _disposed;
|
||||
|
||||
public Guid ID
|
||||
{
|
||||
get;
|
||||
}
|
||||
|
||||
public abstract AssetType Type
|
||||
{
|
||||
get;
|
||||
}
|
||||
|
||||
protected Asset(Guid id)
|
||||
{
|
||||
ID = id;
|
||||
}
|
||||
|
||||
protected virtual void Release(IResourceDatabase resourceDatabase)
|
||||
{
|
||||
}
|
||||
|
||||
public void ReleaseResource(IResourceDatabase database)
|
||||
{
|
||||
if (_disposed)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
Release(database);
|
||||
|
||||
_disposed = true;
|
||||
}
|
||||
}
|
||||
|
||||
public readonly struct AssetReference : IEquatable<AssetReference>
|
||||
{
|
||||
private readonly int _value;
|
||||
@@ -84,71 +44,3 @@ public readonly struct AssetReference : IEquatable<AssetReference>
|
||||
return !(left == right);
|
||||
}
|
||||
}
|
||||
|
||||
[StructLayout(LayoutKind.Sequential, Size = 64)] // Leave extra space for future expansion without breaking compatibility
|
||||
public struct TextureContentHeader
|
||||
{
|
||||
public uint width;
|
||||
public uint height;
|
||||
public uint depth;
|
||||
public uint mipLevels;
|
||||
public uint dimension; // 1 for 1D, 2 for 2D, 3 for 3D
|
||||
public uint colorComponents;
|
||||
}
|
||||
|
||||
public class TextureAsset : Asset
|
||||
{
|
||||
private MemoryBlock _textureData;
|
||||
private readonly uint _width;
|
||||
private readonly uint _height;
|
||||
private readonly uint _depth;
|
||||
private readonly uint _colorComponents;
|
||||
private readonly uint _mipLevels;
|
||||
private readonly uint _dimension;
|
||||
|
||||
private Handle<GPUTexture> _textureHandle;
|
||||
|
||||
public override AssetType Type => AssetType.Texture;
|
||||
|
||||
public uint Width => _width;
|
||||
public uint Height => _height;
|
||||
public uint Depth => _depth;
|
||||
public uint MipLevels => _mipLevels;
|
||||
public uint Dimension => _dimension;
|
||||
public uint ColorComponents => _colorComponents;
|
||||
|
||||
public Handle<GPUTexture> TextureHandle => _textureHandle;
|
||||
|
||||
internal TextureAsset([OwnershipTransfer] ref MemoryBlock data, TextureContentHeader header, Guid id)
|
||||
: base(id)
|
||||
{
|
||||
_textureData = data;
|
||||
_width = header.width;
|
||||
_height = header.height;
|
||||
_depth = header.depth;
|
||||
_mipLevels = header.mipLevels;
|
||||
_dimension = header.dimension;
|
||||
_colorComponents = header.colorComponents;
|
||||
}
|
||||
|
||||
internal void SetTextureHandle(Handle<GPUTexture> handle, bool disposeCPUData = true)
|
||||
{
|
||||
_textureHandle = handle;
|
||||
if (disposeCPUData)
|
||||
{
|
||||
_textureData.Dispose();
|
||||
}
|
||||
}
|
||||
|
||||
public ReadOnlySpan<T> GeData<T>()
|
||||
where T : unmanaged
|
||||
{
|
||||
return _textureData.AsSpan<T>();
|
||||
}
|
||||
|
||||
protected override void Release(IResourceDatabase resourceDatabase)
|
||||
{
|
||||
_textureData.Dispose();
|
||||
resourceDatabase.ReleaseResource(_textureHandle.AsResource());
|
||||
}
|
||||
}
|
||||
@@ -1,13 +1,23 @@
|
||||
using Ghost.Core;
|
||||
using Ghost.Core.Utilities;
|
||||
using Ghost.Engine.AssetLoader;
|
||||
using Ghost.Graphics;
|
||||
using Ghost.Graphics.RHI;
|
||||
using Ghost.Graphics.Utilities;
|
||||
using TerraFX.Interop.Windows;
|
||||
using System.Runtime.InteropServices;
|
||||
|
||||
namespace Ghost.Engine;
|
||||
|
||||
[StructLayout(LayoutKind.Sequential, Size = 64)] // Leave extra space for future expansion without breaking compatibility
|
||||
public struct TextureContentHeader
|
||||
{
|
||||
public uint width;
|
||||
public uint height;
|
||||
public uint depth;
|
||||
public uint mipLevels;
|
||||
public uint dimension; // 1 for 1D, 2 for 2D, 3 for 3D
|
||||
public uint colorComponents;
|
||||
}
|
||||
|
||||
internal partial class AssetEntry
|
||||
{
|
||||
private unsafe class TextureData
|
||||
|
||||
@@ -11,11 +11,24 @@ using Misaki.HighPerformance.LowLevel.Utilities;
|
||||
using System.Collections.Concurrent;
|
||||
using System.Diagnostics.CodeAnalysis;
|
||||
using System.Runtime.CompilerServices;
|
||||
using System.Runtime.InteropServices;
|
||||
|
||||
namespace Ghost.Engine;
|
||||
|
||||
public enum AssetState : byte
|
||||
public enum AssetType
|
||||
{
|
||||
Texture = 0,
|
||||
Mesh = 1,
|
||||
Material = 2,
|
||||
Shaders = 3,
|
||||
Scene = 4,
|
||||
Audio = 5,
|
||||
Video = 6,
|
||||
Json = 7,
|
||||
|
||||
Unknown = 32, // We are unlikely to have more than 32 asset types.
|
||||
}
|
||||
|
||||
public enum AssetState
|
||||
{
|
||||
Unloaded = 0,
|
||||
Scheduled = 1,
|
||||
@@ -192,6 +205,11 @@ internal unsafe partial class AssetEntry
|
||||
public void OnReleaseResource()
|
||||
{
|
||||
s_onReleaseResource[(int)_assetType]?.Invoke(this);
|
||||
|
||||
if (_rawData.IsCreated)
|
||||
{
|
||||
_rawData.Dispose();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -199,7 +217,7 @@ internal struct LoadAssetJob : IJob
|
||||
{
|
||||
public Guid assetID;
|
||||
public AssetType assetType;
|
||||
public GCHandle assetManagerHandle;
|
||||
public AssetManager assetManager;
|
||||
|
||||
private static Result LoadRawData(IContentProvider contentProvider, AssetEntry entry)
|
||||
{
|
||||
@@ -232,8 +250,6 @@ internal struct LoadAssetJob : IJob
|
||||
|
||||
public readonly void Execute(ref readonly JobExecutionContext ctx)
|
||||
{
|
||||
var assetManager = assetManagerHandle.Target as AssetManager;
|
||||
|
||||
Logger.DebugAssert(assetManager is not null);
|
||||
|
||||
if (!assetManager.TryGetEntry(assetID, out var entry))
|
||||
@@ -279,8 +295,6 @@ internal partial class AssetManager : IDisposable
|
||||
|
||||
private readonly ConcurrentDictionary<Guid, AssetEntry> _entries;
|
||||
|
||||
private GCHandle _selfHandle;
|
||||
|
||||
// TODO
|
||||
private Handle<GPUTexture> _fallbackTexture;
|
||||
private Handle<GPUTexture> _fallbackNormalMap;
|
||||
@@ -300,7 +314,6 @@ internal partial class AssetManager : IDisposable
|
||||
_jobScheduler = jobScheduler;
|
||||
|
||||
_entries = new ConcurrentDictionary<Guid, AssetEntry>();
|
||||
_selfHandle = GCHandle.Alloc(this, GCHandleType.Normal);
|
||||
}
|
||||
|
||||
internal bool TryGetEntry(Guid guid, [NotNullWhen(true)] out AssetEntry? entry)
|
||||
@@ -378,10 +391,10 @@ internal partial class AssetManager : IDisposable
|
||||
{
|
||||
assetID = entry.AssetId,
|
||||
assetType = entry.AssetType,
|
||||
assetManagerHandle = _selfHandle,
|
||||
assetManager = this,
|
||||
};
|
||||
|
||||
entry.SetLoadJobHandle(_jobScheduler.Schedule(ref job, dependency, JobPriority.Low)); // Use low priority to avoid blocking main thread critical tasks like rendering and physics.
|
||||
entry.SetLoadJobHandle(_jobScheduler.Schedule(ref job, JobPriority.Low, dependency)); // Use low priority to avoid blocking main thread critical tasks like rendering and physics.
|
||||
}
|
||||
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
@@ -409,18 +422,18 @@ internal partial class AssetManager : IDisposable
|
||||
return;
|
||||
}
|
||||
|
||||
if (entry.State is AssetState.Loading or AssetState.Loaded or AssetState.Uploading)
|
||||
if (Interlocked.CompareExchange(ref entry.StateValue, (int)AssetState.Scheduled, (int)AssetState.Ready) == (int)AssetState.Ready)
|
||||
{
|
||||
// Entry is in Ready state — the old texture is valid and will remain visible.
|
||||
// Go directly to Scheduled → Loading → Loaded → Uploading → Ready again.
|
||||
// The swap cycle in RecordTextureUpload/OnTextureUploadComplete handles the
|
||||
// v1 → v2 transition exactly like the fallback → v1 transition.
|
||||
EnsureScheduled(entry);
|
||||
}
|
||||
else
|
||||
{
|
||||
entry.SetPendingReimport();
|
||||
return;
|
||||
}
|
||||
|
||||
// Entry is in Ready state — the old texture is valid and will remain visible.
|
||||
// Go directly to Scheduled → Loading → Loaded → Uploading → Ready again.
|
||||
// The swap cycle in RecordTextureUpload/OnTextureUploadComplete handles the
|
||||
// v1 → v2 transition exactly like the fallback → v1 transition.
|
||||
entry.State = AssetState.Scheduled;
|
||||
EnsureScheduled(entry);
|
||||
}
|
||||
|
||||
public void Dispose()
|
||||
@@ -431,6 +444,5 @@ internal partial class AssetManager : IDisposable
|
||||
}
|
||||
|
||||
_entries.Clear();
|
||||
_selfHandle.Free();
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user