Add Editor configs, refactor test core, DXC test

Added Debug_Editor/Release_Editor configs to all projects and solution. Refactored test utilities into Ghost.TestCore and updated references. Introduced DXCBindingTest for shader compilation. Updated conditional compilation to use GHOST_EDITOR. Improved platform mappings and performed minor code cleanup.
This commit is contained in:
2026-05-08 13:59:36 +09:00
parent b42398bbce
commit 80e820a858
42 changed files with 392 additions and 101 deletions

View File

@@ -1,4 +1,4 @@
using Ghost.Test.Core;
using Ghost.TestCore;
using Misaki.HighPerformance.Jobs;
using Misaki.HighPerformance.LowLevel.Buffer;
using Misaki.HighPerformance.Mathematics;

View File

@@ -6,6 +6,7 @@
<ImplicitUsings>enable</ImplicitUsings>
<Nullable>enable</Nullable>
<AllowUnsafeBlocks>True</AllowUnsafeBlocks>
<Configurations>Debug;Release;Debug_Editor;Release_Editor</Configurations>
</PropertyGroup>
<ItemGroup>
@@ -15,7 +16,7 @@
<ItemGroup>
<ProjectReference Include="..\..\Runtime\Ghost.Entities\Ghost.Entities.csproj" />
<ProjectReference Include="..\..\Test\Ghost.Test.Core\Ghost.Test.Core.csproj" />
<ProjectReference Include="..\..\Test\Ghost.TestCore\Ghost.TestCore.csproj" />
</ItemGroup>
</Project>

View File

@@ -1,4 +1,4 @@
using Ghost.Test.Core;
using Ghost.TestCore;
using Misaki.HighPerformance.LowLevel.Buffer;
using Misaki.HighPerformance.Mathematics;
using System.Runtime.InteropServices;

View File

@@ -1,4 +1,4 @@
using Ghost.Test.Core;
using Ghost.TestCore;
namespace Ghost.Entities.Test;

View File

@@ -11,6 +11,7 @@
<UseWinUI>true</UseWinUI>
<EnableMsixTooling>true</EnableMsixTooling>
<Nullable>enable</Nullable>
<Configurations>Debug;Release;Debug_Editor;Release_Editor</Configurations>
</PropertyGroup>
<ItemGroup>
@@ -50,7 +51,7 @@
</ItemGroup>
<ItemGroup>
<ProjectReference Include="..\..\Runtime\Ghost.Engine\Ghost.Engine.csproj" />
<ProjectReference Include="..\..\Test\Ghost.Test.Core\Ghost.Test.Core.csproj" />
<ProjectReference Include="..\..\Test\Ghost.TestCore\Ghost.TestCore.csproj" />
<ProjectReference Include="..\..\Runtime\Ghost.Graphics\Ghost.Graphics.csproj" />
<ProjectReference Include="..\..\Editor\Ghost.DSL\Ghost.DSL.csproj" />
<ProjectReference Include="..\..\ThridParty\Ghost.Ufbx\Ghost.Ufbx.csproj" />
@@ -68,6 +69,7 @@
<!-- Publish Properties -->
<PropertyGroup>
<PublishReadyToRun Condition="'$(Configuration)' == 'Debug'">False</PublishReadyToRun>
<PublishReadyToRun Condition="'$(Configuration)'=='Debug_Editor'">False</PublishReadyToRun>
<PublishReadyToRun Condition="'$(Configuration)' != 'Debug'">True</PublishReadyToRun>
<SupportedOSPlatformVersion>10.0.20348.0</SupportedOSPlatformVersion>
<ImplicitUsings>enable</ImplicitUsings>
@@ -76,10 +78,19 @@
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x86'">
<DebugType>embedded</DebugType>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug_Editor|x86'">
<DebugType>embedded</DebugType>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
<DebugType>embedded</DebugType>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug_Editor|x64'">
<DebugType>embedded</DebugType>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|ARM64'">
<DebugType>embedded</DebugType>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug_Editor|ARM64'">
<DebugType>embedded</DebugType>
</PropertyGroup>
</Project>

View File

@@ -0,0 +1,171 @@
using Ghost.DXC;
using Ghost.TestCore;
using System.Runtime.CompilerServices;
using System.Runtime.InteropServices;
using static Ghost.DXC.UUID;
namespace Ghost.MicroTest;
internal unsafe class DXCBindingTest : ITest
{
private static ReadOnlySpan<byte> ShaderCode => @"
struct VSInput
{
float3 position : POSITION;
float3 normal : NORMAL;
};
struct PSInput
{
float4 position : SV_POSITION;
float3 normal : NORMAL;
};
PSInput main(VSInput input)
{
PSInput output;
output.position = float4(input.position, 1.0);
output.normal = input.normal;
return output;
}"u8;
private IDxcCompiler3* _compiler;
private IDxcUtils* _utils;
public void Setup()
{
IDxcCompiler3* pCompiler = default;
IDxcUtils* pUtils = default;
var hr = Api.DxcCreateInstance((Guid*)Unsafe.AsPointer(in Api.CLSID_DxcCompiler), __uuidof(pCompiler), (void**)&pCompiler);
if (hr < 0)
{
throw new InvalidOperationException($"Failed to create DXC compiler instance. HRESULT: 0x{hr:X8}");
}
hr = Api.DxcCreateInstance((Guid*)Unsafe.AsPointer(in Api.CLSID_DxcUtils), __uuidof(pUtils), (void**)&pUtils);
if (hr < 0)
{
pCompiler->Release();
throw new InvalidOperationException($"Failed to create DXC utils instance. HRESULT: 0x{hr:X8}");
}
_compiler = pCompiler;
_utils = pUtils;
}
private static List<string> GetCompilerArguments()
{
return new List<string>
{
"-T", "vs_6_6", // Target profile (vs_6_6 for vertex shader)
"-E", "main", // Entry point
"-HV", "2021", // HLSL version 2021
"-enable-16bit-types" // Enable 16-bit types
};
}
public void Run()
{
IDxcIncludeHandler* includeHandler = default;
IDxcBlobEncoding* sourceBlob = default;
try
{
var hr = _utils->CreateDefaultIncludeHandler(&includeHandler);
Assert.AreEqual(0, hr, $"Failed to create default include handler. HRESULT: 0x{hr:X8}");
fixed (byte* pCode = ShaderCode)
{
hr = _utils->CreateBlobFromPinned(pCode, (uint)ShaderCode.Length, Api.DXC_CP_UTF8, &sourceBlob);
Assert.AreEqual(0, hr, $"Failed to create blob from shader code. HRESULT: 0x{hr:X8}");
}
var argsArray = GetCompilerArguments();
var argPtrs = stackalloc char*[argsArray.Count];
for (var i = 0; i < argsArray.Count; i++)
{
argPtrs[i] = (char*)Marshal.StringToHGlobalUni(argsArray[i]);
}
IDxcResult* result = default;
IDxcBlob* bytecodeBlob = default;
try
{
// Compile shader
var buffer = new DxcBuffer
{
Ptr = sourceBlob->GetBufferPointer(),
Size = sourceBlob->GetBufferSize(),
Encoding = Api.DXC_CP_UTF8
};
hr = _compiler->Compile(&buffer, argPtrs, (uint)argsArray.Count, includeHandler, __uuidof(result), (void**)&result);
Assert.AreEqual(0, hr, $"Failed to compile shader. HRESULT: 0x{hr:X8}");
// Check compilation result
int hrStatus;
result->GetStatus(&hrStatus);
if (hrStatus < 0)
{
// Get error messages
IDxcBlobEncoding* pErrorBlob = default;
result->GetErrorBuffer(&pErrorBlob);
if (pErrorBlob != null)
{
var errorMessage = Marshal.PtrToStringUTF8((IntPtr)pErrorBlob->GetBufferPointer());
pErrorBlob->Release();
throw new InvalidOperationException($"DXC shader compilation failed:\n{errorMessage}");
}
else
{
throw new InvalidOperationException("DXC shader compilation failed with unknown error.");
}
}
// Get compiled bytecode
hr = result->GetResult(&bytecodeBlob);
Assert.AreEqual(0, hr, $"Failed to get compiled shader bytecode. HRESULT: 0x{hr:X8}");
var bytecodeSize = bytecodeBlob->GetBufferSize();
Assert.IsTrue(bytecodeSize > 0, "Compiled shader bytecode is empty.");
}
finally
{
if (result != null)
{
result->Release();
}
if (bytecodeBlob != null)
{
bytecodeBlob->Release();
}
for (var i = 0; i < argsArray.Count; i++)
{
Marshal.FreeHGlobal((nint)argPtrs[i]);
}
}
}
finally
{
if (includeHandler != null)
{
includeHandler->Release();
}
if (sourceBlob != null)
{
sourceBlob->Release();
}
}
}
public void Cleanup()
{
_compiler->Release();
_utils->Release();
}
}

View File

@@ -7,6 +7,7 @@
<Nullable>enable</Nullable>
<AllowUnsafeBlocks>true</AllowUnsafeBlocks>
<PublishAot>True</PublishAot>
<Configurations>Debug;Release;Debug_Editor;Release_Editor</Configurations>
</PropertyGroup>
<ItemGroup>
@@ -15,7 +16,8 @@
<ItemGroup>
<ProjectReference Include="..\..\Runtime\Ghost.Core\Ghost.Core.csproj" />
<ProjectReference Include="..\..\Test\Ghost.Test.Core\Ghost.Test.Core.csproj" />
<ProjectReference Include="..\Ghost.TestCore\Ghost.TestCore.csproj" />
<ProjectReference Include="..\..\ThridParty\Ghost.DXC\Ghost.DXC.csproj" />
<ProjectReference Include="..\..\ThridParty\Ghost.Nvtt\Ghost.Nvtt.csproj" />
<ProjectReference Include="..\..\ThridParty\Ghost.StbI\Ghost.StbI.csproj" />
<ProjectReference Include="..\..\ThridParty\Ghost.Ufbx\Ghost.Ufbx.csproj" />

View File

@@ -1,5 +1,5 @@
using Ghost.Nvtt;
using Ghost.Test.Core;
using Ghost.TestCore;
using System.Runtime.CompilerServices;
using System.Runtime.InteropServices;
using System.Text;

View File

@@ -1,4 +1,4 @@
using Ghost.MicroTest;
using Ghost.Test.Core;
using Ghost.TestCore;
TestRunner.Run<UfbxBindingTest>();
TestRunner.Run<DXCBindingTest>();

View File

@@ -1,5 +1,5 @@
using Ghost.StbI;
using Ghost.Test.Core;
using Ghost.TestCore;
namespace Ghost.MicroTest;

View File

@@ -1,4 +1,4 @@
using Ghost.Test.Core;
using Ghost.TestCore;
using Ghost.Ufbx;
namespace Ghost.MicroTest;

View File

@@ -6,6 +6,7 @@
<ImplicitUsings>enable</ImplicitUsings>
<Nullable>enable</Nullable>
<PublishAot>True</PublishAot>
<Configurations>Debug;Release;Debug_Editor;Release_Editor</Configurations>
</PropertyGroup>
<ItemGroup>

View File

@@ -1,28 +0,0 @@
namespace Ghost.Test.Core;
public class TestRunner
{
public static void Run<T>()
where T : ITest, new()
{
var test = new T();
test.Setup();
test.Run();
test.Cleanup();
}
public static void Run<T>(int iteration)
where T : ITest, new()
{
var test = new T();
test.Setup();
iteration = iteration < 1 ? 1 : iteration;
for (var i = 0; i < iteration; i++)
{
test.Run();
}
test.Cleanup();
}
}

View File

@@ -0,0 +1,33 @@
namespace Ghost.TestCore;
public static class Assert
{
public static void AreEqual<T>(T expected, T actual, string message = "")
{
if (!EqualityComparer<T>.Default.Equals(expected, actual))
{
throw new AssertFailedException($"Assert.AreEqual failed. Expected: {expected}, Actual: {actual}. {message}");
}
}
public static void IsTrue(bool condition, string message = "")
{
if (!condition)
{
throw new AssertFailedException($"Assert.IsTrue failed. {message}");
}
}
public static void IsFalse(bool condition, string message = "")
{
if (condition)
{
throw new AssertFailedException($"Assert.IsFalse failed. {message}");
}
}
public static void Fail(string message = "")
{
throw new AssertFailedException($"Assert.Fail: {message}");
}
}

View File

@@ -0,0 +1,17 @@
namespace Ghost.TestCore;
[Serializable]
internal class AssertFailedException : Exception
{
public AssertFailedException()
{
}
public AssertFailedException(string? message) : base(message)
{
}
public AssertFailedException(string? message, Exception? innerException) : base(message, innerException)
{
}
}

View File

@@ -4,6 +4,7 @@
<TargetFramework>net10.0</TargetFramework>
<ImplicitUsings>enable</ImplicitUsings>
<Nullable>enable</Nullable>
<Configurations>Debug;Release;Debug_Editor;Release_Editor</Configurations>
</PropertyGroup>
</Project>

View File

@@ -1,4 +1,4 @@
namespace Ghost.Test.Core;
namespace Ghost.TestCore;
public interface ITest
{

View File

@@ -0,0 +1,49 @@
namespace Ghost.TestCore;
public class TestRunner
{
public static void Run<T>()
where T : ITest, new()
{
var test = new T();
try
{
test.Setup();
test.Run();
test.Cleanup();
}
catch (Exception ex)
{
Console.WriteLine($"Test failed with exception: {ex.Message}");
}
Console.WriteLine("Test completed.");
}
public static void Run<T>(int iteration)
where T : ITest, new()
{
var test = new T();
var i = 0;
try
{
test.Setup();
iteration = iteration < 1 ? 1 : iteration;
for (i = 0; i < iteration; i++)
{
test.Run();
}
test.Cleanup();
}
catch (Exception ex)
{
Console.WriteLine($"Test failed at iteration {i} with exception: {ex.Message}");
}
Console.WriteLine($"Test completed after {iteration} iterations.");
}
}

View File

@@ -46,7 +46,7 @@ public class ImportCoordinatorTests
[TestMethod]
public async Task TestImportCoordinator_BasicImport()
{
using var catalog = new AssetCatalog(_dbPath);
var catalog = new AssetCatalog(_dbPath);
using var coordinator = new ImportCoordinator(catalog);
var assetGuid = Guid.NewGuid();

View File

@@ -8,6 +8,7 @@
<Platforms>x64;x86;ARM64</Platforms>
<RuntimeIdentifiers>win-x86;win-x64;win-arm64</RuntimeIdentifiers>
<AllowUnsafeBlocks>True</AllowUnsafeBlocks>
<Configurations>Debug;Release;Debug_Editor;Release_Editor</Configurations>
</PropertyGroup>
<ItemGroup>