Refactor rendering projects
This commit is contained in:
1
.gitattributes
vendored
Normal file
1
.gitattributes
vendored
Normal file
@@ -0,0 +1 @@
|
|||||||
|
*.dll filter=lfs diff=lfs merge=lfs -text
|
||||||
75
ARCHITECTURE_CN.md
Normal file
75
ARCHITECTURE_CN.md
Normal file
@@ -0,0 +1,75 @@
|
|||||||
|
# GhostEngine 架构详解
|
||||||
|
|
||||||
|
本文档深入探讨 GhostEngine 核心模块的设计实现,为协同开发提供详细的技术参考。
|
||||||
|
|
||||||
|
## 1. 实体组件系统 (Ghost.Entities)
|
||||||
|
|
||||||
|
Ghost.Entities 采用 Archetype (原型) 模式,旨在优化大规模实体的遍历效率和内存布局。
|
||||||
|
|
||||||
|
### 1.1 核心组件
|
||||||
|
- **World**: 包含实体生命周期管理的顶层容器,包含 `EntityManager`。
|
||||||
|
- **Archetype**: 定义了一组特定组件的组合。具有相同组件集的所有实体都存储在同一 Archetype 中。
|
||||||
|
- **Chunk**: Archetype 内部的数据块,按列存储 (Columnar Storage) 组件数据,以确保对单个组件的线性访问具备极佳的 CPU 缓存亲和性。
|
||||||
|
- **EntityQuery**: 通过位掩码 (Bitmask) 快速匹配 Archetype,支持 `WithAll`, `WithAny`, `WithNone` 过滤规则。
|
||||||
|
|
||||||
|
### 1.2 并行处理
|
||||||
|
- 实体查询支持多线程作业系统 (Job System) 迭代。
|
||||||
|
- **EntityCommandBuffer (ECB)**: 允许在并行作业中排队待处理的实体修改请求 (如创建、删除、添加组件),并在单线程同步点进行统一应用,以避免竞态条件。
|
||||||
|
|
||||||
|
## 2. 渲染架构 (Ghost.Graphics)
|
||||||
|
|
||||||
|
渲染系统设计目标是支持高效、现代的图形渲染流水线,同时降低 D3D12 的开发复杂度。
|
||||||
|
|
||||||
|
### 2.1 RHI (渲染硬件接口)
|
||||||
|
RHI 位于 `Ghost.Graphics.RHI` 命名空间下,抽象了底层的渲染资源:
|
||||||
|
- **IRenderDevice**: 逻辑渲染设备。
|
||||||
|
- **ICommandBuffer**: 用于录制 GPU 指令。
|
||||||
|
- **IPipelineLibrary**: 缓存并管理渲染管线状态对象 (PSO)。
|
||||||
|
- **IResourceDatabase**: 管理显存资源 (Buffer, Texture) 及其生命周期。
|
||||||
|
|
||||||
|
### 2.2 Render Graph (渲染图)
|
||||||
|
Render Graph 是图形模块的核心组件,负责帧内资源的依赖分析和自动调度:
|
||||||
|
- **Pass Builder**: 在帧开始阶段,每个 Pass 声明其读取 (`Read`) 和写入 (`Write`) 的资源。
|
||||||
|
- **Resource Aliasing**: 自动识别不重叠的资源生命周期,实现显存的物理地址复用。
|
||||||
|
- **Automatic Barrier**: 自动根据资源的读写关系插入 `ResourceBarrier` (例如从 `RenderTarget` 状态转换到 `PixelShaderResource` 状态)。
|
||||||
|
|
||||||
|
### 2.3 自定义着色器语言 (Ghost.DSL)
|
||||||
|
引擎支持 `.gshdr` 文件,其语法借鉴了 HLSL 但增强了元数据支持:
|
||||||
|
- **自动属性映射**: DSL 编译器会解析着色器定义的属性,并自动生成与之匹配的 C# 结构体 (`ShaderStructGenerator`),简化 CPU 到 GPU 的数据传递。
|
||||||
|
|
||||||
|
## 3. 编辑器架构 (Ghost.Editor)
|
||||||
|
|
||||||
|
编辑器框架采用模块化设计,重点在于扩展性和资源工作流。
|
||||||
|
|
||||||
|
### 3.1 资源数据库 (Asset Database)
|
||||||
|
- **AssetRegistry**: 通过资源文件的 GUID 进行追踪,支持跨文件引用的完整性校验。
|
||||||
|
- **AssetProcessor**: 插件化系统,针对不同文件扩展名 (如 `.png`, `.fbx`) 提供特定的导入和转换逻辑 (如调用 Nvtt 压缩纹理)。
|
||||||
|
|
||||||
|
### 3.2 检查器 (Inspector)
|
||||||
|
- **Service-driven**: `InspectorService` 动态检测当前选中实体的组件列表,并根据组件类型匹配对应的 `ComponentEditor` 进行 UI 渲染。
|
||||||
|
- **Data Binding**: 利用 `ReflectionBinding` 实现编辑器 UI 与运行时组件数据的双向同步。
|
||||||
|
|
||||||
|
## 4. 核心设计原则 (Core Design Principles)
|
||||||
|
|
||||||
|
项目在底层代码中遵循以下核心设计原则,以确保高性能和系统稳定性:
|
||||||
|
|
||||||
|
### 4.1 Result over Exception (结果对象胜于异常)
|
||||||
|
在引擎的核心运行时(尤其是 `Ghost.Graphics` 和 `Ghost.Entities`)中,我们避免使用异常来处理预期的错误。
|
||||||
|
- **Result 结构体**: 使用 `Ghost.Core.Result` 或 `Result<T>` 结构体返回操作结果。
|
||||||
|
- **性能**: 避免了异常产生的堆栈跟踪开销。
|
||||||
|
- **显性处理**: 强制调用者检查 `IsSuccess` 或使用 `Deconstruct` 模式处理错误,使错误流更加清晰。
|
||||||
|
|
||||||
|
### 4.2 Handle over Ptr/Reference (句柄胜于指针/引用)
|
||||||
|
为了内存安全和支持序列化,引擎广泛使用句柄而非直接的内存指针。
|
||||||
|
- **Handle<T>**: 资源(如 `Texture`, `Buffer`, `Entity`)通过强类型句柄进行引用。
|
||||||
|
- **安全性**: 防止野指针问题,支持资源的延迟加载和卸载,而不破坏引用。
|
||||||
|
- **解耦**: 句柄作为后端资源的索引,使得底层的资源管理器(如 `D3D12ResourceDatabase`)可以自由地重新分配或移动物理资源。
|
||||||
|
|
||||||
|
## 5. 协同开发建议
|
||||||
|
|
||||||
|
|
||||||
|
- **跨项目引用**: 尽量避免 `Runtime` 项目引用 `Editor` 项目。`Editor` 应依赖 `Runtime` 以提供实时预览。
|
||||||
|
- **性能关键点**: 在 `Ghost.Entities` 和 `Ghost.Graphics` 模块中,应尽量避免堆内存分配 (GC Allocation),优先使用 `Span<T>`, `Memory<T>` 及非托管内存。
|
||||||
|
|
||||||
|
---
|
||||||
|
*注:本架构基于当前代码实现,如有变更将及时更新文档。*
|
||||||
76
DEVELOPMENT_CN.md
Normal file
76
DEVELOPMENT_CN.md
Normal file
@@ -0,0 +1,76 @@
|
|||||||
|
# GhostEngine 开发指南
|
||||||
|
|
||||||
|
欢迎参与 GhostEngine 项目。本文档旨在帮助你快速了解项目的当前状态、架构设计、开发规范及环境配置。
|
||||||
|
|
||||||
|
## 1. 开发环境要求 (Prerequisites)
|
||||||
|
|
||||||
|
在开始开发之前,请确保你的开发环境满足以下要求:
|
||||||
|
|
||||||
|
- **操作系统**: Windows 10 版本 1809 (17763) 或更高版本。
|
||||||
|
- **IDE**: Visual Studio 2022 (建议使用最新预览版以支持 .NET 10)。
|
||||||
|
- **.NET SDK**: .NET 10.0 SDK。
|
||||||
|
- **Windows App SDK**: 项目目前使用 Windows App SDK (WinUI 3) 版本 1.8.260101001。
|
||||||
|
- **显卡**: 支持 DirectX 12 (Feature Level 11.0+) 的显卡。
|
||||||
|
- **Visual Studio 工作负载**:
|
||||||
|
- .NET 桌面开发
|
||||||
|
- 使用 C++ 的桌面开发 (部分第三方库包装需要)
|
||||||
|
- 通用 Windows 平台开发 (用于 Windows App SDK 支持)
|
||||||
|
|
||||||
|
## 2. 项目结构 (Project Structure)
|
||||||
|
|
||||||
|
项目代码主要位于 `src` 目录下,按功能分为三个主要部分:
|
||||||
|
|
||||||
|
### 2.1 Runtime (引擎运行时)
|
||||||
|
- **Ghost.Graphics**: 图形渲染核心。包含 RHI (渲染硬件接口) 定义及其 D3D12 实现。集成了 Render Graph (渲染图) 模块用于管理复杂的渲染流水线。
|
||||||
|
- **Ghost.Entities**: 基于 Archetype (原型) 的高性能 ECS (实体组件系统) 实现。包含 `World`, `EntityManager`, `EntityQuery` 等核心组件。
|
||||||
|
- **Ghost.Engine**: 引擎基础逻辑。包含场景管理 (`Scene`)、基础组件 (如 `Hierarchy`, `LocalToWorld`) 及数学工具类。
|
||||||
|
|
||||||
|
### 2.2 Editor (编辑器)
|
||||||
|
- **Ghost.Editor**: 基于 WinUI 3 编写的桌面编辑器前端。采用 MVVM 架构。
|
||||||
|
- **Ghost.Editor.Core**: 编辑器框架层。包含资源管理 (`AssetRegistry`)、检查器服务 (`InspectorService`)、场景树管理 (`SceneGraph`) 等非 UI 逻辑。
|
||||||
|
- **Ghost.DSL**: 引擎自定义着色器语言 (GSL) 的编译器和解析器,用于处理着色器代码生成。
|
||||||
|
|
||||||
|
### 2.3 ThirdParty (第三方库)
|
||||||
|
- 包含对 FMOD (音频)、Nvtt (纹理压缩)、MeshOptimizer (模型优化) 等 C++ 库的 C# 包装。
|
||||||
|
|
||||||
|
## 3. 命名规范 (Naming Conventions)
|
||||||
|
|
||||||
|
项目严格遵守以下 C# 编程规范:
|
||||||
|
|
||||||
|
- **命名空间**: 以 `Ghost.` 开头,后跟模块名 (例如 `Ghost.Graphics.D3D12`)。
|
||||||
|
- **类与方法**: 使用 `PascalCase` (大驼峰命名法)。
|
||||||
|
- **私有字段**: 使用 `_camelCase` (下划线前缀的小驼峰命名法)。
|
||||||
|
- **接口**: 必须以 `I` 作为前缀 (例如 `IRenderDevice`)。
|
||||||
|
- **异步方法**: 必须以 `Async` 作为后缀 (例如 `LoadAssetAsync`)。
|
||||||
|
- **实现类**: 针对接口的具体实现应体现技术细节 (例如 `D3D12GraphicsEngine` 实现了 `IGraphicsEngine`)。
|
||||||
|
|
||||||
|
## 4. 架构设计与模式 (Architecture & Patterns)
|
||||||
|
|
||||||
|
### 4.1 ECS (Entity Component System)
|
||||||
|
运行时逻辑优先使用 ECS 模式以获得最佳的缓存命中率和并行性能:
|
||||||
|
- **Entity**: 纯 ID。
|
||||||
|
- **Component**: 纯数据结构 (Struct)。
|
||||||
|
- **System**: 处理特定组件组合的逻辑类。
|
||||||
|
|
||||||
|
### 4.2 RHI & Render Graph
|
||||||
|
- **RHI (Render Hardware Interface)**: 抽象了底层的图形 API。目前主要实现为 D3D12,通过 Vortice.Windows 进行绑定。
|
||||||
|
- **Render Graph**: 采用有向无环图 (DAG) 管理每一帧的渲染顺序、资源屏障 (Resource Barriers) 和资源复用,简化了 D3D12 的资源管理负担。
|
||||||
|
|
||||||
|
### 4.3 MVVM & Service Pattern (Editor)
|
||||||
|
编辑器部分遵循:
|
||||||
|
- **MVVM**: 分离 UI (`View`) 与业务逻辑 (`ViewModel`)。
|
||||||
|
- **Service/Contract**: 通过接口定义服务 (如 `IAssetRegistry`),并利用依赖注入 (Dependency Injection) 进行解耦。
|
||||||
|
|
||||||
|
### 4.4 核心设计原则 (Core Design Principles)
|
||||||
|
- **Result over Exception (结果对象胜于异常)**: 在核心运行时中,避免使用 `throw` 处理预期错误,优先返回 `Ghost.Core.Result` 结构体,以提高性能和错误流的可控性。
|
||||||
|
- **Handle over Ptr/Reference (句柄胜于指针/引用)**: 资源引用(如实体、纹理、缓冲区)应优先使用 `Handle<T>`,避免持有直接的内存地址,以确保资源管理的安全性并支持高效序列化。
|
||||||
|
|
||||||
|
## 5. 核心逻辑当前状态
|
||||||
|
|
||||||
|
- **渲染系统**: 已具备基础的 D3D12 渲染器、Render Graph 编译器及简单的 Mesh 渲染 pass。支持自定义着色器加载。
|
||||||
|
- **实体系统**: 已实现 Archetype-based ECS,支持高性能的实体查询 (`EntityQuery`) 和作业系统迭代。
|
||||||
|
- **资源管理**: 编辑器端已实现初步的资产数据库 (`AssetRegistry`),支持纹理和模型的导入流程。
|
||||||
|
- **场景管理**: 支持基础的层级结构 (`Hierarchy`) 和变换同步 (`LocalToWorld`)。
|
||||||
|
|
||||||
|
---
|
||||||
|
*注:关于后续的开发计划 (TODO) 及改进方向,我将直接通过会议或即时通讯工具进行沟通。*
|
||||||
@@ -52,7 +52,7 @@ public static class AssetHandlerExtensions
|
|||||||
return await handler.ExportAsync(assetStream, targetStream, options, token);
|
return await handler.ExportAsync(assetStream, targetStream, options, token);
|
||||||
}
|
}
|
||||||
|
|
||||||
public static async ValueTask<Result<Asset>> ReadAsync(this IAssetHandler handler, string assetFilePath, IAssetRegistry assetDatabase, CancellationToken token = default)
|
public static async ValueTask<Result<Asset>> LoadAsync(this IAssetHandler handler, string assetFilePath, IAssetRegistry assetDatabase, CancellationToken token = default)
|
||||||
{
|
{
|
||||||
await using var sourceStream = new FileStream(assetFilePath, FileMode.Open, FileAccess.Read, FileShare.Read);
|
await using var sourceStream = new FileStream(assetFilePath, FileMode.Open, FileAccess.Read, FileShare.Read);
|
||||||
return await handler.LoadAsync(sourceStream, assetDatabase, token);
|
return await handler.LoadAsync(sourceStream, assetDatabase, token);
|
||||||
|
|||||||
@@ -4,8 +4,11 @@ using Ghost.Graphics.Core;
|
|||||||
using Ghost.Graphics.RHI;
|
using Ghost.Graphics.RHI;
|
||||||
using Misaki.HighPerformance.Image;
|
using Misaki.HighPerformance.Image;
|
||||||
using System.Buffers;
|
using System.Buffers;
|
||||||
|
using System.Configuration;
|
||||||
using System.Runtime.CompilerServices;
|
using System.Runtime.CompilerServices;
|
||||||
using System.Runtime.InteropServices;
|
using System.Runtime.InteropServices;
|
||||||
|
using TerraFX.Interop.Windows;
|
||||||
|
using static Ghost.Editor.Core.AssetHandler.TextureAssetSettings;
|
||||||
|
|
||||||
namespace Ghost.Editor.Core.AssetHandler;
|
namespace Ghost.Editor.Core.AssetHandler;
|
||||||
|
|
||||||
@@ -211,8 +214,14 @@ public class TextureAssetSettings : IAssetSettings
|
|||||||
{
|
{
|
||||||
get; set;
|
get; set;
|
||||||
} = new SamplerSettings();
|
} = new SamplerSettings();
|
||||||
|
}
|
||||||
|
|
||||||
public async ValueTask<Result<long>> WriteToStreamAsync(Stream stream, CancellationToken token = default)
|
[CustomAssetHandler(ID = TextureAsset._TYPE_ID, SupportedExtensions = new[] { ".png", ".jpg", ".jpeg", ".tga", ".bmp", ".hdr" })]
|
||||||
|
internal class TextureAssetHandler : IImportableAssetHandler
|
||||||
|
{
|
||||||
|
private const int _CURRENT_VERSION = 1;
|
||||||
|
|
||||||
|
private static async ValueTask<Result<long>> WriteSettingsToStreamAsync(TextureAssetSettings settings, Stream stream, CancellationToken token = default)
|
||||||
{
|
{
|
||||||
var size = Unsafe.SizeOf<BasicSettings>() + Unsafe.SizeOf<AdvancedSettings>() + Unsafe.SizeOf<SamplerSettings>();
|
var size = Unsafe.SizeOf<BasicSettings>() + Unsafe.SizeOf<AdvancedSettings>() + Unsafe.SizeOf<SamplerSettings>();
|
||||||
var tempArray = ArrayPool<byte>.Shared.Rent(size);
|
var tempArray = ArrayPool<byte>.Shared.Rent(size);
|
||||||
@@ -220,9 +229,9 @@ public class TextureAssetSettings : IAssetSettings
|
|||||||
try
|
try
|
||||||
{
|
{
|
||||||
ref byte address = ref MemoryMarshal.GetReference(tempArray);
|
ref byte address = ref MemoryMarshal.GetReference(tempArray);
|
||||||
Unsafe.WriteUnaligned(ref address, Basic);
|
Unsafe.WriteUnaligned(ref address, settings.Basic);
|
||||||
Unsafe.WriteUnaligned(ref Unsafe.Add(ref address, Unsafe.SizeOf<BasicSettings>()), Advanced);
|
Unsafe.WriteUnaligned(ref Unsafe.Add(ref address, Unsafe.SizeOf<BasicSettings>()), settings.Advanced);
|
||||||
Unsafe.WriteUnaligned(ref Unsafe.Add(ref address, Unsafe.SizeOf<BasicSettings>() + Unsafe.SizeOf<AdvancedSettings>()), Sampler);
|
Unsafe.WriteUnaligned(ref Unsafe.Add(ref address, Unsafe.SizeOf<BasicSettings>() + Unsafe.SizeOf<AdvancedSettings>()), settings.Sampler);
|
||||||
|
|
||||||
await stream.WriteAsync(tempArray.AsMemory(0, size), token).ConfigureAwait(false);
|
await stream.WriteAsync(tempArray.AsMemory(0, size), token).ConfigureAwait(false);
|
||||||
|
|
||||||
@@ -238,7 +247,7 @@ public class TextureAssetSettings : IAssetSettings
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public async ValueTask<Result<IAssetSettings>> ReadFromStreamAsync(Stream stream, CancellationToken token = default)
|
private static async ValueTask<Result<IAssetSettings>> ReadSettingsFromStreamAsync(Stream stream, CancellationToken token = default)
|
||||||
{
|
{
|
||||||
var size = Unsafe.SizeOf<BasicSettings>() + Unsafe.SizeOf<AdvancedSettings>() + Unsafe.SizeOf<SamplerSettings>();
|
var size = Unsafe.SizeOf<BasicSettings>() + Unsafe.SizeOf<AdvancedSettings>() + Unsafe.SizeOf<SamplerSettings>();
|
||||||
var tempArray = ArrayPool<byte>.Shared.Rent(size);
|
var tempArray = ArrayPool<byte>.Shared.Rent(size);
|
||||||
@@ -270,12 +279,6 @@ public class TextureAssetSettings : IAssetSettings
|
|||||||
ArrayPool<byte>.Shared.Return(tempArray);
|
ArrayPool<byte>.Shared.Return(tempArray);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
[CustomAssetHandler(ID = TextureAsset._TYPE_ID, SupportedExtensions = new[] { ".png", ".jpg", ".jpeg", ".tga", ".bmp", ".hdr" })]
|
|
||||||
internal class TextureAssetHandler : IImportableAssetHandler
|
|
||||||
{
|
|
||||||
private const int _CURRENT_VERSION = 1;
|
|
||||||
|
|
||||||
public ValueTask<Result> ExportAsync(Stream assetStream, Stream targetStream, IAssetExportOptions? options, CancellationToken token = default)
|
public ValueTask<Result> ExportAsync(Stream assetStream, Stream targetStream, IAssetExportOptions? options, CancellationToken token = default)
|
||||||
{
|
{
|
||||||
@@ -287,7 +290,9 @@ internal class TextureAssetHandler : IImportableAssetHandler
|
|||||||
// ---- 1. Probe image info -----------------------------------------------
|
// ---- 1. Probe image info -----------------------------------------------
|
||||||
var info = ImageInfo.FromStream(sourceStream);
|
var info = ImageInfo.FromStream(sourceStream);
|
||||||
if (info.BitsPerChannel <= 0)
|
if (info.BitsPerChannel <= 0)
|
||||||
|
{
|
||||||
return Result.Failure($"Unsupported image format with {info.BitsPerChannel} bits per channel.");
|
return Result.Failure($"Unsupported image format with {info.BitsPerChannel} bits per channel.");
|
||||||
|
}
|
||||||
|
|
||||||
var isFloat = info.BitsPerChannel > 8;
|
var isFloat = info.BitsPerChannel > 8;
|
||||||
var width = info.Width;
|
var width = info.Width;
|
||||||
@@ -329,14 +334,6 @@ internal class TextureAssetHandler : IImportableAssetHandler
|
|||||||
token).ConfigureAwait(false);
|
token).ConfigureAwait(false);
|
||||||
|
|
||||||
// ---- 4. Write asset file: header + settings + raw image data -----------
|
// ---- 4. Write asset file: header + settings + raw image data -----------
|
||||||
// Content layout (all little-endian):
|
|
||||||
// int32 width
|
|
||||||
// int32 height
|
|
||||||
// byte isFloat (0 = byte, 1 = float)
|
|
||||||
// int32 colorComponents (cast of ColorComponents enum)
|
|
||||||
// byte[] pixelBytes
|
|
||||||
const int _CONTENT_HEADER_SIZE = 4 + 4 + 1 + 4; // 13 bytes
|
|
||||||
var contentSize = _CONTENT_HEADER_SIZE + pixelBytes.Length;
|
|
||||||
|
|
||||||
var header = new AssetMetadata(id, TextureAsset.s_typeGuid)
|
var header = new AssetMetadata(id, TextureAsset.s_typeGuid)
|
||||||
{
|
{
|
||||||
@@ -344,18 +341,24 @@ internal class TextureAssetHandler : IImportableAssetHandler
|
|||||||
SettingsOffset = AssetMetadata.SIZE,
|
SettingsOffset = AssetMetadata.SIZE,
|
||||||
};
|
};
|
||||||
|
|
||||||
// Reserve space for the header, then write settings
|
|
||||||
targetStream.Seek(0, SeekOrigin.Begin);
|
|
||||||
AssetMetadata.WriteToStream(targetStream, ref header);
|
|
||||||
|
|
||||||
targetStream.Seek(header.SettingsOffset, SeekOrigin.Begin);
|
targetStream.Seek(header.SettingsOffset, SeekOrigin.Begin);
|
||||||
var sizeResult = await settings.WriteToStreamAsync(targetStream, token).ConfigureAwait(false);
|
var sizeResult = await WriteSettingsToStreamAsync(settings, targetStream, token).ConfigureAwait(false);
|
||||||
if (sizeResult.IsFailure)
|
if (sizeResult.IsFailure)
|
||||||
|
{
|
||||||
return Result.Failure($"Failed to write texture asset settings: {sizeResult.Message}");
|
return Result.Failure($"Failed to write texture asset settings: {sizeResult.Message}");
|
||||||
|
}
|
||||||
|
|
||||||
|
// Content layout (all little-endian):
|
||||||
|
// int32 width
|
||||||
|
// int32 height
|
||||||
|
// byte isFloat (0 = byte, 1 = float)
|
||||||
|
// int32 colorComponents (cast of ColorComponents enum)
|
||||||
|
// byte[] pixelBytes
|
||||||
|
const int _CONTENT_HEADER_SIZE = 4 + 4 + 1 + 4; // 13 bytes
|
||||||
|
|
||||||
header.SettingsSize = sizeResult.Value;
|
header.SettingsSize = sizeResult.Value;
|
||||||
header.ContentOffset = header.SettingsOffset + sizeResult.Value;
|
header.ContentOffset = header.SettingsOffset + sizeResult.Value;
|
||||||
header.ContentSize = contentSize;
|
header.ContentSize = _CONTENT_HEADER_SIZE + pixelBytes.Length;
|
||||||
|
|
||||||
// Write raw image content
|
// Write raw image content
|
||||||
targetStream.Seek(header.ContentOffset, SeekOrigin.Begin);
|
targetStream.Seek(header.ContentOffset, SeekOrigin.Begin);
|
||||||
@@ -367,6 +370,7 @@ internal class TextureAssetHandler : IImportableAssetHandler
|
|||||||
BitConverter.TryWriteBytes(contentHeader.AsSpan(4, 4), height);
|
BitConverter.TryWriteBytes(contentHeader.AsSpan(4, 4), height);
|
||||||
contentHeader[8] = isFloat ? (byte)1 : (byte)0;
|
contentHeader[8] = isFloat ? (byte)1 : (byte)0;
|
||||||
BitConverter.TryWriteBytes(contentHeader.AsSpan(9, 4), (int)colorComponents);
|
BitConverter.TryWriteBytes(contentHeader.AsSpan(9, 4), (int)colorComponents);
|
||||||
|
|
||||||
await targetStream.WriteAsync(contentHeader.AsMemory(0, _CONTENT_HEADER_SIZE), token).ConfigureAwait(false);
|
await targetStream.WriteAsync(contentHeader.AsMemory(0, _CONTENT_HEADER_SIZE), token).ConfigureAwait(false);
|
||||||
}
|
}
|
||||||
finally
|
finally
|
||||||
|
|||||||
@@ -22,10 +22,6 @@ internal static unsafe class TextureProcessor
|
|||||||
{
|
{
|
||||||
private const string _TEXTURE_CACHE_SUBFOLDER = "TextureCache";
|
private const string _TEXTURE_CACHE_SUBFOLDER = "TextureCache";
|
||||||
|
|
||||||
// -------------------------------------------------------------------------
|
|
||||||
// Public entry point
|
|
||||||
// -------------------------------------------------------------------------
|
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Compresses <paramref name="pixelData"/> according to <paramref name="settings"/>
|
/// Compresses <paramref name="pixelData"/> according to <paramref name="settings"/>
|
||||||
/// and writes the result to the texture cache.
|
/// and writes the result to the texture cache.
|
||||||
@@ -69,10 +65,6 @@ internal static unsafe class TextureProcessor
|
|||||||
return cachePath;
|
return cachePath;
|
||||||
}
|
}
|
||||||
|
|
||||||
// -------------------------------------------------------------------------
|
|
||||||
// NVTT pipeline
|
|
||||||
// -------------------------------------------------------------------------
|
|
||||||
|
|
||||||
private static void RunNvttPipeline(
|
private static void RunNvttPipeline(
|
||||||
string outputPath,
|
string outputPath,
|
||||||
ReadOnlySpan<byte> pixelData,
|
ReadOnlySpan<byte> pixelData,
|
||||||
@@ -110,7 +102,7 @@ internal static unsafe class TextureProcessor
|
|||||||
if (settings.Advanced.StretchToPowerOfTwo)
|
if (settings.Advanced.StretchToPowerOfTwo)
|
||||||
{
|
{
|
||||||
surface.ResizeMakeSquare(maxExtent,
|
surface.ResizeMakeSquare(maxExtent,
|
||||||
NvttRoundMode.NVTT_RoundMode_ToPreviousPowerOfTwo,
|
NvttRoundMode.NVTT_RoundMode_ToNearestPowerOfTwo,
|
||||||
NvttResizeFilter.NVTT_ResizeFilter_Box);
|
NvttResizeFilter.NVTT_ResizeFilter_Box);
|
||||||
}
|
}
|
||||||
else if (surface.Width > maxExtent || surface.Height > maxExtent)
|
else if (surface.Width > maxExtent || surface.Height > maxExtent)
|
||||||
@@ -177,7 +169,7 @@ internal static unsafe class TextureProcessor
|
|||||||
}
|
}
|
||||||
|
|
||||||
// ---- 8. enable CUDA if available ---------------------------------------
|
// ---- 8. enable CUDA if available ---------------------------------------
|
||||||
ctx.SetCudaAcceleration(Ghost.Nvtt.NvttGlobal.IsCudaSupported);
|
ctx.SetCudaAcceleration(NvttGlobal.IsCudaSupported);
|
||||||
|
|
||||||
// ---- 9. write DDS header -----------------------------------------------
|
// ---- 9. write DDS header -----------------------------------------------
|
||||||
ctx.OutputHeader(surface, mipmapCount, compOpts, outOpts);
|
ctx.OutputHeader(surface, mipmapCount, compOpts, outOpts);
|
||||||
@@ -185,18 +177,18 @@ internal static unsafe class TextureProcessor
|
|||||||
// ---- 10. compress mip chain using a working clone ----------------------
|
// ---- 10. compress mip chain using a working clone ----------------------
|
||||||
using var mip = surface.Clone();
|
using var mip = surface.Clone();
|
||||||
|
|
||||||
for (int level = 0; level < mipmapCount; level++)
|
for (var level = 0; level < mipmapCount; level++)
|
||||||
{
|
{
|
||||||
// Scale alpha for coverage on each mip (if requested)
|
// Scale alpha for coverage on each mip (if requested)
|
||||||
if (settings.Advanced.ScaleAlphaForMipCoverage && level > 0)
|
if (settings.Advanced.ScaleAlphaForMipCoverage && level > 0)
|
||||||
{
|
{
|
||||||
float refCoverage = mip.AlphaTestCoverage(
|
var refCoverage = mip.AlphaTestCoverage(
|
||||||
settings.Advanced.ScaleAlphaForMipCoverageThreshold / 255f);
|
settings.Advanced.ScaleAlphaForMipCoverageThreshold / 255f);
|
||||||
mip.ScaleAlphaToCoverage(refCoverage,
|
mip.ScaleAlphaToCoverage(refCoverage,
|
||||||
settings.Advanced.ScaleAlphaForMipCoverageThreshold / 255f);
|
settings.Advanced.ScaleAlphaForMipCoverageThreshold / 255f);
|
||||||
}
|
}
|
||||||
|
|
||||||
ctx.Compress(mip, face: 0, mipmap: level, compOpts, outOpts);
|
ctx.Compress(mip, 0, level, compOpts, outOpts);
|
||||||
|
|
||||||
if (level + 1 < mipmapCount)
|
if (level + 1 < mipmapCount)
|
||||||
{
|
{
|
||||||
@@ -205,10 +197,6 @@ internal static unsafe class TextureProcessor
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// -------------------------------------------------------------------------
|
|
||||||
// Helpers
|
|
||||||
// -------------------------------------------------------------------------
|
|
||||||
|
|
||||||
private static NvttFormat SelectFormat(TextureAssetSettings settings)
|
private static NvttFormat SelectFormat(TextureAssetSettings settings)
|
||||||
=> settings.Basic.TextureType switch
|
=> settings.Basic.TextureType switch
|
||||||
{
|
{
|
||||||
@@ -235,10 +223,6 @@ internal static unsafe class TextureProcessor
|
|||||||
_ => NvttMipmapFilter.NVTT_MipmapFilter_Kaiser,
|
_ => NvttMipmapFilter.NVTT_MipmapFilter_Kaiser,
|
||||||
};
|
};
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Produces a stable 64-bit hash of the settings structs so the cache file
|
|
||||||
/// name changes whenever any setting changes.
|
|
||||||
/// </summary>
|
|
||||||
private static ulong ComputeSettingsHash(TextureAssetSettings s)
|
private static ulong ComputeSettingsHash(TextureAssetSettings s)
|
||||||
{
|
{
|
||||||
var basicSize = Unsafe.SizeOf<TextureAssetSettings.BasicSettings>();
|
var basicSize = Unsafe.SizeOf<TextureAssetSettings.BasicSettings>();
|
||||||
|
|||||||
@@ -37,9 +37,9 @@ internal sealed partial class ScenePage : NavigationTabPage
|
|||||||
|
|
||||||
//private void SwapChainPanel_SizeChanged(object sender, SizeChangedEventArgs e)
|
//private void SwapChainPanel_SizeChanged(object sender, SizeChangedEventArgs e)
|
||||||
//{
|
//{
|
||||||
// if (e.NewSize.Width > 8.0 && e.NewSize.Height > 8.0)
|
// if (e.NewSize.ActualWidth > 8.0 && e.NewSize.ActualHeight > 8.0)
|
||||||
// {
|
// {
|
||||||
// _renderView?.RequestResize((uint)e.NewSize.Width, (uint)e.NewSize.Height);
|
// _renderView?.RequestResize((uint)e.NewSize.ActualWidth, (uint)e.NewSize.ActualHeight);
|
||||||
// }
|
// }
|
||||||
//}
|
//}
|
||||||
}
|
}
|
||||||
@@ -5,6 +5,7 @@
|
|||||||
<Platform Name="x86" />
|
<Platform Name="x86" />
|
||||||
</Configurations>
|
</Configurations>
|
||||||
<Folder Name="/Editor/">
|
<Folder Name="/Editor/">
|
||||||
|
<Project Path="Editor/Ghost.DSL/Ghost.DSL.csproj" />
|
||||||
<Project Path="Editor/Ghost.Editor.Core/Ghost.Editor.Core.csproj" />
|
<Project Path="Editor/Ghost.Editor.Core/Ghost.Editor.Core.csproj" />
|
||||||
<Project Path="Editor/Ghost.Editor/Ghost.Editor.csproj">
|
<Project Path="Editor/Ghost.Editor/Ghost.Editor.csproj">
|
||||||
<Platform Solution="*|ARM64" Project="ARM64" />
|
<Platform Solution="*|ARM64" Project="ARM64" />
|
||||||
@@ -12,7 +13,6 @@
|
|||||||
<Platform Solution="*|x86" Project="x86" />
|
<Platform Solution="*|x86" Project="x86" />
|
||||||
<Deploy />
|
<Deploy />
|
||||||
</Project>
|
</Project>
|
||||||
<Project Path="Editor/Ghost.DSL/Ghost.DSL.csproj" />
|
|
||||||
</Folder>
|
</Folder>
|
||||||
<Folder Name="/ThridParty/">
|
<Folder Name="/ThridParty/">
|
||||||
<Project Path="ThridParty/Ghost.FMOD/Ghost.FMOD.csproj" />
|
<Project Path="ThridParty/Ghost.FMOD/Ghost.FMOD.csproj" />
|
||||||
@@ -24,6 +24,8 @@
|
|||||||
<Project Path="Runtime/Ghost.Engine/Ghost.Engine.csproj" />
|
<Project Path="Runtime/Ghost.Engine/Ghost.Engine.csproj" />
|
||||||
<Project Path="Runtime/Ghost.Entities/Ghost.Entities.csproj" />
|
<Project Path="Runtime/Ghost.Entities/Ghost.Entities.csproj" />
|
||||||
<Project Path="Runtime/Ghost.Generator/Ghost.Generator.csproj" />
|
<Project Path="Runtime/Ghost.Generator/Ghost.Generator.csproj" />
|
||||||
|
<Project Path="Runtime/Ghost.Graphics.D3D12/Ghost.Graphics.D3D12.csproj" Id="e56a0674-beab-414f-8b42-01191a0238fc" />
|
||||||
|
<Project Path="Runtime/Ghost.Graphics.RHI/Ghost.Graphics.RHI.csproj" Id="d6831a89-ea86-4aef-9879-2bdd9b519d1e" />
|
||||||
<Project Path="Runtime/Ghost.Graphics/Ghost.Graphics.csproj" />
|
<Project Path="Runtime/Ghost.Graphics/Ghost.Graphics.csproj" />
|
||||||
</Folder>
|
</Folder>
|
||||||
<Folder Name="/Test/">
|
<Folder Name="/Test/">
|
||||||
|
|||||||
@@ -1,67 +0,0 @@
|
|||||||
using System.Runtime.CompilerServices;
|
|
||||||
|
|
||||||
namespace Ghost.Core;
|
|
||||||
|
|
||||||
public readonly struct TypeHandle
|
|
||||||
{
|
|
||||||
public readonly IntPtr Value
|
|
||||||
{
|
|
||||||
get;
|
|
||||||
}
|
|
||||||
|
|
||||||
private TypeHandle(IntPtr value)
|
|
||||||
{
|
|
||||||
Value = value;
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Gets the space handle for the specified space.
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="type">The space to get the handle for.</param>
|
|
||||||
/// <returns>The space handle as a nint.</returns>
|
|
||||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
|
||||||
public static TypeHandle Get(Type type) => new TypeHandle(type.TypeHandle.Value);
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Gets the space handle for the specified space.
|
|
||||||
/// </summary>
|
|
||||||
/// <typeparam name="T">The space to get the handle for.</typeparam>
|
|
||||||
/// <returns>The space handle as a nint.</returns>
|
|
||||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
|
||||||
public static TypeHandle Get<T>() => Get(typeof(T));
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Converts a TypeHandle to a Type.
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="handle">The TypeHandle to convert.</param>
|
|
||||||
/// <returns>The corresponding Type.</returns>
|
|
||||||
public Type? ToType()
|
|
||||||
{
|
|
||||||
return Type.GetTypeFromHandle(RuntimeTypeHandle.FromIntPtr(Value));
|
|
||||||
}
|
|
||||||
|
|
||||||
public override int GetHashCode()
|
|
||||||
{
|
|
||||||
return Value.GetHashCode();
|
|
||||||
}
|
|
||||||
|
|
||||||
public static implicit operator TypeHandle(IntPtr value)
|
|
||||||
{
|
|
||||||
return new TypeHandle(value);
|
|
||||||
}
|
|
||||||
|
|
||||||
public static implicit operator IntPtr(TypeHandle handle)
|
|
||||||
{
|
|
||||||
return handle.Value;
|
|
||||||
}
|
|
||||||
|
|
||||||
public static implicit operator TypeHandle(Type type)
|
|
||||||
{
|
|
||||||
return Get(type);
|
|
||||||
}
|
|
||||||
|
|
||||||
public static implicit operator Type?(TypeHandle handle)
|
|
||||||
{
|
|
||||||
return handle.ToType();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -10,80 +10,6 @@ namespace Ghost.Core.Utilities;
|
|||||||
[SupportedOSPlatform("windows10.0.19041.0")]
|
[SupportedOSPlatform("windows10.0.19041.0")]
|
||||||
internal static unsafe partial class Win32Utility
|
internal static unsafe partial class Win32Utility
|
||||||
{
|
{
|
||||||
[EditorBrowsable(EditorBrowsableState.Never)]
|
|
||||||
public readonly ref struct IID_PPV
|
|
||||||
{
|
|
||||||
public readonly Guid* iid;
|
|
||||||
public readonly void** ppv;
|
|
||||||
|
|
||||||
public IID_PPV(Guid* iid, void** ppv)
|
|
||||||
{
|
|
||||||
this.iid = iid;
|
|
||||||
this.ppv = ppv;
|
|
||||||
}
|
|
||||||
|
|
||||||
public void Deconstruct(out Guid* iid, out void** ppv)
|
|
||||||
{
|
|
||||||
iid = this.iid;
|
|
||||||
ppv = this.ppv;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public static Guid* IID_NULL
|
|
||||||
{
|
|
||||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
|
||||||
get => (Guid*)Unsafe.AsPointer(ref Unsafe.AsRef(in IID.IID_NULL));
|
|
||||||
}
|
|
||||||
|
|
||||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
|
||||||
public static IID_PPV IID_PPV_ARGS<T>(ComPtr<T>* comPtr)
|
|
||||||
where T : unmanaged, IUnknown.Interface
|
|
||||||
{
|
|
||||||
return new IID_PPV(Windows.__uuidof<T>(), (void**)comPtr);
|
|
||||||
}
|
|
||||||
|
|
||||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
|
||||||
public static void Attach<T>(ref this UniquePtr<T> uPtr, T* other)
|
|
||||||
where T : unmanaged, IUnknown.Interface
|
|
||||||
{
|
|
||||||
var ptr = uPtr.Get();
|
|
||||||
if (ptr != null)
|
|
||||||
{
|
|
||||||
var refCount = ptr->Release();
|
|
||||||
Debug.Assert((refCount != 0) || (ptr != other));
|
|
||||||
}
|
|
||||||
|
|
||||||
uPtr = new UniquePtr<T>(other);
|
|
||||||
}
|
|
||||||
|
|
||||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
|
||||||
public static void Dispose<T>(ref this UniquePtr<T> uPtr)
|
|
||||||
where T : unmanaged, IUnknown.Interface
|
|
||||||
{
|
|
||||||
var ptr = uPtr.Detach();
|
|
||||||
if (ptr != null)
|
|
||||||
{
|
|
||||||
ptr->Release();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
|
||||||
public static Result ToResult(this HRESULT hr, [CallerArgumentExpression(nameof(hr))] string? op = null)
|
|
||||||
{
|
|
||||||
if (hr.SUCCEEDED)
|
|
||||||
{
|
|
||||||
return Result.Success();
|
|
||||||
}
|
|
||||||
|
|
||||||
return Result.Failure($"{op} failed with code {hr}");
|
|
||||||
}
|
|
||||||
|
|
||||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
|
||||||
public static void** ReleaseAndGetVoidAddressOf<T>(ref this ComPtr<T> comPtr)
|
|
||||||
where T : unmanaged, IUnknown.Interface
|
|
||||||
{
|
|
||||||
return (void**)comPtr.ReleaseAndGetAddressOf();
|
|
||||||
}
|
|
||||||
|
|
||||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||||
public static ComPtr<T> Move<T>(ref this ComPtr<T> comPtr)
|
public static ComPtr<T> Move<T>(ref this ComPtr<T> comPtr)
|
||||||
|
|||||||
@@ -1,5 +1,6 @@
|
|||||||
using Ghost.Entities;
|
using Ghost.Entities;
|
||||||
using Ghost.Graphics;
|
using Ghost.Graphics;
|
||||||
|
using Ghost.Graphics.RHI;
|
||||||
using Misaki.HighPerformance.Jobs;
|
using Misaki.HighPerformance.Jobs;
|
||||||
|
|
||||||
namespace Ghost.Engine;
|
namespace Ghost.Engine;
|
||||||
|
|||||||
@@ -208,10 +208,10 @@ public class ComponentManager : IDisposable
|
|||||||
}
|
}
|
||||||
|
|
||||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||||
internal Identifier<EntityQuery> CreateEntityQuery(EntityQueryMask mask, int maskHash)
|
internal Identifier<EntityQuery> CreateEntityQuery(ref readonly EntityQueryMask mask, int maskHash)
|
||||||
{
|
{
|
||||||
var queryID = new Identifier<EntityQuery>(_entityQueries.Count);
|
var queryID = new Identifier<EntityQuery>(_entityQueries.Count);
|
||||||
_entityQueries.Add(new EntityQuery(queryID, _world.ID, mask));
|
_entityQueries.Add(new EntityQuery(queryID, _world.ID, in mask));
|
||||||
_querieLookup.Add(maskHash, queryID);
|
_querieLookup.Add(maskHash, queryID);
|
||||||
|
|
||||||
ref var query = ref _entityQueries[queryID.Value];
|
ref var query = ref _entityQueries[queryID.Value];
|
||||||
|
|||||||
@@ -1,4 +1,3 @@
|
|||||||
using Ghost.Core;
|
|
||||||
using Misaki.HighPerformance.Jobs;
|
using Misaki.HighPerformance.Jobs;
|
||||||
using Misaki.HighPerformance.LowLevel.Collections;
|
using Misaki.HighPerformance.LowLevel.Collections;
|
||||||
using System.Runtime.CompilerServices;
|
using System.Runtime.CompilerServices;
|
||||||
@@ -64,7 +63,7 @@ public unsafe partial struct EntityQuery
|
|||||||
{
|
{
|
||||||
ref var arch = ref world.ComponentManager.GetArchetypeReference(archID);
|
ref var arch = ref world.ComponentManager.GetArchetypeReference(archID);
|
||||||
|
|
||||||
for (int i = 0; i < arch.ChunkCount; i++)
|
for (var i = 0; i < arch.ChunkCount; i++)
|
||||||
{
|
{
|
||||||
var pChunk = (Chunk*)arch._chunks.GetUnsafePtr() + i;
|
var pChunk = (Chunk*)arch._chunks.GetUnsafePtr() + i;
|
||||||
|
|
||||||
|
|||||||
@@ -340,7 +340,7 @@ public unsafe partial struct EntityQuery : IDisposable
|
|||||||
private readonly Identifier<EntityQuery> _id;
|
private readonly Identifier<EntityQuery> _id;
|
||||||
private readonly Identifier<World> _worldID;
|
private readonly Identifier<World> _worldID;
|
||||||
|
|
||||||
internal EntityQuery(Identifier<EntityQuery> id, Identifier<World> worldID, EntityQueryMask mask)
|
internal EntityQuery(Identifier<EntityQuery> id, Identifier<World> worldID, ref readonly EntityQueryMask mask)
|
||||||
{
|
{
|
||||||
_id = id;
|
_id = id;
|
||||||
_worldID = worldID;
|
_worldID = worldID;
|
||||||
@@ -632,7 +632,7 @@ public ref partial struct QueryBuilder
|
|||||||
}
|
}
|
||||||
|
|
||||||
// NOTE: We do not dispose the mask here, as it is now owned by the EntityQuery.
|
// NOTE: We do not dispose the mask here, as it is now owned by the EntityQuery.
|
||||||
queryID = world.ComponentManager.CreateEntityQuery(mask, maskHash);
|
queryID = world.ComponentManager.CreateEntityQuery(in mask, maskHash);
|
||||||
|
|
||||||
Return:
|
Return:
|
||||||
Dispose();
|
Dispose();
|
||||||
|
|||||||
8
src/Runtime/Ghost.Graphics.D3D12/AssemblyInfo.cs
Normal file
8
src/Runtime/Ghost.Graphics.D3D12/AssemblyInfo.cs
Normal file
@@ -0,0 +1,8 @@
|
|||||||
|
global using static TerraFX.Interop.DirectX.D3D12;
|
||||||
|
global using static TerraFX.Interop.DirectX.DirectX;
|
||||||
|
global using static TerraFX.Interop.DirectX.DXGI;
|
||||||
|
global using static TerraFX.Interop.Windows.Windows;
|
||||||
|
|
||||||
|
using System.Runtime.Versioning;
|
||||||
|
|
||||||
|
[assembly: SupportedOSPlatform("windows10.0.19041.0")]
|
||||||
@@ -1,6 +1,5 @@
|
|||||||
using Ghost.Core;
|
using Ghost.Core;
|
||||||
using Ghost.Core.Utilities;
|
using Ghost.Core.Utilities;
|
||||||
using Ghost.Graphics.Core;
|
|
||||||
using Ghost.Graphics.D3D12.Utilities;
|
using Ghost.Graphics.D3D12.Utilities;
|
||||||
using Ghost.Graphics.RHI;
|
using Ghost.Graphics.RHI;
|
||||||
using Misaki.HighPerformance.LowLevel;
|
using Misaki.HighPerformance.LowLevel;
|
||||||
@@ -1,4 +1,5 @@
|
|||||||
using Ghost.Core.Utilities;
|
using Ghost.Core.Utilities;
|
||||||
|
using Ghost.Graphics.D3D12.Utilities;
|
||||||
using Ghost.Graphics.RHI;
|
using Ghost.Graphics.RHI;
|
||||||
using Misaki.HighPerformance.LowLevel;
|
using Misaki.HighPerformance.LowLevel;
|
||||||
using TerraFX.Interop.DirectX;
|
using TerraFX.Interop.DirectX;
|
||||||
@@ -1,4 +1,5 @@
|
|||||||
using Ghost.Core.Utilities;
|
using Ghost.Core.Utilities;
|
||||||
|
using Ghost.Graphics.D3D12.Utilities;
|
||||||
using Misaki.HighPerformance.LowLevel;
|
using Misaki.HighPerformance.LowLevel;
|
||||||
using TerraFX.Interop.DirectX;
|
using TerraFX.Interop.DirectX;
|
||||||
using TerraFX.Interop.Windows;
|
using TerraFX.Interop.Windows;
|
||||||
@@ -1,4 +1,3 @@
|
|||||||
using Ghost.Core.Utilities;
|
|
||||||
using Ghost.Graphics.D3D12.Utilities;
|
using Ghost.Graphics.D3D12.Utilities;
|
||||||
using Misaki.HighPerformance.LowLevel;
|
using Misaki.HighPerformance.LowLevel;
|
||||||
using Misaki.HighPerformance.LowLevel.Collections;
|
using Misaki.HighPerformance.LowLevel.Collections;
|
||||||
@@ -18,9 +17,11 @@ internal unsafe class D3D12DescriptorHeap : IDisposable
|
|||||||
|
|
||||||
private UniquePtr<ID3D12DescriptorHeap> _heap;
|
private UniquePtr<ID3D12DescriptorHeap> _heap;
|
||||||
private UniquePtr<ID3D12DescriptorHeap> _shaderVisibleHeap;
|
private UniquePtr<ID3D12DescriptorHeap> _shaderVisibleHeap;
|
||||||
|
|
||||||
private D3D12_CPU_DESCRIPTOR_HANDLE _startCpuHandle;
|
private D3D12_CPU_DESCRIPTOR_HANDLE _startCpuHandle;
|
||||||
private D3D12_CPU_DESCRIPTOR_HANDLE _startCpuHandleShaderVisible;
|
private D3D12_CPU_DESCRIPTOR_HANDLE _startCpuHandleShaderVisible;
|
||||||
private D3D12_GPU_DESCRIPTOR_HANDLE _startGpuHandleShaderVisible;
|
private D3D12_GPU_DESCRIPTOR_HANDLE _startGpuHandleShaderVisible;
|
||||||
|
|
||||||
private int _searchStart;
|
private int _searchStart;
|
||||||
private UnsafeBitSet _allocatedDescriptors;
|
private UnsafeBitSet _allocatedDescriptors;
|
||||||
|
|
||||||
@@ -3,22 +3,31 @@
|
|||||||
#endif
|
#endif
|
||||||
|
|
||||||
using Ghost.Core;
|
using Ghost.Core;
|
||||||
using Ghost.Graphics.Contracts;
|
|
||||||
using Ghost.Graphics.RHI;
|
|
||||||
using Ghost.Graphics.Core;
|
using Ghost.Graphics.Core;
|
||||||
|
using Ghost.Graphics.RHI;
|
||||||
using System.Collections.Immutable;
|
using System.Collections.Immutable;
|
||||||
using System.Runtime.CompilerServices;
|
using System.Runtime.CompilerServices;
|
||||||
|
using System.Runtime.InteropServices;
|
||||||
|
|
||||||
namespace Ghost.Graphics.D3D12;
|
namespace Ghost.Graphics.D3D12;
|
||||||
|
|
||||||
|
public static class D3D12GraphicsEngineFactory
|
||||||
|
{
|
||||||
|
public static IGraphicsEngine Create(IRenderSystem renderSystem)
|
||||||
|
{
|
||||||
|
return new D3D12GraphicsEngine(renderSystem);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
internal class D3D12GraphicsEngine : IGraphicsEngine
|
internal class D3D12GraphicsEngine : IGraphicsEngine
|
||||||
{
|
{
|
||||||
|
private GCHandle _thisHandle;
|
||||||
|
|
||||||
private readonly IRenderSystem _renderSystem;
|
private readonly IRenderSystem _renderSystem;
|
||||||
|
|
||||||
#if ENABLE_DEBUG
|
#if ENABLE_DEBUG
|
||||||
private readonly D3D12DebugLayer _debugLayer;
|
private readonly D3D12DebugLayer _debugLayer;
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
private readonly D3D12RenderDevice _device;
|
private readonly D3D12RenderDevice _device;
|
||||||
private readonly DxcShaderCompiler _shaderCompiler;
|
private readonly DxcShaderCompiler _shaderCompiler;
|
||||||
private readonly D3D12DescriptorAllocator _descriptorAllocator;
|
private readonly D3D12DescriptorAllocator _descriptorAllocator;
|
||||||
@@ -71,7 +80,7 @@ internal class D3D12GraphicsEngine : IGraphicsEngine
|
|||||||
{
|
{
|
||||||
ThrowIfDisposed();
|
ThrowIfDisposed();
|
||||||
|
|
||||||
var renderer = new D3D12Renderer(this, _resourceDatabase);
|
var renderer = new D3D12Renderer(this);
|
||||||
ImmutableInterlocked.Update(ref _renderers, renderers => renderers.Add(renderer));
|
ImmutableInterlocked.Update(ref _renderers, renderers => renderers.Add(renderer));
|
||||||
return renderer;
|
return renderer;
|
||||||
}
|
}
|
||||||
@@ -157,6 +166,8 @@ internal class D3D12GraphicsEngine : IGraphicsEngine
|
|||||||
_debugLayer.Dispose();
|
_debugLayer.Dispose();
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
_thisHandle.Free();
|
||||||
|
|
||||||
_disposed = true;
|
_disposed = true;
|
||||||
GC.SuppressFinalize(this);
|
GC.SuppressFinalize(this);
|
||||||
}
|
}
|
||||||
@@ -1,8 +1,5 @@
|
|||||||
using Ghost.Core;
|
using Ghost.Core;
|
||||||
using Ghost.Core.Graphics;
|
using Ghost.Core.Graphics;
|
||||||
using Ghost.Core.Utilities;
|
|
||||||
using Ghost.Graphics.Contracts;
|
|
||||||
using Ghost.Graphics.Core;
|
|
||||||
using Ghost.Graphics.D3D12.Utilities;
|
using Ghost.Graphics.D3D12.Utilities;
|
||||||
using Ghost.Graphics.RHI;
|
using Ghost.Graphics.RHI;
|
||||||
using Misaki.HighPerformance.LowLevel;
|
using Misaki.HighPerformance.LowLevel;
|
||||||
@@ -1,4 +1,4 @@
|
|||||||
using Ghost.Core.Utilities;
|
using Ghost.Graphics.D3D12.Utilities;
|
||||||
using Ghost.Graphics.RHI;
|
using Ghost.Graphics.RHI;
|
||||||
using Misaki.HighPerformance.LowLevel;
|
using Misaki.HighPerformance.LowLevel;
|
||||||
using TerraFX.Interop.DirectX;
|
using TerraFX.Interop.DirectX;
|
||||||
@@ -78,7 +78,7 @@ internal unsafe class D3D12RenderDevice : IRenderDevice
|
|||||||
pAdapter->GetDesc1(&desc);
|
pAdapter->GetDesc1(&desc);
|
||||||
|
|
||||||
// Don't select the Basic Render Driver adapter.
|
// Don't select the Basic Render Driver adapter.
|
||||||
if (desc.Flags.HasFlag(DXGI_ADAPTER_FLAG_SOFTWARE))
|
if ((desc.Flags & (uint)DXGI_ADAPTER_FLAG_SOFTWARE) != 0)
|
||||||
{
|
{
|
||||||
goto NEXT_ITERATION;
|
goto NEXT_ITERATION;
|
||||||
}
|
}
|
||||||
@@ -106,7 +106,7 @@ internal unsafe class D3D12RenderDevice : IRenderDevice
|
|||||||
{
|
{
|
||||||
ObjectDisposedException.ThrowIf(_disposed, this);
|
ObjectDisposedException.ThrowIf(_disposed, this);
|
||||||
|
|
||||||
FeatureSupport support = FeatureSupport.None;
|
var support = FeatureSupport.None;
|
||||||
|
|
||||||
D3D12_FEATURE_DATA_D3D12_OPTIONS options = default;
|
D3D12_FEATURE_DATA_D3D12_OPTIONS options = default;
|
||||||
if (_device.Get()->CheckFeatureSupport(D3D12_FEATURE_D3D12_OPTIONS, &options, (uint)sizeof(D3D12_FEATURE_DATA_D3D12_OPTIONS)).SUCCEEDED)
|
if (_device.Get()->CheckFeatureSupport(D3D12_FEATURE_D3D12_OPTIONS, &options, (uint)sizeof(D3D12_FEATURE_DATA_D3D12_OPTIONS)).SUCCEEDED)
|
||||||
124
src/Runtime/Ghost.Graphics.D3D12/D3D12Renderer.cs
Normal file
124
src/Runtime/Ghost.Graphics.D3D12/D3D12Renderer.cs
Normal file
@@ -0,0 +1,124 @@
|
|||||||
|
using Ghost.Core;
|
||||||
|
using Ghost.Graphics.RHI;
|
||||||
|
|
||||||
|
namespace Ghost.Graphics.D3D12;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// D3D12 implementation of the renderer interface using RHI abstractions
|
||||||
|
/// </summary>
|
||||||
|
internal class D3D12Renderer : IRenderer
|
||||||
|
{
|
||||||
|
private readonly D3D12GraphicsEngine _graphicsEngine;
|
||||||
|
private readonly ICommandBuffer _commandBuffer;
|
||||||
|
|
||||||
|
private bool _disposed;
|
||||||
|
|
||||||
|
public IRenderOutput? RenderOutput
|
||||||
|
{
|
||||||
|
get; set;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Func<RenderContext, Error>? RenderFunc
|
||||||
|
{
|
||||||
|
get; set;
|
||||||
|
}
|
||||||
|
|
||||||
|
public D3D12Renderer(D3D12GraphicsEngine graphicsEngine)
|
||||||
|
{
|
||||||
|
_graphicsEngine = graphicsEngine;
|
||||||
|
_commandBuffer = _graphicsEngine.CreateCommandBuffer(CommandBufferType.Graphics);
|
||||||
|
}
|
||||||
|
|
||||||
|
~D3D12Renderer()
|
||||||
|
{
|
||||||
|
Dispose();
|
||||||
|
}
|
||||||
|
|
||||||
|
public Result Render(ICommandAllocator commandAllocator)
|
||||||
|
{
|
||||||
|
if (RenderFunc is null)
|
||||||
|
{
|
||||||
|
return Result.Success(); // No render function set, skip rendering.
|
||||||
|
}
|
||||||
|
|
||||||
|
if (RenderOutput is null)
|
||||||
|
{
|
||||||
|
return Result.Failure("Render target strategy is not set.");
|
||||||
|
}
|
||||||
|
|
||||||
|
var target = RenderOutput.GetRenderTarget();
|
||||||
|
if (target.IsInvalid)
|
||||||
|
{
|
||||||
|
return Result.Failure("Render target is invalid.");
|
||||||
|
}
|
||||||
|
|
||||||
|
_commandBuffer.Begin(commandAllocator);
|
||||||
|
RenderOutput.BeginRender(_commandBuffer);
|
||||||
|
|
||||||
|
var ctx = new RenderContext();
|
||||||
|
var error = RenderFunc.Invoke(ctx);
|
||||||
|
if (error != Error.None)
|
||||||
|
{
|
||||||
|
_commandBuffer.End();
|
||||||
|
return Result.Failure(error);
|
||||||
|
}
|
||||||
|
|
||||||
|
RenderOutput.EndRender(_commandBuffer);
|
||||||
|
var r = _commandBuffer.End();
|
||||||
|
if (r.IsFailure)
|
||||||
|
{
|
||||||
|
return r;
|
||||||
|
}
|
||||||
|
|
||||||
|
_graphicsEngine.Device.GraphicsQueue.Submit(_commandBuffer);
|
||||||
|
RenderOutput.Present();
|
||||||
|
|
||||||
|
return Result.Success();
|
||||||
|
}
|
||||||
|
|
||||||
|
//// TODO: A proper render graph integration.
|
||||||
|
//private Error RenderScene(Handle<Texture> target, ViewportDesc viewport, RectDesc rect)
|
||||||
|
//{
|
||||||
|
// // NOTE: Testing only.
|
||||||
|
// var ctx = new RenderingContext(_graphicsEngine, _commandBuffer);
|
||||||
|
// if (_frameIndex == 0)
|
||||||
|
// {
|
||||||
|
// _pass.Initialize(ref ctx);
|
||||||
|
// }
|
||||||
|
|
||||||
|
// //_commandBuffer.BeginRenderPass(rtDesc, depthDesc, false);
|
||||||
|
// _commandBuffer.SetViewport(viewport);
|
||||||
|
// _commandBuffer.SetScissorRect(rect);
|
||||||
|
|
||||||
|
// _renderGraph.Reset();
|
||||||
|
|
||||||
|
// var backBuffer = _renderGraph.ImportTexture(target, "Back Buffer");
|
||||||
|
// _pass.Build(_renderGraph, backBuffer);
|
||||||
|
|
||||||
|
// // Create view state from viewport
|
||||||
|
// var viewState = new ViewState((uint)viewport.Width, (uint)viewport.Height);
|
||||||
|
|
||||||
|
// // Compile with view state
|
||||||
|
// _renderGraph.Compile(in viewState);
|
||||||
|
// _renderGraph.Execute(_commandBuffer);
|
||||||
|
|
||||||
|
// //_commandBuffer.EndRenderPass();
|
||||||
|
// _frameIndex++;
|
||||||
|
|
||||||
|
// return Error.None;
|
||||||
|
//}
|
||||||
|
|
||||||
|
public void Dispose()
|
||||||
|
{
|
||||||
|
if (_disposed)
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
_commandBuffer.Dispose();
|
||||||
|
|
||||||
|
_disposed = true;
|
||||||
|
|
||||||
|
GC.SuppressFinalize(this);
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -1,7 +1,6 @@
|
|||||||
using Ghost.Core;
|
using Ghost.Core;
|
||||||
using Ghost.Core.Graphics;
|
using Ghost.Core.Graphics;
|
||||||
using Ghost.Core.Utilities;
|
using Ghost.Core.Utilities;
|
||||||
using Ghost.Graphics.Core;
|
|
||||||
using Ghost.Graphics.D3D12.Utilities;
|
using Ghost.Graphics.D3D12.Utilities;
|
||||||
using Ghost.Graphics.RHI;
|
using Ghost.Graphics.RHI;
|
||||||
using Misaki.HighPerformance.LowLevel;
|
using Misaki.HighPerformance.LowLevel;
|
||||||
@@ -866,71 +865,6 @@ internal sealed unsafe partial class D3D12ResourceAllocator : IResourceAllocator
|
|||||||
return _resourceDatabase.CreateSampler(in desc, samplerDescriptor.Value);
|
return _resourceDatabase.CreateSampler(in desc, samplerDescriptor.Value);
|
||||||
}
|
}
|
||||||
|
|
||||||
public Handle<Mesh> CreateMesh(UnsafeList<Vertex> vertices, UnsafeList<uint> indices)
|
|
||||||
{
|
|
||||||
ObjectDisposedException.ThrowIf(_disposed, this);
|
|
||||||
|
|
||||||
var vertexBufferDesc = new BufferDesc
|
|
||||||
{
|
|
||||||
Size = (uint)(vertices.Count * sizeof(Vertex)),
|
|
||||||
Stride = (uint)sizeof(Vertex),
|
|
||||||
Usage = BufferUsage.Vertex | BufferUsage.ShaderResource | BufferUsage.Raw,
|
|
||||||
MemoryType = ResourceMemoryType.Default,
|
|
||||||
};
|
|
||||||
|
|
||||||
var indexBufferDesc = new BufferDesc
|
|
||||||
{
|
|
||||||
Size = (uint)(indices.Count * sizeof(uint)),
|
|
||||||
Stride = sizeof(uint),
|
|
||||||
Usage = BufferUsage.Index | BufferUsage.ShaderResource | BufferUsage.Raw,
|
|
||||||
MemoryType = ResourceMemoryType.Default,
|
|
||||||
};
|
|
||||||
|
|
||||||
var objectBufferDesc = new BufferDesc
|
|
||||||
{
|
|
||||||
Size = (uint)sizeof(PerObjectData),
|
|
||||||
Stride = (uint)sizeof(PerObjectData),
|
|
||||||
Usage = BufferUsage.Raw | BufferUsage.ShaderResource,
|
|
||||||
MemoryType = ResourceMemoryType.Default,
|
|
||||||
};
|
|
||||||
|
|
||||||
var vertexBuffer = CreateBuffer(in vertexBufferDesc, "VertexBuffer");
|
|
||||||
var indexBuffer = CreateBuffer(in indexBufferDesc, "IndexBuffer");
|
|
||||||
var objectBuffer = CreateBuffer(in objectBufferDesc, "ObjectBuffer");
|
|
||||||
|
|
||||||
var data = new Mesh
|
|
||||||
{
|
|
||||||
Vertices = vertices,
|
|
||||||
Indices = indices,
|
|
||||||
VertexBuffer = vertexBuffer,
|
|
||||||
IndexBuffer = indexBuffer,
|
|
||||||
ObjectDataBuffer = objectBuffer,
|
|
||||||
};
|
|
||||||
|
|
||||||
return _resourceDatabase.AddMesh(in data);
|
|
||||||
}
|
|
||||||
|
|
||||||
public Handle<Material> CreateMaterial(Identifier<Shader> shader)
|
|
||||||
{
|
|
||||||
ObjectDisposedException.ThrowIf(_disposed, this);
|
|
||||||
|
|
||||||
var material = new Material();
|
|
||||||
if (material.SetShader(shader, this, _resourceDatabase) != Error.None)
|
|
||||||
{
|
|
||||||
return Handle<Material>.Invalid;
|
|
||||||
}
|
|
||||||
|
|
||||||
return _resourceDatabase.AddMaterial(in material);
|
|
||||||
}
|
|
||||||
|
|
||||||
public Identifier<Shader> CreateGraphicsShader(ShaderDescriptor descriptor)
|
|
||||||
{
|
|
||||||
ObjectDisposedException.ThrowIf(_disposed, this);
|
|
||||||
|
|
||||||
var shader = new Shader(descriptor);
|
|
||||||
return _resourceDatabase.AddShader(shader);
|
|
||||||
}
|
|
||||||
|
|
||||||
public void Dispose()
|
public void Dispose()
|
||||||
{
|
{
|
||||||
if (_disposed)
|
if (_disposed)
|
||||||
@@ -1,5 +1,4 @@
|
|||||||
using Ghost.Core;
|
using Ghost.Core;
|
||||||
using Ghost.Graphics.Core;
|
|
||||||
using Ghost.Graphics.D3D12.Utilities;
|
using Ghost.Graphics.D3D12.Utilities;
|
||||||
using Ghost.Graphics.RHI;
|
using Ghost.Graphics.RHI;
|
||||||
using Misaki.HighPerformance.Collections;
|
using Misaki.HighPerformance.Collections;
|
||||||
@@ -102,15 +101,11 @@ internal class D3D12ResourceDatabase : IResourceDatabase
|
|||||||
private readonly D3D12DescriptorAllocator _descriptorAllocator;
|
private readonly D3D12DescriptorAllocator _descriptorAllocator;
|
||||||
|
|
||||||
private UnsafeSlotMap<ResourceRecord> _resources;
|
private UnsafeSlotMap<ResourceRecord> _resources;
|
||||||
|
private UnsafeHashMap<SamplerDesc, Identifier<Sampler>> _samplers;
|
||||||
#if DEBUG || GHOST_EDITOR
|
#if DEBUG || GHOST_EDITOR
|
||||||
private readonly Dictionary<Handle<GPUResource>, string> _resourceName;
|
private readonly Dictionary<Handle<GPUResource>, string> _resourceName;
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
private UnsafeHashMap<SamplerDesc, Identifier<Sampler>> _samplers;
|
|
||||||
private UnsafeSlotMap<Mesh> _meshes;
|
|
||||||
private UnsafeSlotMap<Material> _materials;
|
|
||||||
private readonly DynamicArray<Shader> _shaders; // TODO: Use SlotMap?
|
|
||||||
|
|
||||||
private UnsafeQueue<ReleaseEntry> _releaseQueue;
|
private UnsafeQueue<ReleaseEntry> _releaseQueue;
|
||||||
|
|
||||||
private bool _disposed;
|
private bool _disposed;
|
||||||
@@ -121,13 +116,10 @@ internal class D3D12ResourceDatabase : IResourceDatabase
|
|||||||
_descriptorAllocator = descriptorAllocator;
|
_descriptorAllocator = descriptorAllocator;
|
||||||
|
|
||||||
_resources = new UnsafeSlotMap<ResourceRecord>(64, Allocator.Persistent, AllocationOption.Clear);
|
_resources = new UnsafeSlotMap<ResourceRecord>(64, Allocator.Persistent, AllocationOption.Clear);
|
||||||
|
_samplers = new UnsafeHashMap<SamplerDesc, Identifier<Sampler>>(32, Allocator.Persistent);
|
||||||
#if DEBUG || GHOST_EDITOR
|
#if DEBUG || GHOST_EDITOR
|
||||||
_resourceName = new Dictionary<Handle<GPUResource>, string>(64);
|
_resourceName = new Dictionary<Handle<GPUResource>, string>(64);
|
||||||
#endif
|
#endif
|
||||||
_samplers = new UnsafeHashMap<SamplerDesc, Identifier<Sampler>>(32, Allocator.Persistent);
|
|
||||||
_meshes = new UnsafeSlotMap<Mesh>(64, Allocator.Persistent, AllocationOption.Clear);
|
|
||||||
_materials = new UnsafeSlotMap<Material>(16, Allocator.Persistent, AllocationOption.Clear);
|
|
||||||
_shaders = new DynamicArray<Shader>(16);
|
|
||||||
|
|
||||||
_releaseQueue = new UnsafeQueue<ReleaseEntry>(32, Allocator.Persistent);
|
_releaseQueue = new UnsafeQueue<ReleaseEntry>(32, Allocator.Persistent);
|
||||||
}
|
}
|
||||||
@@ -137,12 +129,6 @@ internal class D3D12ResourceDatabase : IResourceDatabase
|
|||||||
Dispose();
|
Dispose();
|
||||||
}
|
}
|
||||||
|
|
||||||
private void ReleaseResource<T>(T resource)
|
|
||||||
where T : IResourceReleasable
|
|
||||||
{
|
|
||||||
resource.ReleaseResource(this);
|
|
||||||
}
|
|
||||||
|
|
||||||
internal unsafe Handle<GPUResource> ImportExternalResource(ID3D12Resource* pResource, ResourceBarrierData initialBarrierData, ResourceViewGroup viewGroup, string? name = null)
|
internal unsafe Handle<GPUResource> ImportExternalResource(ID3D12Resource* pResource, ResourceBarrierData initialBarrierData, ResourceViewGroup viewGroup, string? name = null)
|
||||||
{
|
{
|
||||||
ObjectDisposedException.ThrowIf(_disposed, this);
|
ObjectDisposedException.ThrowIf(_disposed, this);
|
||||||
@@ -356,122 +342,6 @@ internal class D3D12ResourceDatabase : IResourceDatabase
|
|||||||
_descriptorAllocator.Release(new Identifier<SamplerDescriptor>(id.Value));
|
_descriptorAllocator.Release(new Identifier<SamplerDescriptor>(id.Value));
|
||||||
}
|
}
|
||||||
|
|
||||||
public Handle<Mesh> AddMesh(ref readonly Mesh mesh)
|
|
||||||
{
|
|
||||||
ObjectDisposedException.ThrowIf(_disposed, this);
|
|
||||||
|
|
||||||
var id = _meshes.Add(mesh, out var generation);
|
|
||||||
return new Handle<Mesh>(id, generation);
|
|
||||||
}
|
|
||||||
|
|
||||||
public bool HasMesh(Handle<Mesh> handle)
|
|
||||||
{
|
|
||||||
ObjectDisposedException.ThrowIf(_disposed, this);
|
|
||||||
return _meshes.Contains(handle.ID, handle.Generation);
|
|
||||||
}
|
|
||||||
|
|
||||||
public RefResult<Mesh, Error> GetMeshReference(Handle<Mesh> handle)
|
|
||||||
{
|
|
||||||
ref var mesh = ref _meshes.GetElementReferenceAt(handle.ID, handle.Generation, out var exist);
|
|
||||||
if (!exist)
|
|
||||||
{
|
|
||||||
return Error.NotFound;
|
|
||||||
}
|
|
||||||
|
|
||||||
return RefResult<Mesh, Error>.Success(ref mesh);
|
|
||||||
}
|
|
||||||
|
|
||||||
public void ReleaseMesh(Handle<Mesh> handle)
|
|
||||||
{
|
|
||||||
ObjectDisposedException.ThrowIf(_disposed, this);
|
|
||||||
|
|
||||||
ref var mesh = ref _meshes.GetElementReferenceAt(handle.ID, handle.Generation, out var exist);
|
|
||||||
if (!exist)
|
|
||||||
{
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
ReleaseResource(mesh);
|
|
||||||
_meshes.Remove(handle.ID, handle.Generation);
|
|
||||||
}
|
|
||||||
|
|
||||||
public Handle<Material> AddMaterial(ref readonly Material material)
|
|
||||||
{
|
|
||||||
ObjectDisposedException.ThrowIf(_disposed, this);
|
|
||||||
|
|
||||||
var id = _materials.Add(material, out var generation);
|
|
||||||
return new Handle<Material>(id, generation);
|
|
||||||
}
|
|
||||||
|
|
||||||
public bool HasMaterial(Handle<Material> handle)
|
|
||||||
{
|
|
||||||
ObjectDisposedException.ThrowIf(_disposed, this);
|
|
||||||
return _materials.Contains(handle.ID, handle.Generation);
|
|
||||||
}
|
|
||||||
|
|
||||||
public RefResult<Material, Error> GetMaterialReference(Handle<Material> handle)
|
|
||||||
{
|
|
||||||
ref var material = ref _materials.GetElementReferenceAt(handle.ID, handle.Generation, out var exist);
|
|
||||||
if (!exist)
|
|
||||||
{
|
|
||||||
return Error.NotFound;
|
|
||||||
}
|
|
||||||
|
|
||||||
return RefResult<Material, Error>.Success(ref material);
|
|
||||||
}
|
|
||||||
|
|
||||||
public void ReleaseMaterial(Handle<Material> handle)
|
|
||||||
{
|
|
||||||
ObjectDisposedException.ThrowIf(_disposed, this);
|
|
||||||
|
|
||||||
ref var material = ref _materials.GetElementReferenceAt(handle.ID, handle.Generation, out var exist);
|
|
||||||
if (!exist)
|
|
||||||
{
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
ReleaseResource(material);
|
|
||||||
_materials.Remove(handle.ID, handle.Generation);
|
|
||||||
}
|
|
||||||
|
|
||||||
public Identifier<Shader> AddShader(Shader shader)
|
|
||||||
{
|
|
||||||
ObjectDisposedException.ThrowIf(_disposed, this);
|
|
||||||
|
|
||||||
var id = _shaders.Count;
|
|
||||||
_shaders.Add(shader);
|
|
||||||
return new Identifier<Shader>(id);
|
|
||||||
}
|
|
||||||
|
|
||||||
public bool HasShader(Identifier<Shader> id)
|
|
||||||
{
|
|
||||||
ObjectDisposedException.ThrowIf(_disposed, this);
|
|
||||||
return id.Value >= 0 && id.Value < _shaders.Count;
|
|
||||||
}
|
|
||||||
|
|
||||||
public RefResult<Shader, Error> GetShaderReference(Identifier<Shader> id)
|
|
||||||
{
|
|
||||||
if (!HasShader(id))
|
|
||||||
{
|
|
||||||
return Error.NotFound;
|
|
||||||
}
|
|
||||||
|
|
||||||
return RefResult<Shader, Error>.Success(ref _shaders[id.Value]);
|
|
||||||
}
|
|
||||||
|
|
||||||
public void ReleaseShader(Identifier<Shader> id)
|
|
||||||
{
|
|
||||||
ObjectDisposedException.ThrowIf(_disposed, this);
|
|
||||||
|
|
||||||
if (!HasShader(id))
|
|
||||||
{
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
ref var shader = ref _shaders[id.Value]!;
|
|
||||||
ReleaseResource(shader);
|
|
||||||
}
|
|
||||||
|
|
||||||
public void EndFrame()
|
public void EndFrame()
|
||||||
{
|
{
|
||||||
ObjectDisposedException.ThrowIf(_disposed, this);
|
ObjectDisposedException.ThrowIf(_disposed, this);
|
||||||
@@ -494,21 +364,6 @@ internal class D3D12ResourceDatabase : IResourceDatabase
|
|||||||
{
|
{
|
||||||
ObjectDisposedException.ThrowIf(_disposed, this);
|
ObjectDisposedException.ThrowIf(_disposed, this);
|
||||||
|
|
||||||
foreach (var mesh in _meshes)
|
|
||||||
{
|
|
||||||
ReleaseResource(mesh);
|
|
||||||
}
|
|
||||||
|
|
||||||
foreach (var material in _materials)
|
|
||||||
{
|
|
||||||
ReleaseResource(material);
|
|
||||||
}
|
|
||||||
|
|
||||||
foreach (var shader in _shaders)
|
|
||||||
{
|
|
||||||
ReleaseResource(shader);
|
|
||||||
}
|
|
||||||
|
|
||||||
foreach (ref var record in _resources)
|
foreach (ref var record in _resources)
|
||||||
{
|
{
|
||||||
record.Release(_descriptorAllocator);
|
record.Release(_descriptorAllocator);
|
||||||
@@ -524,8 +379,6 @@ internal class D3D12ResourceDatabase : IResourceDatabase
|
|||||||
|
|
||||||
_resources.Dispose();
|
_resources.Dispose();
|
||||||
_samplers.Dispose();
|
_samplers.Dispose();
|
||||||
_meshes.Dispose();
|
|
||||||
_materials.Dispose();
|
|
||||||
_releaseQueue.Dispose();
|
_releaseQueue.Dispose();
|
||||||
|
|
||||||
_disposed = true;
|
_disposed = true;
|
||||||
@@ -1,7 +1,4 @@
|
|||||||
using Ghost.Core;
|
using Ghost.Core;
|
||||||
using Ghost.Core.Utilities;
|
|
||||||
using Ghost.Graphics.Contracts;
|
|
||||||
using Ghost.Graphics.Core;
|
|
||||||
using Ghost.Graphics.D3D12.Utilities;
|
using Ghost.Graphics.D3D12.Utilities;
|
||||||
using Ghost.Graphics.RHI;
|
using Ghost.Graphics.RHI;
|
||||||
using Misaki.HighPerformance.LowLevel;
|
using Misaki.HighPerformance.LowLevel;
|
||||||
@@ -1,7 +1,6 @@
|
|||||||
using Ghost.Core;
|
using Ghost.Core;
|
||||||
using Ghost.Core.Graphics;
|
using Ghost.Core.Graphics;
|
||||||
using Ghost.Core.Utilities;
|
using Ghost.Graphics.D3D12.Utilities;
|
||||||
using Ghost.Graphics.Contracts;
|
|
||||||
using Ghost.Graphics.RHI;
|
using Ghost.Graphics.RHI;
|
||||||
using Misaki.HighPerformance.LowLevel;
|
using Misaki.HighPerformance.LowLevel;
|
||||||
using Misaki.HighPerformance.LowLevel.Buffer;
|
using Misaki.HighPerformance.LowLevel.Buffer;
|
||||||
@@ -318,8 +317,7 @@ internal sealed unsafe partial class DxcShaderCompiler : IShaderCompiler
|
|||||||
Encoding = DXC_CP_UTF8
|
Encoding = DXC_CP_UTF8
|
||||||
};
|
};
|
||||||
|
|
||||||
var (iid, ppv) = Win32Utility.IID_PPV_ARGS(&result);
|
ThrowIfFailed(_compiler.Get()->Compile(&buffer, argPtrs, (uint)argsArray.Count, includeHandler, __uuidof(result.Get()), (void**)&result));
|
||||||
ThrowIfFailed(_compiler.Get()->Compile(&buffer, argPtrs, (uint)argsArray.Count, includeHandler, iid, ppv));
|
|
||||||
|
|
||||||
// Check compilation result
|
// Check compilation result
|
||||||
HRESULT hrStatus;
|
HRESULT hrStatus;
|
||||||
@@ -351,9 +349,7 @@ internal sealed unsafe partial class DxcShaderCompiler : IShaderCompiler
|
|||||||
if (config.options.HasFlag(CompilerOption.KeepReflections))
|
if (config.options.HasFlag(CompilerOption.KeepReflections))
|
||||||
{
|
{
|
||||||
using ComPtr<IDxcBlob> reflection = default;
|
using ComPtr<IDxcBlob> reflection = default;
|
||||||
(iid, ppv) = Win32Utility.IID_PPV_ARGS(&reflection);
|
if (result.Get()->GetOutput(DXC_OUT_KIND.DXC_OUT_REFLECTION, __uuidof(reflection.Get()), (void**)&reflection, null).SUCCEEDED)
|
||||||
|
|
||||||
if (result.Get()->GetOutput(DXC_OUT_KIND.DXC_OUT_REFLECTION, iid, ppv, null).SUCCEEDED)
|
|
||||||
{
|
{
|
||||||
reflectionData = PerformDXCReflection(reflection).GetValueOrDefault();
|
reflectionData = PerformDXCReflection(reflection).GetValueOrDefault();
|
||||||
}
|
}
|
||||||
37
src/Runtime/Ghost.Graphics.D3D12/Ghost.Graphics.D3D12.csproj
Normal file
37
src/Runtime/Ghost.Graphics.D3D12/Ghost.Graphics.D3D12.csproj
Normal file
@@ -0,0 +1,37 @@
|
|||||||
|
<Project Sdk="Microsoft.NET.Sdk">
|
||||||
|
|
||||||
|
<PropertyGroup>
|
||||||
|
<TargetFramework>net10.0</TargetFramework>
|
||||||
|
<ImplicitUsings>enable</ImplicitUsings>
|
||||||
|
<Nullable>enable</Nullable>
|
||||||
|
<AllowUnsafeBlocks>true</AllowUnsafeBlocks>
|
||||||
|
<PublishAot>true</PublishAot>
|
||||||
|
</PropertyGroup>
|
||||||
|
|
||||||
|
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|AnyCPU'">
|
||||||
|
<IsAotCompatible>True</IsAotCompatible>
|
||||||
|
</PropertyGroup>
|
||||||
|
|
||||||
|
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|AnyCPU'">
|
||||||
|
<IsAotCompatible>True</IsAotCompatible>
|
||||||
|
</PropertyGroup>
|
||||||
|
|
||||||
|
<ItemGroup>
|
||||||
|
<Content Include="runtimes\win-x64\native\dxcompiler.dll">
|
||||||
|
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
|
||||||
|
</Content>
|
||||||
|
<Content Include="runtimes\win-x64\native\dxil.dll">
|
||||||
|
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
|
||||||
|
</Content>
|
||||||
|
</ItemGroup>
|
||||||
|
|
||||||
|
<ItemGroup>
|
||||||
|
<PackageReference Include="TerraFX.Interop.D3D12MemoryAllocator" Version="3.0.1" />
|
||||||
|
</ItemGroup>
|
||||||
|
|
||||||
|
<ItemGroup>
|
||||||
|
<ProjectReference Include="..\Ghost.Core\Ghost.Core.csproj" />
|
||||||
|
<ProjectReference Include="..\Ghost.Graphics.RHI\Ghost.Graphics.RHI.csproj" />
|
||||||
|
</ItemGroup>
|
||||||
|
|
||||||
|
</Project>
|
||||||
@@ -1,9 +1,8 @@
|
|||||||
using System.Runtime.InteropServices;
|
using System.Runtime.InteropServices;
|
||||||
using TerraFX.Interop.Windows;
|
|
||||||
|
|
||||||
namespace Ghost.Graphics.Contracts;
|
namespace Ghost.Graphics.D3D12;
|
||||||
|
|
||||||
public unsafe readonly struct ISwapChainPanelNative : ISwapChainPanelNative.Interface, IDisposable
|
public readonly unsafe struct ISwapChainPanelNative : ISwapChainPanelNative.Interface, IDisposable
|
||||||
{
|
{
|
||||||
[ComImport]
|
[ComImport]
|
||||||
[Guid("63aad0b8-7c24-40ff-85a8-640d944cc325")]
|
[Guid("63aad0b8-7c24-40ff-85a8-640d944cc325")]
|
||||||
@@ -0,0 +1,27 @@
|
|||||||
|
using Ghost.Graphics.RHI;
|
||||||
|
using System.Runtime.CompilerServices;
|
||||||
|
using TerraFX.Interop.DirectX;
|
||||||
|
|
||||||
|
using static TerraFX.Interop.DirectX.D3D12_INPUT_CLASSIFICATION;
|
||||||
|
using static TerraFX.Interop.DirectX.DXGI_FORMAT;
|
||||||
|
|
||||||
|
namespace Ghost.Graphics.D3D12.Utilities;
|
||||||
|
|
||||||
|
internal static unsafe class D3D12PipelineResource
|
||||||
|
{
|
||||||
|
private static readonly D3D12_INPUT_ELEMENT_DESC[] s_inputElementDescs = [
|
||||||
|
new D3D12_INPUT_ELEMENT_DESC{ SemanticName = (sbyte*)Vertex.Semantic.Position.GetUnsafePtr(), SemanticIndex = 0u, Format = DXGI_FORMAT_R32G32B32A32_FLOAT, InputSlot = 0u, AlignedByteOffset = 0u, InputSlotClass = D3D12_INPUT_CLASSIFICATION_PER_VERTEX_DATA, InstanceDataStepRate = 0 },
|
||||||
|
new D3D12_INPUT_ELEMENT_DESC{ SemanticName = (sbyte*)Vertex.Semantic.Normal.GetUnsafePtr(), SemanticIndex = 0u, Format = DXGI_FORMAT_R32G32B32A32_FLOAT, InputSlot = 0u, AlignedByteOffset = 16u, InputSlotClass = D3D12_INPUT_CLASSIFICATION_PER_VERTEX_DATA, InstanceDataStepRate = 0 },
|
||||||
|
new D3D12_INPUT_ELEMENT_DESC{ SemanticName = (sbyte*)Vertex.Semantic.Tangent.GetUnsafePtr(), SemanticIndex = 0u, Format = DXGI_FORMAT_R32G32B32A32_FLOAT, InputSlot = 0u, AlignedByteOffset = 32u, InputSlotClass = D3D12_INPUT_CLASSIFICATION_PER_VERTEX_DATA, InstanceDataStepRate = 0 },
|
||||||
|
new D3D12_INPUT_ELEMENT_DESC{ SemanticName = (sbyte*)Vertex.Semantic.Uv.GetUnsafePtr(), SemanticIndex = 0u, Format = DXGI_FORMAT_R32G32B32A32_FLOAT, InputSlot = 0u, AlignedByteOffset = 48u, InputSlotClass = D3D12_INPUT_CLASSIFICATION_PER_VERTEX_DATA, InstanceDataStepRate = 0 },
|
||||||
|
new D3D12_INPUT_ELEMENT_DESC{ SemanticName = (sbyte*)Vertex.Semantic.Color.GetUnsafePtr(), SemanticIndex = 0u, Format = DXGI_FORMAT_R32G32B32A32_FLOAT, InputSlot = 0u, AlignedByteOffset = 64u, InputSlotClass = D3D12_INPUT_CLASSIFICATION_PER_VERTEX_DATA, InstanceDataStepRate = 0 },
|
||||||
|
];
|
||||||
|
|
||||||
|
public const DXGI_FORMAT SWAP_CHAIN_BACK_BUFFER_FORMAT = DXGI_FORMAT_B8G8R8A8_UNORM;
|
||||||
|
|
||||||
|
public static D3D12_INPUT_LAYOUT_DESC InputLayoutDescription => new()
|
||||||
|
{
|
||||||
|
pInputElementDescs = (D3D12_INPUT_ELEMENT_DESC*)Unsafe.AsPointer(ref s_inputElementDescs[0]),
|
||||||
|
NumElements = (uint)s_inputElementDescs.Length
|
||||||
|
};
|
||||||
|
}
|
||||||
@@ -1,7 +1,12 @@
|
|||||||
|
using Ghost.Core;
|
||||||
using Ghost.Core.Graphics;
|
using Ghost.Core.Graphics;
|
||||||
using Ghost.Graphics.RHI;
|
using Ghost.Graphics.RHI;
|
||||||
|
using Misaki.HighPerformance.LowLevel;
|
||||||
|
using System.ComponentModel;
|
||||||
|
using System.Diagnostics;
|
||||||
|
using System.Runtime.CompilerServices;
|
||||||
using TerraFX.Interop.DirectX;
|
using TerraFX.Interop.DirectX;
|
||||||
|
using TerraFX.Interop.Windows;
|
||||||
using static TerraFX.Aliases.D3D12_Alias;
|
using static TerraFX.Aliases.D3D12_Alias;
|
||||||
using static TerraFX.Aliases.DXGI_Alias;
|
using static TerraFX.Aliases.DXGI_Alias;
|
||||||
|
|
||||||
@@ -9,6 +14,82 @@ namespace Ghost.Graphics.D3D12.Utilities;
|
|||||||
|
|
||||||
internal static unsafe class D3D12Utility
|
internal static unsafe class D3D12Utility
|
||||||
{
|
{
|
||||||
|
[EditorBrowsable(EditorBrowsableState.Never)]
|
||||||
|
public readonly ref struct IID_PPV
|
||||||
|
{
|
||||||
|
public readonly Guid* iid;
|
||||||
|
public readonly void** ppv;
|
||||||
|
|
||||||
|
public IID_PPV(Guid* iid, void** ppv)
|
||||||
|
{
|
||||||
|
this.iid = iid;
|
||||||
|
this.ppv = ppv;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void Deconstruct(out Guid* iid, out void** ppv)
|
||||||
|
{
|
||||||
|
iid = this.iid;
|
||||||
|
ppv = this.ppv;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public static Guid* IID_NULL
|
||||||
|
{
|
||||||
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||||
|
get => (Guid*)Unsafe.AsPointer(ref Unsafe.AsRef(in IID.IID_NULL));
|
||||||
|
}
|
||||||
|
|
||||||
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||||
|
public static IID_PPV IID_PPV_ARGS<T>(ComPtr<T>* comPtr)
|
||||||
|
where T : unmanaged, IUnknown.Interface
|
||||||
|
{
|
||||||
|
return new IID_PPV(__uuidof<T>(), (void**)comPtr);
|
||||||
|
}
|
||||||
|
|
||||||
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||||
|
public static void Attach<T>(ref this UniquePtr<T> uPtr, T* other)
|
||||||
|
where T : unmanaged, IUnknown.Interface
|
||||||
|
{
|
||||||
|
var ptr = uPtr.Get();
|
||||||
|
if (ptr != null)
|
||||||
|
{
|
||||||
|
var refCount = ptr->Release();
|
||||||
|
Debug.Assert((refCount != 0) || (ptr != other));
|
||||||
|
}
|
||||||
|
|
||||||
|
uPtr = new UniquePtr<T>(other);
|
||||||
|
}
|
||||||
|
|
||||||
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||||
|
public static void Dispose<T>(ref this UniquePtr<T> uPtr)
|
||||||
|
where T : unmanaged, IUnknown.Interface
|
||||||
|
{
|
||||||
|
var ptr = uPtr.Detach();
|
||||||
|
if (ptr != null)
|
||||||
|
{
|
||||||
|
var refCount = ptr->Release();
|
||||||
|
Debug.Assert((refCount != 0));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||||
|
public static Result ToResult(this HRESULT hr, [CallerArgumentExpression(nameof(hr))] string? op = null)
|
||||||
|
{
|
||||||
|
if (hr.SUCCEEDED)
|
||||||
|
{
|
||||||
|
return Result.Success();
|
||||||
|
}
|
||||||
|
|
||||||
|
return Result.Failure($"{op} failed with code {hr}");
|
||||||
|
}
|
||||||
|
|
||||||
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||||
|
public static void** ReleaseAndGetVoidAddressOf<T>(ref this ComPtr<T> comPtr)
|
||||||
|
where T : unmanaged, IUnknown.Interface
|
||||||
|
{
|
||||||
|
return (void**)comPtr.ReleaseAndGetAddressOf();
|
||||||
|
}
|
||||||
|
|
||||||
public static void SetName<T>(ref this T obj, ReadOnlySpan<char> name)
|
public static void SetName<T>(ref this T obj, ReadOnlySpan<char> name)
|
||||||
where T : unmanaged, ID3D12Object.Interface
|
where T : unmanaged, ID3D12Object.Interface
|
||||||
{
|
{
|
||||||
BIN
src/Runtime/Ghost.Graphics.D3D12/runtimes/win-x64/native/dxcompiler.dll
LFS
Normal file
BIN
src/Runtime/Ghost.Graphics.D3D12/runtimes/win-x64/native/dxcompiler.dll
LFS
Normal file
Binary file not shown.
BIN
src/Runtime/Ghost.Graphics.D3D12/runtimes/win-x64/native/dxil.dll
LFS
Normal file
BIN
src/Runtime/Ghost.Graphics.D3D12/runtimes/win-x64/native/dxil.dll
LFS
Normal file
Binary file not shown.
@@ -1,16 +1,178 @@
|
|||||||
using Ghost.Core;
|
using Ghost.Core;
|
||||||
using Ghost.Core.Graphics;
|
using Ghost.Core.Graphics;
|
||||||
using Ghost.Graphics.Core;
|
using Misaki.HighPerformance.LowLevel.Collections;
|
||||||
using Misaki.HighPerformance.Mathematics;
|
using Misaki.HighPerformance.Mathematics;
|
||||||
using System.Diagnostics;
|
using System.Diagnostics;
|
||||||
|
using System.Diagnostics.CodeAnalysis;
|
||||||
|
using System.Drawing;
|
||||||
using System.Runtime.CompilerServices;
|
using System.Runtime.CompilerServices;
|
||||||
using System.Runtime.InteropServices;
|
using System.Runtime.InteropServices;
|
||||||
|
|
||||||
namespace Ghost.Graphics.RHI;
|
namespace Ghost.Graphics.RHI;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Represents a color with 4 bytes components.
|
||||||
|
/// </summary>
|
||||||
|
[StructLayout(LayoutKind.Sequential, Size = 4)]
|
||||||
|
public struct Color32 : IEquatable<Color32>
|
||||||
|
{
|
||||||
|
public byte r;
|
||||||
|
public byte g;
|
||||||
|
public byte b;
|
||||||
|
public byte a;
|
||||||
|
|
||||||
|
public Color32(byte r, byte g, byte b, byte a)
|
||||||
|
{
|
||||||
|
this.r = r;
|
||||||
|
this.g = g;
|
||||||
|
this.b = b;
|
||||||
|
this.a = a;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Color32(Color color)
|
||||||
|
: this(color.R, color.G, color.B, color.A)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
public Color32(Color128 color128)
|
||||||
|
: this((byte)(color128.r * 255.0f), (byte)(color128.g * 255.0f), (byte)(color128.b * 255.0f), (byte)(color128.a * 255.0f))
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
public Color32(float4 v)
|
||||||
|
: this((byte)(v.x * 255.0f), (byte)(v.y * 255.0f), (byte)(v.z * 255.0f), (byte)(v.w * 255.0f))
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
public readonly bool Equals(Color32 other)
|
||||||
|
{
|
||||||
|
return r == other.r && g == other.g && b == other.b && a == other.a;
|
||||||
|
}
|
||||||
|
|
||||||
|
public override readonly bool Equals(object? obj)
|
||||||
|
{
|
||||||
|
return obj is Color32 color && Equals(color);
|
||||||
|
}
|
||||||
|
|
||||||
|
public override readonly int GetHashCode()
|
||||||
|
{
|
||||||
|
return HashCode.Combine(r, g, b, a);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static bool operator ==(Color32 left, Color32 right)
|
||||||
|
{
|
||||||
|
return left.Equals(right);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static bool operator !=(Color32 left, Color32 right)
|
||||||
|
{
|
||||||
|
return !(left == right);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Represents a color with 16 bytes components.
|
||||||
|
/// </summary>
|
||||||
|
[StructLayout(LayoutKind.Sequential, Size = 16)]
|
||||||
|
public struct Color128 : IEquatable<Color128>
|
||||||
|
{
|
||||||
|
public float r;
|
||||||
|
public float g;
|
||||||
|
public float b;
|
||||||
|
public float a;
|
||||||
|
|
||||||
|
public Color128(float r, float g, float b, float a)
|
||||||
|
{
|
||||||
|
this.r = r;
|
||||||
|
this.g = g;
|
||||||
|
this.b = b;
|
||||||
|
this.a = a;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Color128(Color color)
|
||||||
|
: this(color.R / 255.0f, color.G / 255.0f, color.B / 255.0f, color.A / 255.0f)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
public Color128(Color32 color32)
|
||||||
|
: this(color32.r / 255.0f, color32.g / 255.0f, color32.b / 255.0f, color32.a / 255.0f)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
public Color128(float4 v)
|
||||||
|
: this(v.x, v.y, v.z, v.w)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
public readonly bool Equals(Color128 other)
|
||||||
|
{
|
||||||
|
return r.Equals(other.r) && g.Equals(other.g) && b.Equals(other.b) && a.Equals(other.a);
|
||||||
|
}
|
||||||
|
|
||||||
|
public override readonly bool Equals(object? obj)
|
||||||
|
{
|
||||||
|
return obj is Color128 color && Equals(color);
|
||||||
|
}
|
||||||
|
|
||||||
|
public readonly override int GetHashCode()
|
||||||
|
{
|
||||||
|
return HashCode.Combine(r, g, b, a);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static bool operator ==(Color128 left, Color128 right)
|
||||||
|
{
|
||||||
|
return left.Equals(right);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static bool operator !=(Color128 left, Color128 right)
|
||||||
|
{
|
||||||
|
return !(left == right);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
[StructLayout(LayoutKind.Sequential)]
|
||||||
|
public struct Vertex
|
||||||
|
{
|
||||||
|
public static class Semantic
|
||||||
|
{
|
||||||
|
public const int COUNT = 5;
|
||||||
|
|
||||||
|
public static readonly FixedText32 Position = new("POSITION");
|
||||||
|
public static readonly FixedText32 Normal = new("NORMAL");
|
||||||
|
public static readonly FixedText32 Tangent = new("TANGENT");
|
||||||
|
public static readonly FixedText32 Uv = new("TEXCOORD");
|
||||||
|
public static readonly FixedText32 Color = new("COLOR");
|
||||||
|
}
|
||||||
|
|
||||||
|
public float4 position;
|
||||||
|
public float4 normal;
|
||||||
|
public float4 tangent;
|
||||||
|
public float4 uv;
|
||||||
|
public Color128 color;
|
||||||
|
}
|
||||||
|
|
||||||
public readonly struct ShaderVariant;
|
public readonly struct ShaderVariant;
|
||||||
public readonly struct GraphicsPipeline;
|
public readonly struct GraphicsPipeline;
|
||||||
|
|
||||||
|
public readonly struct ShaderPass
|
||||||
|
{
|
||||||
|
public Key64<ShaderPass> Key
|
||||||
|
{
|
||||||
|
get; init;
|
||||||
|
}
|
||||||
|
|
||||||
|
public PipelineState DefaultState
|
||||||
|
{
|
||||||
|
get; init;
|
||||||
|
}
|
||||||
|
|
||||||
|
public LocalKeywordSet KeywordIDs
|
||||||
|
{
|
||||||
|
get; init;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
public readonly struct PassPipelineHash : IEquatable<PassPipelineHash>
|
public readonly struct PassPipelineHash : IEquatable<PassPipelineHash>
|
||||||
{
|
{
|
||||||
public readonly UInt128 value;
|
public readonly UInt128 value;
|
||||||
@@ -431,31 +593,23 @@ public struct ResourceDesc
|
|||||||
get; init;
|
get; init;
|
||||||
}
|
}
|
||||||
|
|
||||||
public TextureDesc TextureDescription
|
[UnscopedRef]
|
||||||
|
public ref TextureDesc TextureDescription
|
||||||
{
|
{
|
||||||
readonly get
|
get
|
||||||
{
|
{
|
||||||
Debug.Assert(Type == ResourceType.Texture);
|
Debug.Assert(Type == ResourceType.Texture);
|
||||||
return _desc.textureDescription;
|
return ref _desc.textureDescription;
|
||||||
}
|
|
||||||
set
|
|
||||||
{
|
|
||||||
Debug.Assert(Type == ResourceType.Texture);
|
|
||||||
_desc.textureDescription = value;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public BufferDesc BufferDescription
|
[UnscopedRef]
|
||||||
|
public ref BufferDesc BufferDescription
|
||||||
{
|
{
|
||||||
readonly get
|
get
|
||||||
{
|
{
|
||||||
Debug.Assert(Type == ResourceType.Buffer);
|
Debug.Assert(Type == ResourceType.Buffer);
|
||||||
return _desc.bufferDescription;
|
return ref _desc.bufferDescription;
|
||||||
}
|
|
||||||
set
|
|
||||||
{
|
|
||||||
Debug.Assert(Type == ResourceType.Buffer);
|
|
||||||
_desc.bufferDescription = value;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
22
src/Runtime/Ghost.Graphics.RHI/Ghost.Graphics.RHI.csproj
Normal file
22
src/Runtime/Ghost.Graphics.RHI/Ghost.Graphics.RHI.csproj
Normal file
@@ -0,0 +1,22 @@
|
|||||||
|
<Project Sdk="Microsoft.NET.Sdk">
|
||||||
|
|
||||||
|
<PropertyGroup>
|
||||||
|
<TargetFramework>net10.0</TargetFramework>
|
||||||
|
<ImplicitUsings>enable</ImplicitUsings>
|
||||||
|
<Nullable>enable</Nullable>
|
||||||
|
<AllowUnsafeBlocks>True</AllowUnsafeBlocks>
|
||||||
|
</PropertyGroup>
|
||||||
|
|
||||||
|
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|AnyCPU'">
|
||||||
|
<IsAotCompatible>True</IsAotCompatible>
|
||||||
|
</PropertyGroup>
|
||||||
|
|
||||||
|
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|AnyCPU'">
|
||||||
|
<IsAotCompatible>True</IsAotCompatible>
|
||||||
|
</PropertyGroup>
|
||||||
|
|
||||||
|
<ItemGroup>
|
||||||
|
<ProjectReference Include="..\Ghost.Core\Ghost.Core.csproj" />
|
||||||
|
</ItemGroup>
|
||||||
|
|
||||||
|
</Project>
|
||||||
@@ -1,5 +1,4 @@
|
|||||||
using Ghost.Core;
|
using Ghost.Core;
|
||||||
using Ghost.Graphics.Core;
|
|
||||||
|
|
||||||
namespace Ghost.Graphics.RHI;
|
namespace Ghost.Graphics.RHI;
|
||||||
|
|
||||||
@@ -1,5 +1,4 @@
|
|||||||
using Ghost.Core;
|
using Ghost.Core;
|
||||||
using Ghost.Graphics.Contracts;
|
|
||||||
|
|
||||||
namespace Ghost.Graphics.RHI;
|
namespace Ghost.Graphics.RHI;
|
||||||
|
|
||||||
@@ -31,15 +30,15 @@ public interface IGraphicsEngine : IDisposable
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Creates a new instance of an object that implements the IRenderer interface.
|
/// Creates a new instance of a renderer for drawing graphical content.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <returns>An object that provides rendering functionality through the IRenderer interface.</returns>
|
/// <returns>An object that implements the IRenderer interface, which can be used to render graphics.</returns>
|
||||||
IRenderer CreateRenderer();
|
IRenderer CreateRenderer();
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Removes the specified renderer from the collection of active renderers.
|
/// Removes the specified renderer from the collection of active renderers.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <param name="renderer">The renderer instance to remove. Cannot be null.</param>
|
/// <param name="renderer">The renderer instance to remove.</param>
|
||||||
void RemoveRenderer(IRenderer renderer);
|
void RemoveRenderer(IRenderer renderer);
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
@@ -1,5 +1,4 @@
|
|||||||
using Ghost.Core;
|
using Ghost.Core;
|
||||||
using Ghost.Graphics.Contracts;
|
|
||||||
|
|
||||||
namespace Ghost.Graphics.RHI;
|
namespace Ghost.Graphics.RHI;
|
||||||
|
|
||||||
@@ -1,8 +1,6 @@
|
|||||||
using Ghost.Core;
|
using Ghost.Core;
|
||||||
using Ghost.Graphics.Core;
|
|
||||||
using Ghost.Graphics.RHI;
|
|
||||||
|
|
||||||
namespace Ghost.Graphics.Contracts;
|
namespace Ghost.Graphics.RHI;
|
||||||
|
|
||||||
public interface IRenderOutput
|
public interface IRenderOutput
|
||||||
{
|
{
|
||||||
47
src/Runtime/Ghost.Graphics.RHI/IRenderSystem.cs
Normal file
47
src/Runtime/Ghost.Graphics.RHI/IRenderSystem.cs
Normal file
@@ -0,0 +1,47 @@
|
|||||||
|
using Misaki.HighPerformance.Mathematics;
|
||||||
|
|
||||||
|
namespace Ghost.Graphics.RHI;
|
||||||
|
|
||||||
|
public interface IFenceSynchronizer
|
||||||
|
{
|
||||||
|
uint CPUFenceValue
|
||||||
|
{
|
||||||
|
get;
|
||||||
|
}
|
||||||
|
|
||||||
|
uint GPUFenceValue
|
||||||
|
{
|
||||||
|
get;
|
||||||
|
}
|
||||||
|
|
||||||
|
uint FrameIndex
|
||||||
|
{
|
||||||
|
get;
|
||||||
|
}
|
||||||
|
|
||||||
|
uint MaxFrameLatency
|
||||||
|
{
|
||||||
|
get;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool WaitForGPUReady(int timeOut = -1);
|
||||||
|
void SignalCPUReady();
|
||||||
|
void WaitIdle();
|
||||||
|
}
|
||||||
|
|
||||||
|
public interface IRenderSystem : IFenceSynchronizer, IDisposable
|
||||||
|
{
|
||||||
|
IGraphicsEngine GraphicsEngine
|
||||||
|
{
|
||||||
|
get;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool IsRunning
|
||||||
|
{
|
||||||
|
get;
|
||||||
|
}
|
||||||
|
|
||||||
|
void Start();
|
||||||
|
void Stop();
|
||||||
|
void RequestSwapChainResize(ISwapChain swapChain, uint2 newSize);
|
||||||
|
}
|
||||||
@@ -1,18 +1,33 @@
|
|||||||
using Ghost.Core;
|
using Ghost.Core;
|
||||||
using Ghost.Graphics.Contracts;
|
|
||||||
|
|
||||||
namespace Ghost.Graphics.RHI;
|
namespace Ghost.Graphics.RHI;
|
||||||
|
|
||||||
|
public readonly struct RenderContext
|
||||||
|
{
|
||||||
|
public ICommandBuffer CommandBuffer { get; init; }
|
||||||
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// High-level renderer interface that uses RHI abstractions
|
/// High-level renderer interface that uses RHI abstractions
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public interface IRenderer : IDisposable
|
public interface IRenderer : IDisposable
|
||||||
{
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Gets or sets the render output target for this renderer.
|
||||||
|
/// </summary>
|
||||||
IRenderOutput? RenderOutput
|
IRenderOutput? RenderOutput
|
||||||
{
|
{
|
||||||
get; set;
|
get; set;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// The function that performs the actual rendering operations. Skip rendering if this is null.
|
||||||
|
/// </summary>
|
||||||
|
Func<RenderContext, Error>? RenderFunc
|
||||||
|
{
|
||||||
|
get; set;
|
||||||
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Renders a frame
|
/// Renders a frame
|
||||||
/// </summary>
|
/// </summary>
|
||||||
@@ -1,6 +1,5 @@
|
|||||||
using Ghost.Core;
|
using Ghost.Core;
|
||||||
using Ghost.Core.Graphics;
|
using Ghost.Core.Graphics;
|
||||||
using Ghost.Graphics.Core;
|
|
||||||
using Misaki.HighPerformance.LowLevel.Collections;
|
using Misaki.HighPerformance.LowLevel.Collections;
|
||||||
|
|
||||||
namespace Ghost.Graphics.RHI;
|
namespace Ghost.Graphics.RHI;
|
||||||
@@ -138,26 +137,4 @@ public interface IResourceAllocator : IDisposable
|
|||||||
/// <param name="desc">A read-only reference to a <see cref="SamplerDesc"/> structure that defines the properties of the sampler to be created.</param>
|
/// <param name="desc">A read-only reference to a <see cref="SamplerDesc"/> structure that defines the properties of the sampler to be created.</param>
|
||||||
/// <returns>An <see cref="Identifier{Sampler}"/> that uniquely identifies the created sampler object.</returns>
|
/// <returns>An <see cref="Identifier{Sampler}"/> that uniquely identifies the created sampler object.</returns>
|
||||||
Identifier<Sampler> CreateSampler(ref readonly SamplerDesc desc);
|
Identifier<Sampler> CreateSampler(ref readonly SamplerDesc desc);
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Creates a new mesh from the specified vertex and index data.
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="vertices">A UnsafeList containing the vertices that define the geometry of the mesh. Must contain at least one vertex.</param>
|
|
||||||
/// <param name="indices">A UnsafeList containing the indices that specify how vertices are connected to form primitives. Must contain at least one index.</param>
|
|
||||||
/// <returns>An <see cref="Identifier{Mesh}"/> representing the newly created mesh.</returns>
|
|
||||||
Handle<Mesh> CreateMesh(UnsafeList<Vertex> vertices, UnsafeList<uint> indices);
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Creates a new material instance using the specified shader.
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="shader">The identifier of the shader to associate with the new material. Cannot be null.</param>
|
|
||||||
/// <returns>An <see cref="Identifier{Material}"/> representing the newly created material.</returns>
|
|
||||||
Handle<Material> CreateMaterial(Identifier<Shader> shader);
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Creates a new shader and returns its unique identifier.
|
|
||||||
/// </summary>
|
|
||||||
/// <returns>An <see cref="Identifier{Shader}"/> representing the newly created shader.</returns>
|
|
||||||
/// <param name="descriptor">The viewGroup containing the shader's properties and passes.</param>
|
|
||||||
Identifier<Shader> CreateGraphicsShader(ShaderDescriptor descriptor);
|
|
||||||
}
|
}
|
||||||
@@ -1,5 +1,4 @@
|
|||||||
using Ghost.Core;
|
using Ghost.Core;
|
||||||
using Ghost.Graphics.Core;
|
|
||||||
|
|
||||||
namespace Ghost.Graphics.RHI;
|
namespace Ghost.Graphics.RHI;
|
||||||
|
|
||||||
@@ -129,85 +128,4 @@ public interface IResourceDatabase : IDisposable
|
|||||||
/// </summary>
|
/// </summary>
|
||||||
/// <param name="id">The identifier of the sampler to release. Must reference a valid, existing sampler.</param>
|
/// <param name="id">The identifier of the sampler to release. Must reference a valid, existing sampler.</param>
|
||||||
void ReleaseSampler(Identifier<Sampler> id);
|
void ReleaseSampler(Identifier<Sampler> id);
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Adds a mesh to the resource database and returns its handle.
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="mesh">The mesh data to be added to the database.</param>
|
|
||||||
/// <returns>The <see cref="Handle{Mesh}"/> representing the newly added mesh.</returns>"/>
|
|
||||||
Handle<Mesh> AddMesh(ref readonly Mesh mesh);
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Determines whether a mesh with the specified Handle exists.
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="handle">The handle of the mesh to check for existence. Cannot be null.</param>
|
|
||||||
/// <returns>true if a mesh with the specified Handle exists; otherwise, false.</returns>
|
|
||||||
bool HasMesh(Handle<Mesh> handle);
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Returns a reference to the mesh associated with the specified handle.
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="handle">The handle of the mesh to retrieve. Must refer to a valid mesh; otherwise, the behavior is undefined.</param>
|
|
||||||
/// <returns>A result containing a reference to the mesh corresponding to the specified handle, or an error status if the handle is invalid.</returns>
|
|
||||||
RefResult<Mesh, Error> GetMeshReference(Handle<Mesh> handle);
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Releases the mesh resource associated with the specified handle, freeing any resources held by it. Includes both CPU and GPU resources.
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="handle">The handle of the mesh to release. Must refer to a mesh that was previously created and not already released.</param>
|
|
||||||
void ReleaseMesh(Handle<Mesh> handle);
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Adds a new material to the collection and returns its unique handle.
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="material">The material to add. The material must be fully initialized before calling this method.</param>
|
|
||||||
/// <returns>The <see cref="Handle{Material}"/> representing the newly added material.</returns>
|
|
||||||
Handle<Material> AddMaterial(ref readonly Material material);
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Determines whether a material with the specified handle exists in the collection.
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="handle">The handle of the material to check for existence.</param>
|
|
||||||
/// <returns>true if a material with the specified handle exists; otherwise, false.</returns>
|
|
||||||
bool HasMaterial(Handle<Material> handle);
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Gets a reference to the material associated with the specified handle.
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="handle">The handle of the material to retrieve. Must refer to a valid material.</param>
|
|
||||||
/// <returns>A result containing a reference to the material corresponding to the specified handle, or an error status if the handle is invalid.</returns>
|
|
||||||
RefResult<Material, Error> GetMaterialReference(Handle<Material> handle);
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Releases the material associated with the specified handle, making it available for reuse or disposal.
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="handle">The handle of the material to release. Must refer to a material that has been previously acquired.</param>
|
|
||||||
void ReleaseMaterial(Handle<Material> handle);
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Adds the specified shader to the collection and returns its unique identifier.
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="shader">The shader to add. The shader is passed by read-only reference and will not be modified.</param>
|
|
||||||
/// <returns>The <see cref="Identifier{Shader}"/> representing the newly added shader.</returns>
|
|
||||||
Identifier<Shader> AddShader(Shader shader);
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Determines whether a shader with the specified identifier exists in the collection.
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="id">The identifier of the shader to check for existence.</param>
|
|
||||||
/// <returns>true if a shader with the specified identifier exists; otherwise, false.</returns>
|
|
||||||
bool HasShader(Identifier<Shader> id);
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Returns a reference to the shader associated with the specified identifier.
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="id">The identifier of the shader to retrieve. Must refer to a valid shader.</param>
|
|
||||||
/// <returns>A result containing a reference to the shader corresponding to the specified identifier, or an error status if the identifier is invalid.</returns>
|
|
||||||
RefResult<Shader, Error> GetShaderReference(Identifier<Shader> id);
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Releases the shader associated with the specified identifier, freeing any resources allocated to it.
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="id">The identifier of the shader to release. Must refer to a valid, previously created shader.</param>
|
|
||||||
void ReleaseShader(Identifier<Shader> id);
|
|
||||||
}
|
}
|
||||||
@@ -1,10 +1,9 @@
|
|||||||
using Ghost.Core;
|
using Ghost.Core;
|
||||||
using Ghost.Core.Graphics;
|
using Ghost.Core.Graphics;
|
||||||
using Ghost.Graphics.RHI;
|
|
||||||
using Misaki.HighPerformance.LowLevel.Buffer;
|
using Misaki.HighPerformance.LowLevel.Buffer;
|
||||||
using Misaki.HighPerformance.LowLevel.Collections;
|
using Misaki.HighPerformance.LowLevel.Collections;
|
||||||
|
|
||||||
namespace Ghost.Graphics.Contracts;
|
namespace Ghost.Graphics.RHI;
|
||||||
|
|
||||||
public struct ShaderCompileResult : IDisposable
|
public struct ShaderCompileResult : IDisposable
|
||||||
{
|
{
|
||||||
@@ -1,5 +1,4 @@
|
|||||||
using Ghost.Core;
|
using Ghost.Core;
|
||||||
using Ghost.Graphics.Core;
|
|
||||||
|
|
||||||
namespace Ghost.Graphics.RHI;
|
namespace Ghost.Graphics.RHI;
|
||||||
|
|
||||||
@@ -1,8 +1,7 @@
|
|||||||
using System.Runtime.Intrinsics;
|
using System.Runtime.Intrinsics;
|
||||||
using TerraFX.Interop.Windows;
|
|
||||||
using ElementType = uint;
|
using ElementType = uint;
|
||||||
|
|
||||||
namespace Ghost.Graphics.Core;
|
namespace Ghost.Graphics.RHI;
|
||||||
|
|
||||||
public unsafe struct LocalKeywordSet
|
public unsafe struct LocalKeywordSet
|
||||||
{
|
{
|
||||||
@@ -42,7 +41,7 @@ public unsafe struct LocalKeywordSet
|
|||||||
|
|
||||||
public ulong GetHash64()
|
public ulong GetHash64()
|
||||||
{
|
{
|
||||||
ulong hash = 14695981039346656037ul; // FNV Offset basis
|
var hash = 14695981039346656037ul; // FNV Offset basis
|
||||||
|
|
||||||
for (var i = 0; i < _DATA_ARRAY_LENGTH; i++)
|
for (var i = 0; i < _DATA_ARRAY_LENGTH; i++)
|
||||||
{
|
{
|
||||||
@@ -1,13 +1,12 @@
|
|||||||
using Ghost.Core;
|
using Ghost.Core;
|
||||||
using Ghost.Core.Graphics;
|
using Ghost.Core.Graphics;
|
||||||
using Ghost.Core.Utilities;
|
using Ghost.Core.Utilities;
|
||||||
using Ghost.Graphics.Core;
|
|
||||||
using System.IO.Hashing;
|
using System.IO.Hashing;
|
||||||
using System.Runtime.InteropServices;
|
using System.Runtime.InteropServices;
|
||||||
|
|
||||||
namespace Ghost.Graphics.RHI;
|
namespace Ghost.Graphics.RHI;
|
||||||
|
|
||||||
internal static class RHIUtility
|
public static class RHIUtility
|
||||||
{
|
{
|
||||||
public const int MAX_RENDER_TARGETS = 8;
|
public const int MAX_RENDER_TARGETS = 8;
|
||||||
|
|
||||||
@@ -1,6 +1,6 @@
|
|||||||
using Ghost.Core;
|
using Ghost.Core;
|
||||||
|
|
||||||
namespace Ghost.Graphics.Core;
|
namespace Ghost.Graphics.RHI;
|
||||||
|
|
||||||
public readonly struct GPUResource;
|
public readonly struct GPUResource;
|
||||||
public readonly struct Texture;
|
public readonly struct Texture;
|
||||||
@@ -20,12 +20,12 @@ public static class ResourceHandleExtensions
|
|||||||
return new Handle<GPUResource>(buffer.ID, buffer.Generation);
|
return new Handle<GPUResource>(buffer.ID, buffer.Generation);
|
||||||
}
|
}
|
||||||
|
|
||||||
internal static Handle<Texture> AsTexture(this Handle<GPUResource> resource)
|
public static Handle<Texture> AsTexture(this Handle<GPUResource> resource)
|
||||||
{
|
{
|
||||||
return new Handle<Texture>(resource.ID, resource.Generation);
|
return new Handle<Texture>(resource.ID, resource.Generation);
|
||||||
}
|
}
|
||||||
|
|
||||||
internal static Handle<GraphicsBuffer> AsGraphicsBuffer(this Handle<GPUResource> resource)
|
public static Handle<GraphicsBuffer> AsGraphicsBuffer(this Handle<GPUResource> resource)
|
||||||
{
|
{
|
||||||
return new Handle<GraphicsBuffer>(resource.ID, resource.Generation);
|
return new Handle<GraphicsBuffer>(resource.ID, resource.Generation);
|
||||||
}
|
}
|
||||||
@@ -1,7 +1,7 @@
|
|||||||
using Misaki.HighPerformance.Mathematics;
|
using Misaki.HighPerformance.Mathematics;
|
||||||
using System.Runtime.InteropServices;
|
using System.Runtime.InteropServices;
|
||||||
|
|
||||||
namespace Ghost.Graphics.Core;
|
namespace Ghost.Graphics.RHI;
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// The layout of the root signature is:
|
/// The layout of the root signature is:
|
||||||
@@ -1,18 +1,10 @@
|
|||||||
global using static TerraFX.Interop.DirectX.D3D12;
|
|
||||||
global using static TerraFX.Interop.DirectX.DirectX;
|
|
||||||
global using static TerraFX.Interop.DirectX.DXGI;
|
|
||||||
global using static TerraFX.Interop.Windows.Windows;
|
|
||||||
|
|
||||||
using Ghost.Core.Attributes;
|
using Ghost.Core.Attributes;
|
||||||
using System.Runtime.CompilerServices;
|
using System.Runtime.CompilerServices;
|
||||||
using System.Runtime.Versioning;
|
|
||||||
|
|
||||||
[assembly: InternalsVisibleTo("Ghost.Engine")]
|
[assembly: InternalsVisibleTo("Ghost.Engine")]
|
||||||
[assembly: InternalsVisibleTo("Ghost.Editor")]
|
[assembly: InternalsVisibleTo("Ghost.Editor")]
|
||||||
[assembly: InternalsVisibleTo("Ghost.Editor.Core")]
|
[assembly: InternalsVisibleTo("Ghost.Editor.Core")]
|
||||||
[assembly: InternalsVisibleTo("Ghost.Graphics.Test")]
|
[assembly: InternalsVisibleTo("Ghost.Graphics.Test")]
|
||||||
[assembly: InternalsVisibleTo("Ghost.Graphics.Test-Winui")]
|
[assembly: InternalsVisibleTo("Ghost.Graphics.Test-Winui")]
|
||||||
[assembly: SupportedOSPlatform("windows10.0.19041.0")]
|
|
||||||
|
|
||||||
|
|
||||||
[assembly: EngineAssembly]
|
[assembly: EngineAssembly]
|
||||||
@@ -1,13 +1,11 @@
|
|||||||
using Ghost.Core;
|
using Ghost.Core;
|
||||||
using Ghost.Graphics.Core;
|
|
||||||
using Ghost.Graphics.RenderGraphModule;
|
using Ghost.Graphics.RenderGraphModule;
|
||||||
using Ghost.Graphics.RHI;
|
|
||||||
|
|
||||||
namespace Ghost.Graphics.Contracts;
|
namespace Ghost.Graphics.Core.Contracts;
|
||||||
|
|
||||||
public interface IRenderPass
|
public interface IRenderPass
|
||||||
{
|
{
|
||||||
void Initialize(ref readonly RenderingContext ctx);
|
void Initialize(ref readonly RenderingContext ctx);
|
||||||
void Build(RenderGraph graph, Identifier<RGTexture> backbuffer);
|
void Build(RenderGraph graph, Identifier<RGTexture> backbuffer);
|
||||||
void Cleanup(IResourceDatabase resourceDatabase);
|
void Cleanup(IResourceManager resourceManager);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,5 +1,72 @@
|
|||||||
|
using Ghost.Core;
|
||||||
|
using Ghost.Graphics.RenderGraphModule;
|
||||||
|
using Ghost.Graphics.RHI;
|
||||||
|
|
||||||
namespace Ghost.Graphics.Core;
|
namespace Ghost.Graphics.Core;
|
||||||
|
|
||||||
public class Camera
|
public class Camera
|
||||||
{
|
{
|
||||||
|
private readonly IRenderer _renderer;
|
||||||
|
|
||||||
|
private Handle<Texture> _colorTexture;
|
||||||
|
private Handle<Texture> _depthTexture;
|
||||||
|
|
||||||
|
private uint _actualWidth;
|
||||||
|
private uint _actualHeight;
|
||||||
|
|
||||||
|
private uint _virtualWidth;
|
||||||
|
private uint _virtualHeight;
|
||||||
|
|
||||||
|
public IRenderer Renderer => _renderer;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Gets the actual width of the camera's render target in pixels. If upscaler is used, this is the width before upscaling.
|
||||||
|
/// </summary>
|
||||||
|
public uint ActualWidth => _actualWidth;
|
||||||
|
/// <summary>
|
||||||
|
/// Gets the actual height of the camera's render target in pixels. If upscaler is used, this is the height before upscaling.
|
||||||
|
/// </summary>
|
||||||
|
public uint ActualHeight => _actualHeight;
|
||||||
|
/// <summary>
|
||||||
|
/// Gets the virtual width of the camera's render target in pixels. If upscaler is used, this is the width after upscaling.
|
||||||
|
/// </summary>
|
||||||
|
public uint VirtualWidth => _virtualWidth;
|
||||||
|
/// <summary>
|
||||||
|
/// Gets the virtual height of the camera's render target in pixels. If upscaler is used, this is the height after upscaling.
|
||||||
|
/// </summary>
|
||||||
|
public uint VirtualHeight => _virtualHeight;
|
||||||
|
|
||||||
|
public RenderGraph? RenderGraph
|
||||||
|
{
|
||||||
|
get; set;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Camera(IGraphicsEngine graphicsEngine)
|
||||||
|
{
|
||||||
|
_renderer = graphicsEngine.CreateRenderer();
|
||||||
|
}
|
||||||
|
|
||||||
|
public Camera(IGraphicsEngine graphicsEngine, RenderGraph renderGraph)
|
||||||
|
{
|
||||||
|
_renderer = graphicsEngine.CreateRenderer();
|
||||||
|
RenderGraph = renderGraph;
|
||||||
|
|
||||||
|
_renderer.RenderFunc = DefaultRenderFunc;
|
||||||
|
}
|
||||||
|
|
||||||
|
private Error DefaultRenderFunc(RenderContext context)
|
||||||
|
{
|
||||||
|
if (RenderGraph == null)
|
||||||
|
{
|
||||||
|
return Error.None;
|
||||||
|
}
|
||||||
|
|
||||||
|
RenderGraph.Reset();
|
||||||
|
|
||||||
|
var view = new ViewState(_virtualWidth, _virtualHeight, _actualWidth, _actualHeight);
|
||||||
|
RenderGraph.Compile(in view);
|
||||||
|
RenderGraph.Execute(context.CommandBuffer);
|
||||||
|
|
||||||
|
return Error.None;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
@@ -1,150 +0,0 @@
|
|||||||
using Misaki.HighPerformance.LowLevel.Collections;
|
|
||||||
using Misaki.HighPerformance.Mathematics;
|
|
||||||
using System.Drawing;
|
|
||||||
using System.Runtime.InteropServices;
|
|
||||||
using TerraFX.Interop.DirectX;
|
|
||||||
|
|
||||||
namespace Ghost.Graphics.Core;
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Represents a color with 4 bytes components.
|
|
||||||
/// </summary>
|
|
||||||
[StructLayout(LayoutKind.Sequential, Size = 4)]
|
|
||||||
public struct Color32 : IEquatable<Color32>
|
|
||||||
{
|
|
||||||
public byte r;
|
|
||||||
public byte g;
|
|
||||||
public byte b;
|
|
||||||
public byte a;
|
|
||||||
|
|
||||||
public Color32(byte r, byte g, byte b, byte a)
|
|
||||||
{
|
|
||||||
this.r = r;
|
|
||||||
this.g = g;
|
|
||||||
this.b = b;
|
|
||||||
this.a = a;
|
|
||||||
}
|
|
||||||
|
|
||||||
public Color32(Color color)
|
|
||||||
: this(color.R, color.G, color.B, color.A)
|
|
||||||
{
|
|
||||||
}
|
|
||||||
|
|
||||||
public Color32(Color128 color128)
|
|
||||||
: this((byte)(color128.r * 255.0f), (byte)(color128.g * 255.0f), (byte)(color128.b * 255.0f), (byte)(color128.a * 255.0f))
|
|
||||||
{
|
|
||||||
}
|
|
||||||
|
|
||||||
public Color32(float4 v)
|
|
||||||
: this((byte)(v.x * 255.0f), (byte)(v.y * 255.0f), (byte)(v.z * 255.0f), (byte)(v.w * 255.0f))
|
|
||||||
{
|
|
||||||
}
|
|
||||||
|
|
||||||
public readonly bool Equals(Color32 other)
|
|
||||||
{
|
|
||||||
return r == other.r && g == other.g && b == other.b && a == other.a;
|
|
||||||
}
|
|
||||||
|
|
||||||
public override readonly bool Equals(object? obj)
|
|
||||||
{
|
|
||||||
return obj is Color32 color && Equals(color);
|
|
||||||
}
|
|
||||||
|
|
||||||
public override readonly int GetHashCode()
|
|
||||||
{
|
|
||||||
return HashCode.Combine(r, g, b, a);
|
|
||||||
}
|
|
||||||
|
|
||||||
public static bool operator ==(Color32 left, Color32 right)
|
|
||||||
{
|
|
||||||
return left.Equals(right);
|
|
||||||
}
|
|
||||||
|
|
||||||
public static bool operator !=(Color32 left, Color32 right)
|
|
||||||
{
|
|
||||||
return !(left == right);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Represents a color with 16 bytes components.
|
|
||||||
/// </summary>
|
|
||||||
[StructLayout(LayoutKind.Sequential, Size = 16)]
|
|
||||||
public struct Color128 : IEquatable<Color128>
|
|
||||||
{
|
|
||||||
public float r;
|
|
||||||
public float g;
|
|
||||||
public float b;
|
|
||||||
public float a;
|
|
||||||
|
|
||||||
public Color128(float r, float g, float b, float a)
|
|
||||||
{
|
|
||||||
this.r = r;
|
|
||||||
this.g = g;
|
|
||||||
this.b = b;
|
|
||||||
this.a = a;
|
|
||||||
}
|
|
||||||
|
|
||||||
public Color128(Color color)
|
|
||||||
: this(color.R / 255.0f, color.G / 255.0f, color.B / 255.0f, color.A / 255.0f)
|
|
||||||
{
|
|
||||||
}
|
|
||||||
|
|
||||||
public Color128(Color32 color32)
|
|
||||||
: this(color32.r / 255.0f, color32.g / 255.0f, color32.b / 255.0f, color32.a / 255.0f)
|
|
||||||
{
|
|
||||||
}
|
|
||||||
|
|
||||||
public Color128(float4 v)
|
|
||||||
: this(v.x, v.y, v.z, v.w)
|
|
||||||
{
|
|
||||||
}
|
|
||||||
|
|
||||||
public readonly bool Equals(Color128 other)
|
|
||||||
{
|
|
||||||
return r.Equals(other.r) && g.Equals(other.g) && b.Equals(other.b) && a.Equals(other.a);
|
|
||||||
}
|
|
||||||
|
|
||||||
public override readonly bool Equals(object? obj)
|
|
||||||
{
|
|
||||||
return obj is Color128 color && Equals(color);
|
|
||||||
}
|
|
||||||
|
|
||||||
public readonly override int GetHashCode()
|
|
||||||
{
|
|
||||||
return HashCode.Combine(r, g, b, a);
|
|
||||||
}
|
|
||||||
|
|
||||||
public static bool operator ==(Color128 left, Color128 right)
|
|
||||||
{
|
|
||||||
return left.Equals(right);
|
|
||||||
}
|
|
||||||
|
|
||||||
public static bool operator !=(Color128 left, Color128 right)
|
|
||||||
{
|
|
||||||
return !(left == right);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
[StructLayout(LayoutKind.Sequential)]
|
|
||||||
public struct Vertex
|
|
||||||
{
|
|
||||||
public static class Semantic
|
|
||||||
{
|
|
||||||
public const DXGI_FORMAT ALIGNED_FORMAT = DXGI_FORMAT.DXGI_FORMAT_R32G32B32A32_FLOAT;
|
|
||||||
public const int COUNT = 5;
|
|
||||||
|
|
||||||
public static readonly FixedText32 Position = new("POSITION");
|
|
||||||
public static readonly FixedText32 Normal = new("NORMAL");
|
|
||||||
public static readonly FixedText32 Tangent = new("TANGENT");
|
|
||||||
public static readonly FixedText32 Uv = new("TEXCOORD");
|
|
||||||
public static readonly FixedText32 Color = new("COLOR");
|
|
||||||
}
|
|
||||||
|
|
||||||
public float4 position;
|
|
||||||
public float4 normal;
|
|
||||||
public float4 tangent;
|
|
||||||
public float4 uv;
|
|
||||||
public Color128 color;
|
|
||||||
}
|
|
||||||
@@ -65,17 +65,17 @@ public struct Material : IResourceReleasable
|
|||||||
get; set;
|
get; set;
|
||||||
}
|
}
|
||||||
|
|
||||||
public Error SetShader(Identifier<Shader> shaderId, IResourceAllocator allocator, IResourceDatabase database)
|
public Error SetShader(Identifier<Shader> shaderId, IResourceManager manager)
|
||||||
{
|
{
|
||||||
if (!shaderId.IsValid)
|
if (!shaderId.IsValid)
|
||||||
{
|
{
|
||||||
return Error.InvalidArgument;
|
return Error.InvalidArgument;
|
||||||
}
|
}
|
||||||
|
|
||||||
_cBufferCache.ReleaseResource(database);
|
_cBufferCache.ReleaseResource(manager.ResourceDatabase);
|
||||||
_shader = shaderId;
|
_shader = shaderId;
|
||||||
|
|
||||||
var r = database.GetShaderReference(shaderId);
|
var r = manager.GetShaderReference(shaderId);
|
||||||
if (r.IsFailure)
|
if (r.IsFailure)
|
||||||
{
|
{
|
||||||
return r.Error;
|
return r.Error;
|
||||||
@@ -101,7 +101,7 @@ public struct Material : IResourceReleasable
|
|||||||
_passPipelineOverride[i] = new PipelineOverride
|
_passPipelineOverride[i] = new PipelineOverride
|
||||||
{
|
{
|
||||||
shaderPass = pass.Key,
|
shaderPass = pass.Key,
|
||||||
options = pass.DeafaultState,
|
options = pass.DefaultState,
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -114,7 +114,7 @@ public struct Material : IResourceReleasable
|
|||||||
MemoryType = ResourceMemoryType.Default,
|
MemoryType = ResourceMemoryType.Default,
|
||||||
};
|
};
|
||||||
|
|
||||||
var buffer = allocator.CreateBuffer(ref desc, "MaterialCBuffer");
|
var buffer = manager.ResourceAllocator.CreateBuffer(ref desc, "MaterialCBuffer");
|
||||||
_cBufferCache = new CBufferCache(buffer, shader.CBufferSize);
|
_cBufferCache = new CBufferCache(buffer, shader.CBufferSize);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -201,9 +201,9 @@ public struct Material : IResourceReleasable
|
|||||||
}
|
}
|
||||||
|
|
||||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||||
public Error SetKeyword(IResourceDatabase resourceDatabase, int keywordId, bool enabled)
|
public Error SetKeyword(IResourceManager manager, int keywordId, bool enabled)
|
||||||
{
|
{
|
||||||
var r = resourceDatabase.GetShaderReference(_shader);
|
var r = manager.GetShaderReference(_shader);
|
||||||
if (r.IsFailure)
|
if (r.IsFailure)
|
||||||
{
|
{
|
||||||
return r.Error;
|
return r.Error;
|
||||||
@@ -223,9 +223,9 @@ public struct Material : IResourceReleasable
|
|||||||
}
|
}
|
||||||
|
|
||||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||||
public readonly bool IsKeywordEnabled(IResourceDatabase resourceDatabase, int keywordId)
|
public readonly bool IsKeywordEnabled(IResourceManager manager, int keywordId)
|
||||||
{
|
{
|
||||||
var r = resourceDatabase.GetShaderReference(_shader);
|
var r = manager.GetShaderReference(_shader);
|
||||||
if (r.IsFailure)
|
if (r.IsFailure)
|
||||||
{
|
{
|
||||||
return false;
|
return false;
|
||||||
|
|||||||
@@ -1,5 +1,4 @@
|
|||||||
using Ghost.Core;
|
using Ghost.Core;
|
||||||
using Ghost.Graphics.Contracts;
|
|
||||||
using Ghost.Graphics.RHI;
|
using Ghost.Graphics.RHI;
|
||||||
|
|
||||||
namespace Ghost.Graphics.Core;
|
namespace Ghost.Graphics.Core;
|
||||||
|
|||||||
@@ -1,5 +1,4 @@
|
|||||||
using Ghost.Core;
|
using Ghost.Core;
|
||||||
using Ghost.Graphics.Contracts;
|
|
||||||
using Ghost.Graphics.RHI;
|
using Ghost.Graphics.RHI;
|
||||||
using Misaki.HighPerformance.LowLevel.Buffer;
|
using Misaki.HighPerformance.LowLevel.Buffer;
|
||||||
using Misaki.HighPerformance.LowLevel.Collections;
|
using Misaki.HighPerformance.LowLevel.Collections;
|
||||||
|
|||||||
@@ -7,24 +7,6 @@ using System.Runtime.InteropServices;
|
|||||||
|
|
||||||
namespace Ghost.Graphics.Core;
|
namespace Ghost.Graphics.Core;
|
||||||
|
|
||||||
public readonly struct ShaderPass
|
|
||||||
{
|
|
||||||
public Key64<ShaderPass> Key
|
|
||||||
{
|
|
||||||
get; init;
|
|
||||||
}
|
|
||||||
|
|
||||||
public PipelineState DeafaultState
|
|
||||||
{
|
|
||||||
get; init;
|
|
||||||
}
|
|
||||||
|
|
||||||
public LocalKeywordSet KeywordIDs
|
|
||||||
{
|
|
||||||
get; init;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public struct ShaderProperty;
|
public struct ShaderProperty;
|
||||||
|
|
||||||
public partial struct Shader
|
public partial struct Shader
|
||||||
@@ -146,7 +128,7 @@ public partial struct Shader : IResourceReleasable
|
|||||||
_shaderPasses[i] = new ShaderPass
|
_shaderPasses[i] = new ShaderPass
|
||||||
{
|
{
|
||||||
Key = passKey,
|
Key = passKey,
|
||||||
DeafaultState = pass.localPipeline,
|
DefaultState = pass.localPipeline,
|
||||||
KeywordIDs = keywords,
|
KeywordIDs = keywords,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|||||||
@@ -1,139 +0,0 @@
|
|||||||
using Ghost.Core;
|
|
||||||
using Ghost.Graphics.RHI;
|
|
||||||
using Ghost.Graphics.Core;
|
|
||||||
using Ghost.Graphics.RenderPasses;
|
|
||||||
using Ghost.Graphics.Contracts;
|
|
||||||
using Ghost.Graphics.RenderGraphModule;
|
|
||||||
|
|
||||||
namespace Ghost.Graphics.D3D12;
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// D3D12 implementation of the renderer interface using RHI abstractions
|
|
||||||
/// </summary>
|
|
||||||
internal class D3D12Renderer : IRenderer
|
|
||||||
{
|
|
||||||
private readonly D3D12GraphicsEngine _graphicsEngine;
|
|
||||||
private readonly D3D12ResourceDatabase _resourceDatabase;
|
|
||||||
|
|
||||||
private readonly ICommandBuffer _commandBuffer;
|
|
||||||
private readonly RenderGraph _renderGraph;
|
|
||||||
|
|
||||||
private uint _frameIndex;
|
|
||||||
private bool _disposed;
|
|
||||||
|
|
||||||
// NOTE: Testing only.
|
|
||||||
private readonly MeshRenderPass _pass;
|
|
||||||
|
|
||||||
public IRenderOutput? RenderOutput
|
|
||||||
{
|
|
||||||
get; set;
|
|
||||||
}
|
|
||||||
|
|
||||||
// TODO: Add render graph support
|
|
||||||
|
|
||||||
public D3D12Renderer(D3D12GraphicsEngine graphicsEngine, D3D12ResourceDatabase resourceDatabase)
|
|
||||||
{
|
|
||||||
_graphicsEngine = graphicsEngine;
|
|
||||||
_resourceDatabase = resourceDatabase;
|
|
||||||
|
|
||||||
_commandBuffer = _graphicsEngine.CreateCommandBuffer(CommandBufferType.Graphics);
|
|
||||||
_renderGraph = new RenderGraph(_graphicsEngine);
|
|
||||||
|
|
||||||
// NOTE: Testing only.
|
|
||||||
_pass = new();
|
|
||||||
}
|
|
||||||
|
|
||||||
~D3D12Renderer()
|
|
||||||
{
|
|
||||||
Dispose();
|
|
||||||
}
|
|
||||||
|
|
||||||
public Result Render(ICommandAllocator commandAllocator)
|
|
||||||
{
|
|
||||||
if (RenderOutput is null)
|
|
||||||
{
|
|
||||||
return Result.Failure("Render target strategy is not set.");
|
|
||||||
}
|
|
||||||
|
|
||||||
var target = RenderOutput.GetRenderTarget();
|
|
||||||
if (target.IsInvalid)
|
|
||||||
{
|
|
||||||
return Result.Failure("Render target is invalid.");
|
|
||||||
}
|
|
||||||
|
|
||||||
_commandBuffer.Begin(commandAllocator);
|
|
||||||
RenderOutput.BeginRender(_commandBuffer);
|
|
||||||
|
|
||||||
// NOTE: Temporary solution: render directly to the swap chain back buffer if available.
|
|
||||||
// HACK: This is hard coded for testing purposes only.
|
|
||||||
|
|
||||||
var error = RenderScene(target, RenderOutput.Viewport, RenderOutput.Scissor);
|
|
||||||
if (error != Error.None)
|
|
||||||
{
|
|
||||||
_commandBuffer.End();
|
|
||||||
return Result.Failure(error);
|
|
||||||
}
|
|
||||||
|
|
||||||
RenderOutput.EndRender(_commandBuffer);
|
|
||||||
var r = _commandBuffer.End();
|
|
||||||
if (r.IsFailure)
|
|
||||||
{
|
|
||||||
return r;
|
|
||||||
}
|
|
||||||
|
|
||||||
_graphicsEngine.Device.GraphicsQueue.Submit(_commandBuffer);
|
|
||||||
RenderOutput.Present();
|
|
||||||
|
|
||||||
return Result.Success();
|
|
||||||
}
|
|
||||||
|
|
||||||
// TODO: A proper render graph integration.
|
|
||||||
private Error RenderScene(Handle<Texture> target, ViewportDesc viewport, RectDesc rect)
|
|
||||||
{
|
|
||||||
// NOTE: Testing only.
|
|
||||||
var ctx = new RenderingContext(_graphicsEngine, _commandBuffer);
|
|
||||||
if (_frameIndex == 0)
|
|
||||||
{
|
|
||||||
_pass.Initialize(ref ctx);
|
|
||||||
}
|
|
||||||
|
|
||||||
//_commandBuffer.BeginRenderPass(rtDesc, depthDesc, false);
|
|
||||||
_commandBuffer.SetViewport(viewport);
|
|
||||||
_commandBuffer.SetScissorRect(rect);
|
|
||||||
|
|
||||||
_renderGraph.Reset();
|
|
||||||
|
|
||||||
var backBuffer = _renderGraph.ImportTexture(target, "Back Buffer");
|
|
||||||
_pass.Build(_renderGraph, backBuffer);
|
|
||||||
|
|
||||||
// Create view state from viewport
|
|
||||||
var viewState = new ViewState((uint)viewport.Width, (uint)viewport.Height);
|
|
||||||
|
|
||||||
// Compile with view state
|
|
||||||
_renderGraph.Compile(in viewState);
|
|
||||||
_renderGraph.Execute(_commandBuffer);
|
|
||||||
|
|
||||||
//_commandBuffer.EndRenderPass();
|
|
||||||
_frameIndex++;
|
|
||||||
|
|
||||||
return Error.None;
|
|
||||||
}
|
|
||||||
|
|
||||||
public void Dispose()
|
|
||||||
{
|
|
||||||
if (_disposed)
|
|
||||||
{
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
// NOTE: Testing only.
|
|
||||||
_pass.Cleanup(_resourceDatabase);
|
|
||||||
_renderGraph.Dispose();
|
|
||||||
|
|
||||||
_commandBuffer.Dispose();
|
|
||||||
|
|
||||||
_disposed = true;
|
|
||||||
|
|
||||||
GC.SuppressFinalize(this);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,24 +0,0 @@
|
|||||||
using System.Runtime.CompilerServices;
|
|
||||||
using TerraFX.Interop.DirectX;
|
|
||||||
using Ghost.Graphics.Core;
|
|
||||||
|
|
||||||
namespace Ghost.Graphics.D3D12.Utilities;
|
|
||||||
|
|
||||||
internal unsafe static class D3D12PipelineResource
|
|
||||||
{
|
|
||||||
private readonly static D3D12_INPUT_ELEMENT_DESC[] s_inputElementDescs = [
|
|
||||||
new D3D12_INPUT_ELEMENT_DESC{ SemanticName = (sbyte*)Vertex.Semantic.Position.GetUnsafePtr(), SemanticIndex = 0u, Format = Vertex.Semantic.ALIGNED_FORMAT, InputSlot = 0u, AlignedByteOffset = 0u, InputSlotClass = D3D12_INPUT_CLASSIFICATION.D3D12_INPUT_CLASSIFICATION_PER_VERTEX_DATA, InstanceDataStepRate = 0 },
|
|
||||||
new D3D12_INPUT_ELEMENT_DESC{ SemanticName = (sbyte*)Vertex.Semantic.Normal.GetUnsafePtr(), SemanticIndex = 0u, Format = Vertex.Semantic.ALIGNED_FORMAT, InputSlot = 0u, AlignedByteOffset = 16u, InputSlotClass = D3D12_INPUT_CLASSIFICATION.D3D12_INPUT_CLASSIFICATION_PER_VERTEX_DATA, InstanceDataStepRate = 0 },
|
|
||||||
new D3D12_INPUT_ELEMENT_DESC{ SemanticName = (sbyte*)Vertex.Semantic.Tangent.GetUnsafePtr(), SemanticIndex = 0u, Format = Vertex.Semantic.ALIGNED_FORMAT, InputSlot = 0u, AlignedByteOffset = 32u, InputSlotClass = D3D12_INPUT_CLASSIFICATION.D3D12_INPUT_CLASSIFICATION_PER_VERTEX_DATA, InstanceDataStepRate = 0 },
|
|
||||||
new D3D12_INPUT_ELEMENT_DESC{ SemanticName = (sbyte*)Vertex.Semantic.Uv.GetUnsafePtr(), SemanticIndex = 0u, Format = Vertex.Semantic.ALIGNED_FORMAT, InputSlot = 0u, AlignedByteOffset = 48u, InputSlotClass = D3D12_INPUT_CLASSIFICATION.D3D12_INPUT_CLASSIFICATION_PER_VERTEX_DATA, InstanceDataStepRate = 0 },
|
|
||||||
new D3D12_INPUT_ELEMENT_DESC{ SemanticName = (sbyte*)Vertex.Semantic.Color.GetUnsafePtr(), SemanticIndex = 0u, Format = Vertex.Semantic.ALIGNED_FORMAT, InputSlot = 0u, AlignedByteOffset = 64u, InputSlotClass = D3D12_INPUT_CLASSIFICATION.D3D12_INPUT_CLASSIFICATION_PER_VERTEX_DATA, InstanceDataStepRate = 0 },
|
|
||||||
];
|
|
||||||
|
|
||||||
public const DXGI_FORMAT SWAP_CHAIN_BACK_BUFFER_FORMAT = DXGI_FORMAT.DXGI_FORMAT_B8G8R8A8_UNORM;
|
|
||||||
|
|
||||||
public static D3D12_INPUT_LAYOUT_DESC InputLayoutDescription => new()
|
|
||||||
{
|
|
||||||
pInputElementDescs = (D3D12_INPUT_ELEMENT_DESC*)Unsafe.AsPointer(ref s_inputElementDescs[0]),
|
|
||||||
NumElements = (uint)s_inputElementDescs.Length
|
|
||||||
};
|
|
||||||
}
|
|
||||||
@@ -9,6 +9,7 @@
|
|||||||
|
|
||||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|AnyCPU'">
|
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|AnyCPU'">
|
||||||
<DebugType>embedded</DebugType>
|
<DebugType>embedded</DebugType>
|
||||||
|
<IsAotCompatible>True</IsAotCompatible>
|
||||||
</PropertyGroup>
|
</PropertyGroup>
|
||||||
|
|
||||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|AnyCPU'">
|
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|AnyCPU'">
|
||||||
@@ -16,27 +17,19 @@
|
|||||||
<IsTrimmable>True</IsTrimmable>
|
<IsTrimmable>True</IsTrimmable>
|
||||||
</PropertyGroup>
|
</PropertyGroup>
|
||||||
|
|
||||||
<ItemGroup>
|
|
||||||
<Content Include="runtimes\win-x64\native\dxcompiler.dll">
|
|
||||||
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
|
|
||||||
</Content>
|
|
||||||
<Content Include="runtimes\win-x64\native\dxil.dll">
|
|
||||||
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
|
|
||||||
</Content>
|
|
||||||
</ItemGroup>
|
|
||||||
|
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<PackageReference Include="Misaki.HighPerformance.Analyzer" Version="1.0.0">
|
<PackageReference Include="Misaki.HighPerformance.Analyzer" Version="1.0.0">
|
||||||
<PrivateAssets>all</PrivateAssets>
|
<PrivateAssets>all</PrivateAssets>
|
||||||
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
|
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
|
||||||
</PackageReference>
|
</PackageReference>
|
||||||
<PackageReference Include="Misaki.HighPerformance.Image" Version="1.1.0" />
|
<PackageReference Include="Misaki.HighPerformance.Image" Version="1.1.0" />
|
||||||
<PackageReference Include="TerraFX.Interop.D3D12MemoryAllocator" Version="3.0.1" />
|
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
|
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<ProjectReference Include="../../Runtime/Ghost.Core/Ghost.Core.csproj" />
|
<ProjectReference Include="..\..\Runtime\Ghost.Core\Ghost.Core.csproj" />
|
||||||
<ProjectReference Include="../../Editor/Ghost.DSL/Ghost.DSL.csproj" />
|
<ProjectReference Include="..\..\Editor\Ghost.DSL\Ghost.DSL.csproj" />
|
||||||
|
<ProjectReference Include="..\Ghost.Graphics.D3D12\Ghost.Graphics.D3D12.csproj" />
|
||||||
|
<ProjectReference Include="..\Ghost.Graphics.RHI\Ghost.Graphics.RHI.csproj" />
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
|
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
|
|||||||
@@ -1,5 +1,4 @@
|
|||||||
using Ghost.Core;
|
using Ghost.Core;
|
||||||
using Ghost.Graphics.Core;
|
|
||||||
using Ghost.Graphics.RHI;
|
using Ghost.Graphics.RHI;
|
||||||
|
|
||||||
namespace Ghost.Graphics.RenderGraphModule;
|
namespace Ghost.Graphics.RenderGraphModule;
|
||||||
@@ -10,7 +9,7 @@ namespace Ghost.Graphics.RenderGraphModule;
|
|||||||
/// </summary>
|
/// </summary>
|
||||||
public sealed class RenderGraph : IDisposable
|
public sealed class RenderGraph : IDisposable
|
||||||
{
|
{
|
||||||
private readonly IGraphicsEngine _graphicsEngine;
|
private readonly IResourceManager _resourceManager;
|
||||||
|
|
||||||
private readonly RenderGraphObjectPool _objectPool;
|
private readonly RenderGraphObjectPool _objectPool;
|
||||||
private readonly RenderGraphResourceRegistry _resources;
|
private readonly RenderGraphResourceRegistry _resources;
|
||||||
@@ -31,16 +30,15 @@ public sealed class RenderGraph : IDisposable
|
|||||||
private readonly RenderGraphExecutor _executor;
|
private readonly RenderGraphExecutor _executor;
|
||||||
private readonly RenderGraphNativePassBuilder _nativePassBuilder;
|
private readonly RenderGraphNativePassBuilder _nativePassBuilder;
|
||||||
|
|
||||||
|
private readonly RenderGraphBlackboard _blackboard;
|
||||||
|
|
||||||
private bool _compiled;
|
private bool _compiled;
|
||||||
|
|
||||||
public RenderGraphBlackboard Blackboard
|
public RenderGraphBlackboard Blackboard => _blackboard;
|
||||||
{
|
|
||||||
get;
|
|
||||||
}
|
|
||||||
|
|
||||||
public RenderGraph(IGraphicsEngine graphicsEngine)
|
public RenderGraph(IResourceManager resourceManager, IPipelineLibrary pipelineLibrary, IShaderCompiler shaderCompiler)
|
||||||
{
|
{
|
||||||
_graphicsEngine = graphicsEngine;
|
_resourceManager = resourceManager;
|
||||||
|
|
||||||
_objectPool = new RenderGraphObjectPool();
|
_objectPool = new RenderGraphObjectPool();
|
||||||
_resources = new RenderGraphResourceRegistry(_objectPool);
|
_resources = new RenderGraphResourceRegistry(_objectPool);
|
||||||
@@ -50,40 +48,32 @@ public sealed class RenderGraph : IDisposable
|
|||||||
_nativePasses = new List<NativeRenderPass>(32);
|
_nativePasses = new List<NativeRenderPass>(32);
|
||||||
|
|
||||||
_builder = new RenderGraphBuilder();
|
_builder = new RenderGraphBuilder();
|
||||||
_aliasingManager = new ResourceAliasingManager(graphicsEngine.ResourceAllocator, _objectPool);
|
_aliasingManager = new ResourceAliasingManager(resourceManager.ResourceAllocator, _objectPool);
|
||||||
|
|
||||||
_compilationCache = new RenderGraphCompilationCache();
|
_compilationCache = new RenderGraphCompilationCache();
|
||||||
|
|
||||||
_context = new RenderGraphContext(
|
_context = new RenderGraphContext(
|
||||||
_graphicsEngine.ResourceDatabase,
|
resourceManager,
|
||||||
_graphicsEngine.PipelineLibrary,
|
pipelineLibrary,
|
||||||
_graphicsEngine.ShaderCompiler,
|
shaderCompiler,
|
||||||
_resources
|
_resources
|
||||||
);
|
);
|
||||||
|
|
||||||
_nativePassBuilder = new RenderGraphNativePassBuilder(_objectPool, _resources);
|
_nativePassBuilder = new RenderGraphNativePassBuilder(_objectPool, _resources);
|
||||||
_compiler = new RenderGraphCompiler(_graphicsEngine, _resources, _aliasingManager, _nativePassBuilder, _compilationCache);
|
_compiler = new RenderGraphCompiler(resourceManager, _resources, _aliasingManager, _nativePassBuilder, _compilationCache);
|
||||||
_executor = new RenderGraphExecutor(_graphicsEngine, _resources, _context);
|
_executor = new RenderGraphExecutor(resourceManager, _resources, _context);
|
||||||
|
|
||||||
Blackboard = new RenderGraphBlackboard();
|
_blackboard = new RenderGraphBlackboard();
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Resets the render graph for a new frame.
|
/// Resets the render graph for a new frame.
|
||||||
/// Reuses existing allocations to minimize GC.
|
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public void Reset()
|
public void Reset()
|
||||||
{
|
{
|
||||||
// Clear blackboard data
|
_blackboard.Clear();
|
||||||
Blackboard.Clear();
|
_resources.Clear();
|
||||||
|
_aliasingManager.Clear();
|
||||||
// Reset resources but keep allocations
|
|
||||||
_resources.Reset();
|
|
||||||
|
|
||||||
// Reset aliasing manager
|
|
||||||
_aliasingManager.Reset();
|
|
||||||
|
|
||||||
// Clear compiled barriers
|
|
||||||
_compiledBarriers.Clear();
|
_compiledBarriers.Clear();
|
||||||
|
|
||||||
// Return passes to the pool and reset count
|
// Return passes to the pool and reset count
|
||||||
@@ -94,11 +84,8 @@ public sealed class RenderGraph : IDisposable
|
|||||||
}
|
}
|
||||||
|
|
||||||
_passes.Clear();
|
_passes.Clear();
|
||||||
|
|
||||||
// Clear compiled passes list
|
|
||||||
_compiledPasses.Clear();
|
_compiledPasses.Clear();
|
||||||
|
|
||||||
// Return native passes to pool
|
|
||||||
for (var i = 0; i < _nativePasses.Count; i++)
|
for (var i = 0; i < _nativePasses.Count; i++)
|
||||||
{
|
{
|
||||||
_objectPool.Return(_nativePasses[i]);
|
_objectPool.Return(_nativePasses[i]);
|
||||||
@@ -117,14 +104,14 @@ public sealed class RenderGraph : IDisposable
|
|||||||
Color128 clearColor = default, float clearDepth = 1.0f, byte clearStencil = 0,
|
Color128 clearColor = default, float clearDepth = 1.0f, byte clearStencil = 0,
|
||||||
bool clearAtFirstUse = true, bool discardAtLastUse = true)
|
bool clearAtFirstUse = true, bool discardAtLastUse = true)
|
||||||
{
|
{
|
||||||
var r = _graphicsEngine.ResourceDatabase.GetResourceDescription(texture.AsResource());
|
var r = _resourceManager.ResourceDatabase.GetResourceDescription(texture.AsResource());
|
||||||
if (r.IsFailure)
|
if (r.IsFailure)
|
||||||
{
|
{
|
||||||
return Identifier<RGTexture>.Invalid;
|
return Identifier<RGTexture>.Invalid;
|
||||||
}
|
}
|
||||||
|
|
||||||
var desc = r.Value;
|
var desc = r.Value;
|
||||||
return _resources.ImportTexture(in desc._desc.textureDescription, texture, name, clearColor, clearDepth, clearStencil, clearAtFirstUse, discardAtLastUse);
|
return _resources.ImportTexture(in desc.TextureDescription, texture, name, clearColor, clearDepth, clearStencil, clearAtFirstUse, discardAtLastUse);
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
@@ -134,14 +121,14 @@ public sealed class RenderGraph : IDisposable
|
|||||||
/// <returns>The identifier of the imported render graph buffer. Invalid if import fails.</returns>
|
/// <returns>The identifier of the imported render graph buffer. Invalid if import fails.</returns>
|
||||||
public Identifier<RGBuffer> ImportBuffer(Handle<GraphicsBuffer> buffer, string name)
|
public Identifier<RGBuffer> ImportBuffer(Handle<GraphicsBuffer> buffer, string name)
|
||||||
{
|
{
|
||||||
var r = _graphicsEngine.ResourceDatabase.GetResourceDescription(buffer.AsResource());
|
var r = _resourceManager.ResourceDatabase.GetResourceDescription(buffer.AsResource());
|
||||||
if (r.IsFailure)
|
if (r.IsFailure)
|
||||||
{
|
{
|
||||||
return Identifier<RGBuffer>.Invalid;
|
return Identifier<RGBuffer>.Invalid;
|
||||||
}
|
}
|
||||||
|
|
||||||
var desc = r.Value;
|
var desc = r.Value;
|
||||||
return _resources.ImportBuffer(in desc._desc.bufferDescription, buffer, name);
|
return _resources.ImportBuffer(in desc.BufferDescription, buffer, name);
|
||||||
}
|
}
|
||||||
|
|
||||||
public IRasterRenderGraphBuilder AddRasterRenderPass<TPassData>(string name, out TPassData passData)
|
public IRasterRenderGraphBuilder AddRasterRenderPass<TPassData>(string name, out TPassData passData)
|
||||||
|
|||||||
@@ -326,7 +326,7 @@ internal sealed class ResourceAliasingManager
|
|||||||
_logicalToPlaced = new Dictionary<int, int>(64);
|
_logicalToPlaced = new Dictionary<int, int>(64);
|
||||||
}
|
}
|
||||||
|
|
||||||
public void Reset()
|
public void Clear()
|
||||||
{
|
{
|
||||||
for (var i = 0; i < _placedResources.Count; i++)
|
for (var i = 0; i < _placedResources.Count; i++)
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -74,7 +74,7 @@ internal sealed class ResourceStateTracker
|
|||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Represents a compiled barrier with only the target state.
|
/// Represents a compiled barrier with only the target state.
|
||||||
/// The before state is always queried from ResourceDatabase at execution time.
|
/// The before state is always queried from ResourceManager at execution time.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
internal struct CompiledBarrier
|
internal struct CompiledBarrier
|
||||||
{
|
{
|
||||||
@@ -208,7 +208,7 @@ internal static class RenderGraphBarriers
|
|||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Compiles implicit state transitions for all resources accessed by a pass.
|
/// Compiles implicit state transitions for all resources accessed by a pass.
|
||||||
/// Stores only the target state - the before state will be queried from ResourceDatabase at execution time.
|
/// Stores only the target state - the before state will be queried from ResourceManager at execution time.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
private static void CompileImplicitTransitions(
|
private static void CompileImplicitTransitions(
|
||||||
RenderGraphPassBase pass,
|
RenderGraphPassBase pass,
|
||||||
|
|||||||
@@ -1,5 +1,4 @@
|
|||||||
using Ghost.Core;
|
using Ghost.Core;
|
||||||
using Ghost.Graphics.Core;
|
|
||||||
using Ghost.Graphics.RHI;
|
using Ghost.Graphics.RHI;
|
||||||
using System.Diagnostics.CodeAnalysis;
|
using System.Diagnostics.CodeAnalysis;
|
||||||
|
|
||||||
@@ -23,7 +22,7 @@ internal sealed class CachedCompilation
|
|||||||
// Placed resource metadata
|
// Placed resource metadata
|
||||||
public readonly List<PlacedResourceData> placedResources = new(32);
|
public readonly List<PlacedResourceData> placedResources = new(32);
|
||||||
|
|
||||||
// Compiled barriers (stores only target states, queries before state from ResourceDatabase)
|
// Compiled barriers (stores only target states, queries before state from ResourceManager)
|
||||||
public readonly List<CompiledBarrier> compiledBarriers = new(128);
|
public readonly List<CompiledBarrier> compiledBarriers = new(128);
|
||||||
|
|
||||||
// Real gpu resource
|
// Real gpu resource
|
||||||
|
|||||||
@@ -1,5 +1,4 @@
|
|||||||
using Ghost.Core;
|
using Ghost.Core;
|
||||||
using Ghost.Graphics.Core;
|
|
||||||
using Ghost.Graphics.RHI;
|
using Ghost.Graphics.RHI;
|
||||||
|
|
||||||
namespace Ghost.Graphics.RenderGraphModule;
|
namespace Ghost.Graphics.RenderGraphModule;
|
||||||
@@ -10,7 +9,7 @@ namespace Ghost.Graphics.RenderGraphModule;
|
|||||||
/// </summary>
|
/// </summary>
|
||||||
internal sealed class RenderGraphCompiler
|
internal sealed class RenderGraphCompiler
|
||||||
{
|
{
|
||||||
private readonly IGraphicsEngine _graphicsEngine;
|
private readonly IResourceManager _resourceManager;
|
||||||
private readonly RenderGraphResourceRegistry _resources;
|
private readonly RenderGraphResourceRegistry _resources;
|
||||||
private readonly ResourceAliasingManager _aliasingManager;
|
private readonly ResourceAliasingManager _aliasingManager;
|
||||||
private readonly RenderGraphNativePassBuilder _nativePassBuilder;
|
private readonly RenderGraphNativePassBuilder _nativePassBuilder;
|
||||||
@@ -19,13 +18,13 @@ internal sealed class RenderGraphCompiler
|
|||||||
private Handle<GPUResource> _resourceHeap;
|
private Handle<GPUResource> _resourceHeap;
|
||||||
|
|
||||||
public RenderGraphCompiler(
|
public RenderGraphCompiler(
|
||||||
IGraphicsEngine graphicsEngine,
|
IResourceManager resourceManager,
|
||||||
RenderGraphResourceRegistry resources,
|
RenderGraphResourceRegistry resources,
|
||||||
ResourceAliasingManager aliasingManager,
|
ResourceAliasingManager aliasingManager,
|
||||||
RenderGraphNativePassBuilder nativePassBuilder,
|
RenderGraphNativePassBuilder nativePassBuilder,
|
||||||
RenderGraphCompilationCache compilationCache)
|
RenderGraphCompilationCache compilationCache)
|
||||||
{
|
{
|
||||||
_graphicsEngine = graphicsEngine;
|
_resourceManager = resourceManager;
|
||||||
_resources = resources;
|
_resources = resources;
|
||||||
_aliasingManager = aliasingManager;
|
_aliasingManager = aliasingManager;
|
||||||
_nativePassBuilder = nativePassBuilder;
|
_nativePassBuilder = nativePassBuilder;
|
||||||
@@ -212,10 +211,10 @@ internal sealed class RenderGraphCompiler
|
|||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
_graphicsEngine.ResourceDatabase.ScheduleReleaseResource(res.backingResource);
|
_resourceManager.ResourceDatabase.ScheduleReleaseResource(res.backingResource);
|
||||||
}
|
}
|
||||||
|
|
||||||
_graphicsEngine.ResourceDatabase.ScheduleReleaseResource(_resourceHeap);
|
_resourceManager.ResourceDatabase.ScheduleReleaseResource(_resourceHeap);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (_aliasingManager.Heap.size == 0)
|
if (_aliasingManager.Heap.size == 0)
|
||||||
@@ -231,7 +230,7 @@ internal sealed class RenderGraphCompiler
|
|||||||
HeapType = HeapType.Default
|
HeapType = HeapType.Default
|
||||||
};
|
};
|
||||||
|
|
||||||
_resourceHeap = _graphicsEngine.ResourceAllocator.Allocate(in allocationDesc, "RenderGraphResourceHeap");
|
_resourceHeap = _resourceManager.ResourceAllocator.Allocate(in allocationDesc, "RenderGraphResourceHeap");
|
||||||
|
|
||||||
for (var i = 0; i < _resources.Resources.Count; i++)
|
for (var i = 0; i < _resources.Resources.Count; i++)
|
||||||
{
|
{
|
||||||
@@ -253,11 +252,11 @@ internal sealed class RenderGraphCompiler
|
|||||||
if (res.type == RenderGraphResourceType.Texture)
|
if (res.type == RenderGraphResourceType.Texture)
|
||||||
{
|
{
|
||||||
var textureDesc = res.rgTextureDesc.ToTextureDesc(res.resolvedWidth, res.resolvedHeight);
|
var textureDesc = res.rgTextureDesc.ToTextureDesc(res.resolvedWidth, res.resolvedHeight);
|
||||||
res.backingResource = _graphicsEngine.ResourceAllocator.CreateTexture(in textureDesc, res.name, ops).AsResource();
|
res.backingResource = _resourceManager.ResourceAllocator.CreateTexture(in textureDesc, res.name, ops).AsResource();
|
||||||
}
|
}
|
||||||
else if (res.type == RenderGraphResourceType.Buffer)
|
else if (res.type == RenderGraphResourceType.Buffer)
|
||||||
{
|
{
|
||||||
res.backingResource = _graphicsEngine.ResourceAllocator.CreateBuffer(in res.bufferDesc, res.name, ops).AsResource();
|
res.backingResource = _resourceManager.ResourceAllocator.CreateBuffer(in res.bufferDesc, res.name, ops).AsResource();
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
@@ -380,11 +379,11 @@ internal sealed class RenderGraphCompiler
|
|||||||
{
|
{
|
||||||
if (!res.isImported)
|
if (!res.isImported)
|
||||||
{
|
{
|
||||||
_graphicsEngine.ResourceDatabase.ScheduleReleaseResource(res.backingResource);
|
_resourceManager.ResourceDatabase.ScheduleReleaseResource(res.backingResource);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
_graphicsEngine.ResourceDatabase.ScheduleReleaseResource(_resourceHeap);
|
_resourceManager.ResourceDatabase.ScheduleReleaseResource(_resourceHeap);
|
||||||
_resourceHeap = Handle<GPUResource>.Invalid;
|
_resourceHeap = Handle<GPUResource>.Invalid;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,5 +1,4 @@
|
|||||||
using Ghost.Core;
|
using Ghost.Core;
|
||||||
using Ghost.Graphics.Contracts;
|
|
||||||
using Ghost.Graphics.Core;
|
using Ghost.Graphics.Core;
|
||||||
using Ghost.Graphics.RHI;
|
using Ghost.Graphics.RHI;
|
||||||
using Misaki.HighPerformance.Mathematics;
|
using Misaki.HighPerformance.Mathematics;
|
||||||
@@ -8,7 +7,7 @@ namespace Ghost.Graphics.RenderGraphModule;
|
|||||||
|
|
||||||
public interface IRenderGraphContext
|
public interface IRenderGraphContext
|
||||||
{
|
{
|
||||||
IResourceDatabase ResourceDatabase { get; }
|
IResourceManager ResourceManager { get; }
|
||||||
|
|
||||||
Handle<GPUResource> GetActualResource(Identifier<RGResource> resource);
|
Handle<GPUResource> GetActualResource(Identifier<RGResource> resource);
|
||||||
Handle<Texture> GetActualTexture(Identifier<RGTexture> texture);
|
Handle<Texture> GetActualTexture(Identifier<RGTexture> texture);
|
||||||
@@ -38,7 +37,7 @@ public interface IUnsafeRenderContext : IRasterRenderContext, IRenderGraphContex
|
|||||||
|
|
||||||
internal sealed class RenderGraphContext : IRasterRenderContext, IComputeRenderContext, IUnsafeRenderContext
|
internal sealed class RenderGraphContext : IRasterRenderContext, IComputeRenderContext, IUnsafeRenderContext
|
||||||
{
|
{
|
||||||
private readonly IResourceDatabase _resourceDatabase;
|
private readonly IResourceManager _resourceManager;
|
||||||
private readonly IPipelineLibrary _pipelineLibrary;
|
private readonly IPipelineLibrary _pipelineLibrary;
|
||||||
private readonly IShaderCompiler _shaderCompiler;
|
private readonly IShaderCompiler _shaderCompiler;
|
||||||
private readonly RenderGraphResourceRegistry _resources;
|
private readonly RenderGraphResourceRegistry _resources;
|
||||||
@@ -53,15 +52,15 @@ internal sealed class RenderGraphContext : IRasterRenderContext, IComputeRenderC
|
|||||||
private Handle<GraphicsBuffer> _activePerMeshData;
|
private Handle<GraphicsBuffer> _activePerMeshData;
|
||||||
private int _activeMeshIndexCount;
|
private int _activeMeshIndexCount;
|
||||||
|
|
||||||
public IResourceDatabase ResourceDatabase => _resourceDatabase;
|
public IResourceManager ResourceManager => _resourceManager;
|
||||||
|
|
||||||
public int ActiveMeshIndexCount => _activeMeshIndexCount;
|
public int ActiveMeshIndexCount => _activeMeshIndexCount;
|
||||||
|
|
||||||
public ICommandBuffer CommandBuffer => _commandBuffer;
|
public ICommandBuffer CommandBuffer => _commandBuffer;
|
||||||
|
|
||||||
internal RenderGraphContext(IResourceDatabase resourceDatabase, IPipelineLibrary pipelineLibrary, IShaderCompiler shaderCompiler, RenderGraphResourceRegistry resources)
|
internal RenderGraphContext(IResourceManager resourceManager, IPipelineLibrary pipelineLibrary, IShaderCompiler shaderCompiler, RenderGraphResourceRegistry resources)
|
||||||
{
|
{
|
||||||
_resourceDatabase = resourceDatabase;
|
_resourceManager = resourceManager;
|
||||||
_pipelineLibrary = pipelineLibrary;
|
_pipelineLibrary = pipelineLibrary;
|
||||||
_shaderCompiler = shaderCompiler;
|
_shaderCompiler = shaderCompiler;
|
||||||
_resources = resources;
|
_resources = resources;
|
||||||
@@ -103,7 +102,7 @@ internal sealed class RenderGraphContext : IRasterRenderContext, IComputeRenderC
|
|||||||
|
|
||||||
public void SetActiveMaterial(Handle<Material> material)
|
public void SetActiveMaterial(Handle<Material> material)
|
||||||
{
|
{
|
||||||
var r = _resourceDatabase.GetMaterialReference(material);
|
var r = _resourceManager.GetMaterialReference(material);
|
||||||
if (r.IsFailure)
|
if (r.IsFailure)
|
||||||
{
|
{
|
||||||
_activePerMaterialData = Handle<GraphicsBuffer>.Invalid;
|
_activePerMaterialData = Handle<GraphicsBuffer>.Invalid;
|
||||||
@@ -116,7 +115,7 @@ internal sealed class RenderGraphContext : IRasterRenderContext, IComputeRenderC
|
|||||||
|
|
||||||
public void SetActiveMaterial(ref readonly Material material)
|
public void SetActiveMaterial(ref readonly Material material)
|
||||||
{
|
{
|
||||||
var shaderResult = _resourceDatabase.GetShaderReference(material.Shader);
|
var shaderResult = _resourceManager.GetShaderReference(material.Shader);
|
||||||
if (shaderResult.IsFailure)
|
if (shaderResult.IsFailure)
|
||||||
{
|
{
|
||||||
_activePerMaterialData = Handle<GraphicsBuffer>.Invalid;
|
_activePerMaterialData = Handle<GraphicsBuffer>.Invalid;
|
||||||
@@ -161,7 +160,7 @@ internal sealed class RenderGraphContext : IRasterRenderContext, IComputeRenderC
|
|||||||
|
|
||||||
public void SetActiveMesh(Handle<Mesh> mesh)
|
public void SetActiveMesh(Handle<Mesh> mesh)
|
||||||
{
|
{
|
||||||
var r = _resourceDatabase.GetMeshReference(mesh);
|
var r = _resourceManager.GetMeshReference(mesh);
|
||||||
if (r.IsFailure)
|
if (r.IsFailure)
|
||||||
{
|
{
|
||||||
_activePerMeshData = Handle<GraphicsBuffer>.Invalid;
|
_activePerMeshData = Handle<GraphicsBuffer>.Invalid;
|
||||||
@@ -184,8 +183,8 @@ internal sealed class RenderGraphContext : IRasterRenderContext, IComputeRenderC
|
|||||||
// TODO: Global and view constants
|
// TODO: Global and view constants
|
||||||
var data = new PushConstantsData
|
var data = new PushConstantsData
|
||||||
{
|
{
|
||||||
objectIndex = _resourceDatabase.GetBindlessIndex(_activePerMeshData.AsResource()),
|
objectIndex = _resourceManager.ResourceDatabase.GetBindlessIndex(_activePerMeshData.AsResource()),
|
||||||
materialIndex = _resourceDatabase.GetBindlessIndex(_activePerMaterialData.AsResource()),
|
materialIndex = _resourceManager.ResourceDatabase.GetBindlessIndex(_activePerMaterialData.AsResource()),
|
||||||
};
|
};
|
||||||
|
|
||||||
var pushConstantSpan = new ReadOnlySpan<uint>(&data, sizeof(PushConstantsData) / sizeof(uint));
|
var pushConstantSpan = new ReadOnlySpan<uint>(&data, sizeof(PushConstantsData) / sizeof(uint));
|
||||||
|
|||||||
@@ -1,5 +1,4 @@
|
|||||||
using Ghost.Core;
|
using Ghost.Core;
|
||||||
using Ghost.Graphics.Core;
|
|
||||||
using Ghost.Graphics.RHI;
|
using Ghost.Graphics.RHI;
|
||||||
|
|
||||||
namespace Ghost.Graphics.RenderGraphModule;
|
namespace Ghost.Graphics.RenderGraphModule;
|
||||||
@@ -9,16 +8,16 @@ namespace Ghost.Graphics.RenderGraphModule;
|
|||||||
/// </summary>
|
/// </summary>
|
||||||
internal sealed class RenderGraphExecutor
|
internal sealed class RenderGraphExecutor
|
||||||
{
|
{
|
||||||
private readonly IGraphicsEngine _graphicsEngine;
|
private readonly IResourceManager _resourceManager;
|
||||||
private readonly RenderGraphResourceRegistry _resources;
|
private readonly RenderGraphResourceRegistry _resources;
|
||||||
private readonly RenderGraphContext _context;
|
private readonly RenderGraphContext _context;
|
||||||
|
|
||||||
public RenderGraphExecutor(
|
public RenderGraphExecutor(
|
||||||
IGraphicsEngine graphicsEngine,
|
IResourceManager resourceManager,
|
||||||
RenderGraphResourceRegistry resources,
|
RenderGraphResourceRegistry resources,
|
||||||
RenderGraphContext context)
|
RenderGraphContext context)
|
||||||
{
|
{
|
||||||
_graphicsEngine = graphicsEngine;
|
_resourceManager = resourceManager;
|
||||||
_resources = resources;
|
_resources = resources;
|
||||||
_context = context;
|
_context = context;
|
||||||
}
|
}
|
||||||
@@ -130,7 +129,7 @@ internal sealed class RenderGraphExecutor
|
|||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Executes all barriers for a specific pass.
|
/// Executes all barriers for a specific pass.
|
||||||
/// Uses pre-compiled barriers and queries before state from ResourceDatabase.
|
/// Uses pre-compiled barriers and queries before state from ResourceManager.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
private unsafe void ExecuteBarriersForPass(
|
private unsafe void ExecuteBarriersForPass(
|
||||||
ICommandBuffer cmd,
|
ICommandBuffer cmd,
|
||||||
@@ -158,8 +157,8 @@ internal sealed class RenderGraphExecutor
|
|||||||
var resource = _resources.GetResource(compiledBarrier.Resource);
|
var resource = _resources.GetResource(compiledBarrier.Resource);
|
||||||
var resourceHandle = resource.backingResource;
|
var resourceHandle = resource.backingResource;
|
||||||
|
|
||||||
// Always query the before state from ResourceDatabase (single source of truth)
|
// Always query the before state from ResourceManager (single source of truth)
|
||||||
var currentState = _graphicsEngine.ResourceDatabase.GetResourceBarrierData(resourceHandle).GetValueOrThrow();
|
var currentState = _resourceManager.ResourceDatabase.GetResourceBarrierData(resourceHandle).GetValueOrThrow();
|
||||||
|
|
||||||
BarrierLayout layoutBefore;
|
BarrierLayout layoutBefore;
|
||||||
BarrierAccess accessBefore;
|
BarrierAccess accessBefore;
|
||||||
@@ -169,7 +168,7 @@ internal sealed class RenderGraphExecutor
|
|||||||
if (compiledBarrier.AliasingPredecessor.IsValid)
|
if (compiledBarrier.AliasingPredecessor.IsValid)
|
||||||
{
|
{
|
||||||
var predHandle = _resources.GetResource(compiledBarrier.AliasingPredecessor).backingResource;
|
var predHandle = _resources.GetResource(compiledBarrier.AliasingPredecessor).backingResource;
|
||||||
var predState = _graphicsEngine.ResourceDatabase.GetResourceBarrierData(predHandle).GetValueOrThrow();
|
var predState = _resourceManager.ResourceDatabase.GetResourceBarrierData(predHandle).GetValueOrThrow();
|
||||||
|
|
||||||
layoutBefore = BarrierLayout.Undefined;
|
layoutBefore = BarrierLayout.Undefined;
|
||||||
accessBefore = BarrierAccess.NoAccess;
|
accessBefore = BarrierAccess.NoAccess;
|
||||||
|
|||||||
@@ -168,7 +168,7 @@ internal sealed class RenderGraphResourceRegistry
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public void Reset()
|
public void Clear()
|
||||||
{
|
{
|
||||||
// Return all resources to pool
|
// Return all resources to pool
|
||||||
for (var i = 0; i < _resources.Count; i++)
|
for (var i = 0; i < _resources.Count; i++)
|
||||||
|
|||||||
@@ -37,15 +37,22 @@ public struct ViewState : IEquatable<ViewState>
|
|||||||
public uint viewportWidth;
|
public uint viewportWidth;
|
||||||
public uint viewportHeight;
|
public uint viewportHeight;
|
||||||
|
|
||||||
public ViewState(uint width, uint height)
|
// For upscalers that need to know the original render target size before upscaling
|
||||||
|
public uint actualWidth;
|
||||||
|
public uint actualHeight;
|
||||||
|
|
||||||
|
public ViewState(uint width, uint height, uint actualWidth, uint actualHeight)
|
||||||
{
|
{
|
||||||
viewportWidth = width;
|
viewportWidth = width;
|
||||||
viewportHeight = height;
|
viewportHeight = height;
|
||||||
|
this.actualWidth = actualWidth;
|
||||||
|
this.actualHeight = actualHeight;
|
||||||
}
|
}
|
||||||
|
|
||||||
public readonly bool Equals(ViewState other)
|
public readonly bool Equals(ViewState other)
|
||||||
{
|
{
|
||||||
return viewportWidth == other.viewportWidth && viewportHeight == other.viewportHeight;
|
return viewportWidth == other.viewportWidth && viewportHeight == other.viewportHeight
|
||||||
|
&& actualWidth == other.actualWidth && actualHeight == other.actualHeight;
|
||||||
}
|
}
|
||||||
|
|
||||||
public override readonly bool Equals(object? obj)
|
public override readonly bool Equals(object? obj)
|
||||||
|
|||||||
@@ -1,8 +1,8 @@
|
|||||||
using Ghost.Core;
|
using Ghost.Core;
|
||||||
using Ghost.Core.Graphics;
|
using Ghost.Core.Graphics;
|
||||||
using Ghost.DSL.ShaderCompiler;
|
using Ghost.DSL.ShaderCompiler;
|
||||||
using Ghost.Graphics.Contracts;
|
|
||||||
using Ghost.Graphics.Core;
|
using Ghost.Graphics.Core;
|
||||||
|
using Ghost.Graphics.Core.Contracts;
|
||||||
using Ghost.Graphics.RenderGraphModule;
|
using Ghost.Graphics.RenderGraphModule;
|
||||||
using Ghost.Graphics.RHI;
|
using Ghost.Graphics.RHI;
|
||||||
using Ghost.Graphics.Utilities;
|
using Ghost.Graphics.Utilities;
|
||||||
@@ -159,7 +159,7 @@ internal class MeshRenderPass : IRenderPass
|
|||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
var shaderResult = ctx.ResourceDatabase.GetShaderReference(_shader);
|
var shaderResult = ctx.ResourceManager.GetShaderReference(_shader);
|
||||||
if (shaderResult.IsFailure)
|
if (shaderResult.IsFailure)
|
||||||
{
|
{
|
||||||
throw new InvalidOperationException("Failed to get shader reference.");
|
throw new InvalidOperationException("Failed to get shader reference.");
|
||||||
@@ -201,7 +201,6 @@ internal class MeshRenderPass : IRenderPass
|
|||||||
{
|
{
|
||||||
using var stream = File.OpenRead(_textureFiles[i]);
|
using var stream = File.OpenRead(_textureFiles[i]);
|
||||||
using var imageData = ImageResult.FromStream(stream, ColorComponents.RGBA);
|
using var imageData = ImageResult.FromStream(stream, ColorComponents.RGBA);
|
||||||
|
|
||||||
var desc = new TextureDesc
|
var desc = new TextureDesc
|
||||||
{
|
{
|
||||||
Width = imageData.Width,
|
Width = imageData.Width,
|
||||||
@@ -227,7 +226,7 @@ internal class MeshRenderPass : IRenderPass
|
|||||||
|
|
||||||
_sampler = ctx.ResourceAllocator.CreateSampler(in samplerDesc);
|
_sampler = ctx.ResourceAllocator.CreateSampler(in samplerDesc);
|
||||||
|
|
||||||
var meshResult = ctx.ResourceDatabase.GetMaterialReference(_material);
|
var meshResult = ctx.ResourceManager.GetMaterialReference(_material);
|
||||||
if (meshResult.IsFailure)
|
if (meshResult.IsFailure)
|
||||||
{
|
{
|
||||||
throw new InvalidOperationException("Failed to get material reference.");
|
throw new InvalidOperationException("Failed to get material reference.");
|
||||||
@@ -283,7 +282,7 @@ internal class MeshRenderPass : IRenderPass
|
|||||||
|
|
||||||
builder.SetRenderFunc<BlitPassData>(static (data, ctx) =>
|
builder.SetRenderFunc<BlitPassData>(static (data, ctx) =>
|
||||||
{
|
{
|
||||||
var r = ctx.ResourceDatabase.GetMaterialReference(data.blitMaterial);
|
var r = ctx.ResourceManager.GetMaterialReference(data.blitMaterial);
|
||||||
if (r.IsFailure)
|
if (r.IsFailure)
|
||||||
{
|
{
|
||||||
return;
|
return;
|
||||||
@@ -292,12 +291,12 @@ internal class MeshRenderPass : IRenderPass
|
|||||||
ref var matRef = ref r.Value;
|
ref var matRef = ref r.Value;
|
||||||
var blitProps = new ShaderProperties_Hidden_Blit
|
var blitProps = new ShaderProperties_Hidden_Blit
|
||||||
{
|
{
|
||||||
mainTex = ctx.ResourceDatabase.GetBindlessIndex(ctx.GetActualResource(data.source.AsResource())),
|
mainTex = ctx.ResourceManager.ResourceDatabase.GetBindlessIndex(ctx.GetActualResource(data.source.AsResource())),
|
||||||
sampler_mainTex = (uint)data.sampler.Value,
|
sampler_mainTex = (uint)data.sampler.Value,
|
||||||
};
|
};
|
||||||
|
|
||||||
matRef.SetPropertyCache(in blitProps).ThrowIfFailed();
|
matRef.SetPropertyCache(in blitProps).ThrowIfFailed();
|
||||||
matRef.UploadData(ctx.CommandBuffer, ctx.ResourceDatabase);
|
matRef.UploadData(ctx.CommandBuffer, ctx.ResourceManager.ResourceDatabase);
|
||||||
|
|
||||||
ctx.CommandBuffer.SetRenderTargets([ctx.GetActualTexture(data.destination)], Handle<Texture>.Invalid);
|
ctx.CommandBuffer.SetRenderTargets([ctx.GetActualTexture(data.destination)], Handle<Texture>.Invalid);
|
||||||
|
|
||||||
@@ -308,20 +307,20 @@ internal class MeshRenderPass : IRenderPass
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public void Cleanup(IResourceDatabase resourceDatabase)
|
public void Cleanup(IResourceManager resourceManager)
|
||||||
{
|
{
|
||||||
resourceDatabase.ReleaseMaterial(_blitMaterial);
|
resourceManager.ReleaseMaterial(_blitMaterial);
|
||||||
|
|
||||||
resourceDatabase.ReleaseMaterial(_material);
|
resourceManager.ReleaseMaterial(_material);
|
||||||
resourceDatabase.ReleaseShader(_shader);
|
resourceManager.ReleaseShader(_shader);
|
||||||
resourceDatabase.ReleaseMesh(_mesh);
|
resourceManager.ReleaseMesh(_mesh);
|
||||||
resourceDatabase.ReleaseSampler(_sampler);
|
resourceManager.ResourceDatabase.ReleaseSampler(_sampler);
|
||||||
|
|
||||||
if (_textures != null)
|
if (_textures != null)
|
||||||
{
|
{
|
||||||
foreach (var texture in _textures)
|
foreach (var texture in _textures)
|
||||||
{
|
{
|
||||||
resourceDatabase.ScheduleReleaseResource(texture.AsResource());
|
resourceManager.ResourceDatabase.ScheduleReleaseResource(texture.AsResource());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,4 +1,5 @@
|
|||||||
using Ghost.Core;
|
using Ghost.Core;
|
||||||
|
using Ghost.Graphics.D3D12;
|
||||||
using Ghost.Graphics.RHI;
|
using Ghost.Graphics.RHI;
|
||||||
using Misaki.HighPerformance.Mathematics;
|
using Misaki.HighPerformance.Mathematics;
|
||||||
using System.Collections.Concurrent;
|
using System.Collections.Concurrent;
|
||||||
@@ -23,50 +24,6 @@ public struct RenderingConfig
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public interface IFenceSynchronizer
|
|
||||||
{
|
|
||||||
uint CPUFenceValue
|
|
||||||
{
|
|
||||||
get;
|
|
||||||
}
|
|
||||||
|
|
||||||
uint GPUFenceValue
|
|
||||||
{
|
|
||||||
get;
|
|
||||||
}
|
|
||||||
|
|
||||||
uint FrameIndex
|
|
||||||
{
|
|
||||||
get;
|
|
||||||
}
|
|
||||||
|
|
||||||
uint MaxFrameLatency
|
|
||||||
{
|
|
||||||
get;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool WaitForGPUReady(int timeOut = -1);
|
|
||||||
void SignalCPUReady();
|
|
||||||
void WaitIdle();
|
|
||||||
}
|
|
||||||
|
|
||||||
public interface IRenderSystem : IFenceSynchronizer, IDisposable
|
|
||||||
{
|
|
||||||
IGraphicsEngine GraphicsEngine
|
|
||||||
{
|
|
||||||
get;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool IsRunning
|
|
||||||
{
|
|
||||||
get;
|
|
||||||
}
|
|
||||||
|
|
||||||
void Start();
|
|
||||||
void Stop();
|
|
||||||
void RequestSwapChainResize(ISwapChain swapChain, uint2 newSize);
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Application-level render system that orchestrates multiple renderers
|
/// Application-level render system that orchestrates multiple renderers
|
||||||
/// and handles frame synchronization
|
/// and handles frame synchronization
|
||||||
@@ -130,11 +87,25 @@ internal class RenderSystem : IRenderSystem
|
|||||||
public RenderSystem(RenderingConfig config)
|
public RenderSystem(RenderingConfig config)
|
||||||
{
|
{
|
||||||
_config = config;
|
_config = config;
|
||||||
_graphicsEngine = config.GraphicsAPI switch
|
|
||||||
|
switch (config.GraphicsAPI)
|
||||||
{
|
{
|
||||||
GraphicsAPI.Direct3D12 => new D3D12.D3D12GraphicsEngine(this),
|
case GraphicsAPI.Direct3D12:
|
||||||
_ => throw new NotSupportedException($"Graphics API {config.GraphicsAPI} is not supported.")
|
if (OperatingSystem.IsWindowsVersionAtLeast(10, 0, 19041))
|
||||||
};
|
{
|
||||||
|
_graphicsEngine = D3D12GraphicsEngineFactory.Create(this);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
// TODO: Fallback to Vulkan once it's implemented.
|
||||||
|
throw new PlatformNotSupportedException("Direct3D12 requires Windows 10 version 2004 (build 19041) or later.");
|
||||||
|
}
|
||||||
|
|
||||||
|
break;
|
||||||
|
|
||||||
|
default:
|
||||||
|
throw new NotSupportedException($"The specified graphics API '{config.GraphicsAPI}' is not supported.");
|
||||||
|
}
|
||||||
|
|
||||||
// Create frame resources for synchronization
|
// Create frame resources for synchronization
|
||||||
_frameResources = new FrameResource[config.FrameBufferCount];
|
_frameResources = new FrameResource[config.FrameBufferCount];
|
||||||
|
|||||||
330
src/Runtime/Ghost.Graphics/ResourceManager.cs
Normal file
330
src/Runtime/Ghost.Graphics/ResourceManager.cs
Normal file
@@ -0,0 +1,330 @@
|
|||||||
|
using Ghost.Core;
|
||||||
|
using Ghost.Core.Graphics;
|
||||||
|
using Ghost.Graphics.Core;
|
||||||
|
using Ghost.Graphics.RHI;
|
||||||
|
using Misaki.HighPerformance.LowLevel.Buffer;
|
||||||
|
using Misaki.HighPerformance.LowLevel.Collections;
|
||||||
|
|
||||||
|
namespace Ghost.Graphics;
|
||||||
|
|
||||||
|
public interface IResourceManager
|
||||||
|
{
|
||||||
|
IResourceAllocator ResourceAllocator
|
||||||
|
{
|
||||||
|
get;
|
||||||
|
}
|
||||||
|
|
||||||
|
IResourceDatabase ResourceDatabase
|
||||||
|
{
|
||||||
|
get;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Creates a new mesh from the specified vertex and index data.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="vertices">A UnsafeList containing the vertices that define the geometry of the mesh. Must contain at least one vertex.</param>
|
||||||
|
/// <param name="indices">A UnsafeList containing the indices that specify how vertices are connected to form primitives. Must contain at least one index.</param>
|
||||||
|
/// <returns>An <see cref="Identifier{Mesh}"/> representing the newly created mesh.</returns>
|
||||||
|
Handle<Mesh> CreateMesh(UnsafeList<Vertex> vertices, UnsafeList<uint> indices);
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Creates a new material instance using the specified shader.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="shader">The identifier of the shader to associate with the new material.</param>
|
||||||
|
/// <returns>An <see cref="Identifier{Material}"/> representing the newly created material.</returns>
|
||||||
|
Handle<Material> CreateMaterial(Identifier<Shader> shader);
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Creates a new shader and returns its unique identifier.
|
||||||
|
/// </summary>
|
||||||
|
/// <returns>An <see cref="Identifier{Shader}"/> representing the newly created shader.</returns>
|
||||||
|
/// <param name="descriptor">The viewGroup containing the shader's properties and passes.</param>
|
||||||
|
Identifier<Shader> CreateGraphicsShader(ShaderDescriptor descriptor);
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Determines whether a mesh with the specified Handle exists.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="handle">The handle of the mesh to check for existence. Cannot be null.</param>
|
||||||
|
/// <returns>true if a mesh with the specified Handle exists; otherwise, false.</returns>
|
||||||
|
bool HasMesh(Handle<Mesh> handle);
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Returns a reference to the mesh associated with the specified handle.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="handle">The handle of the mesh to retrieve. Must refer to a valid mesh; otherwise, the behavior is undefined.</param>
|
||||||
|
/// <returns>A result containing a reference to the mesh corresponding to the specified handle, or an error status if the handle is invalid.</returns>
|
||||||
|
RefResult<Mesh, Error> GetMeshReference(Handle<Mesh> handle);
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Releases the mesh resource associated with the specified handle, freeing any resources held by it. Includes both CPU and GPU resources.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="handle">The handle of the mesh to release. Must refer to a mesh that was previously created and not already released.</param>
|
||||||
|
void ReleaseMesh(Handle<Mesh> handle);
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Determines whether a material with the specified handle exists in the collection.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="handle">The handle of the material to check for existence.</param>
|
||||||
|
/// <returns>true if a material with the specified handle exists; otherwise, false.</returns>
|
||||||
|
bool HasMaterial(Handle<Material> handle);
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Gets a reference to the material associated with the specified handle.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="handle">The handle of the material to retrieve. Must refer to a valid material.</param>
|
||||||
|
/// <returns>A result containing a reference to the material corresponding to the specified handle, or an error status if the handle is invalid.</returns>
|
||||||
|
RefResult<Material, Error> GetMaterialReference(Handle<Material> handle);
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Releases the material associated with the specified handle, making it available for reuse or disposal.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="handle">The handle of the material to release. Must refer to a material that has been previously acquired.</param>
|
||||||
|
void ReleaseMaterial(Handle<Material> handle);
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Determines whether a shader with the specified identifier exists in the collection.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="id">The identifier of the shader to check for existence.</param>
|
||||||
|
/// <returns>true if a shader with the specified identifier exists; otherwise, false.</returns>
|
||||||
|
bool HasShader(Identifier<Shader> id);
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Returns a reference to the shader associated with the specified identifier.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="id">The identifier of the shader to retrieve. Must refer to a valid shader.</param>
|
||||||
|
/// <returns>A result containing a reference to the shader corresponding to the specified identifier, or an error status if the identifier is invalid.</returns>
|
||||||
|
RefResult<Shader, Error> GetShaderReference(Identifier<Shader> id);
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Releases the shader associated with the specified identifier, freeing any resources allocated to it.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="id">The identifier of the shader to release. Must refer to a valid, previously created shader.</param>
|
||||||
|
void ReleaseShader(Identifier<Shader> id);
|
||||||
|
}
|
||||||
|
|
||||||
|
internal sealed class ResourceManager : IResourceManager, IDisposable
|
||||||
|
{
|
||||||
|
private readonly IResourceAllocator _resourceAllocator;
|
||||||
|
private readonly IResourceDatabase _resourceDatabase;
|
||||||
|
|
||||||
|
private UnsafeSlotMap<Mesh> _meshes;
|
||||||
|
private UnsafeSlotMap<Material> _materials;
|
||||||
|
private UnsafeList<Shader> _shaders; // TODO: Use SlotMap?
|
||||||
|
|
||||||
|
private bool _disposed;
|
||||||
|
|
||||||
|
public IResourceAllocator ResourceAllocator => _resourceAllocator;
|
||||||
|
public IResourceDatabase ResourceDatabase => _resourceDatabase;
|
||||||
|
|
||||||
|
public ResourceManager(IResourceAllocator resourceAllocator, IResourceDatabase resourceDatabase)
|
||||||
|
{
|
||||||
|
_resourceAllocator = resourceAllocator;
|
||||||
|
_resourceDatabase = resourceDatabase;
|
||||||
|
|
||||||
|
_meshes = new UnsafeSlotMap<Mesh>(64, Allocator.Persistent);
|
||||||
|
_materials = new UnsafeSlotMap<Material>(16, Allocator.Persistent);
|
||||||
|
_shaders = new UnsafeList<Shader>(16, Allocator.Persistent);
|
||||||
|
}
|
||||||
|
|
||||||
|
~ResourceManager()
|
||||||
|
{
|
||||||
|
Dispose();
|
||||||
|
}
|
||||||
|
|
||||||
|
public unsafe Handle<Mesh> CreateMesh(UnsafeList<Vertex> vertices, UnsafeList<uint> indices)
|
||||||
|
{
|
||||||
|
ObjectDisposedException.ThrowIf(_disposed, this);
|
||||||
|
|
||||||
|
var vertexBufferDesc = new BufferDesc
|
||||||
|
{
|
||||||
|
Size = (uint)(vertices.Count * sizeof(Vertex)),
|
||||||
|
Stride = (uint)sizeof(Vertex),
|
||||||
|
Usage = BufferUsage.Vertex | BufferUsage.ShaderResource | BufferUsage.Raw,
|
||||||
|
MemoryType = ResourceMemoryType.Default,
|
||||||
|
};
|
||||||
|
|
||||||
|
var indexBufferDesc = new BufferDesc
|
||||||
|
{
|
||||||
|
Size = (uint)(indices.Count * sizeof(uint)),
|
||||||
|
Stride = sizeof(uint),
|
||||||
|
Usage = BufferUsage.Index | BufferUsage.ShaderResource | BufferUsage.Raw,
|
||||||
|
MemoryType = ResourceMemoryType.Default,
|
||||||
|
};
|
||||||
|
|
||||||
|
var objectBufferDesc = new BufferDesc
|
||||||
|
{
|
||||||
|
Size = (uint)sizeof(PerObjectData),
|
||||||
|
Stride = (uint)sizeof(PerObjectData),
|
||||||
|
Usage = BufferUsage.Raw | BufferUsage.ShaderResource,
|
||||||
|
MemoryType = ResourceMemoryType.Default,
|
||||||
|
};
|
||||||
|
|
||||||
|
var vertexBuffer = _resourceAllocator.CreateBuffer(in vertexBufferDesc, "VertexBuffer");
|
||||||
|
var indexBuffer = _resourceAllocator.CreateBuffer(in indexBufferDesc, "IndexBuffer");
|
||||||
|
var objectBuffer = _resourceAllocator.CreateBuffer(in objectBufferDesc, "ObjectBuffer");
|
||||||
|
|
||||||
|
var mesh = new Mesh
|
||||||
|
{
|
||||||
|
Vertices = vertices,
|
||||||
|
Indices = indices,
|
||||||
|
VertexBuffer = vertexBuffer,
|
||||||
|
IndexBuffer = indexBuffer,
|
||||||
|
ObjectDataBuffer = objectBuffer,
|
||||||
|
};
|
||||||
|
|
||||||
|
var id = _meshes.Add(mesh, out var generation);
|
||||||
|
return new Handle<Mesh>(id, generation);
|
||||||
|
}
|
||||||
|
|
||||||
|
public Handle<Material> CreateMaterial(Identifier<Shader> shader)
|
||||||
|
{
|
||||||
|
ObjectDisposedException.ThrowIf(_disposed, this);
|
||||||
|
|
||||||
|
var material = new Material();
|
||||||
|
if (material.SetShader(shader, this) != Error.None)
|
||||||
|
{
|
||||||
|
return Handle<Material>.Invalid;
|
||||||
|
}
|
||||||
|
|
||||||
|
var id = _materials.Add(material, out var generation);
|
||||||
|
return new Handle<Material>(id, generation);
|
||||||
|
}
|
||||||
|
|
||||||
|
public Identifier<Shader> CreateGraphicsShader(ShaderDescriptor descriptor)
|
||||||
|
{
|
||||||
|
ObjectDisposedException.ThrowIf(_disposed, this);
|
||||||
|
|
||||||
|
var shader = new Shader(descriptor);
|
||||||
|
|
||||||
|
var id = _shaders.Count;
|
||||||
|
_shaders.Add(shader);
|
||||||
|
return new Identifier<Shader>(id);
|
||||||
|
}
|
||||||
|
|
||||||
|
public bool HasMesh(Handle<Mesh> handle)
|
||||||
|
{
|
||||||
|
ObjectDisposedException.ThrowIf(_disposed, this);
|
||||||
|
return _meshes.Contains(handle.ID, handle.Generation);
|
||||||
|
}
|
||||||
|
|
||||||
|
public RefResult<Mesh, Error> GetMeshReference(Handle<Mesh> handle)
|
||||||
|
{
|
||||||
|
ref var mesh = ref _meshes.GetElementReferenceAt(handle.ID, handle.Generation, out var exist);
|
||||||
|
if (!exist)
|
||||||
|
{
|
||||||
|
return Error.NotFound;
|
||||||
|
}
|
||||||
|
|
||||||
|
return RefResult<Mesh, Error>.Success(ref mesh);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void ReleaseMesh(Handle<Mesh> handle)
|
||||||
|
{
|
||||||
|
ObjectDisposedException.ThrowIf(_disposed, this);
|
||||||
|
|
||||||
|
ref var mesh = ref _meshes.GetElementReferenceAt(handle.ID, handle.Generation, out var exist);
|
||||||
|
if (!exist)
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
ReleaseResource(mesh);
|
||||||
|
_meshes.Remove(handle.ID, handle.Generation);
|
||||||
|
}
|
||||||
|
|
||||||
|
public bool HasMaterial(Handle<Material> handle)
|
||||||
|
{
|
||||||
|
ObjectDisposedException.ThrowIf(_disposed, this);
|
||||||
|
return _materials.Contains(handle.ID, handle.Generation);
|
||||||
|
}
|
||||||
|
|
||||||
|
public RefResult<Material, Error> GetMaterialReference(Handle<Material> handle)
|
||||||
|
{
|
||||||
|
ref var material = ref _materials.GetElementReferenceAt(handle.ID, handle.Generation, out var exist);
|
||||||
|
if (!exist)
|
||||||
|
{
|
||||||
|
return Error.NotFound;
|
||||||
|
}
|
||||||
|
|
||||||
|
return RefResult<Material, Error>.Success(ref material);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void ReleaseMaterial(Handle<Material> handle)
|
||||||
|
{
|
||||||
|
ObjectDisposedException.ThrowIf(_disposed, this);
|
||||||
|
|
||||||
|
ref var material = ref _materials.GetElementReferenceAt(handle.ID, handle.Generation, out var exist);
|
||||||
|
if (!exist)
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
ReleaseResource(material);
|
||||||
|
_materials.Remove(handle.ID, handle.Generation);
|
||||||
|
}
|
||||||
|
|
||||||
|
public bool HasShader(Identifier<Shader> id)
|
||||||
|
{
|
||||||
|
ObjectDisposedException.ThrowIf(_disposed, this);
|
||||||
|
return id.Value >= 0 && id.Value < _shaders.Count;
|
||||||
|
}
|
||||||
|
|
||||||
|
public RefResult<Shader, Error> GetShaderReference(Identifier<Shader> id)
|
||||||
|
{
|
||||||
|
if (!HasShader(id))
|
||||||
|
{
|
||||||
|
return Error.NotFound;
|
||||||
|
}
|
||||||
|
|
||||||
|
return RefResult<Shader, Error>.Success(ref _shaders[id.Value]);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void ReleaseShader(Identifier<Shader> id)
|
||||||
|
{
|
||||||
|
ObjectDisposedException.ThrowIf(_disposed, this);
|
||||||
|
|
||||||
|
if (!HasShader(id))
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
ref var shader = ref _shaders[id.Value]!;
|
||||||
|
ReleaseResource(shader);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void ReleaseResource<T>(T resource)
|
||||||
|
where T : IResourceReleasable
|
||||||
|
{
|
||||||
|
resource.ReleaseResource(_resourceDatabase);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void Dispose()
|
||||||
|
{
|
||||||
|
if (_disposed)
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
foreach (var mesh in _meshes)
|
||||||
|
{
|
||||||
|
ReleaseResource(mesh);
|
||||||
|
}
|
||||||
|
|
||||||
|
foreach (var material in _materials)
|
||||||
|
{
|
||||||
|
ReleaseResource(material);
|
||||||
|
}
|
||||||
|
|
||||||
|
foreach (var shader in _shaders)
|
||||||
|
{
|
||||||
|
ReleaseResource(shader);
|
||||||
|
}
|
||||||
|
|
||||||
|
_meshes.Dispose();
|
||||||
|
_materials.Dispose();
|
||||||
|
_shaders.Dispose();
|
||||||
|
|
||||||
|
_disposed = true;
|
||||||
|
GC.SuppressFinalize(this);
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -1,11 +1,11 @@
|
|||||||
|
using Ghost.Graphics.RHI;
|
||||||
using Misaki.HighPerformance.LowLevel.Buffer;
|
using Misaki.HighPerformance.LowLevel.Buffer;
|
||||||
using Misaki.HighPerformance.LowLevel.Collections;
|
using Misaki.HighPerformance.LowLevel.Collections;
|
||||||
using Misaki.HighPerformance.Mathematics;
|
using Misaki.HighPerformance.Mathematics;
|
||||||
using Ghost.Graphics.Core;
|
|
||||||
|
|
||||||
namespace Ghost.Graphics.Utilities;
|
namespace Ghost.Graphics.Utilities;
|
||||||
|
|
||||||
public unsafe static class MeshBuilder
|
public static unsafe class MeshBuilder
|
||||||
{
|
{
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Creates a unit cube centered at the origin with size 1.
|
/// Creates a unit cube centered at the origin with size 1.
|
||||||
|
|||||||
Binary file not shown.
Binary file not shown.
@@ -32,13 +32,22 @@ public partial class UnitTestApp : Application
|
|||||||
OperatingSystem.IsMacOS() ? "osx" : "unknown";
|
OperatingSystem.IsMacOS() ? "osx" : "unknown";
|
||||||
var arch = Environment.Is64BitProcess ? "x64" : "x86";
|
var arch = Environment.Is64BitProcess ? "x64" : "x86";
|
||||||
var nativeDllDir = Path.Combine(currentDir, "runtimes", platform + "-" + arch, "native");
|
var nativeDllDir = Path.Combine(currentDir, "runtimes", platform + "-" + arch, "native");
|
||||||
if (Directory.Exists(nativeDllDir))
|
//if (Directory.Exists(nativeDllDir))
|
||||||
|
//{
|
||||||
|
// foreach (var dll in Directory.EnumerateFiles(nativeDllDir, "*.dll"))
|
||||||
|
// {
|
||||||
|
// NativeLibrary.Load(dll);
|
||||||
|
// }
|
||||||
|
//}
|
||||||
|
NativeLibrary.SetDllImportResolver(typeof(UnitTestApp).Assembly, (libraryName, assembly, searchPath) =>
|
||||||
{
|
{
|
||||||
foreach (var dll in Directory.EnumerateFiles(nativeDllDir, "*.dll"))
|
if (libraryName == "dxcompiler")
|
||||||
{
|
{
|
||||||
NativeLibrary.Load(dll);
|
NativeLibrary.Load(Path.Combine(nativeDllDir, "dxil.dll"));
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
return IntPtr.Zero;
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
|
|||||||
@@ -6,6 +6,7 @@
|
|||||||
<ImplicitUsings>enable</ImplicitUsings>
|
<ImplicitUsings>enable</ImplicitUsings>
|
||||||
<Nullable>enable</Nullable>
|
<Nullable>enable</Nullable>
|
||||||
<AllowUnsafeBlocks>true</AllowUnsafeBlocks>
|
<AllowUnsafeBlocks>true</AllowUnsafeBlocks>
|
||||||
|
<PublishAot>True</PublishAot>
|
||||||
</PropertyGroup>
|
</PropertyGroup>
|
||||||
|
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
|
|||||||
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Reference in New Issue
Block a user