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