6 个版本
0.40.0-beta.1 | 2024 年 8 月 11 日 |
---|---|
0.3.3 | 2024 年 8 月 22 日 |
0.2.8 | 2024 年 7 月 29 日 |
0.2.7 | 2024 年 3 月 8 日 |
#366 在 模拟器
380 每月下载量
在 2 个软件包中(通过 librashader)使用
615KB
11K SLoC
librashader
DirectX 11 上的 Mega Bezel SMOOTH-ADV
librashader (/ˈli:brəʃeɪdɚ/)是 RetroArch 'slang' 着色器的预处理器、编译器和运行时,使用纯 Rust 重写。
安装
对于最终用户,librashader 可从各种 Linux 发行版和平台上的 Open Build Service 获取。Windows 和 macOS 用户可以从 GitHub 发布版 下载最新的二进制文件。
支持的渲染 API
librashader 支持所有现代图形运行时,包括 wgpu、Vulkan、OpenGL 3.3+ 和 4.6(带 DSA)、Direct3D 11、Direct3D 12 和 Metal。
librashader 不支持旧版渲染 API,如较旧的 OpenGL 或 Direct3D 版本,但 experimental support for Direct3D 9 是例外。
API | 状态 | librashader 功能 |
---|---|---|
OpenGL 3.3+ | ✅ | gl |
OpenGL 4.6 | ✅ | gl |
Vulkan | ✅ | vk |
Direct3D 9 | ⚠️ | d3d9 |
Direct3D 11 | ✅ | d3d11 |
Direct3D 12 | ✅ | d3d12 |
Metal | ✅ | metal |
wgpu | 🆗 | wgpu |
✅ 全支持 — 🆗 二级支持 — ⚠️ 实验支持
由于 WGSL 的限制,wgpu 可能不支持所有着色器。Direct3D 9 的支持是实验性的,并且不完全支持如前一帧反馈或历史记录等功能,同时无法支持仅需要 Direct3D 10+ 功能的着色器。
使用方法
librashader 提供了在 librashader
软件包下的 Rust API 和 C API。这两个 API 都是一等公民,且完全受支持。C API 更适合与现有项目集成。Rust librashader
软件包暴露了 librashader 的更多内部功能,如果您只想部分使用 librashader。
librashader C API的最佳使用方法是包含项目中的librashader_ld.h
,它实现了一个动态加载器,可以在搜索路径中动态加载librashader的实现(librashader.so
、librashader.dll
或librashader.dylib
)。
C 兼容性
将librashader
集成到项目中的推荐方式是通过实现librashader_ld
单头文件库的动态加载器,该库实现了对librashader.dll
/ librashader.so
/ librashader.dylib
的动态加载。有关librashader如何处理C ABI和API稳定性以及库更新的详细信息,请参阅版本策略。您也可以仅使用librashader.h
及其等效的-lrashader
动态链接。
静态链接到librashader.h
是可能的,但不是官方支持的。您需要确保链接参数正确,以便成功链接到librashader.lib
或librashader.a
。强烈推荐使用corrosion CMake包。
线程安全
除Metal运行时外,通常从不同的线程创建过滤链实例是安全的,但绘图帧需要过滤链对象的**外部同步**。
过滤链可以在任何线程中创建,但在适用的情况下需要外部同步图形设备队列(在Direct3D 11中,立即上下文被认为是图形设备队列),因为加载查找表需要向GPU提交命令。可以使用filter_chain_create_deferred
函数异步延迟初始化GPU资源,但调用者负责将记录的命令提交到图形设备队列,并在绘制着色器传递帧之前确保工作完成。
OpenGL有一个附加限制,即在创建过滤链实例的不同线程中是安全的,**当且仅当**线程本地的OpenGL上下文初始化为与绘图线程相同的上下文。OpenGL不支持GPU资源初始化的延迟。
Metal运行时不**线程安全**。但是,您仍然可以通过filter_chain_create_deferred
函数延迟提交GPU资源初始化。
四边形顶点和旋转
所有运行时都使用单位矩阵MVP和范围[-1, 1]
的VBO渲染中间传递。默认情况下,最终传递使用范围[0, 1]
的四边形VBO和以下投影矩阵。
static DEFAULT_MVP: &[f32; 16] = &[
2.0, 0.0, 0.0, 0.0,
0.0, 2.0, 0.0, 0.0,
0.0, 0.0, 0.0, 0.0,
-1.0, -1.0, 0.0, 1.0,
];
与RetroArch一样,这些运行时的MVP上的旋转只会应用于最终传递。这是将方向信息传递给着色器的唯一方式。
构建
对于Rust项目,只需将crate添加到您的Cargo.toml
中。
cargo add librashader
要构建C兼容的动态库,运行构建脚本。
cargo run -p librashader-build-script -- --profile optimized
这将在目标文件夹中输出一个 librashader.dll
或 librashader.so
。配置可以是 debug
、release
或 optimized
以实现完全的 LTO。
虽然 librashader 没有构建时依赖,但使用 librashader_ld.h
可能需要相关运行时图形 API 的头文件。
编写 librashader 运行时
如果您希望贡献一个尚未提供的运行时实现,请参阅 librashader-runtime crate,了解所有 librashader 运行时实现使用的辅助工具和共享逻辑。使用这些辅助工具和特性将确保您的运行时在统一和纹理语义绑定方面与现有 librashader 运行时具有一致的行为。
这些类型不应在运行时的公共 API 中暴露,而应保留在运行时实现的内部。
示例
以下 Rust 示例展示了如何使用每个 librashader 运行时。
还提供了一些使用 C API 的基本示例。
兼容性
librashader 实现了整个 RetroArch 着色器管道,并与现有着色器高度兼容。
如果您发现某个在 RetroArch 中可以工作但在 librashader 中不能工作的着色器,请报告问题。
- 过滤器链不会终止在后缓冲区。
- 与 RetroArch 不同,librashader 并不知道整个渲染状态,并且设计为可以在您的渲染管道中的任何位置插入。相反,过滤器链终止在调用者提供的输出表面和视口。将表面复制回后缓冲区的责任在于调用者。
- 尽可能并行编译着色器。这应该会显著减少预设编译时间。OpenGL 不支持并行着色器编译。
- HDR10 支持不是任何着色器运行时的部分,也不受 librashader 支持。
- 出于性能原因,从不为输入纹理生成米柏。理论上,这意味着具有
mipmap_input0 = "true"
的预设将不会得到米柏输入。在实践中,没有已知的着色器预设设置了mipmap_input0 = "true"
。 - 预设解析器是一个比 RetroArch 中的更严格的实现。并非所有着色器预设都可能是兼容的。如果您发现这种情况,请提交问题以便添加解决方案。
运行时特定差异
- OpenGL
- 通过
glBlitFramebuffer
而不是绘制一个四边形到中间的 FBO 来将正在进行的帧缓冲区内容复制到历史记录中。 - 使用采样器对象而不是
glTexParameter
。 - 采样器输入和输出不会重命名。这对于在 RenderDoc 中调试着色器很有用。
- UBO 和 Push Constant 缓冲区的大小填充到 16 字节边界。
- OpenGL 运行时与其他运行时使用相同的 VBO,以及中间传递的恒等矩阵 MVP。RetroArch 的 OpenGL 驱动程序只使用最终的 VBO。
- 通过
- OpenGL 4.6+
- 应考虑 OpenGL 3.3+ 部分的所有注意事项。
- 应在 OpenGL 4.5 上正常工作,但这不能保证。OpenGL 4.6 运行时最终可能会切换到使用
ARB_spirv_extensions
来加载着色器,并且这不会被视为破坏性更改。 - OpenGL 4.6 运行时使用直接状态访问来最小化对 OpenGL 状态的更改。对于过去 5 年内发布的 GPU,这可能会提高性能。
- OpenGL 运行时与其他运行时使用相同的 VBO,以及中间传递的恒等矩阵 MVP。RetroArch 的 OpenGL 驱动程序只使用最终的 VBO。
- Vulkan
- Vulkan 运行时可以使用
VK_KHR_dynamic_rendering
扩展。此扩展必须在创建设备时启用。启用动态渲染可能有助于提高性能,前提是主机硬件支持。 - 运行时中的分配是通过 gpu-allocator 而不是手动处理。
- Vulkan 运行时可以使用
- Direct3D 11
- 帧缓冲区复制是通过
ID3D11DeviceContext::CopySubresourceRegion
而不是 CPU 转换 + 复制来完成的。
- 帧缓冲区复制是通过
- Direct3D 12
- Direct3D 12 运行时使用 渲染通道。此功能自 Windows 10 版本 1809 以来一直可用,该版本于 2018 年晚些时候发布。
- 为了与着色器实现最大兼容性,使用基于
spirv-to-dxil
的着色器编译管道,SPIRV-Cross HLSL 管道作为后备。这带来了比 RetroArch Direct3D 12 驱动程序提供的更大的着色器兼容性。随着spirv-to-dxil
的改进,HLSL 管道后备可能在未来被移除。 - Direct3D 12 运行时需要从 DirectX 着色器编译器 获取
dxcompiler.dll
,这可能是作为 Direct3D12 的一部分安装的。不需要dxil.dll
。
- Metal
- Metal 运行时与其他运行时使用相同的 VBO,以及用于中间通道的 MVP 单位矩阵。RetroArch 的 Metal 驱动程序只使用最终的 VBO。
大多数(如果不是全部)着色器预设应该在 librashader 上正常工作。运行时特定的差异不应影响输出,更多的是为了提醒将 librashader 集成到您的项目中。
版本号
librashader 通常遵循有关 Rust API 的 语义版本控制,其中次要版本号的增加表示在 0.x.y
期间的“破坏性更改”,而在 1.x.y
之后则为非“破坏性更改”。然而,导致版本号增加的“破坏性更改”并不对应于 0.1.0 版本之后的 C API 的中断。
C API 是单独进行版本控制的,并向 librashader C 标头导出两个单调递增的版本号。
LIBRASHADER_CURRENT_VERSION
指定 librashader 实现导出的 API 版本。LIBRASHADER_CURRENT_ABI
指定 librashader 实现导出的 ABI 版本。
LIBRASHADER_CURRENT_VERSION
的增加保证对相同的 LIBRASHADER_CURRENT_ABI
具有向后兼容性。它在语义版本控制术语中类似于“次要”版本,只是它始终单调递增。向后兼容性添加到 C API 将导致 LIBRASHADER_CURRENT_VERSION
的增加。
在某个 LIBRASHADER_CURRENT_VERSION
之后引入的 API 可能 或 不一定 可用于先前版本。特别是,由过滤器或帧选项结构启用的新功能 需要 LIBRASHADER_CURRENT_VERSION
大于或等于引入该选项的版本,否则将传递默认值,这可能会或可能不会根据该特定功能的向后兼容性启用功能。
对 LIBRASHADER_CURRENT_ABI
的任何更改都意味着 C ABI 的重大更改。出于安全考虑,librashader_ld.h
将检查以确保 LIBRASHADER_CURRENT_ABI
与加载的 librashader 二进制文件匹配。如果不匹配,librashader 将无法加载。如果 LIBRASHADER_CURRENT_ABI
的值为 0
,则表示“空”实例,其中每个操作都是无操作,如果没有找到兼容的 librashader 实现。
当通过软件包管理器安装时,librashader.so
的 SONAME
被设置为 LIBRASHADER_CURRENT_ABI
。
以上内容不适用于 0.1.0
之前的 librashader 版本,这些版本可以在不增加 LIBRASHADER_CURRENT_VERSION
或 LIBRASHADER_CURRENT_ABI
的情况下,在 Rust 和 C API 中破坏 API 和 ABI 兼容性。
MSRV 政策
尽管 librashader 需要夜间 Rust,但以下 MSRV 政策强制执行不稳定库功能。
- Windows 和 macOS:最新的夜间版本
- Linux:1.76
每周运行一个 CI 任务,以确保 librashader 继续在夜间构建。请注意,MSRV 仅用于简化 Linux 的分发,可以随时更改。它通常跟踪 Ubuntu 最新版本中可用的最新 Rust 版本,但在补丁版本中可能没有警告地更改。
许可证
librashader 的核心部分,如预处理器、预置解析器、反射库和运行时,均在 Mozilla 公共许可证版本 2.0 下授权。
librashader 的 C API(即其头文件和定义),而不是其在 librashader-capi
中的实现,具有更自由的许可证,可能允许您在使用自由许可或专有项目的 librashader。
为了便于在不符合 MPL-2.0 的项目中使用 librashader,librashader_ld
实现了一个加载器,该加载器将其调用 thunk 到在加载路径中找到的任何 librashader.so
、librashader.dll
或 librashader.dylib
库。项目可以链接到 librashader_ld
以使用 librashader 运行时,前提是 librashader.so
、librashader.dll
或 librashader.dylib
在 MPLv2 的限制下分发。
请注意,这意味着如果您的项目无法遵守 MPL-2.0 的要求,您 不能将 librashader.so
、librashader.dll
或 librashader.dylib
与您的项目一起分发。最终用户必须自己获取 librashader 的实现。有关更多信息,请参阅 MPL 2.0 FAQ。
您可以选择在 GPLv3 条款下分发 librashader
而不是 MPL-2.0。
依赖项
~30–81MB
~1.5M SLoC