1 //! Raw Pipeline State Objects
2 //!
3 //! This module contains items used to create and manage Pipelines.
4 
5 use crate::{device, pass, Backend};
6 use std::{fmt, io, slice};
7 
8 mod compute;
9 mod descriptor;
10 mod graphics;
11 mod input_assembler;
12 mod output_merger;
13 mod specialization;
14 
15 pub use self::{
16     compute::*,
17     descriptor::*,
18     graphics::*,
19     input_assembler::*,
20     output_merger::*,
21     specialization::*,
22 };
23 
24 /// Error types happening upon PSO creation on the device side.
25 #[derive(Clone, Debug, PartialEq)]
26 pub enum CreationError {
27     /// Unknown other error.
28     Other,
29     /// Invalid subpass (not part of renderpass).
30     InvalidSubpass(pass::SubpassId),
31     /// Shader compilation error.
32     Shader(device::ShaderError),
33     /// Out of either host or device memory.
34     OutOfMemory(device::OutOfMemory),
35 }
36 
37 impl From<device::OutOfMemory> for CreationError {
from(err: device::OutOfMemory) -> Self38     fn from(err: device::OutOfMemory) -> Self {
39         CreationError::OutOfMemory(err)
40     }
41 }
42 
43 bitflags!(
44     /// Stages of the logical pipeline.
45     ///
46     /// The pipeline is structured by the ordering of the flags.
47     /// Some stages are queue type dependent.
48     #[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
49     pub struct PipelineStage: u32 {
50         /// Beginning of the command queue.
51         const TOP_OF_PIPE = 0x1;
52         /// Indirect data consumption.
53         const DRAW_INDIRECT = 0x2;
54         /// Vertex data consumption.
55         const VERTEX_INPUT = 0x4;
56         /// Vertex shader execution.
57         const VERTEX_SHADER = 0x8;
58         /// Hull shader execution.
59         const HULL_SHADER = 0x10;
60         /// Domain shader execution.
61         const DOMAIN_SHADER = 0x20;
62         /// Geometry shader execution.
63         const GEOMETRY_SHADER = 0x40;
64         /// Fragment shader execution.
65         const FRAGMENT_SHADER = 0x80;
66         /// Stage of early depth and stencil test.
67         const EARLY_FRAGMENT_TESTS = 0x100;
68         /// Stage of late depth and stencil test.
69         const LATE_FRAGMENT_TESTS = 0x200;
70         /// Stage of final color value calculation.
71         const COLOR_ATTACHMENT_OUTPUT = 0x400;
72         /// Compute shader execution,
73         const COMPUTE_SHADER = 0x800;
74         /// Copy/Transfer command execution.
75         const TRANSFER = 0x1000;
76         /// End of the command queue.
77         const BOTTOM_OF_PIPE = 0x2000;
78         /// Read/Write access from host.
79         /// (Not a real pipeline stage)
80         const HOST = 0x4000;
81     }
82 );
83 
84 bitflags!(
85     /// Combination of different shader pipeline stages.
86     #[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
87     pub struct ShaderStageFlags: u32 {
88         /// Vertex shader stage.
89         const VERTEX   = 0x1;
90         /// Hull (tessellation) shader stage.
91         const HULL     = 0x2;
92         /// Domain (tessellation) shader stage.
93         const DOMAIN   = 0x4;
94         /// Geometry shader stage.
95         const GEOMETRY = 0x8;
96         /// Fragment shader stage.
97         const FRAGMENT = 0x10;
98         /// Compute shader stage.
99         const COMPUTE  = 0x20;
100         /// All graphics pipeline shader stages.
101         const GRAPHICS = Self::VERTEX.bits | Self::HULL.bits |
102             Self::DOMAIN.bits | Self::GEOMETRY.bits | Self::FRAGMENT.bits;
103         /// All shader stages.
104         const ALL      = Self::GRAPHICS.bits | Self::COMPUTE.bits;
105     }
106 );
107 
108 // Note: this type is only needed for backends, not used anywhere within gfx_hal.
109 /// Which program stage this shader represents.
110 #[allow(missing_docs)]
111 #[derive(Clone, Copy, Debug, Eq, Hash, PartialEq)]
112 #[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
113 #[repr(u8)]
114 pub enum Stage {
115     Vertex,
116     Hull,
117     Domain,
118     Geometry,
119     Fragment,
120     Compute,
121 }
122 
123 impl From<Stage> for ShaderStageFlags {
from(stage: Stage) -> Self124     fn from(stage: Stage) -> Self {
125         match stage {
126             Stage::Vertex => ShaderStageFlags::VERTEX,
127             Stage::Hull => ShaderStageFlags::HULL,
128             Stage::Domain => ShaderStageFlags::DOMAIN,
129             Stage::Geometry => ShaderStageFlags::GEOMETRY,
130             Stage::Fragment => ShaderStageFlags::FRAGMENT,
131             Stage::Compute => ShaderStageFlags::COMPUTE,
132         }
133     }
134 }
135 
136 impl fmt::Display for Stage {
fmt(&self, f: &mut fmt::Formatter) -> fmt::Result137     fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
138         f.write_str(match self {
139             Stage::Vertex => "vertex",
140             Stage::Hull => "hull",
141             Stage::Domain => "domain",
142             Stage::Geometry => "geometry",
143             Stage::Fragment => "fragment",
144             Stage::Compute => "compute",
145         })
146     }
147 }
148 
149 /// Shader entry point.
150 #[derive(Debug)]
151 pub struct EntryPoint<'a, B: Backend> {
152     /// Entry point name.
153     pub entry: &'a str,
154     /// Shader module reference.
155     pub module: &'a B::ShaderModule,
156     /// Specialization.
157     pub specialization: Specialization<'a>,
158 }
159 
160 impl<'a, B: Backend> Clone for EntryPoint<'a, B> {
clone(&self) -> Self161     fn clone(&self) -> Self {
162         EntryPoint {
163             entry: self.entry,
164             module: self.module,
165             specialization: self.specialization.clone(),
166         }
167     }
168 }
169 
170 bitflags!(
171     /// Pipeline creation flags.
172     #[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
173     pub struct PipelineCreationFlags: u32 {
174         /// Disable pipeline optimizations.
175         ///
176         /// May speedup pipeline creation.
177         const DISABLE_OPTIMIZATION = 0x1;
178         /// Allow derivatives (children) of the pipeline.
179         ///
180         /// Must be set when pipelines set the pipeline as base.
181         const ALLOW_DERIVATIVES = 0x2;
182     }
183 );
184 
185 /// A reference to a parent pipeline.  The assumption is that
186 /// a parent and derivative/child pipeline have most settings
187 /// in common, and one may be switched for another more quickly
188 /// than entirely unrelated pipelines would be.
189 #[derive(Debug)]
190 pub enum BasePipeline<'a, P: 'a> {
191     /// Referencing an existing pipeline as parent.
192     Pipeline(&'a P),
193     /// A pipeline in the same create pipelines call.
194     ///
195     /// The index of the parent must be lower than the index of the child.
196     Index(usize),
197     /// No parent pipeline exists.
198     None,
199 }
200 
201 /// Pipeline state which may be static or dynamic.
202 #[derive(Clone, Copy, Debug, Eq, Hash, Ord, PartialEq, PartialOrd)]
203 #[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
204 pub enum State<T> {
205     /// Static state that cannot be altered.
206     Static(T),
207     /// Dynamic state set through a command buffer.
208     Dynamic,
209 }
210 
211 impl<T> State<T> {
212     /// Returns the static value or a default.
static_or(self, default: T) -> T213     pub fn static_or(self, default: T) -> T {
214         match self {
215             State::Static(v) => v,
216             State::Dynamic => default,
217         }
218     }
219 
220     /// Whether the state is static.
is_static(self) -> bool221     pub fn is_static(self) -> bool {
222         match self {
223             State::Static(_) => true,
224             State::Dynamic => false,
225         }
226     }
227 
228     /// Whether the state is dynamic.
is_dynamic(self) -> bool229     pub fn is_dynamic(self) -> bool {
230         !self.is_static()
231     }
232 }
233 
234 
235 /// Safely read SPIR-V
236 ///
237 /// Converts to native endianness and returns correctly aligned storage without unnecessary
238 /// copying. Returns an `InvalidData` error if the input is trivially not SPIR-V.
239 ///
240 /// This function can also be used to convert an already in-memory `&[u8]` to a valid `Vec<u32>`,
241 /// but prefer working with `&[u32]` from the start whenever possible.
242 ///
243 /// # Examples
244 /// ```no_run
245 /// let mut file = std::fs::File::open("/path/to/shader.spv").unwrap();
246 /// let words = gfx_hal::pso::read_spirv(&mut file).unwrap();
247 /// ```
248 /// ```
249 /// const SPIRV: &[u8] = &[
250 ///     0x03, 0x02, 0x23, 0x07, // ...
251 /// ];
252 /// let words = gfx_hal::pso::read_spirv(std::io::Cursor::new(&SPIRV[..])).unwrap();
253 /// ```
read_spirv<R: io::Read + io::Seek>(mut x: R) -> io::Result<Vec<u32>>254 pub fn read_spirv<R: io::Read + io::Seek>(mut x: R) -> io::Result<Vec<u32>> {
255     let size = x.seek(io::SeekFrom::End(0))?;
256     if size % 4 != 0 {
257         return Err(io::Error::new(
258             io::ErrorKind::InvalidData,
259             "input length not divisible by 4",
260         ));
261     }
262     if size > usize::max_value() as u64 {
263         return Err(io::Error::new(io::ErrorKind::InvalidData, "input too long"));
264     }
265     let words = (size / 4) as usize;
266     let mut result = Vec::<u32>::with_capacity(words);
267     x.seek(io::SeekFrom::Start(0))?;
268     unsafe {
269         // Writing all bytes through a pointer with less strict alignment when our type has no
270         // invalid bitpatterns is safe.
271         x.read_exact(slice::from_raw_parts_mut(
272             result.as_mut_ptr() as *mut u8,
273             words * 4,
274         ))?;
275         result.set_len(words);
276     }
277     const MAGIC_NUMBER: u32 = 0x07230203;
278     if result.len() > 0 && result[0] == MAGIC_NUMBER.swap_bytes() {
279         for word in &mut result {
280             *word = word.swap_bytes();
281         }
282     }
283     if result.len() == 0 || result[0] != MAGIC_NUMBER {
284         return Err(io::Error::new(
285             io::ErrorKind::InvalidData,
286             "input missing SPIR-V magic number",
287         ));
288     }
289     Ok(result)
290 }
291