mallumo_gls/
compute_program.rs

1use super::errors::*;
2
3use std::path::Path;
4use std::fs::File;
5use std::io::Read;
6
7use raw::{attach_shader, compile_shader, create_program, create_shader, delete_program, delete_shader, detach_shader,
8          get_integer_i_v, get_program_info_log, get_shader_info_log, link_program, shader_source, use_program,
9          GetParameterName, ProgramId, ShaderType};
10
11#[derive(Debug)]
12pub struct ComputeProgram {
13    id: ProgramId,
14}
15
16impl ComputeProgram {
17    #[allow(unused_must_use)]
18    pub fn new(sources: &[&str]) -> Result<ComputeProgram> {
19        let program_id: ProgramId;
20        unsafe {
21            let shader_id = create_shader(ShaderType::Compute);
22
23            shader_source(shader_id, sources);
24            compile_shader(shader_id);
25
26            let shader_info_log = get_shader_info_log(shader_id);
27
28            match shader_info_log {
29                Ok(log) => if log.len() > 1 {
30                    delete_shader(shader_id);
31                    bail!(log);
32                },
33                Err(_) => {
34                    delete_shader(shader_id);
35                    shader_info_log.chain_err(|| "Could not get shader compilation log")?;
36                }
37            }
38
39            program_id = create_program();
40            let attach_status = attach_shader(program_id, shader_id);
41            if attach_status.is_err() {
42                delete_program(program_id);
43                delete_shader(shader_id);
44                attach_status.chain_err(|| "Could not attach shader")?;
45            }
46
47            let link_status = link_program(program_id);
48            if link_status.is_err() {
49                let program_info_log = get_program_info_log(program_id);
50                match program_info_log {
51                    Ok(log) => if log.len() > 1 {
52                        delete_program(program_id);
53                        delete_shader(shader_id);
54                        bail!(log);
55                    },
56                    Err(_) => {
57                        delete_program(program_id);
58                        delete_shader(shader_id);
59                        program_info_log.chain_err(|| "Could not get program link log")?;
60                    }
61                }
62            }
63
64            // ignoring error, because according to spec it cannot fail
65            // because program_id is program object, shader_id is shader object
66            //         shader_id is attached to program_id
67            detach_shader(program_id, shader_id);
68
69            delete_shader(shader_id);
70        }
71        Ok(ComputeProgram { id: program_id })
72    }
73
74    pub fn from_file(filepath: &Path) -> Result<ComputeProgram> {
75        let mut file = match File::open(&filepath) {
76            Ok(file) => file,
77            Err(e) => return Err(format!("Could not open shader file : {}", e).into()),
78        };
79
80        let mut source = String::new();
81        match file.read_to_string(&mut source) {
82            Ok(_) => {}
83            Err(e) => return Err(format!("Could not read shader file! : {}", e).into()),
84        };
85
86        ComputeProgram::new(&[source.as_str()])
87    }
88
89    pub fn bind(&self) -> Result<()> {
90        unsafe { use_program(self.id).chain_err(|| "Could not bind compute program") }
91    }
92
93    pub fn get_id(&self) -> ProgramId {
94        self.id
95    }
96
97    pub fn max_group_count() -> (u32, u32, u32) {
98        unsafe {
99            let x = get_integer_i_v(GetParameterName::MaxComputeWorkGroupCount, 0).unwrap() as u32;
100            let y = get_integer_i_v(GetParameterName::MaxComputeWorkGroupCount, 1).unwrap() as u32;
101            let z = get_integer_i_v(GetParameterName::MaxComputeWorkGroupCount, 2).unwrap() as u32;
102
103            (x, y, z)
104        }
105    }
106
107    pub fn max_group_size() -> (u32, u32, u32) {
108        unsafe {
109            let x = get_integer_i_v(GetParameterName::MaxComputeWorkGroupSize, 0).unwrap() as u32;
110            let y = get_integer_i_v(GetParameterName::MaxComputeWorkGroupSize, 1).unwrap() as u32;
111            let z = get_integer_i_v(GetParameterName::MaxComputeWorkGroupSize, 2).unwrap() as u32;
112
113            (x, y, z)
114        }
115    }
116
117    pub fn max_group_invocations() -> u32 {
118        unsafe { get_integer_i_v(GetParameterName::MaxComputeWorkGroupInvocations, 0).unwrap() as u32 }
119    }
120}
121
122impl Drop for ComputeProgram {
123    fn drop(&mut self) {
124        unsafe {
125            delete_program(self.id);
126        }
127    }
128}