use std::fmt;
use std::error::Error;
use std::sync::Mutex;
use crate::CapabilitiesSource;
use crate::gl;
use crate::version::Api;
use crate::version::Version;
pub use self::compute::{ComputeShader, ComputeCommand};
pub use self::program::Program;
pub use self::reflection::{Uniform, UniformBlock, BlockLayout, OutputPrimitives};
pub use self::reflection::{Attribute, TransformFeedbackVarying, TransformFeedbackBuffer, TransformFeedbackMode};
pub use self::reflection::{ShaderStage, SubroutineData, SubroutineUniform};
mod compute;
mod program;
mod raw;
mod reflection;
mod shader;
mod uniforms_storage;
mod binary_header;
#[inline]
pub fn is_geometry_shader_supported<C: ?Sized>(ctxt: &C) -> bool where C: CapabilitiesSource {
shader::check_shader_type_compatibility(ctxt, gl::GEOMETRY_SHADER)
}
#[inline]
pub fn is_tessellation_shader_supported<C: ?Sized>(ctxt: &C) -> bool where C: CapabilitiesSource {
shader::check_shader_type_compatibility(ctxt, gl::TESS_CONTROL_SHADER)
}
#[inline]
pub fn is_binary_supported<C: ?Sized>(ctxt: &C) -> bool where C: CapabilitiesSource {
ctxt.get_version() >= &Version(Api::Gl, 4, 1) || ctxt.get_version() >= &Version(Api::GlEs, 2, 0)
|| ctxt.get_extensions().gl_arb_get_programy_binary
}
#[inline]
pub fn is_subroutine_supported<C: ?Sized>(ctxt: &C) -> bool where C: CapabilitiesSource {
if cfg!(target_os = "windows")
&& ctxt.get_version() <= &Version(Api::Gl, 4, 0)
&& ctxt.get_capabilities().vendor == "NVIDIA Corporation" {
return false;
}
ctxt.get_version() >= &Version(Api::Gl, 4, 0) || ctxt.get_extensions().gl_arb_shader_subroutine
}
static COMPILER_GLOBAL_LOCK: Mutex<()> = Mutex::new(());
#[derive(Copy, Clone, Debug, PartialEq, Eq)]
pub enum ShaderType {
Vertex,
Geometry,
Fragment,
TesselationControl,
TesselationEvaluation,
Compute,
}
impl ShaderType {
pub fn to_opengl_type(self) -> gl::types::GLenum {
match self {
ShaderType::Vertex => gl::VERTEX_SHADER,
ShaderType::Geometry => gl::GEOMETRY_SHADER,
ShaderType::Fragment => gl::FRAGMENT_SHADER,
ShaderType::TesselationControl => gl::TESS_CONTROL_SHADER,
ShaderType::TesselationEvaluation => gl::TESS_EVALUATION_SHADER,
ShaderType::Compute => gl::COMPUTE_SHADER,
}
}
pub fn from_opengl_type(gl_type: gl::types::GLenum) -> Self {
match gl_type {
gl::VERTEX_SHADER => ShaderType::Vertex,
gl::GEOMETRY_SHADER => ShaderType::Geometry,
gl::FRAGMENT_SHADER => ShaderType::Fragment,
gl::TESS_CONTROL_SHADER => ShaderType::TesselationControl,
gl::TESS_EVALUATION_SHADER => ShaderType::TesselationEvaluation,
gl::COMPUTE_SHADER => ShaderType::Compute,
_ => {
panic!("Unsupported shader type")
}
}
}
}
#[derive(Clone, Debug)]
pub enum ProgramCreationError {
CompilationError(String, ShaderType),
LinkingError(String),
ShaderTypeNotSupported,
CompilationNotSupported,
TransformFeedbackNotSupported,
PointSizeNotSupported,
BinaryHeaderError,
}
impl fmt::Display for ProgramCreationError {
fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> Result<(), fmt::Error> {
use self::ProgramCreationError::*;
let desc = match *self {
CompilationError(_,typ) => {
match typ {
ShaderType::Vertex => "Compilation error in vertex shader",
ShaderType::Geometry => "Compilation error in geometry shader",
ShaderType::Fragment => "Compilation error in fragment shader",
ShaderType::TesselationControl => "Compilation error in tesselation control shader",
ShaderType::TesselationEvaluation => "Compilation error in tesselation evaluation shader",
ShaderType::Compute => "Compilation error in compute shader"
}
},
LinkingError(_) =>
"Error while linking shaders together",
ShaderTypeNotSupported =>
"One of the request shader type is not supported by the backend",
CompilationNotSupported =>
"The backend doesn't support shaders compilation",
TransformFeedbackNotSupported =>
"Transform feedback is not supported by the backend.",
PointSizeNotSupported =>
"Point size is not supported by the backend.",
BinaryHeaderError =>
"The glium-specific binary header was not found or is corrupt.",
};
match *self {
CompilationError(ref s, _) =>
write!(fmt, "{}: {}", desc, s),
LinkingError(ref s) =>
write!(fmt, "{}: {}", desc, s),
_ =>
write!(fmt, "{}", desc),
}
}
}
impl Error for ProgramCreationError {}
#[derive(Clone, Debug)]
pub enum ProgramChooserCreationError {
NoVersion,
ProgramCreationError(ProgramCreationError),
}
impl fmt::Display for ProgramChooserCreationError {
#[inline]
fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> Result<(), fmt::Error> {
use self::ProgramChooserCreationError::*;
match *self {
ProgramCreationError(ref err) => write!(fmt, "{}", err),
NoVersion => fmt.write_str("No version of the program has been found for the current OpenGL version."),
}
}
}
impl Error for ProgramChooserCreationError {
#[inline]
fn source(&self) -> Option<&(dyn Error + 'static)> {
use self::ProgramChooserCreationError::*;
match *self {
ProgramCreationError(ref err) => Some(err),
_ => None,
}
}
}
impl From<ProgramCreationError> for ProgramChooserCreationError {
fn from(err: ProgramCreationError) -> ProgramChooserCreationError {
ProgramChooserCreationError::ProgramCreationError(err)
}
}
#[derive(Copy, Clone, Debug)]
pub enum GetBinaryError {
NotSupported,
NoFormats,
}
impl fmt::Display for GetBinaryError {
fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result {
use self::GetBinaryError::*;
let desc = match *self {
NotSupported => "The backend doesn't support binary",
NoFormats => "The backend does not supply any binary formats.",
};
fmt.write_str(desc)
}
}
impl Error for GetBinaryError {}
pub enum ProgramCreationInput<'a> {
SourceCode {
vertex_shader: &'a str,
tessellation_control_shader: Option<&'a str>,
tessellation_evaluation_shader: Option<&'a str>,
geometry_shader: Option<&'a str>,
fragment_shader: &'a str,
transform_feedback_varyings: Option<(Vec<String>, TransformFeedbackMode)>,
outputs_srgb: bool,
uses_point_size: bool,
},
Binary {
data: Binary,
outputs_srgb: bool,
uses_point_size: bool,
},
SpirV(SpirvProgram<'a>),
}
#[derive(Clone)]
pub struct SpirvProgram<'a> {
pub vertex_shader: SpirvEntryPoint<'a>,
pub fragment_shader: SpirvEntryPoint<'a>,
pub tessellation_control_shader: Option<SpirvEntryPoint<'a>>,
pub tessellation_evaluation_shader: Option<SpirvEntryPoint<'a>>,
pub geometry_shader: Option<SpirvEntryPoint<'a>>,
pub transform_feedback_varyings: Option<(Vec<String>, TransformFeedbackMode)>,
pub outputs_srgb: bool,
pub uses_point_size: bool,
}
impl<'a> SpirvProgram<'a> {
pub fn from_vs_and_fs(
vertex_shader: SpirvEntryPoint<'a>,
fragment_shader: SpirvEntryPoint<'a>,
) -> Self {
Self {
vertex_shader,
fragment_shader,
tessellation_control_shader: None,
tessellation_evaluation_shader: None,
geometry_shader: None,
transform_feedback_varyings: None,
outputs_srgb: true,
uses_point_size: false,
}
}
pub fn tessellation_control_shader(mut self, tessellation_control_shader: Option<SpirvEntryPoint<'a>>) -> Self {
self.tessellation_control_shader = tessellation_control_shader;
self
}
pub fn tessellation_evaluation_shader(mut self, tessellation_evaluation_shader: Option<SpirvEntryPoint<'a>>) -> Self {
self.tessellation_evaluation_shader = tessellation_evaluation_shader;
self
}
pub fn geometry_shader(mut self, geometry_shader: Option<SpirvEntryPoint<'a>>) -> Self {
self.geometry_shader = geometry_shader;
self
}
pub fn transform_feedback_varyings(mut self, transform_feedback_varyings: Option<(Vec<String>, TransformFeedbackMode)>) -> Self {
self.transform_feedback_varyings = transform_feedback_varyings;
self
}
pub fn outputs_srgb(mut self, outputs_srgb: bool) -> Self {
self.outputs_srgb = outputs_srgb;
self
}
pub fn uses_point_size(mut self, uses_point_size: bool) -> Self {
self.uses_point_size = uses_point_size;
self
}
}
#[derive(Copy, Clone)]
pub struct SpirvEntryPoint<'a> {
pub binary: &'a [u8],
pub entry_point: &'a str,
}
pub struct SourceCode<'a> {
pub vertex_shader: &'a str,
pub tessellation_control_shader: Option<&'a str>,
pub tessellation_evaluation_shader: Option<&'a str>,
pub geometry_shader: Option<&'a str>,
pub fragment_shader: &'a str,
}
impl<'a> From<SourceCode<'a>> for ProgramCreationInput<'a> {
#[inline]
fn from(code: SourceCode<'a>) -> ProgramCreationInput<'a> {
let SourceCode { vertex_shader, fragment_shader, geometry_shader,
tessellation_control_shader, tessellation_evaluation_shader } = code;
ProgramCreationInput::SourceCode {
vertex_shader,
tessellation_control_shader,
tessellation_evaluation_shader,
geometry_shader,
fragment_shader,
transform_feedback_varyings: None,
outputs_srgb: true,
uses_point_size: false,
}
}
}
pub struct Binary {
pub format: u32,
pub content: Vec<u8>,
}
impl<'a> From<Binary> for ProgramCreationInput<'a> {
#[inline]
fn from(binary: Binary) -> ProgramCreationInput<'a> {
ProgramCreationInput::Binary {
data: binary,
outputs_srgb: true,
uses_point_size: false,
}
}
}