vg/renderer/opengl/
program.rs1use 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 unsafe {
20 context.shader_source(id, src);
21 context.compile_shader(id);
22 }
23
24 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 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 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 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}