librashader_test/render/gl/
mod.rs1mod context;
2
3use crate::render::gl::context::{GLVersion, GlfwContext};
4use crate::render::{CommonFrameOptions, RenderTest};
5use anyhow::anyhow;
6use glow::{HasContext, PixelPackData, PixelUnpackData};
7use image::RgbaImage;
8use librashader::presets::ShaderPreset;
9use librashader::runtime::gl::{FilterChain, FilterChainOptions, FrameOptions, GLImage};
10use librashader::runtime::{FilterChainParameters, RuntimeParameters};
11use librashader::runtime::{Size, Viewport};
12use librashader_runtime::image::{Image, UVDirection, RGBA8};
13use std::path::Path;
14use std::sync::Arc;
15
16struct OpenGl {
17 context: GlfwContext,
18 texture: GLImage,
19 image_bytes: Image<RGBA8>,
20}
21
22pub struct OpenGl3(OpenGl);
23pub struct OpenGl4(OpenGl);
24
25impl RenderTest for OpenGl3 {
26 fn new(path: &Path) -> anyhow::Result<Self>
27 where
28 Self: Sized,
29 {
30 OpenGl3::new(path)
31 }
32
33 fn image_size(&self) -> Size<u32> {
34 self.0.image_bytes.size
35 }
36
37 fn render_with_preset_and_params(
38 &mut self,
39 preset: ShaderPreset,
40 frame_count: usize,
41 output_size: Option<Size<u32>>,
42 param_setter: Option<&dyn Fn(&RuntimeParameters)>,
43 frame_options: Option<CommonFrameOptions>,
44 ) -> anyhow::Result<image::RgbaImage> {
45 let mut filter_chain = unsafe {
46 FilterChain::load_from_preset(
47 preset,
48 Arc::clone(&self.0.context.gl),
49 Some(&FilterChainOptions {
50 glsl_version: 330,
51 use_dsa: false,
52 force_no_mipmaps: false,
53 disable_cache: false,
54 ..Default::default()
55 }),
56 )
57 }?;
58
59 if let Some(setter) = param_setter {
60 setter(filter_chain.parameters());
61 }
62
63 Ok(self.0.render(
64 &mut filter_chain,
65 frame_count,
66 output_size,
67 frame_options
68 .map(|options| FrameOptions {
69 clear_history: options.clear_history,
70 frame_direction: options.frame_direction,
71 rotation: options.rotation,
72 total_subframes: options.total_subframes,
73 current_subframe: options.current_subframe,
74 aspect_ratio: options.aspect_ratio,
75 frametime_delta: options.frametime_delta,
76 frames_per_second: options.frames_per_second,
77 ..Default::default()
78 })
79 .as_ref(),
80 )?)
81 }
82}
83
84impl RenderTest for OpenGl4 {
85 fn new(path: &Path) -> anyhow::Result<Self>
86 where
87 Self: Sized,
88 {
89 OpenGl4::new(path)
90 }
91
92 fn image_size(&self) -> Size<u32> {
93 self.0.image_bytes.size
94 }
95
96 fn render_with_preset_and_params(
97 &mut self,
98 preset: ShaderPreset,
99 frame_count: usize,
100 output_size: Option<Size<u32>>,
101 param_setter: Option<&dyn Fn(&RuntimeParameters)>,
102 frame_options: Option<CommonFrameOptions>,
103 ) -> anyhow::Result<image::RgbaImage> {
104 let mut filter_chain = unsafe {
105 FilterChain::load_from_preset(
106 preset,
107 Arc::clone(&self.0.context.gl),
108 Some(&FilterChainOptions {
109 glsl_version: 460,
110 use_dsa: true,
111 force_no_mipmaps: false,
112 disable_cache: true,
113 ..Default::default()
114 }),
115 )
116 }?;
117
118 if let Some(setter) = param_setter {
119 setter(filter_chain.parameters());
120 }
121
122 Ok(self.0.render(
123 &mut filter_chain,
124 frame_count,
125 output_size,
126 frame_options
127 .map(|options| FrameOptions {
128 clear_history: options.clear_history,
129 frame_direction: options.frame_direction,
130 rotation: options.rotation,
131 total_subframes: options.total_subframes,
132 current_subframe: options.current_subframe,
133 aspect_ratio: options.aspect_ratio,
134 frametime_delta: options.frametime_delta,
135 frames_per_second: options.frames_per_second,
136 ..Default::default()
137 })
138 .as_ref(),
139 )?)
140 }
141}
142
143impl OpenGl3 {
144 pub fn new(image_path: &Path) -> anyhow::Result<Self> {
145 Ok(Self(OpenGl::new(image_path, false)?))
146 }
147}
148
149impl OpenGl4 {
150 pub fn new(image_path: &Path) -> anyhow::Result<Self> {
151 Ok(Self(OpenGl::new(image_path, true)?))
152 }
153}
154
155impl OpenGl {
156 pub fn new(image_path: &Path, use_dsa: bool) -> anyhow::Result<Self> {
157 let image: Image<RGBA8> = Image::load(image_path, UVDirection::TopLeft)?;
158 let height = image.size.height;
159 let width = image.size.width;
160 let version = if use_dsa {
161 GLVersion(4, 6)
162 } else {
163 GLVersion(3, 3)
164 };
165
166 let context = GlfwContext::new(version, width, height)?;
167
168 let texture = unsafe {
169 let tex = context.gl.create_texture().map_err(|s| anyhow!("{}", s))?;
170 context.gl.bind_texture(glow::TEXTURE_2D, Some(tex));
171 context.gl.tex_storage_2d(
172 glow::TEXTURE_2D,
173 1,
174 glow::RGBA8,
175 image.size.width as i32,
176 image.size.height as i32,
177 );
178
179 context.gl.pixel_store_i32(glow::UNPACK_ROW_LENGTH, 0);
180 context.gl.pixel_store_i32(glow::UNPACK_ALIGNMENT, 4);
181 context.gl.bind_buffer(glow::PIXEL_UNPACK_BUFFER, None);
182
183 context.gl.tex_sub_image_2d(
184 glow::TEXTURE_2D,
185 0,
186 0,
187 0,
188 image.size.width as i32,
189 image.size.height as i32,
190 glow::RGBA,
191 glow::UNSIGNED_BYTE,
192 PixelUnpackData::Slice(Some(&image.bytes)),
193 );
194
195 context.gl.bind_texture(glow::TEXTURE_2D, None);
196 tex
197 };
198
199 Ok(Self {
200 context,
201 texture: GLImage {
202 handle: Some(texture),
203 format: glow::RGBA8,
204 size: image.size,
205 },
206 image_bytes: image,
207 })
208 }
209
210 pub fn render(
211 &self,
212 chain: &mut FilterChain,
213 frame_count: usize,
214 output_size: Option<Size<u32>>,
215 options: Option<&FrameOptions>,
216 ) -> Result<RgbaImage, anyhow::Error> {
217 let output_size = output_size.unwrap_or(self.image_bytes.size);
218
219 let render_texture = unsafe {
220 let tex = self
221 .context
222 .gl
223 .create_texture()
224 .map_err(|s| anyhow!("{}", s))?;
225 self.context.gl.bind_texture(glow::TEXTURE_2D, Some(tex));
226 self.context.gl.tex_storage_2d(
227 glow::TEXTURE_2D,
228 1,
229 glow::RGBA8,
230 output_size.width as i32,
231 output_size.height as i32,
232 );
233 self.context.gl.bind_texture(glow::TEXTURE_2D, None);
234 tex
235 };
236
237 let output = GLImage {
238 handle: Some(render_texture),
239 format: glow::RGBA8,
240 size: output_size,
241 };
242
243 let viewport = Viewport::new_render_target_sized_origin(&output, None)?;
244 for frame in 0..=frame_count {
245 unsafe {
246 chain.frame(&self.texture, &viewport, frame, options)?;
247 }
248 }
249
250 let mut data = vec![0u8; output_size.width as usize * output_size.height as usize * 4];
251
252 unsafe {
253 self.context
254 .gl
255 .bind_texture(glow::TEXTURE_2D, output.handle);
256 self.context.gl.get_tex_image(
257 glow::TEXTURE_2D,
258 0,
259 glow::RGBA,
260 glow::UNSIGNED_BYTE,
261 PixelPackData::Slice(Some(&mut data)),
262 )
263 }
264 Ok(
265 RgbaImage::from_raw(output_size.width, output_size.height, data)
266 .ok_or(anyhow!("failed to create image from slice"))?,
267 )
268 }
269}