smithay/backend/renderer/gles/shaders/
mod.rs

1mod implicit;
2
3use std::fmt::Write;
4
5pub use implicit::*;
6
7// define constants
8/// No alpha shader define
9pub const NO_ALPHA: &str = "NO_ALPHA";
10/// External texture shader define
11pub const EXTERNAL: &str = "EXTERNAL";
12/// Debug flags shader define
13pub const DEBUG_FLAGS: &str = "DEBUG_FLAGS";
14
15use super::*;
16
17/// Compiles a shader variant.
18///
19/// # Safety
20///
21/// You must call this only when it is safe to compile shaders with GL.
22pub 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
68/// Compiles and links a shader program.
69///
70/// # Safety
71///
72/// You must call this only when it is safe to compile and link shaders with GL.
73pub 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            // debug flags
209            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}