1use std::fmt;
4use std::error::Error;
5use std::sync::Mutex;
6use crate::CapabilitiesSource;
7
8use crate::gl;
9use crate::version::Api;
10use crate::version::Version;
11
12pub use self::compute::{ComputeShader, ComputeCommand};
13pub use self::program::Program;
14pub use self::reflection::{Uniform, UniformBlock, BlockLayout, OutputPrimitives};
15pub use self::reflection::{Attribute, TransformFeedbackVarying, TransformFeedbackBuffer, TransformFeedbackMode};
16pub use self::reflection::{ShaderStage, SubroutineData, SubroutineUniform};
17
18mod compute;
19mod program;
20mod raw;
21mod reflection;
22mod shader;
23mod uniforms_storage;
24mod binary_header;
25
26#[inline]
28pub fn is_geometry_shader_supported<C: ?Sized>(ctxt: &C) -> bool where C: CapabilitiesSource {
29 shader::check_shader_type_compatibility(ctxt, gl::GEOMETRY_SHADER)
30}
31
32#[inline]
34pub fn is_tessellation_shader_supported<C: ?Sized>(ctxt: &C) -> bool where C: CapabilitiesSource {
35 shader::check_shader_type_compatibility(ctxt, gl::TESS_CONTROL_SHADER)
36}
37
38#[inline]
40pub fn is_binary_supported<C: ?Sized>(ctxt: &C) -> bool where C: CapabilitiesSource {
41 ctxt.get_version() >= &Version(Api::Gl, 4, 1) || ctxt.get_version() >= &Version(Api::GlEs, 2, 0)
42 || ctxt.get_extensions().gl_arb_get_programy_binary
43}
44
45#[inline]
47pub fn is_subroutine_supported<C: ?Sized>(ctxt: &C) -> bool where C: CapabilitiesSource {
48 if cfg!(target_os = "windows")
51 && ctxt.get_version() <= &Version(Api::Gl, 4, 0)
52 && ctxt.get_capabilities().vendor == "NVIDIA Corporation" {
53 return false;
54 }
55 ctxt.get_version() >= &Version(Api::Gl, 4, 0) || ctxt.get_extensions().gl_arb_shader_subroutine
56}
57
58static COMPILER_GLOBAL_LOCK: Mutex<()> = Mutex::new(());
61
62#[derive(Copy, Clone, Debug, PartialEq, Eq)]
64pub enum ShaderType {
65 Vertex,
67 Geometry,
69 Fragment,
71 TesselationControl,
73 TesselationEvaluation,
75 Compute,
77}
78
79impl ShaderType {
80 pub fn to_opengl_type(self) -> gl::types::GLenum {
82 match self {
83 ShaderType::Vertex => gl::VERTEX_SHADER,
84 ShaderType::Geometry => gl::GEOMETRY_SHADER,
85 ShaderType::Fragment => gl::FRAGMENT_SHADER,
86 ShaderType::TesselationControl => gl::TESS_CONTROL_SHADER,
87 ShaderType::TesselationEvaluation => gl::TESS_EVALUATION_SHADER,
88 ShaderType::Compute => gl::COMPUTE_SHADER,
89 }
90 }
91 pub fn from_opengl_type(gl_type: gl::types::GLenum) -> Self {
94 match gl_type {
95 gl::VERTEX_SHADER => ShaderType::Vertex,
96 gl::GEOMETRY_SHADER => ShaderType::Geometry,
97 gl::FRAGMENT_SHADER => ShaderType::Fragment,
98 gl::TESS_CONTROL_SHADER => ShaderType::TesselationControl,
99 gl::TESS_EVALUATION_SHADER => ShaderType::TesselationEvaluation,
100 gl::COMPUTE_SHADER => ShaderType::Compute,
101 _ => {
102 panic!("Unsupported shader type")
103 }
104 }
105 }
106}
107
108#[derive(Clone, Debug)]
110pub enum ProgramCreationError {
111 CompilationError(String, ShaderType),
113
114 LinkingError(String),
116
117 ShaderTypeNotSupported,
121
122 CompilationNotSupported,
124
125 TransformFeedbackNotSupported,
128
129 PointSizeNotSupported,
132
133 BinaryHeaderError,
135}
136
137impl fmt::Display for ProgramCreationError {
138 fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> Result<(), fmt::Error> {
139 use self::ProgramCreationError::*;
140 let desc = match *self {
141 CompilationError(_,typ) => {
142 match typ {
143 ShaderType::Vertex => "Compilation error in vertex shader",
144 ShaderType::Geometry => "Compilation error in geometry shader",
145 ShaderType::Fragment => "Compilation error in fragment shader",
146 ShaderType::TesselationControl => "Compilation error in tesselation control shader",
147 ShaderType::TesselationEvaluation => "Compilation error in tesselation evaluation shader",
148 ShaderType::Compute => "Compilation error in compute shader"
149 }
150 },
151 LinkingError(_) =>
152 "Error while linking shaders together",
153 ShaderTypeNotSupported =>
154 "One of the request shader type is not supported by the backend",
155 CompilationNotSupported =>
156 "The backend doesn't support shaders compilation",
157 TransformFeedbackNotSupported =>
158 "Transform feedback is not supported by the backend.",
159 PointSizeNotSupported =>
160 "Point size is not supported by the backend.",
161 BinaryHeaderError =>
162 "The glium-specific binary header was not found or is corrupt.",
163 };
164 match *self {
165 CompilationError(ref s, _) =>
166 write!(fmt, "{}: {}", desc, s),
167 LinkingError(ref s) =>
168 write!(fmt, "{}: {}", desc, s),
169 _ =>
170 write!(fmt, "{}", desc),
171 }
172 }
173}
174
175impl Error for ProgramCreationError {}
176
177#[derive(Clone, Debug)]
179pub enum ProgramChooserCreationError {
180 NoVersion,
182
183 ProgramCreationError(ProgramCreationError),
185}
186
187impl fmt::Display for ProgramChooserCreationError {
188 #[inline]
189 fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> Result<(), fmt::Error> {
190 use self::ProgramChooserCreationError::*;
191 match *self {
192 ProgramCreationError(ref err) => write!(fmt, "{}", err),
193 NoVersion => fmt.write_str("No version of the program has been found for the current OpenGL version."),
194 }
195 }
196}
197
198impl Error for ProgramChooserCreationError {
199 #[inline]
200 fn source(&self) -> Option<&(dyn Error + 'static)> {
201 use self::ProgramChooserCreationError::*;
202 match *self {
203 ProgramCreationError(ref err) => Some(err),
204 _ => None,
205 }
206 }
207}
208
209impl From<ProgramCreationError> for ProgramChooserCreationError {
210 fn from(err: ProgramCreationError) -> ProgramChooserCreationError {
211 ProgramChooserCreationError::ProgramCreationError(err)
212 }
213}
214
215#[derive(Copy, Clone, Debug)]
217pub enum GetBinaryError {
218 NotSupported,
220 NoFormats,
222}
223
224impl fmt::Display for GetBinaryError {
225 fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result {
226 use self::GetBinaryError::*;
227 let desc = match *self {
228 NotSupported => "The backend doesn't support binary",
229 NoFormats => "The backend does not supply any binary formats.",
230 };
231 fmt.write_str(desc)
232 }
233}
234
235impl Error for GetBinaryError {}
236
237pub enum ProgramCreationInput<'a> {
239 SourceCode {
241 vertex_shader: &'a str,
243
244 tessellation_control_shader: Option<&'a str>,
246
247 tessellation_evaluation_shader: Option<&'a str>,
249
250 geometry_shader: Option<&'a str>,
252
253 fragment_shader: &'a str,
255
256 transform_feedback_varyings: Option<(Vec<String>, TransformFeedbackMode)>,
261
262 outputs_srgb: bool,
268
269 uses_point_size: bool,
271 },
272
273 Binary {
275 data: Binary,
277
278 outputs_srgb: bool,
280
281 uses_point_size: bool,
283 },
284
285 SpirV(SpirvProgram<'a>),
287}
288
289#[derive(Clone)]
291pub struct SpirvProgram<'a> {
292 pub vertex_shader: SpirvEntryPoint<'a>,
294
295 pub fragment_shader: SpirvEntryPoint<'a>,
297
298 pub tessellation_control_shader: Option<SpirvEntryPoint<'a>>,
300
301 pub tessellation_evaluation_shader: Option<SpirvEntryPoint<'a>>,
303
304 pub geometry_shader: Option<SpirvEntryPoint<'a>>,
306
307 pub transform_feedback_varyings: Option<(Vec<String>, TransformFeedbackMode)>,
312
313 pub outputs_srgb: bool,
315
316 pub uses_point_size: bool,
318}
319
320impl<'a> SpirvProgram<'a> {
321 pub fn from_vs_and_fs(
323 vertex_shader: SpirvEntryPoint<'a>,
324 fragment_shader: SpirvEntryPoint<'a>,
325 ) -> Self {
326 Self {
327 vertex_shader,
328 fragment_shader,
329 tessellation_control_shader: None,
330 tessellation_evaluation_shader: None,
331 geometry_shader: None,
332 transform_feedback_varyings: None,
333 outputs_srgb: true,
334 uses_point_size: false,
335 }
336 }
337
338 pub fn tessellation_control_shader(mut self, tessellation_control_shader: Option<SpirvEntryPoint<'a>>) -> Self {
340 self.tessellation_control_shader = tessellation_control_shader;
341 self
342 }
343
344 pub fn tessellation_evaluation_shader(mut self, tessellation_evaluation_shader: Option<SpirvEntryPoint<'a>>) -> Self {
346 self.tessellation_evaluation_shader = tessellation_evaluation_shader;
347 self
348 }
349
350 pub fn geometry_shader(mut self, geometry_shader: Option<SpirvEntryPoint<'a>>) -> Self {
352 self.geometry_shader = geometry_shader;
353 self
354 }
355
356 pub fn transform_feedback_varyings(mut self, transform_feedback_varyings: Option<(Vec<String>, TransformFeedbackMode)>) -> Self {
358 self.transform_feedback_varyings = transform_feedback_varyings;
359 self
360 }
361
362 pub fn outputs_srgb(mut self, outputs_srgb: bool) -> Self {
364 self.outputs_srgb = outputs_srgb;
365 self
366 }
367
368 pub fn uses_point_size(mut self, uses_point_size: bool) -> Self {
370 self.uses_point_size = uses_point_size;
371 self
372 }
373}
374
375#[derive(Copy, Clone)]
377pub struct SpirvEntryPoint<'a> {
378 pub binary: &'a [u8],
380
381 pub entry_point: &'a str,
383}
384
385pub struct SourceCode<'a> {
387 pub vertex_shader: &'a str,
389
390 pub tessellation_control_shader: Option<&'a str>,
392
393 pub tessellation_evaluation_shader: Option<&'a str>,
395
396 pub geometry_shader: Option<&'a str>,
398
399 pub fragment_shader: &'a str,
401}
402
403impl<'a> From<SourceCode<'a>> for ProgramCreationInput<'a> {
404 #[inline]
405 fn from(code: SourceCode<'a>) -> ProgramCreationInput<'a> {
406 let SourceCode { vertex_shader, fragment_shader, geometry_shader,
407 tessellation_control_shader, tessellation_evaluation_shader } = code;
408
409 ProgramCreationInput::SourceCode {
410 vertex_shader,
411 tessellation_control_shader,
412 tessellation_evaluation_shader,
413 geometry_shader,
414 fragment_shader,
415 transform_feedback_varyings: None,
416 outputs_srgb: true,
417 uses_point_size: false,
418 }
419 }
420}
421
422pub struct Binary {
424 pub format: u32,
426
427 pub content: Vec<u8>,
429}
430
431impl<'a> From<Binary> for ProgramCreationInput<'a> {
432 #[inline]
433 fn from(binary: Binary) -> ProgramCreationInput<'a> {
434 ProgramCreationInput::Binary {
435 data: binary,
436 outputs_srgb: true,
437 uses_point_size: false,
438 }
439 }
440}