use super::errors::*;
use std::path::Path;
use std::fs::File;
use std::io::Read;
use raw::{attach_shader, compile_shader, create_program, create_shader, delete_program, delete_shader, detach_shader,
get_integer_i_v, get_program_info_log, get_shader_info_log, link_program, shader_source, use_program,
GetParameterName, ProgramId, ShaderType};
#[derive(Debug)]
pub struct ComputeProgram {
id: ProgramId,
}
impl ComputeProgram {
#[allow(unused_must_use)]
pub fn new(sources: &[&str]) -> Result<ComputeProgram> {
let program_id: ProgramId;
unsafe {
let shader_id = create_shader(ShaderType::Compute);
shader_source(shader_id, sources);
compile_shader(shader_id);
let shader_info_log = get_shader_info_log(shader_id);
match shader_info_log {
Ok(log) => if log.len() > 1 {
delete_shader(shader_id);
bail!(log);
},
Err(_) => {
delete_shader(shader_id);
shader_info_log.chain_err(|| "Could not get shader compilation log")?;
}
}
program_id = create_program();
let attach_status = attach_shader(program_id, shader_id);
if attach_status.is_err() {
delete_program(program_id);
delete_shader(shader_id);
attach_status.chain_err(|| "Could not attach shader")?;
}
let link_status = link_program(program_id);
if link_status.is_err() {
let program_info_log = get_program_info_log(program_id);
match program_info_log {
Ok(log) => if log.len() > 1 {
delete_program(program_id);
delete_shader(shader_id);
bail!(log);
},
Err(_) => {
delete_program(program_id);
delete_shader(shader_id);
program_info_log.chain_err(|| "Could not get program link log")?;
}
}
}
detach_shader(program_id, shader_id);
delete_shader(shader_id);
}
Ok(ComputeProgram { id: program_id })
}
pub fn from_file(filepath: &Path) -> Result<ComputeProgram> {
let mut file = match File::open(&filepath) {
Ok(file) => file,
Err(e) => return Err(format!("Could not open shader file : {}", e).into()),
};
let mut source = String::new();
match file.read_to_string(&mut source) {
Ok(_) => {}
Err(e) => return Err(format!("Could not read shader file! : {}", e).into()),
};
ComputeProgram::new(&[source.as_str()])
}
pub fn bind(&self) -> Result<()> {
unsafe { use_program(self.id).chain_err(|| "Could not bind compute program") }
}
pub fn get_id(&self) -> ProgramId {
self.id
}
pub fn max_group_count() -> (u32, u32, u32) {
unsafe {
let x = get_integer_i_v(GetParameterName::MaxComputeWorkGroupCount, 0).unwrap() as u32;
let y = get_integer_i_v(GetParameterName::MaxComputeWorkGroupCount, 1).unwrap() as u32;
let z = get_integer_i_v(GetParameterName::MaxComputeWorkGroupCount, 2).unwrap() as u32;
(x, y, z)
}
}
pub fn max_group_size() -> (u32, u32, u32) {
unsafe {
let x = get_integer_i_v(GetParameterName::MaxComputeWorkGroupSize, 0).unwrap() as u32;
let y = get_integer_i_v(GetParameterName::MaxComputeWorkGroupSize, 1).unwrap() as u32;
let z = get_integer_i_v(GetParameterName::MaxComputeWorkGroupSize, 2).unwrap() as u32;
(x, y, z)
}
}
pub fn max_group_invocations() -> u32 {
unsafe { get_integer_i_v(GetParameterName::MaxComputeWorkGroupInvocations, 0).unwrap() as u32 }
}
}
impl Drop for ComputeProgram {
fn drop(&mut self) {
unsafe {
delete_program(self.id);
}
}
}