gfx_app/
shade.rs

1// Copyright 2016 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
16use std::error::Error;
17use std::fmt;
18
19pub use gfx_device_gl::Version as GlslVersion;
20#[cfg(target_os = "windows")]
21pub use gfx_device_dx11::ShaderModel as DxShaderModel;
22#[cfg(feature = "metal")]
23pub use gfx_device_metal::ShaderModel as MetalShaderModel;
24/// Shader backend with version numbers.
25#[derive(Copy, Clone, Debug, PartialEq)]
26pub enum Backend {
27    Glsl(GlslVersion),
28    GlslEs(GlslVersion),
29    #[cfg(target_os = "windows")]
30    Hlsl(DxShaderModel),
31    #[cfg(feature = "metal")]
32    Msl(MetalShaderModel),
33    #[cfg(feature = "vulkan")]
34    Vulkan,
35}
36
37pub const EMPTY: &'static [u8] = &[];
38
39/// A type storing shader source for different graphics APIs and versions.
40#[derive(Copy, Clone, PartialEq, Debug)]
41pub struct Source<'a> {
42    pub glsl_120: &'a [u8],
43    pub glsl_130: &'a [u8],
44    pub glsl_140: &'a [u8],
45    pub glsl_150: &'a [u8],
46    pub glsl_400: &'a [u8],
47    pub glsl_430: &'a [u8],
48    pub glsl_es_100: &'a [u8],
49    pub glsl_es_200: &'a [u8],
50    pub glsl_es_300: &'a [u8],
51    pub hlsl_30: &'a [u8],
52    pub hlsl_40: &'a [u8],
53    pub hlsl_41: &'a [u8],
54    pub hlsl_50: &'a [u8],
55    pub msl_10: &'a [u8],
56    pub msl_11: &'a [u8],
57    pub vulkan: &'a [u8],
58}
59
60/// Error selecting a backend.
61#[derive(Clone, Copy, Debug, PartialEq)]
62pub struct SelectError(Backend);
63
64impl fmt::Display for SelectError {
65    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
66        write!(f, "An error occurred when selecting the {:?} backend", self.0)
67    }
68}
69
70impl Error for SelectError {
71    fn description(&self) -> &str {
72        "An error occurred when selecting a backend"
73    }
74}
75
76impl<'a> Source<'a> {
77    /// Create an empty shader source. Useful for specifying the remaining
78    /// structure members upon construction.
79    pub fn empty() -> Source<'a> {
80        Source {
81            glsl_120: EMPTY,
82            glsl_130: EMPTY,
83            glsl_140: EMPTY,
84            glsl_150: EMPTY,
85            glsl_400: EMPTY,
86            glsl_430: EMPTY,
87            glsl_es_100: EMPTY,
88            glsl_es_200: EMPTY,
89            glsl_es_300: EMPTY,
90            hlsl_30: EMPTY,
91            hlsl_40: EMPTY,
92            hlsl_41: EMPTY,
93            hlsl_50: EMPTY,
94            msl_10: EMPTY,
95            msl_11: EMPTY,
96            vulkan: EMPTY,
97        }
98    }
99
100    /// Pick one of the stored versions that is the highest supported by the backend.
101    pub fn select(&self, backend: Backend) -> Result<&'a [u8], SelectError> {
102        Ok(match backend {
103            Backend::Glsl(version) => {
104                let v = version.major * 100 + version.minor;
105                match *self {
106                    Source { glsl_430: s, .. } if s != EMPTY && v >= 430 => s,
107                    Source { glsl_400: s, .. } if s != EMPTY && v >= 400 => s,
108                    Source { glsl_150: s, .. } if s != EMPTY && v >= 150 => s,
109                    Source { glsl_140: s, .. } if s != EMPTY && v >= 140 => s,
110                    Source { glsl_130: s, .. } if s != EMPTY && v >= 130 => s,
111                    Source { glsl_120: s, .. } if s != EMPTY && v >= 120 => s,
112                    _ => return Err(SelectError(backend)),
113                }
114            }
115            Backend::GlslEs(version) => {
116                let v = version.major * 100 + version.minor;
117                match *self {
118                    Source { glsl_es_100: s, .. } if s != EMPTY && v >= 100 => s,
119                    Source { glsl_es_200: s, .. } if s != EMPTY && v >= 200 => s,
120                    Source { glsl_es_300: s, .. } if s != EMPTY && v >= 300 => s,
121                    _ => return Err(SelectError(backend)),
122                }
123            }
124            #[cfg(target_os = "windows")]
125            Backend::Hlsl(model) => {
126                match *self {
127                    Source { hlsl_50: s, .. } if s != EMPTY && model >= 50 => s,
128                    Source { hlsl_41: s, .. } if s != EMPTY && model >= 41 => s,
129                    Source { hlsl_40: s, .. } if s != EMPTY && model >= 40 => s,
130                    Source { hlsl_30: s, .. } if s != EMPTY && model >= 30 => s,
131                    _ => return Err(SelectError(backend)),
132                }
133            }
134            #[cfg(feature = "metal")]
135            Backend::Msl(revision) => {
136                match *self {
137                    Source { msl_11: s, .. } if s != EMPTY && revision >= 11 => s,
138                    Source { msl_10: s, .. } if s != EMPTY && revision >= 10 => s,
139                    _ => return Err(SelectError(backend)),
140                }
141            }
142            #[cfg(feature = "vulkan")]
143            Backend::Vulkan => {
144                match *self {
145                    Source { vulkan: s, .. } if s != EMPTY => s,
146                    _ => return Err(SelectError(backend)),
147                }
148            }
149        })
150    }
151}