Skip to main content

librashader_test/render/gl/
mod.rs

1mod 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}