[go: up one dir, main page]

gfx_core/
shade.rs

1// Copyright 2014 The Gfx-rs Developers.
2//
3// Licensed under the Apache License, Version 2.0 (the "License");
4// you may not use this file except in compliance with the License.
5// You may obtain a copy of the License at
6//
7//     http://www.apache.org/licenses/LICENSE-2.0
8//
9// Unless required by applicable law or agreed to in writing, software
10// distributed under the License is distributed on an "AS IS" BASIS,
11// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12// See the License for the specific language governing permissions and
13// limitations under the License.
14
15//! Shader handling.
16
17#![allow(missing_docs)]
18
19use std::{fmt, cmp, hash};
20use std::error::Error;
21use {Resources};
22use {AttributeSlot, ColorSlot, ConstantBufferSlot, ResourceViewSlot, SamplerSlot, UnorderedViewSlot};
23
24#[cfg(feature = "mint")]
25use mint;
26
27/// Number of components in a container type (vectors/matrices)
28pub type Dimension = u8;
29
30/// Whether the sampler samples an array texture.
31#[derive(Clone, Copy, Debug, Eq, Hash, PartialEq)]
32#[cfg_attr(feature = "serialize", derive(Serialize, Deserialize))]
33pub enum IsArray { Array, NoArray }
34
35/// Whether the sampler compares the depth value upon sampling.
36#[derive(Clone, Copy, Debug, Eq, Hash, PartialEq)]
37#[cfg_attr(feature = "serialize", derive(Serialize, Deserialize))]
38pub enum IsComparison { Compare, NoCompare }
39
40/// Whether the sampler samples a multisample texture.
41#[derive(Clone, Copy, Debug, Eq, Hash, PartialEq)]
42#[cfg_attr(feature = "serialize", derive(Serialize, Deserialize))]
43pub enum IsMultiSample { MultiSample, NoMultiSample }
44
45/// Whether the sampler samples a rectangle texture.
46///
47/// Rectangle textures are the same as 2D textures, but accessed with absolute texture coordinates
48/// (as opposed to the usual, normalized to [0, 1]).
49#[derive(Clone, Copy, Debug, Eq, Hash, PartialEq)]
50#[cfg_attr(feature = "serialize", derive(Serialize, Deserialize))]
51pub enum IsRect { Rect, NoRect }
52
53/// Whether the matrix is column or row major.
54#[derive(Clone, Copy, Debug, Eq, Hash, PartialEq)]
55#[cfg_attr(feature = "serialize", derive(Serialize, Deserialize))]
56pub enum MatrixFormat { ColumnMajor, RowMajor }
57
58/// A type of the texture variable.
59/// This has to match the actual data we bind to the shader.
60#[derive(Clone, Copy, Debug, Eq, Hash, PartialEq)]
61#[cfg_attr(feature = "serialize", derive(Serialize, Deserialize))]
62pub enum TextureType {
63    /// Sample from a buffer.
64    Buffer,
65    /// Sample from a 1D texture
66    D1(IsArray),
67    /// Sample from a 2D texture
68    D2(IsArray, IsMultiSample),
69    /// Sample from a 3D texture
70    D3,
71    /// Sample from a cubemap.
72    Cube(IsArray),
73}
74
75impl TextureType {
76    /// Check if this texture can be used with a sampler.
77    pub fn can_sample(&self) -> bool {
78        match self {
79            &TextureType::Buffer => false,
80            &TextureType::D1(_) => true,
81            &TextureType::D2(_, IsMultiSample::MultiSample) => false,
82            &TextureType::D2(_, IsMultiSample::NoMultiSample) => true,
83            &TextureType::D3 => true,
84            &TextureType::Cube(_) => true,
85        }
86    }
87}
88
89/// A type of the sampler variable.
90#[derive(Clone, Copy, Debug, Eq, Hash, PartialEq)]
91#[cfg_attr(feature = "serialize", derive(Serialize, Deserialize))]
92pub struct SamplerType(pub IsComparison, pub IsRect);
93
94/// Base type of this shader parameter.
95#[allow(missing_docs)]
96#[derive(Clone, Copy, Debug, Eq, Hash, PartialEq)]
97#[cfg_attr(feature = "serialize", derive(Serialize, Deserialize))]
98pub enum BaseType {
99    I32,
100    U32,
101    F32,
102    F64,
103    Bool,
104}
105
106/// Number of components this parameter represents.
107#[derive(Clone, Copy, Debug, Eq, Hash, PartialEq)]
108#[cfg_attr(feature = "serialize", derive(Serialize, Deserialize))]
109pub enum ContainerType {
110    /// Scalar value
111    Single,
112    /// A vector with `Dimension` components.
113    Vector(Dimension),
114    /// A matrix.
115    Matrix(MatrixFormat, Dimension, Dimension),
116}
117
118// Describing object data
119
120/// Which program stage this shader represents.
121#[allow(missing_docs)]
122#[derive(Clone, Copy, Debug, Eq, Hash, PartialEq)]
123#[cfg_attr(feature = "serialize", derive(Serialize, Deserialize))]
124#[repr(u8)]
125pub enum Stage {
126    Vertex,
127    Hull,
128    Domain,
129    Geometry,
130    Pixel,
131}
132
133/// A constant static array of all shader stages.
134pub const STAGES: [Stage; 5] = [Stage::Vertex, Stage::Hull, Stage::Domain, Stage::Geometry, Stage::Pixel];
135
136// Describing program data
137
138/// Location of a parameter in the program.
139pub type Location = usize;
140
141// unable to derive anything for fixed arrays
142/// A value that can be uploaded to the device as a uniform.
143#[allow(missing_docs)]
144#[derive(Clone, Copy, PartialEq, PartialOrd)]
145#[cfg_attr(feature = "serialize", derive(Serialize, Deserialize))]
146pub enum UniformValue {
147    I32(i32),
148    U32(u32),
149    F32(f32),
150
151    I32Vector2([i32; 2]),
152    I32Vector3([i32; 3]),
153    I32Vector4([i32; 4]),
154
155    U32Vector2([u32; 2]),
156    U32Vector3([u32; 3]),
157    U32Vector4([u32; 4]),
158
159    F32Vector2([f32; 2]),
160    F32Vector3([f32; 3]),
161    F32Vector4([f32; 4]),
162
163    F32Matrix2([[f32; 2]; 2]),
164    F32Matrix3([[f32; 3]; 3]),
165    F32Matrix4([[f32; 4]; 4]),
166}
167
168impl fmt::Debug for UniformValue {
169    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
170        match *self {
171            UniformValue::I32(x)            => write!(f, "ValueI32({:?})", x),
172            UniformValue::U32(x)            => write!(f, "ValueU32({:?})", x),
173            UniformValue::F32(x)            => write!(f, "ValueF32({:?})", x),
174
175            UniformValue::I32Vector2(ref v) => write!(f, "ValueI32Vector2({:?})", &v[..]),
176            UniformValue::I32Vector3(ref v) => write!(f, "ValueI32Vector3({:?})", &v[..]),
177            UniformValue::I32Vector4(ref v) => write!(f, "ValueI32Vector4({:?})", &v[..]),
178
179            UniformValue::U32Vector2(ref v) => write!(f, "ValueU32Vector2({:?})", &v[..]),
180            UniformValue::U32Vector3(ref v) => write!(f, "ValueU32Vector3({:?})", &v[..]),
181            UniformValue::U32Vector4(ref v) => write!(f, "ValueU32Vector4({:?})", &v[..]),
182
183            UniformValue::F32Vector2(ref v) => write!(f, "ValueF32Vector2({:?})", &v[..]),
184            UniformValue::F32Vector3(ref v) => write!(f, "ValueF32Vector3({:?})", &v[..]),
185            UniformValue::F32Vector4(ref v) => write!(f, "ValueF32Vector4({:?})", &v[..]),
186
187            UniformValue::F32Matrix2(ref m) => {
188                try!(write!(f, "ValueF32Matrix2("));
189                for v in m.iter() {
190                    try!(write!(f, "{:?}", &v[..]));
191                }
192                write!(f, ")")
193            },
194            UniformValue::F32Matrix3(ref m) => {
195                try!(write!(f, "ValueF32Matrix3("));
196                for v in m.iter() {
197                    try!(write!(f, "{:?}", &v[..]));
198                }
199                write!(f, ")")
200            },
201            UniformValue::F32Matrix4(ref m) => {
202                try!(write!(f, "ValueF32Matrix4("));
203                for v in m.iter() {
204                    try!(write!(f, "{:?}", &v[..]));
205                }
206                write!(f, ")")
207            },
208        }
209    }
210}
211
212/// Format of a shader constant.
213pub type ConstFormat = (BaseType, ContainerType);
214
215/// A trait that statically links simple data types to
216/// base types of the shader constants.
217pub trait BaseTyped {
218    fn get_base_type() -> BaseType;
219}
220
221/// A trait that statically links simple data types to
222/// constant formats.
223pub trait Formatted {
224    /// Get the associated constant format.
225    fn get_format() -> ConstFormat;
226}
227
228macro_rules! impl_base_type {
229    ( $($name:ty = $value:ident ,)* ) => {
230        $(
231            impl BaseTyped for $name {
232                fn get_base_type() -> BaseType {
233                    BaseType::$value
234                }
235            }
236        )*
237    }
238}
239
240macro_rules! impl_const_vector {
241    ( $( $num:expr ),* ) => {
242        $(
243            impl<T: BaseTyped> Formatted for [T; $num] {
244                fn get_format() -> ConstFormat {
245                    (T::get_base_type(), ContainerType::Vector($num))
246                }
247            }
248        )*
249    }
250}
251
252macro_rules! impl_const_matrix {
253    ( $( [$n:expr, $m:expr] ),* ) => {
254        $(
255            impl<T: BaseTyped> Formatted for [[T; $n]; $m] {
256                fn get_format() -> ConstFormat {
257                    let mf = MatrixFormat::ColumnMajor;
258                    (T::get_base_type(), ContainerType::Matrix(mf, $n, $m))
259                }
260            }
261        )*
262    }
263}
264
265#[cfg(feature = "mint")]
266macro_rules! impl_const_vector_mint {
267    ( $( $name:ident = $num:expr, )* ) => {
268        $(
269            impl<T: BaseTyped> Formatted for mint::$name<T> {
270                fn get_format() -> ConstFormat {
271                    (T::get_base_type(), ContainerType::Vector($num))
272                }
273            }
274        )*
275    }
276}
277
278#[cfg(feature = "mint")]
279macro_rules! impl_const_matrix_mint {
280    ( $( $name:ident = $format:ident $size:expr, )* ) => {
281        $(
282            impl<T: BaseTyped> Formatted for mint::$name<T> {
283                fn get_format() -> ConstFormat {
284                    let mf = MatrixFormat::$format;
285                    (T::get_base_type(), ContainerType::Matrix(mf, $size, $size))
286                }
287            }
288        )*
289    }
290}
291
292impl_base_type! {
293    i32 = I32,
294    u32 = U32,
295    f32 = F32,
296    f64 = F64,
297    bool = Bool,
298}
299
300impl<T: BaseTyped> Formatted for T {
301    fn get_format() -> ConstFormat {
302        (T::get_base_type(), ContainerType::Single)
303    }
304}
305
306impl_const_vector!(2, 3, 4);
307impl_const_matrix!([2,2], [3,3], [4,4], [4,3]);
308
309#[cfg(feature = "mint")]
310impl_const_vector_mint! {
311    Point2 = 2,
312    Point3 = 3,
313    Vector2 = 2,
314    Vector3 = 3,
315    Vector4 = 4,
316}
317
318#[cfg(feature = "mint")]
319impl_const_matrix_mint! {
320    ColumnMatrix2 = ColumnMajor 2,
321    ColumnMatrix3 = ColumnMajor 3,
322    ColumnMatrix4 = ColumnMajor 4,
323    RowMatrix2 = RowMajor 2,
324    RowMatrix3 = RowMajor 3,
325    RowMatrix4 = RowMajor 4,
326}
327
328bitflags!(
329    /// Parameter usage flags.
330    #[cfg_attr(feature = "serialize", derive(Serialize, Deserialize))]
331    pub struct Usage: u8 {
332        /// Used by the vertex shader
333        const VERTEX   = 0x1;
334        /// Used by the geometry shader
335        const GEOMETRY = 0x2;
336        /// Used by the pixel shader
337        const PIXEL    = 0x4;
338        /// Used by the hull shader
339        const HULL     = 0x8;
340        /// Used by the pixel shader
341        const DOMAIN   = 0x16;
342    }
343);
344
345impl From<Stage> for Usage {
346    fn from(stage: Stage) -> Self {
347        match stage {
348            Stage::Vertex => Self::VERTEX,
349            Stage::Geometry => Self::GEOMETRY,
350            Stage::Pixel => Self::PIXEL,
351            Stage::Hull => Self::HULL,
352            Stage::Domain => Self::DOMAIN,
353        }
354    }
355}
356
357/// Vertex information that a shader takes as input.
358#[derive(Clone, Debug, Eq, Hash, PartialEq)]
359#[cfg_attr(feature = "serialize", derive(Serialize, Deserialize))]
360pub struct AttributeVar {
361    /// Name of this attribute.
362    pub name: String,
363    /// Slot of the vertex attribute.
364    pub slot: AttributeSlot,
365    /// Type that this attribute is composed of.
366    pub base_type: BaseType,
367    /// "Scalarness" of this attribute.
368    pub container: ContainerType,
369}
370
371/// A constant in the shader - a bit of data that doesn't vary
372// between the shader execution units (vertices/pixels/etc).
373#[derive(Clone, Debug, Eq, Hash, PartialEq)]
374#[cfg_attr(feature = "serialize", derive(Serialize, Deserialize))]
375pub struct ConstVar {
376    /// Name of this constant.
377    pub name: String,
378    /// Location of this constant in the program.
379    /// For constant buffer elements, it's the offset in bytes.
380    pub location: Location,
381    /// Number of elements this constant represents.
382    pub count: usize,
383    /// Type that this constant is composed of
384    pub base_type: BaseType,
385    /// "Scalarness" of this constant.
386    pub container: ContainerType,
387}
388
389/// A constant buffer.
390#[derive(Clone, Debug, Eq, Hash, PartialEq)]
391#[cfg_attr(feature = "serialize", derive(Serialize, Deserialize))]
392pub struct ConstantBufferVar {
393    /// Name of this constant buffer.
394    pub name: String,
395    /// Slot of the constant buffer.
396    pub slot: ConstantBufferSlot,
397    /// Size (in bytes) of this buffer's data.
398    pub size: usize,
399    /// What program stage this buffer is used in.
400    pub usage: Usage,
401    /// List of individual elements in this buffer.
402    pub elements: Vec<ConstVar>,
403}
404
405/// Texture shader parameter.
406#[derive(Clone, Debug, Eq, Hash, PartialEq)]
407#[cfg_attr(feature = "serialize", derive(Serialize, Deserialize))]
408pub struct TextureVar {
409    /// Name of this texture variable.
410    pub name: String,
411    /// Slot of this texture variable.
412    pub slot: ResourceViewSlot,
413    /// Base type for the texture.
414    pub base_type: BaseType,
415    /// Type of this texture.
416    pub ty: TextureType,
417    /// What program stage this texture is used in.
418    pub usage: Usage,
419}
420
421/// Unordered access shader parameter.
422#[derive(Clone, Debug, Eq, Hash, PartialEq)]
423#[cfg_attr(feature = "serialize", derive(Serialize, Deserialize))]
424pub struct UnorderedVar {
425    /// Name of this unordered variable.
426    pub name: String,
427    /// Slot of this unordered variable.
428    pub slot: UnorderedViewSlot,
429    /// What program stage this UAV is used in.
430    pub usage: Usage,
431}
432
433/// Sampler shader parameter.
434#[derive(Clone, Debug, Eq, Hash, PartialEq)]
435#[cfg_attr(feature = "serialize", derive(Serialize, Deserialize))]
436pub struct SamplerVar {
437    /// Name of this sampler variable.
438    pub name: String,
439    /// Slot of this sampler variable.
440    pub slot: SamplerSlot,
441    /// Type of this sampler.
442    pub ty: SamplerType,
443    /// What program stage this texture is used in.
444    pub usage: Usage,
445}
446
447/// Target output variable.
448#[derive(Clone, Debug, Eq, Hash, PartialEq)]
449#[cfg_attr(feature = "serialize", derive(Serialize, Deserialize))]
450pub struct OutputVar {
451    /// Name of this output variable.
452    pub name: String,
453    /// Output color target index.
454    pub slot: ColorSlot,
455    /// Type of the output component.
456    pub base_type: BaseType,
457    /// "Scalarness" of this output.
458    pub container: ContainerType,
459}
460
461/// Metadata about a program.
462#[derive(Clone, Debug, Eq, Hash, PartialEq)]
463#[cfg_attr(feature = "serialize", derive(Serialize, Deserialize))]
464pub struct ProgramInfo {
465    /// Attributes in the program
466    pub vertex_attributes: Vec<AttributeVar>,
467    /// Global constants in the program
468    pub globals: Vec<ConstVar>,
469    /// Constant buffers in the program
470    pub constant_buffers: Vec<ConstantBufferVar>,
471    /// Textures in the program
472    pub textures: Vec<TextureVar>,
473    /// Unordered access resources in the program
474    pub unordereds: Vec<UnorderedVar>,
475    /// Samplers in the program
476    pub samplers: Vec<SamplerVar>,
477    /// Output targets in the program
478    pub outputs: Vec<OutputVar>,
479    /// A flag indicating that the pixel shader manually assigns the depth.
480    pub output_depth: bool,
481    /// A hacky flag to make sure the clients know we are
482    /// unable to actually get the output variable info
483    pub knows_outputs: bool,
484}
485
486/// A program
487#[derive(Debug)]
488pub struct Program<R: Resources> {
489    resource: R::Program,
490    info: ProgramInfo,
491}
492
493impl<R: Resources> Program<R> {
494    #[doc(hidden)]
495    pub fn new(resource: R::Program, info: ProgramInfo) -> Self {
496        Program {
497            resource: resource,
498            info: info,
499        }
500    }
501
502    #[doc(hidden)]
503    pub fn resource(&self) -> &R::Program { &self.resource }
504
505    /// Get program info
506    pub fn get_info(&self) -> &ProgramInfo { &self.info }
507}
508
509impl<R: Resources + cmp::PartialEq> cmp::PartialEq for Program<R> {
510    fn eq(&self, other: &Program<R>) -> bool {
511        self.resource().eq(other.resource())
512    }
513}
514
515impl<R: Resources + cmp::Eq> cmp::Eq for Program<R> {}
516
517impl<R: Resources + hash::Hash> hash::Hash for Program<R> {
518    fn hash<H>(&self, state: &mut H) where H: hash::Hasher {
519        self.resource().hash(state);
520    }
521}
522
523/// Error type for trying to store a UniformValue in a ConstVar.
524#[derive(Clone, Copy, Debug, Eq, PartialEq)]
525pub enum CompatibilityError {
526    /// Array sizes differ between the value and the var (trying to upload a vec2 as a vec4, etc)
527    ErrorArraySize,
528    /// Base types differ between the value and the var (trying to upload a f32 as a u16, etc)
529    ErrorBaseType,
530    /// Container-ness differs between the value and the var (trying to upload a scalar as a vec4,
531    /// etc)
532    ErrorContainer,
533}
534
535impl fmt::Display for CompatibilityError {
536    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
537        write!(f, "{}", self.description())
538    }
539}
540
541impl Error for CompatibilityError {
542    fn description(&self) -> &str {
543        match *self {
544            CompatibilityError::ErrorArraySize =>
545                "Array sizes differ between the value and the var \
546                 (trying to upload a vec2 as a vec4, etc)",
547            CompatibilityError::ErrorBaseType =>
548                "Base types differ between the value and the var \
549                 (trying to upload a f32 as a u16, etc)",
550            CompatibilityError::ErrorContainer =>
551                "Container-ness differs between the value and the var \
552                 (trying to upload a scalar as a vec4, etc)",
553        }
554    }
555}
556
557impl ConstVar {
558    /// Whether a value is compatible with this variable. That is, whether the value can be stored
559    /// in this variable.
560    pub fn is_compatible(&self, value: &UniformValue) -> Result<(), CompatibilityError> {
561        if self.count != 1 {
562            return Err(CompatibilityError::ErrorArraySize)
563        }
564        match (self.base_type, self.container, *value) {
565            (BaseType::I32, ContainerType::Single,         UniformValue::I32(_))        => Ok(()),
566            (BaseType::U32, ContainerType::Single,         UniformValue::U32(_))        => Ok(()),
567            (BaseType::F32, ContainerType::Single,         UniformValue::F32(_))        => Ok(()),
568
569            (BaseType::I32, ContainerType::Vector(2),      UniformValue::I32Vector2(_)) => Ok(()),
570            (BaseType::I32, ContainerType::Vector(3),      UniformValue::I32Vector3(_)) => Ok(()),
571            (BaseType::I32, ContainerType::Vector(4),      UniformValue::I32Vector4(_)) => Ok(()),
572
573            (BaseType::U32, ContainerType::Vector(2),      UniformValue::U32Vector2(_)) => Ok(()),
574            (BaseType::U32, ContainerType::Vector(3),      UniformValue::U32Vector3(_)) => Ok(()),
575            (BaseType::U32, ContainerType::Vector(4),      UniformValue::U32Vector4(_)) => Ok(()),
576
577            (BaseType::F32, ContainerType::Vector(2),      UniformValue::F32Vector2(_)) => Ok(()),
578            (BaseType::F32, ContainerType::Vector(3),      UniformValue::F32Vector3(_)) => Ok(()),
579            (BaseType::F32, ContainerType::Vector(4),      UniformValue::F32Vector4(_)) => Ok(()),
580
581            (BaseType::F32, ContainerType::Matrix(_, 2,2), UniformValue::F32Matrix2(_)) => Ok(()),
582            (BaseType::F32, ContainerType::Matrix(_, 3,3), UniformValue::F32Matrix3(_)) => Ok(()),
583            (BaseType::F32, ContainerType::Matrix(_, 4,4), UniformValue::F32Matrix4(_)) => Ok(()),
584
585            _ => Err(CompatibilityError::ErrorBaseType)
586        }
587    }
588}
589
590/// An error type for creating shaders.
591#[derive(Clone, Debug, PartialEq)]
592pub enum CreateShaderError {
593    /// The device does not support the requested shader model.
594    ModelNotSupported,
595    /// The device does not support the shader stage.
596    StageNotSupported(Stage),
597    /// The shader failed to compile.
598    CompilationFailed(String),
599}
600
601impl fmt::Display for CreateShaderError {
602    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
603        let desc = self.description();
604        match *self {
605            CreateShaderError::StageNotSupported(ref stage) => write!(f, "{}: {:?}", desc, stage),
606            CreateShaderError::CompilationFailed(ref string) => write!(f, "{}: {}", desc, string),
607            _ => write!(f, "{}", desc),
608        }
609    }
610}
611
612impl Error for CreateShaderError {
613    fn description(&self) -> &str {
614        match *self {
615            CreateShaderError::ModelNotSupported => "The device does not support the requested shader model",
616            CreateShaderError::StageNotSupported(_) => "The device does not support the shader stage",
617            CreateShaderError::CompilationFailed(_) => "The shader failed to compile",
618        }
619    }
620}
621
622/// An error type for creating programs.
623#[derive(Clone, Debug, Eq, PartialEq)]
624pub struct CreateProgramError(String);
625
626impl fmt::Display for CreateProgramError {
627    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
628        f.pad(&self.0)
629    }
630}
631
632impl Error for CreateProgramError {
633    fn description(&self) -> &str {
634        &self.0
635    }
636}
637
638impl<S: Into<String>> From<S> for CreateProgramError {
639    fn from(s: S) -> CreateProgramError {
640        CreateProgramError(s.into())
641    }
642}