vg/renderer/opengl/
program.rs

1use std::rc::Rc;
2
3use crate::ErrorKind;
4
5use glow::HasContext;
6
7const GLSL_VERSION: &str = "#version 100";
8
9pub(crate) struct Shader {
10    context: Rc<glow::Context>,
11    id: <glow::Context as glow::HasContext>::Shader,
12}
13
14impl Shader {
15    pub fn new(context: &Rc<glow::Context>, src: &str, kind: u32) -> Result<Self, ErrorKind> {
16        let id = unsafe { context.create_shader(kind).unwrap() };
17
18        // Compile
19        unsafe {
20            context.shader_source(id, src);
21            context.compile_shader(id);
22        }
23
24        // Validate
25
26        let success = unsafe { context.get_shader_compile_status(id) };
27        if !success {
28            let error = unsafe { context.get_shader_info_log(id) };
29
30            let name = match kind {
31                glow::VERTEX_SHADER => "Vertex stage",
32                glow::FRAGMENT_SHADER => "Fragment stage",
33                _ => "Shader stage",
34            };
35
36            return Err(ErrorKind::ShaderCompileError(format!("{}: {}", name, error)));
37        }
38
39        Ok(Shader {
40            context: context.clone(),
41            id,
42        })
43    }
44
45    pub fn id(&self) -> <glow::Context as glow::HasContext>::Shader {
46        self.id
47    }
48}
49
50impl Drop for Shader {
51    fn drop(&mut self) {
52        unsafe {
53            self.context.delete_shader(self.id);
54        }
55    }
56}
57
58pub(crate) struct Program {
59    context: Rc<glow::Context>,
60    id: <glow::Context as glow::HasContext>::Program,
61}
62
63impl Program {
64    pub fn new(context: &Rc<glow::Context>, shaders: &[Shader], attrib_locations: &[&str]) -> Result<Self, ErrorKind> {
65        let program = Self {
66            context: context.clone(),
67            id: unsafe { context.create_program().unwrap() },
68        };
69
70        // Attach stages
71        for shader in shaders {
72            unsafe {
73                context.attach_shader(program.id, shader.id());
74            }
75        }
76
77        for (i, loc) in attrib_locations.iter().enumerate() {
78            unsafe {
79                context.bind_attrib_location(program.id, i as u32, *loc);
80            }
81        }
82
83        unsafe {
84            context.link_program(program.id);
85        }
86
87        // Check for error
88
89        let success = unsafe { context.get_program_link_status(program.id) };
90
91        if !success {
92            let error = unsafe { context.get_program_info_log(program.id) };
93
94            return Err(ErrorKind::ShaderLinkError(error));
95        }
96
97        // Detach stages
98        for shader in shaders {
99            unsafe {
100                context.detach_shader(program.id, shader.id());
101            }
102        }
103
104        Ok(program)
105    }
106
107    pub(crate) fn bind(&self) {
108        unsafe {
109            self.context.use_program(Some(self.id));
110        }
111    }
112
113    pub(crate) fn unbind(&self) {
114        unsafe {
115            self.context.use_program(None);
116        }
117    }
118
119    fn uniform_location(&self, name: &str) -> Result<<glow::Context as glow::HasContext>::UniformLocation, ErrorKind> {
120        unsafe { Ok(self.context.get_uniform_location(self.id, name).unwrap()) }
121    }
122}
123
124impl Drop for Program {
125    fn drop(&mut self) {
126        unsafe {
127            self.context.delete_program(self.id);
128        }
129    }
130}
131
132pub struct MainProgram {
133    context: Rc<glow::Context>,
134    program: Program,
135    loc_viewsize: <glow::Context as glow::HasContext>::UniformLocation,
136    loc_tex: <glow::Context as glow::HasContext>::UniformLocation,
137    loc_glyphtex: <glow::Context as glow::HasContext>::UniformLocation,
138    loc_frag: <glow::Context as glow::HasContext>::UniformLocation,
139}
140
141impl MainProgram {
142    pub(crate) fn new(context: &Rc<glow::Context>, antialias: bool) -> Result<Self, ErrorKind> {
143        let shader_defs = if antialias { "#define EDGE_AA 1" } else { "" };
144        let vert_shader_src = format!("{}\n{}\n{}", GLSL_VERSION, shader_defs, include_str!("main-vs.glsl"));
145        let frag_shader_src = format!("{}\n{}\n{}", GLSL_VERSION, shader_defs, include_str!("main-fs.glsl"));
146
147        let vert_shader = Shader::new(context, &vert_shader_src, glow::VERTEX_SHADER)?;
148        let frag_shader = Shader::new(context, &frag_shader_src, glow::FRAGMENT_SHADER)?;
149
150        let program = Program::new(context, &[vert_shader, frag_shader], &["vertex", "tcoord"])?;
151
152        let loc_viewsize = program.uniform_location("viewSize")?;
153        let loc_tex = program.uniform_location("tex")?;
154        let loc_glyphtex = program.uniform_location("glyphtex")?;
155        let loc_frag = program.uniform_location("frag")?;
156
157        Ok(Self {
158            context: context.clone(),
159            program,
160            loc_viewsize,
161            loc_tex,
162            loc_glyphtex,
163            loc_frag,
164        })
165    }
166
167    pub(crate) fn set_tex(&self, tex: i32) {
168        unsafe {
169            self.context.uniform_1_i32(Some(&self.loc_tex), tex);
170        }
171    }
172
173    pub(crate) fn set_glyphtex(&self, tex: i32) {
174        unsafe {
175            self.context.uniform_1_i32(Some(&self.loc_glyphtex), tex);
176        }
177    }
178
179    pub(crate) fn set_view(&self, view: [f32; 2]) {
180        unsafe {
181            self.context.uniform_2_f32_slice(Some(&self.loc_viewsize), &view);
182        }
183    }
184
185    pub(crate) fn set_config(&self, config: &[f32]) {
186        unsafe {
187            self.context.uniform_4_f32_slice(Some(&self.loc_frag), config);
188        }
189    }
190
191    pub(crate) fn bind(&self) {
192        self.program.bind();
193    }
194
195    pub(crate) fn unbind(&self) {
196        self.program.unbind();
197    }
198}