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