Replace Magick.NET with stb_image; refactor asset pipeline

- Switched image loading/saving from Magick.NET to native stb_image (Ghost.StbI), removing Magick.NET dependency.
- Added Ghost.StbI project with native DLL, P/Invoke bindings, and wrapper.
- Refactored TextureAssetHandler and TextureProcessor for stb_image, memory-mapped IO, and HDR/16-bit support.
- Split IAssetHandler into IImportableAssetHandler and IPackableAssetHandler; updated interfaces to use FileStream.
- Added shader and mesh asset handlers (GraphicsShaderAssetHandler, ComputeShaderAssetHandler, FBXAssetHandler).
- Improved asset registry/catalog path handling and naming consistency.
- Updated asset import pipeline to use new interfaces and trigger engine reimport.
- Enhanced UI toolbar button styles and EditPage layout.
- Added StbIBindingTest, DisableRuntimeMarshalling, and native wrapper attributes.
- Updated wrapper generator for regex derivesFrom; added stbi.json config.
- Removed Magick.NET reference; added Ghost.StbI and Ghost.Ufbx references.
- Miscellaneous bugfixes and code cleanup.
This commit is contained in:
2026-04-24 00:40:27 +09:00
parent 3533d3367f
commit 4757c0c91a
52 changed files with 8343 additions and 270 deletions

View File

@@ -60,18 +60,56 @@ public struct PassDescriptor
public class GraphicsShaderDescriptor
{
public required string name = string.Empty;
public required uint propertyBufferSize;
public required ShaderModel shaderModel;
public required PassDescriptor[] passes = Array.Empty<PassDescriptor>();
public required string Name
{
get; init;
}
public required uint PropertyBufferSize
{
get; init;
}
public required ShaderModel ShaderModel
{
get; init;
}
public required PassDescriptor[] Passes
{
get; init;
}
}
public class ComputeShaderDescriptor
{
public required string name = string.Empty;
public required uint propertyBufferSize;
public required ShaderModel shaderModel;
public required ShaderCode[] shaderCodes;
public required string[] defines;
public required KeywordsGroup[] keywords;
public required string Name
{
get; init;
}
public required uint PropertyBufferSize
{
get; init;
}
public required ShaderModel ShaderModel
{
get; init;
}
public required ShaderCode[] ShaderCodes
{
get; init;
}
public required string[] Defines
{
get; init;
}
public required KeywordsGroup[] Keywords
{
get; init;
}
}

View File

@@ -197,7 +197,7 @@ internal unsafe partial class AssetEntry
if (Interlocked.CompareExchange(ref _pendingReimport, false, true))
{
_assetManager.InvalidateAsset(_assetId); // re-queue
_assetManager.ReimportAsset(_assetId); // re-queue
}
}
@@ -415,7 +415,7 @@ internal partial class AssetManager : IDisposable
return entry;
}
public void InvalidateAsset(Guid guid)
public void ReimportAsset(Guid guid)
{
if (!_entries.TryGetValue(guid, out var entry))
{

View File

@@ -4,6 +4,12 @@ using Misaki.HighPerformance.Jobs;
namespace Ghost.Engine;
public interface IRuntimeInitializeCallback
{
void Initialize();
void Shutdown();
}
public sealed partial class EngineCore : IDisposable
{
private readonly IContentProvider _contentProvider;
@@ -13,6 +19,10 @@ public sealed partial class EngineCore : IDisposable
private readonly RenderSystem _renderSystem;
private readonly AssetManager _assetManager;
internal JobScheduler JobScheduler => _jobScheduler;
internal RenderSystem RenderSystem => _renderSystem;
internal AssetManager AssetManager => _assetManager;
public EngineCore(IContentProvider contentProvider)
{
_contentProvider = contentProvider;

View File

@@ -0,0 +1,13 @@
using System;
using System.Collections.Generic;
using System.Text;
namespace Ghost.Engine;
internal class TestSetup : IDisposable
{
public void Dispose()
{
throw new NotImplementedException();
}
}

View File

@@ -188,11 +188,16 @@ internal sealed unsafe partial class D3D12ResourceAllocator : IResourceAllocator
if (isSubAllocation)
{
hr = CreateResource(&allocationDesc, &resourceDesc, D3D12_BARRIER_LAYOUT_COMMON, options, (uint)additionalDesc.CastableFormat.Length, pCastableFormats, __uuidof(pResource), (void**)&pResource);
hr = CreateResource(&allocationDesc, &resourceDesc, D3D12_BARRIER_LAYOUT_COMMON, options,
(uint)additionalDesc.CastableFormat.Length, pCastableFormats,
__uuidof(pResource), (void**)&pResource);
}
else
{
hr = CreateResource(&allocationDesc, &resourceDesc, D3D12_BARRIER_LAYOUT_COMMON, options, (uint)additionalDesc.CastableFormat.Length, pCastableFormats, __uuidof(pAllocation), (void**)&pAllocation);
hr = CreateResource(&allocationDesc, &resourceDesc, D3D12_BARRIER_LAYOUT_COMMON, options,
(uint)additionalDesc.CastableFormat.Length, pCastableFormats,
__uuidof(pAllocation), (void**)&pAllocation);
if (hr.SUCCEEDED)
{
pResource = pAllocation->GetResource();
@@ -249,11 +254,16 @@ internal sealed unsafe partial class D3D12ResourceAllocator : IResourceAllocator
if (isSubAllocation)
{
hr = CreateResource(&allocationDesc, &resourceDesc, D3D12_BARRIER_LAYOUT_UNDEFINED, options, 0u, null, __uuidof(pResource), (void**)&pResource);
hr = CreateResource(&allocationDesc, &resourceDesc, D3D12_BARRIER_LAYOUT_UNDEFINED, options,
0u, null,
__uuidof(pResource), (void**)&pResource);
}
else
{
hr = CreateResource(&allocationDesc, &resourceDesc, D3D12_BARRIER_LAYOUT_UNDEFINED, options, 0u, null, __uuidof(pAllocation), (void**)&pAllocation);
hr = CreateResource(&allocationDesc, &resourceDesc, D3D12_BARRIER_LAYOUT_UNDEFINED, options,
0u, null,
__uuidof(pAllocation), (void**)&pAllocation);
if (hr.SUCCEEDED)
{
pResource = pAllocation->GetResource();

View File

@@ -75,15 +75,15 @@ public partial struct Shader : IResourceReleasable
internal Shader(GraphicsShaderDescriptor descriptor)
{
_nameHash = RHIUtility.GetShaderID(descriptor.name);
_propertyBufferSize = descriptor.propertyBufferSize;
_shaderPasses = new UnsafeArray<ShaderPass>(descriptor.passes.Length, AllocationHandle.Persistent);
_passIDToLocal = new UnsafeHashMap<int, int>(descriptor.passes.Length, AllocationHandle.Persistent);
_nameHash = RHIUtility.GetShaderID(descriptor.Name);
_propertyBufferSize = descriptor.PropertyBufferSize;
_shaderPasses = new UnsafeArray<ShaderPass>(descriptor.Passes.Length, AllocationHandle.Persistent);
_passIDToLocal = new UnsafeHashMap<int, int>(descriptor.Passes.Length, AllocationHandle.Persistent);
_keywordIDToLocal = new UnsafeHashMap<int, int>(32, AllocationHandle.Persistent);
for (var i = 0; i < descriptor.passes.Length; i++)
for (var i = 0; i < descriptor.Passes.Length; i++)
{
ref readonly var pass = ref descriptor.passes[i];
ref readonly var pass = ref descriptor.Passes[i];
var keywords = new LocalKeywordSet();
@@ -189,7 +189,7 @@ public partial struct Shader : IResourceReleasable
public unsafe partial struct ComputeShader : IResourceReleasable
{
private readonly ulong _nameHash;
private fixed ulong entryHashes[8]; // Support up to 8 entry points for now, can be extended if needed.
private fixed ulong _entryHashes[8]; // Support up to 8 entry points for now, can be extended if needed.
private readonly uint _propertyBufferSize;
private LocalKeywordSet _localKeywordSet;
@@ -200,20 +200,20 @@ public unsafe partial struct ComputeShader : IResourceReleasable
internal ComputeShader(ComputeShaderDescriptor descriptor)
{
_nameHash = RHIUtility.GetShaderID(descriptor.name);
_propertyBufferSize = descriptor.propertyBufferSize;
_nameHash = RHIUtility.GetShaderID(descriptor.Name);
_propertyBufferSize = descriptor.PropertyBufferSize;
_keywordIDToLocal = new UnsafeHashMap<int, int>(32, AllocationHandle.Persistent);
for (var i = 0; i < descriptor.shaderCodes.Length; i++)
for (var i = 0; i < descriptor.ShaderCodes.Length; i++)
{
entryHashes[i] = RHIUtility.GetPassID(_nameHash, i);
_entryHashes[i] = RHIUtility.GetPassID(_nameHash, i);
}
var localKeywordIndex = 0;
for (var i = 0; i < descriptor.keywords.Length; i++)
for (var i = 0; i < descriptor.Keywords.Length; i++)
{
var group = descriptor.keywords[i];
var group = descriptor.Keywords[i];
if (group.keywords == null)
{
continue;
@@ -236,7 +236,7 @@ public unsafe partial struct ComputeShader : IResourceReleasable
public ulong GetEntryID(int entryIndex)
{
Logger.DebugAssert(entryIndex >= 0 && entryIndex < 8, "Entry index out of bounds.");
return entryHashes[entryIndex];
return _entryHashes[entryIndex];
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]

View File

@@ -251,7 +251,6 @@ public class RenderSystem : IDisposable
try
{
// Wait for either CPU ready signal or shutdown signal
waitHandles[0] = frameResource.CpuReadyEvent;
var waitResult = WaitHandle.WaitAny(waitHandles);