1use 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#[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#[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#[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 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 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}