63 个版本
0.40.0-beta.1 | 2024年8月11日 |
---|---|
0.2.8 | 2024年7月29日 |
0.2.7 | 2024年3月8日 |
0.2.0-beta.2 | 2023年11月30日 |
0.1.0-alpha.4 | 2022年12月5日 |
#93 在 模拟器 中
每月381次 下载
在 2 个crate中(通过 librashader)使用
605KB
10K SLoC
librashader
DirectX 11上的Mega Bezel SMOOTH-ADV
librashader (/ˈli:brəʃeɪdɚ/) 是一个用于RetroArch 'slang' 着色器的预处理器、编译器和运行时,是用纯Rust重写的。
安装
对于最终用户,librashader可以从Open Build Service为多种Linux发行版和平台获取。Windows和macOS用户可以从GitHub Releases获取最新的二进制文件。
支持的渲染API
librashader支持所有现代图形运行时,包括wgpu、Vulkan、OpenGL 3.3+ 和 4.6(带有DSA)、Direct3D 11、Direct3D 12和Metal。
librashader不支持旧版渲染API,如较老的OpenGL或Direct3D版本,除了对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
crate下的Rust API和C API。这两个API都是一等公民,并且完全受支持。C API更适合与现有项目集成。如果您希望分部分使用librashader,Rust librashader
crate会暴露更多内部信息。
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 中,即时上下文被认为是图形设备队列)需要外部同步图形设备队列。可以使用 filter_chain_create_deferred
函数异步延迟 GPU 资源初始化,但调用者负责将记录的命令提交到图形设备队列,并在绘制着色器传递帧之前确保工作完成。
OpenGL 有一个额外的限制,即只有在将线程局部 OpenGL 上下文初始化为与绘制线程相同的上下文时,从不同的线程创建过滤器链实例才是安全的。OpenGL 不支持 GPU 资源初始化的延迟。
Metal 运行时不支持线程安全性。然而,您仍然可以通过 filter_chain_create_deferred
函数延迟提交 GPU 资源初始化。
四边形顶点和旋转
所有运行时都使用单位矩阵 MVP 和范围在 [-1, 1]
的 VBO 来渲染中间传递。默认情况下,最终传递使用范围在 [0, 1]
的 Quad 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 项目,只需将包添加到您的 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 包,其中包含所有 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 运行时使用 渲染阶段。该功能自 2018 年晚些时候发布的 Windows 10 版本 1809 以来可用。
- 为了与着色器有最大兼容性,使用基于
spirv-to-dxil
的着色器编译管道,SPIRV-Cross HLSL 管道作为后备。这使着色器兼容性超越了 RetroArch Direct3D 12 驱动器所提供的。随着spirv-to-dxil
的改进,HLSL 管道后备可能会在未来移除。 - Direct3D 12 运行时需要来自 DirectX Shader Compiler 的
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 实现时,LIBRASHADER_CURRENT_ABI
的值为 0
表示“空”实例,此时每个操作都是无操作。
当通过包管理器安装时,librashader.so
的 SONAME
被设置为 LIBRASHADER_CURRENT_ABI
。
以上内容不适用于早于0.1.0
版本的librashader发布,这些版本允许在Rust和C API中打破API和ABI兼容性,而无需增加LIBRASHADER_CURRENT_VERSION
或LIBRASHADER_CURRENT_ABI
。
MSRV策略
虽然librashader需要nightly Rust,但对于不稳定库功能,实施以下MSRV策略。
- Windows和macOS:最新nightly版
- Linux:1.76
每周运行CI任务以确保librashader在nightly上持续构建。请注意,MSRV仅旨在简化Linux的发行,且任何时间都可以更改。它通常跟踪Ubuntu最新版本中可用的最新Rust版本,但此版本可能在补丁版本中没有任何警告地更改。
许可证
librashader的核心部分,如预处理器、预设解析器、反射库和运行时,均在Mozilla公共许可证第2.0版下授权。
librashader的C API(即其头文件和定义),而不是librashader-capi
中的实现,具有更宽松的许可,可能允许你在许可宽松或专有项目中使用librashader。
为了便于在不符合MPL-2.0的项目中使用librashader,librashader_ld
实现了一个加载器,该加载器将调用传递给任何在加载路径中找到的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的条款下而不是MPL-2.0下分发librashader
。
依赖项
~31–82MB
~1.5M SLoC