smithay/backend/renderer/gles/shaders/
mod.rs1mod implicit;
2
3use std::fmt::Write;
4
5pub use implicit::*;
6
7pub const NO_ALPHA: &str = "NO_ALPHA";
10pub const EXTERNAL: &str = "EXTERNAL";
12pub const DEBUG_FLAGS: &str = "DEBUG_FLAGS";
14
15use super::*;
16
17pub unsafe fn compile_shader(
23 gl: &ffi::Gles2,
24 variant: ffi::types::GLuint,
25 src: &str,
26) -> Result<ffi::types::GLuint, GlesError> {
27 let shader = gl.CreateShader(variant);
28 if shader == 0 {
29 return Err(GlesError::CreateShaderObject);
30 }
31
32 gl.ShaderSource(
33 shader,
34 1,
35 &src.as_ptr() as *const *const u8 as *const *const ffi::types::GLchar,
36 &(src.len() as i32) as *const _,
37 );
38 gl.CompileShader(shader);
39
40 let mut status = ffi::FALSE as i32;
41 gl.GetShaderiv(shader, ffi::COMPILE_STATUS, &mut status as *mut _);
42 if status == ffi::FALSE as i32 {
43 let mut max_len = 0;
44 gl.GetShaderiv(shader, ffi::INFO_LOG_LENGTH, &mut max_len as *mut _);
45
46 let mut error = Vec::with_capacity(max_len as usize);
47 let mut len = 0;
48 gl.GetShaderInfoLog(
49 shader,
50 max_len as _,
51 &mut len as *mut _,
52 error.as_mut_ptr() as *mut _,
53 );
54 error.set_len(len as usize);
55
56 error!(
57 "[GL] {}",
58 std::str::from_utf8(&error).unwrap_or("<Error Message no utf8>")
59 );
60
61 gl.DeleteShader(shader);
62 return Err(GlesError::ShaderCompileError);
63 }
64
65 Ok(shader)
66}
67
68pub unsafe fn link_program(
74 gl: &ffi::Gles2,
75 vert_src: &str,
76 frag_src: &str,
77) -> Result<ffi::types::GLuint, GlesError> {
78 let vert = compile_shader(gl, ffi::VERTEX_SHADER, vert_src)?;
79 let frag = compile_shader(gl, ffi::FRAGMENT_SHADER, frag_src)?;
80 let program = gl.CreateProgram();
81 gl.AttachShader(program, vert);
82 gl.AttachShader(program, frag);
83 gl.LinkProgram(program);
84 gl.DetachShader(program, vert);
85 gl.DetachShader(program, frag);
86 gl.DeleteShader(vert);
87 gl.DeleteShader(frag);
88
89 let mut status = ffi::FALSE as i32;
90 gl.GetProgramiv(program, ffi::LINK_STATUS, &mut status as *mut _);
91 if status == ffi::FALSE as i32 {
92 let mut max_len = 0;
93 gl.GetProgramiv(program, ffi::INFO_LOG_LENGTH, &mut max_len as *mut _);
94
95 let mut error = Vec::with_capacity(max_len as usize);
96 let mut len = 0;
97 gl.GetProgramInfoLog(
98 program,
99 max_len as _,
100 &mut len as *mut _,
101 error.as_mut_ptr() as *mut _,
102 );
103 error.set_len(len as usize);
104
105 error!(
106 "[GL] {}",
107 std::str::from_utf8(&error).unwrap_or("<Error Message no utf8>")
108 );
109
110 gl.DeleteProgram(program);
111 return Err(GlesError::ProgramLinkError);
112 }
113
114 Ok(program)
115}
116
117pub(super) unsafe fn texture_program(
118 gl: &ffi::Gles2,
119 src: &str,
120 additional_uniforms: &[UniformName<'_>],
121 destruction_callback_sender: Sender<CleanupResource>,
122) -> Result<GlesTexProgram, GlesError> {
123 let create_variant = |defines: &[&str]| -> Result<GlesTexProgramVariant, GlesError> {
124 let shader = src.replace(
125 "//_DEFINES_",
126 &defines.iter().fold(String::new(), |mut shader, define| {
127 let _ = writeln!(&mut shader, "#define {define}");
128 shader
129 }),
130 );
131 let debug_shader = src.replace(
132 "//_DEFINES_",
133 &defines
134 .iter()
135 .chain(&[shaders::DEBUG_FLAGS])
136 .fold(String::new(), |mut shader, define| {
137 let _ = writeln!(shader, "#define {define}");
138 shader
139 }),
140 );
141
142 let program = unsafe { link_program(gl, shaders::VERTEX_SHADER, &shader)? };
143 let debug_program = unsafe { link_program(gl, shaders::VERTEX_SHADER, debug_shader.as_ref())? };
144
145 let vert = c"vert";
146 let vert_position = c"vert_position";
147 let tex = c"tex";
148 let matrix = c"matrix";
149 let tex_matrix = c"tex_matrix";
150 let alpha = c"alpha";
151 let tint = c"tint";
152
153 Ok(GlesTexProgramVariant {
154 normal: GlesTexProgramInternal {
155 program,
156 uniform_tex: gl.GetUniformLocation(program, tex.as_ptr() as *const ffi::types::GLchar),
157 uniform_matrix: gl.GetUniformLocation(program, matrix.as_ptr() as *const ffi::types::GLchar),
158 uniform_tex_matrix: gl
159 .GetUniformLocation(program, tex_matrix.as_ptr() as *const ffi::types::GLchar),
160 uniform_alpha: gl.GetUniformLocation(program, alpha.as_ptr() as *const ffi::types::GLchar),
161 attrib_vert: gl.GetAttribLocation(program, vert.as_ptr() as *const ffi::types::GLchar),
162 attrib_vert_position: gl
163 .GetAttribLocation(program, vert_position.as_ptr() as *const ffi::types::GLchar),
164 additional_uniforms: additional_uniforms
165 .iter()
166 .map(|uniform| {
167 let name = CString::new(uniform.name.as_bytes()).expect("Interior null in name");
168 let location =
169 gl.GetUniformLocation(program, name.as_ptr() as *const ffi::types::GLchar);
170 (
171 uniform.name.clone().into_owned(),
172 UniformDesc {
173 location,
174 type_: uniform.type_,
175 },
176 )
177 })
178 .collect(),
179 },
180 debug: GlesTexProgramInternal {
181 program: debug_program,
182 uniform_tex: gl.GetUniformLocation(debug_program, tex.as_ptr() as *const ffi::types::GLchar),
183 uniform_matrix: gl
184 .GetUniformLocation(debug_program, matrix.as_ptr() as *const ffi::types::GLchar),
185 uniform_tex_matrix: gl
186 .GetUniformLocation(debug_program, tex_matrix.as_ptr() as *const ffi::types::GLchar),
187 uniform_alpha: gl
188 .GetUniformLocation(debug_program, alpha.as_ptr() as *const ffi::types::GLchar),
189 attrib_vert: gl.GetAttribLocation(debug_program, vert.as_ptr() as *const ffi::types::GLchar),
190 attrib_vert_position: gl
191 .GetAttribLocation(debug_program, vert_position.as_ptr() as *const ffi::types::GLchar),
192 additional_uniforms: additional_uniforms
193 .iter()
194 .map(|uniform| {
195 let name = CString::new(uniform.name.as_bytes()).expect("Interior null in name");
196 let location =
197 gl.GetUniformLocation(debug_program, name.as_ptr() as *const ffi::types::GLchar);
198 (
199 uniform.name.clone().into_owned(),
200 UniformDesc {
201 location,
202 type_: uniform.type_,
203 },
204 )
205 })
206 .collect(),
207 },
208 uniform_tint: gl.GetUniformLocation(debug_program, tint.as_ptr() as *const ffi::types::GLchar),
210 })
211 };
212
213 Ok(GlesTexProgram(Arc::new(GlesTexProgramInner {
214 variants: [
215 create_variant(&[])?,
216 create_variant(&[shaders::NO_ALPHA])?,
217 create_variant(&[shaders::EXTERNAL])?,
218 ],
219 destruction_callback_sender,
220 })))
221}
222
223pub(super) unsafe fn solid_program(gl: &ffi::Gles2) -> Result<GlesSolidProgram, GlesError> {
224 let program = link_program(gl, shaders::VERTEX_SHADER_SOLID, shaders::FRAGMENT_SHADER_SOLID)?;
225
226 let matrix = c"matrix";
227 let color = c"color";
228 let vert = c"vert";
229 let position = c"position";
230
231 Ok(GlesSolidProgram {
232 program,
233 uniform_matrix: gl.GetUniformLocation(program, matrix.as_ptr() as *const ffi::types::GLchar),
234 uniform_color: gl.GetUniformLocation(program, color.as_ptr() as *const ffi::types::GLchar),
235 attrib_vert: gl.GetAttribLocation(program, vert.as_ptr() as *const ffi::types::GLchar),
236 attrib_position: gl.GetAttribLocation(program, position.as_ptr() as *const ffi::types::GLchar),
237 })
238}