rafx-api 0.0.16

Rendering framework built on an extensible asset pipeline
Documentation
use crate::gles2::{Gles2CompiledShader, ProgramId, RafxDeviceContextGles2};
use crate::{RafxPipelineReflection, RafxResult, RafxShaderStageDef, RafxShaderStageFlags};
use std::sync::Arc;

#[derive(Debug)]
struct RafxShaderGles2Inner {
    device_context: RafxDeviceContextGles2,
    stage_flags: RafxShaderStageFlags,
    stages: Vec<RafxShaderStageDef>,
    pipeline_reflection: RafxPipelineReflection,
    vertex_shader: Gles2CompiledShader,
    fragment_shader: Gles2CompiledShader,
    program_id: ProgramId,
}

impl Drop for RafxShaderGles2Inner {
    fn drop(&mut self) {
        self.device_context
            .gl_context()
            .gl_destroy_program(self.program_id)
            .unwrap();
    }
}

#[derive(Clone, Debug)]
pub struct RafxShaderGles2 {
    inner: Arc<RafxShaderGles2Inner>,
}

impl RafxShaderGles2 {
    pub fn stages(&self) -> &[RafxShaderStageDef] {
        &self.inner.stages
    }

    pub fn pipeline_reflection(&self) -> &RafxPipelineReflection {
        &self.inner.pipeline_reflection
    }

    pub fn stage_flags(&self) -> RafxShaderStageFlags {
        self.inner.stage_flags
    }

    pub fn gl_program_id(&self) -> ProgramId {
        self.inner.program_id
    }

    pub fn gl_vertex_shader(&self) -> &Gles2CompiledShader {
        &self.inner.vertex_shader
    }

    pub fn gl_fragment_shader(&self) -> &Gles2CompiledShader {
        &self.inner.fragment_shader
    }

    pub fn new(
        device_context: &RafxDeviceContextGles2,
        stages: Vec<RafxShaderStageDef>,
    ) -> RafxResult<Self> {
        let pipeline_reflection = RafxPipelineReflection::from_stages(&stages)?;
        let mut stage_flags = RafxShaderStageFlags::empty();

        let mut vertex_shader_id = None;
        let mut fragment_shader_id = None;

        for stage in &stages {
            stage_flags |= stage.reflection.shader_stage;

            log::debug!(
                "Compiling shader for stage {:?}",
                stage.reflection.shader_stage
            );
            let compiled = stage
                .shader_module
                .gles2_shader_module()
                .unwrap()
                .compile_shader(stage.reflection.shader_stage)?;
            if stage.reflection.shader_stage == RafxShaderStageFlags::VERTEX {
                vertex_shader_id = Some(compiled);
            } else if stage.reflection.shader_stage == RafxShaderStageFlags::FRAGMENT {
                fragment_shader_id = Some(compiled);
            } else {
                return Err(format!(
                    "Unexpected shader stage for GL ES 2.0: {:?}",
                    stage.reflection.shader_stage
                ))?;
            }
        }

        let vertex_shader =
            vertex_shader_id.ok_or("No vertex shader specified, it is required for GL ES 2.0")?;
        let fragment_shader = fragment_shader_id
            .ok_or("No fragment shader specified, it is required for GL ES 2.0")?;

        let gl_context = device_context.gl_context();
        let program_id = gl_context.gl_create_program()?;
        gl_context.gl_attach_shader(program_id, vertex_shader.shader_id())?;
        gl_context.gl_attach_shader(program_id, fragment_shader.shader_id())?;

        gl_context.link_shader_program(program_id)?;

        let inner = RafxShaderGles2Inner {
            device_context: device_context.clone(),
            stages,
            pipeline_reflection,
            stage_flags,
            vertex_shader,
            fragment_shader,
            program_id,
        };

        Ok(RafxShaderGles2 {
            inner: Arc::new(inner),
        })
    }
}