首页 > 基础资料 博客日记
Zenith.NET v0.0.7:Metal 后端落地,.NET GPU 抽象的跨平台旅程
2026-04-01 12:00:04基础资料围观1次
从第一行代码写下 GraphicsContext.CreateDirectX12() 到今天 GraphicsContext.CreateMetal() 跑通全部测试,Zenith.NET 终于实现了最初的承诺——用同一套 .NET API 覆盖三大图形后端。
这篇文章聊聊 Metal 后端的技术选型、架构设计,以及 Zenith.NET 作为一个 .NET GPU 抽象层的设计哲学。
为什么要做 Zenith.NET?
.NET 生态有不少图形相关的库——绑定层如 Silk.NET、Vortice,抽象层如 Veldrid、Evergine。但现有的抽象层要么停留在较旧的 API 版本(如 DX11/OpenGL),要么是商业引擎的一部分,难以作为独立的 GPU 抽象层使用。
Zenith.NET 的定位是:一个面向现代图形 API(DirectX 12、Metal 4、Vulkan 1.4)的轻量 GPU 抽象层,只做抽象、不做引擎,让开发者写一次代码、跑在所有平台上。
这就是 Zenith.NET 要做的事:
| 后端 | 策略 |
|---|---|
| DirectX 12 | Windows 独占,性能天花板 |
| Metal 4 | Apple 全平台,仅支持 Apple Silicon |
| Vulkan 1.4 | 跨平台兜底,覆盖 Linux/Android |
三个后端不是互相替代的关系,而是各守一方——在每个平台上选最原生的那个 API。
Metal 后端:架构决策
为什么选 Metal.NET?
v0.0.6 的 release notes 里提到过,当时在 SharpMetal 和 .NET macios TFM 之间评估。最终选了 Metal.NET(NuGet 包 Metal.NET 2.3.0)——这是我在开发期间制作的绑定库。相比 SharpMetal,Metal.NET 提供更完善的 Metal 4 API 覆盖,并且所有接口都是类型安全的。
不过坦率地说,Metal.NET 基于 class 封装 Objective-C 对象,在 GC 方面会有一定开销。
整体结构
| Zenith.NET 抽象 | Metal 实现 |
|---|---|
GraphicsContext |
MTLDevice + MTL4Compiler + MTLResidencySet |
CommandBuffer |
MTL4CommandBuffer + 双编码器(Render/Compute) |
ResourceLayout |
绑定槽位计数(Buffer/Texture/Sampler) |
ResourceTable |
MTL4ArgumentTable,通过 GPU 地址绑定资源 |
Pipeline |
MTLRenderPipelineState + MTLDepthStencilState |
SwapChain |
CAMetalLayer + CAMetalDrawable |
AccelerationStructure |
MTLAccelerationStructure + 实例缓冲区 |
Metal 4 新特性的应用
Metal 4 引入了几个对抽象层至关重要的新特性,Zenith.NET 的 Metal 后端全面采用了它们。
MTL4ArgumentTable——这是 Metal 4 全新的资源绑定模型。相比旧版 Metal 需要逐个 setBuffer/setTexture/setSampler 绑定资源,Argument Table 允许将所有资源打包到一张表中,通过 GPU 地址一次性绑定。这与 Zenith.NET 的 ResourceLayout + ResourceTable 抽象天然吻合:
| Zenith.NET | Metal 4 |
|---|---|
ResourceLayout |
声明 Buffer/Texture/Sampler 槽位计数 |
ResourceTable |
创建 MTL4ArgumentTable,填入 GPU 地址 |
SetResourceTable() |
一次调用绑定整张表 |
MTL4CommandBuffer 采用双编码器模型——同一时刻只能有一种活跃编码器。CommandBuffer 默认开启 Compute 编码器,当用户开启渲染 Pass 时关闭 Compute、切换到 Render 编码器;Pass 结束后自动切回 Compute:
[Compute 编码器] → 开启 Pass → [Render 编码器] → 结束 Pass → [Compute 编码器]
这样设计的好处是:Compute 编码器始终可用于拷贝(Blit)和计算调度,用户无需手动管理编码器生命周期。所有拷贝操作都走 Compute Encoder 的 Blit 路径,统一了屏障语义。
MTL4Compiler 支持设备端编译——把 Slang 输出的 metallib IR 在目标 GPU 上编译为最终 ISA,比传统 offline 编译能更好地利用 GPU 特定优化。
Objective-C 内存桥接
Metal API 基于 Objective-C 运行时,返回的对象都是 autoreleased 的——出了当前 autorelease pool 就会被回收。在 .NET 的托管环境里,这是个隐蔽的坑。
解决方案是一个统一的桥接工具:
public static T Own<T>(Func<T> func) where T : NSObject
{
using NSAutoreleasePool _ = new();
return func().Retain();
}
所有从 Metal API 获取的对象都通过 NSAutorelease.Own() 包装,确保 Retain 延长生命周期,后续由 .NET 的 Dispose 模式释放。
Shader 编译:Slang 统一管线
三个后端共享同一套 Slang 着色器源码:
.slang 源文件
├─→ metallib (Metal Shader Library)
├─→ dxil (DirectX Intermediate Language)
└─→ spirv (SPIR-V for Vulkan)
开发者只需维护一份 .slang 着色器,编译到哪个后端由 Slangc.NET 自动处理。
光线追踪
Metal 后端完整支持硬件光线追踪:
- BLAS/TLAS:标准的两级加速结构
- 实例缓冲区:CPU 可写的间接寻址,更新 transform 无需重建 TLAS
- RayQuery:在任意着色器阶段内联查询,无需专用光追管线
这与 v0.0.6 移除 RayTracingPipeline 的决策一脉相承——统一用 RayQuery,三个后端的光追能力完全对齐。
设计哲学
只暴露共同能力
Zenith.NET 的核心原则是:采用最新 API 版本,只暴露三个后端共同支持的能力。平台特有的特性被刻意排除,以维护一致的跨平台体验。
这意味着你不会在 Zenith.NET 的 API 里看到 DX12 的 Enhanced Barriers、Vulkan 的 Push Descriptors 或 Metal 的 Tile Shading——这些都是某个 API 独有的。暴露出来只会让其他后端无法实现,破坏"一次编写、处处运行"的承诺。
对于硬件能力差异(比如并非所有 GPU 都支持光追),则通过 Capabilities 动态查询:
if (context.Capabilities.RayTracingSupported) { /* 光追路径 */ }
if (context.Capabilities.MeshShadingSupported) { /* Mesh Shader 路径 */ }
共同能力统一暴露,硬件差异动态检测——这是 Zenith.NET 和其他抽象层最大的区别。
每个平台用最原生的 API
Zenith.NET 不像 bgfx 那样用 Vulkan 覆盖所有平台。在 Windows 上用 DirectX 12,在 Apple 上用 Metal 4,在 Linux/Android 上用 Vulkan 1.4。
虽然上层只暴露共同能力,但每个后端内部都用对应 API 最地道的方式实现——不需要在一种 API 上模拟另一种 API 的行为模式。
AOT 友好
整个库从第一天就为 Native AOT 设计。没有反射、没有动态代码生成、没有 Activator.CreateInstance。Metal.NET 和 Silk.NET 底层都是 P/Invoke + 函数指针,AOT 编译器能完整处理。
下一步
Metal 后端落地后,Zenith.NET 的三大后端全部就位。接下来的重点:
- SkiaSharp 集成——用 GPU 后端加速 2D 渲染
- API 稳定化——向 1.0 迈进
Zenith.NET 是开源项目,欢迎关注:
- GitHub:github.com/qian-o/Zenith.NET
- 文档站:qian-o.github.io/Zenith.NET
- NuGet:搜索
Zenith.NET
本文由 AI 辅助生成,经作者审核校对。
本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:jacktools123@163.com进行投诉反馈,一经查实,立即删除!
标签:
相关文章
最新发布
- 同样都是九年义务教育,他知道的AI算力科普好像比我多耶
- Slickflow 与 OpenClaw 结合实践:技术原理、集成方式与 Skill 说明
- 如何使用 UEFI Shell 执行 Hello World 程序
- Agent构建:声明式优于硬编码
- AI 可以取代运维了吗?
- 测试人必备的4个AI Skills(附下载地址和详细用法)
- 记一次Webshell流量分析2 | 添柴不加火
- 直击政企AI落地“深水区”,华为混合云推出OpenClaw本地部署方案
- FastAPI里玩转Redis和数据库的正确姿势,别让异步任务把你坑哭了!
- 在 React 项目中优雅实现新用户引导:HagiCode 的 driver.js 实践

