librashader_test/render/
mod.rs1#[cfg(all(windows, feature = "d3d11"))]
2pub mod d3d11;
3
4#[cfg(all(windows, feature = "d3d12"))]
5pub mod d3d12;
6
7#[cfg(all(windows, feature = "d3d9"))]
8pub mod d3d9;
9
10#[cfg(feature = "opengl")]
11pub mod gl;
12
13#[cfg(feature = "vulkan")]
14pub mod vk;
15
16#[cfg(feature = "wgpu")]
17pub mod wgpu;
18
19#[cfg(all(target_vendor = "apple", feature = "metal"))]
20pub mod mtl;
21
22use librashader::presets::{ShaderFeatures, ShaderPreset};
23use librashader::runtime::Size;
24use librashader_runtime::impl_default_frame_options;
25use librashader_runtime::parameters::RuntimeParameters;
26use std::path::Path;
27
28pub trait RenderTest {
30 fn new(path: &Path) -> anyhow::Result<Self>
32 where
33 Self: Sized;
34
35 fn image_size(&self) -> Size<u32>;
37
38 fn render(
47 &mut self,
48 path: &Path,
49 flags: ShaderFeatures,
50 frame_count: usize,
51 output_size: Option<Size<u32>>,
52 ) -> anyhow::Result<image::RgbaImage> {
53 let preset = ShaderPreset::try_parse(path, flags)?;
54 self.render_with_preset(preset, frame_count, output_size)
55 }
56
57 fn render_with_preset(
66 &mut self,
67 preset: ShaderPreset,
68 frame_count: usize,
69 output_size: Option<Size<u32>>,
70 ) -> anyhow::Result<image::RgbaImage> {
71 self.render_with_preset_and_params(preset, frame_count, output_size, None, None)
72 }
73
74 fn render_with_preset_and_params(
83 &mut self,
84 preset: ShaderPreset,
85 frame_count: usize,
86 output_size: Option<Size<u32>>,
87 param_setter: Option<&dyn Fn(&RuntimeParameters)>,
88 frame_options: Option<CommonFrameOptions>,
89 ) -> anyhow::Result<image::RgbaImage>;
90}
91
92impl_default_frame_options!(CommonFrameOptions);
93
94#[cfg(test)]
95mod test {
96
97 use crate::render::RenderTest;
98 use image::codecs::png::PngEncoder;
99 use librashader::presets::ShaderFeatures;
100 use std::fs::File;
101
102 const IMAGE_PATH: &str = "../triangle.png";
103 const FILTER_PATH: &str = "../test/shaders_slang/crt/crt-royale.slangp";
104
105 fn do_test<T: RenderTest>() -> anyhow::Result<()> {
109 let mut test = T::new(IMAGE_PATH.as_ref())?;
110 let image = test.render(FILTER_PATH.as_ref(), ShaderFeatures::NONE, 100)?;
111
112 let out = File::create("out.png")?;
113 image.write_with_encoder(PngEncoder::new(out))?;
114 Ok(())
115 }
116
117 #[test]
118 #[cfg(all(windows, feature = "d3d11"))]
119 pub fn test_d3d11() -> anyhow::Result<()> {
120 do_test::<crate::render::d3d11::Direct3D11>()
121 }
122
123 #[test]
124 #[cfg(feature = "wgpu")]
125 pub fn test_wgpu() -> anyhow::Result<()> {
126 do_test::<crate::render::wgpu::Wgpu>()
127 }
128
129 #[test]
130 #[cfg(feature = "vulkan")]
131 pub fn test_vk() -> anyhow::Result<()> {
132 do_test::<crate::render::vk::Vulkan>()
133 }
134
135 #[test]
136 #[cfg(feature = "opengl")]
137 pub fn test_gl3() -> anyhow::Result<()> {
138 do_test::<crate::render::gl::OpenGl3>()
139 }
140
141 #[test]
142 #[cfg(feature = "opengl")]
143 pub fn test_gl4() -> anyhow::Result<()> {
144 do_test::<crate::render::gl::OpenGl4>()
145 }
146
147 #[test]
148 #[cfg(all(target_vendor = "apple", feature = "metal"))]
149 pub fn test_metal() -> anyhow::Result<()> {
150 do_test::<crate::render::mtl::Metal>()
151 }
152
153 #[test]
154 #[cfg(all(windows, feature = "d3d9"))]
155 pub fn test_d3d9() -> anyhow::Result<()> {
156 do_test::<crate::render::d3d9::Direct3D9>()
157 }
158
159 #[test]
160 #[cfg(all(windows, feature = "d3d12"))]
161 pub fn test_d3d12() -> anyhow::Result<()> {
162 do_test::<crate::render::d3d12::Direct3D12>()
163 }
164
165 pub fn compare<A: RenderTest, B: RenderTest>() -> anyhow::Result<()> {
166 let mut a = A::new(IMAGE_PATH.as_ref())?;
167 let mut b = B::new(IMAGE_PATH.as_ref())?;
168
169 let a_image = a.render(FILTER_PATH.as_ref(), ShaderFeatures::NONE, 100)?;
170 let b_image = b.render(FILTER_PATH.as_ref(), ShaderFeatures::NONE, 100)?;
171
172 let similarity = image_compare::rgba_hybrid_compare(&a_image, &b_image)?;
173 assert!(similarity.score > 0.95);
174 Ok(())
175 }
176}