62个版本
新版本 0.3.3 | 2024年8月22日 |
---|---|
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日 |
#230 in 模拟器
每月622次下载
在 2 个crate中使用 (通过 librashader)
630KB
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 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 |
✅ 完全支持 — 🆗 二级支持
在具有二级支持的渲染API上,无法保证着色器的兼容性。
wgpu对无法转换为WGSL的着色器有限制,例如使用 inverse
的着色器。Direct3D 9不支持仅支持Direct3D 10+功能的着色器,或者无法编译为 Shader Model 3.0 的着色器。
用法
librashader提供了在 librashader
crate下的Rust API和C API。这两个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 中,立即上下文被认为是图形设备队列),因为加载查找表需要向 GPU 提交命令。可以使用 filter_chain_create_deferred
函数异步延迟 GPU 资源初始化,但调用者负责将记录的命令提交到图形设备队列,并在绘制着色器传递帧之前确保工作已完成。
OpenGL 有一个额外的限制,即只有在创建过滤器链实例的线程将本地 OpenGL 上下文初始化为与绘图线程相同的上下文时,在不同的线程中创建过滤器链实例才是安全的。OpenGL 不提供 GPU 资源初始化延迟的支持。
Metal 运行时不具备线程安全性。但是,您仍然可以通过 filter_chain_create_deferred
函数延迟提交 GPU 资源初始化。
Direct3D 9 API 不具备线程安全性,除非在设备创建时启用了 D3DCREATE_MULTITHREADED
。
四边形顶点和旋转
所有运行时都使用单位矩阵 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 项目,只需将 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着色器管道,并且与现有着色器高度兼容。
如果您在librashader中遇到在RetroArch中工作但在librashader中不工作的着色器,请报告问题。
- 过滤器链不在后缓冲区终止。
- 与RetroArch不同,librashader并不完全了解整个渲染状态,并设计为可以在渲染管道的任何位置进行插件。相反,过滤器链在调用者提供的输出表面和视口处终止。将表面从调用者复制回后缓冲区的责任在于调用者。
- 尽可能并行编译着色器。这应该会显著减少预设编译时间。OpenGL不支持并行着色器编译。
- HDR10支持不是任何着色器运行时的部分,并且librashader不支持HDR10。
- 出于性能原因,不会为输入纹理生成mipmap。理论上,这意味着带有
mipmap_input0 = "true"
的预设将不会获得mipmap输入。实际上,没有已知的着色器预设设置了mipmap_input0 = "true"
。 - 预设解析器是一个比RetroArch中实现的更严格的实现。并非所有着色器预设都可能是兼容的。如果您发现这种情况,请提交问题,以便添加解决方案。
- 在传递给驱动程序之前,着色器在SPIR-V级别预先链接。在片段着色器中未使用的输入被删除,相应的顶点着色器输入被降级为全局变量。
运行时特定差异
- OpenGL
- 通过
glBlitFramebuffer
而不是将四边形绘制到中间FBO中来将正在进行的帧缓冲区内容复制到历史记录中。 - 使用采样对象而不是
glTexParameter
。 - 采样输入和输出不会被重命名。这对于在RenderDoc中调试着色器很有用。
- UBO和推送常量缓冲区大小填充到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_CURRENT_ABI
的值为 0
时,表示“空”实例,其中每个操作都是无操作,这种情况发生在找不到兼容的 librashader 实现时。
通过软件包管理器安装时,librashader.so
的 SONAME
设置为 LIBRASHADER_CURRENT_ABI
。
上述内容不适用于 0.1.0
之前的 librashader 发布版本,这些版本允许在不增加 LIBRASHADER_CURRENT_VERSION
或 LIBRASHADER_CURRENT_ABI
的情况下,同时破坏 Rust 和 C API 的兼容性。
MSRV 政策
虽然 librashader 需要 nightly Rust,但以下 MSRV 政策强制执行不稳定库功能。
- Windows 和 macOS:最新版 nightly
- Linux:1.76
每周运行一个 CI 作业,以确保 librashader 继续在 nightly 上构建。请注意,MSRV 仅用于简化 Linux 的分发,允许随时更改。它通常跟踪 Ubuntu 最新版本中可用的最新 Rust 版本,但补丁版本中可能会没有警告地进行更改。
许可
librashader 的核心部分,如预处理器、预设解析器、反射库和运行时,均采用 Mozilla Public License 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
。
依赖关系
~32–43MB
~756K SLoC