1 // Copyright (c) 2017 The vulkano developers
2 // Licensed under the Apache License, Version 2.0
3 // <LICENSE-APACHE or
4 // https://www.apache.org/licenses/LICENSE-2.0> or the MIT
5 // license <LICENSE-MIT or https://opensource.org/licenses/MIT>,
6 // at your option. All files in the project carrying such
7 // notice may not be copied, modified, or distributed except
8 // according to those terms.
9 
10 //! A pipeline that performs graphics processing operations.
11 //!
12 //! Unlike a compute pipeline, which performs general-purpose work, a graphics pipeline is geared
13 //! specifically towards doing graphical processing. To that end, it consists of several shaders,
14 //! with additional state and glue logic in between.
15 //!
16 //! A graphics pipeline performs many separate steps, that execute more or less in sequence.
17 //! Due to the parallel nature of a GPU, no strict ordering guarantees may exist.
18 //!
19 //! 1. Vertex input and assembly: vertex input data is read from data buffers and then assembled
20 //!    into primitives (points, lines, triangles etc.).
21 //! 2. Vertex shader invocations: the vertex data of each primitive is fed as input to the vertex
22 //!    shader, which performs transformations on the data and generates new data as output.
23 //! 3. (Optional) Tessellation: primitives are subdivided by the operations of two shaders, the
24 //!    tessellation control and tessellation evaluation shaders. The control shader produces the
25 //!    tessellation level to apply for the primitive, while the evaluation shader postprocesses the
26 //!    newly created vertices.
27 //! 4. (Optional) Geometry shading: whole primitives are fed as input and processed into a new set
28 //!    of output primitives.
29 //! 5. Vertex post-processing, including:
30 //!    - Clipping primitives to the view frustum and user-defined clipping planes.
31 //!    - Perspective division.
32 //!    - Viewport mapping.
33 //! 6. Rasterization: converting primitives into a two-dimensional representation. Primitives may be
34 //!    discarded depending on their orientation, and are then converted into a collection of
35 //!    fragments that are processed further.
36 //! 7. Fragment operations. These include invocations of the fragment shader, which generates the
37 //!    values to be written to the color attachment. Various testing and discarding operations can
38 //!    be performed both before and after the fragment shader ("early" and "late" fragment tests),
39 //!    including:
40 //!    - Discard rectangle test
41 //!    - Scissor test
42 //!    - Sample mask test
43 //!    - Depth bounds test
44 //!    - Stencil test
45 //!    - Depth test
46 //! 8. Color attachment output: the final pixel data is written to a framebuffer. Blending and
47 //!    logical operations can be applied to combine incoming pixel data with data already present
48 //!    in the framebuffer.
49 //!
50 //! A graphics pipeline contains many configuration options, which are grouped into collections of
51 //! "state". Often, these directly correspond to one or more steps in the graphics pipeline. Each
52 //! state collection has a dedicated submodule.
53 //!
54 //! Once a graphics pipeline has been created, you can execute it by first *binding* it in a command
55 //! buffer, binding the necessary vertex buffers, binding any descriptor sets, setting push
56 //! constants, and setting any dynamic state that the pipeline may need. Then you issue a `draw`
57 //! command.
58 
59 pub use self::{builder::GraphicsPipelineBuilder, creation_error::GraphicsPipelineCreationError};
60 use self::{
61     color_blend::ColorBlendState, depth_stencil::DepthStencilState,
62     discard_rectangle::DiscardRectangleState, input_assembly::InputAssemblyState,
63     multisample::MultisampleState, rasterization::RasterizationState,
64     render_pass::PipelineRenderPassType, tessellation::TessellationState,
65     vertex_input::VertexInputState, viewport::ViewportState,
66 };
67 use super::{DynamicState, Pipeline, PipelineBindPoint, PipelineLayout};
68 use crate::{
69     device::{Device, DeviceOwned},
70     macros::impl_id_counter,
71     shader::{DescriptorBindingRequirements, FragmentTestsStages, ShaderStage},
72     VulkanObject,
73 };
74 use ahash::HashMap;
75 use std::{
76     fmt::{Debug, Error as FmtError, Formatter},
77     num::NonZeroU64,
78     ptr,
79     sync::Arc,
80 };
81 
82 mod builder;
83 pub mod color_blend;
84 mod creation_error;
85 pub mod depth_stencil;
86 pub mod discard_rectangle;
87 pub mod input_assembly;
88 pub mod multisample;
89 pub mod rasterization;
90 pub mod render_pass;
91 pub mod tessellation;
92 pub mod vertex_input;
93 pub mod viewport;
94 // FIXME: restore
95 //mod tests;
96 
97 /// Defines how the implementation should perform a draw operation.
98 ///
99 /// This object contains the shaders and the various fixed states that describe how the
100 /// implementation should perform the various operations needed by a draw command.
101 pub struct GraphicsPipeline {
102     handle: ash::vk::Pipeline,
103     device: Arc<Device>,
104     id: NonZeroU64,
105     layout: Arc<PipelineLayout>,
106     render_pass: PipelineRenderPassType,
107 
108     // TODO: replace () with an object that describes the shaders in some way.
109     shaders: HashMap<ShaderStage, ()>,
110     descriptor_binding_requirements: HashMap<(u32, u32), DescriptorBindingRequirements>,
111     num_used_descriptor_sets: u32,
112     fragment_tests_stages: Option<FragmentTestsStages>,
113 
114     vertex_input_state: VertexInputState,
115     input_assembly_state: InputAssemblyState,
116     tessellation_state: Option<TessellationState>,
117     viewport_state: Option<ViewportState>,
118     discard_rectangle_state: Option<DiscardRectangleState>,
119     rasterization_state: RasterizationState,
120     multisample_state: Option<MultisampleState>,
121     depth_stencil_state: Option<DepthStencilState>,
122     color_blend_state: Option<ColorBlendState>,
123     dynamic_state: HashMap<DynamicState, bool>,
124 }
125 
126 impl GraphicsPipeline {
127     /// Starts the building process of a graphics pipeline. Returns a builder object that you can
128     /// fill with the various parameters.
129     #[inline]
start() -> GraphicsPipelineBuilder< 'static, 'static, 'static, 'static, 'static, VertexInputState, (), (), (), (), (), >130     pub fn start() -> GraphicsPipelineBuilder<
131         'static,
132         'static,
133         'static,
134         'static,
135         'static,
136         VertexInputState,
137         (),
138         (),
139         (),
140         (),
141         (),
142     > {
143         GraphicsPipelineBuilder::new()
144     }
145 
146     /// Returns the device used to create this pipeline.
147     #[inline]
device(&self) -> &Arc<Device>148     pub fn device(&self) -> &Arc<Device> {
149         &self.device
150     }
151 
152     /// Returns the render pass this graphics pipeline is rendering to.
153     #[inline]
render_pass(&self) -> &PipelineRenderPassType154     pub fn render_pass(&self) -> &PipelineRenderPassType {
155         &self.render_pass
156     }
157 
158     /// Returns information about a particular shader.
159     ///
160     /// `None` is returned if the pipeline does not contain this shader.
161     ///
162     /// Compatibility note: `()` is temporary, it will be replaced with something else in the
163     /// future.
164     // TODO: ^ implement and make this public
165     #[inline]
shader(&self, stage: ShaderStage) -> Option<()>166     pub(crate) fn shader(&self, stage: ShaderStage) -> Option<()> {
167         self.shaders.get(&stage).copied()
168     }
169 
170     /// Returns the vertex input state used to create this pipeline.
171     #[inline]
vertex_input_state(&self) -> &VertexInputState172     pub fn vertex_input_state(&self) -> &VertexInputState {
173         &self.vertex_input_state
174     }
175 
176     /// Returns the input assembly state used to create this pipeline.
177     #[inline]
input_assembly_state(&self) -> &InputAssemblyState178     pub fn input_assembly_state(&self) -> &InputAssemblyState {
179         &self.input_assembly_state
180     }
181 
182     /// Returns the tessellation state used to create this pipeline.
183     #[inline]
tessellation_state(&self) -> Option<&TessellationState>184     pub fn tessellation_state(&self) -> Option<&TessellationState> {
185         self.tessellation_state.as_ref()
186     }
187 
188     /// Returns the viewport state used to create this pipeline.
189     #[inline]
viewport_state(&self) -> Option<&ViewportState>190     pub fn viewport_state(&self) -> Option<&ViewportState> {
191         self.viewport_state.as_ref()
192     }
193 
194     /// Returns the discard rectangle state used to create this pipeline.
195     #[inline]
discard_rectangle_state(&self) -> Option<&DiscardRectangleState>196     pub fn discard_rectangle_state(&self) -> Option<&DiscardRectangleState> {
197         self.discard_rectangle_state.as_ref()
198     }
199 
200     /// Returns the rasterization state used to create this pipeline.
201     #[inline]
rasterization_state(&self) -> &RasterizationState202     pub fn rasterization_state(&self) -> &RasterizationState {
203         &self.rasterization_state
204     }
205 
206     /// Returns the multisample state used to create this pipeline.
207     #[inline]
multisample_state(&self) -> Option<&MultisampleState>208     pub fn multisample_state(&self) -> Option<&MultisampleState> {
209         self.multisample_state.as_ref()
210     }
211 
212     /// Returns the depth/stencil state used to create this pipeline.
213     #[inline]
depth_stencil_state(&self) -> Option<&DepthStencilState>214     pub fn depth_stencil_state(&self) -> Option<&DepthStencilState> {
215         self.depth_stencil_state.as_ref()
216     }
217 
218     /// Returns the color blend state used to create this pipeline.
219     #[inline]
color_blend_state(&self) -> Option<&ColorBlendState>220     pub fn color_blend_state(&self) -> Option<&ColorBlendState> {
221         self.color_blend_state.as_ref()
222     }
223 
224     /// Returns whether a particular state is must be dynamically set.
225     ///
226     /// `None` is returned if the pipeline does not contain this state. Previously set dynamic
227     /// state is not disturbed when binding it.
228     #[inline]
dynamic_state(&self, state: DynamicState) -> Option<bool>229     pub fn dynamic_state(&self, state: DynamicState) -> Option<bool> {
230         self.dynamic_state.get(&state).copied()
231     }
232 
233     /// Returns all potentially dynamic states in the pipeline, and whether they are dynamic or not.
234     #[inline]
dynamic_states(&self) -> impl ExactSizeIterator<Item = (DynamicState, bool)> + '_235     pub fn dynamic_states(&self) -> impl ExactSizeIterator<Item = (DynamicState, bool)> + '_ {
236         self.dynamic_state.iter().map(|(k, v)| (*k, *v))
237     }
238 
239     /// If the pipeline has a fragment shader, returns the fragment tests stages used.
240     #[inline]
fragment_tests_stages(&self) -> Option<FragmentTestsStages>241     pub fn fragment_tests_stages(&self) -> Option<FragmentTestsStages> {
242         self.fragment_tests_stages
243     }
244 }
245 
246 impl Pipeline for GraphicsPipeline {
247     #[inline]
bind_point(&self) -> PipelineBindPoint248     fn bind_point(&self) -> PipelineBindPoint {
249         PipelineBindPoint::Graphics
250     }
251 
252     #[inline]
layout(&self) -> &Arc<PipelineLayout>253     fn layout(&self) -> &Arc<PipelineLayout> {
254         &self.layout
255     }
256 
257     #[inline]
num_used_descriptor_sets(&self) -> u32258     fn num_used_descriptor_sets(&self) -> u32 {
259         self.num_used_descriptor_sets
260     }
261 
262     #[inline]
descriptor_binding_requirements( &self, ) -> &HashMap<(u32, u32), DescriptorBindingRequirements>263     fn descriptor_binding_requirements(
264         &self,
265     ) -> &HashMap<(u32, u32), DescriptorBindingRequirements> {
266         &self.descriptor_binding_requirements
267     }
268 }
269 
270 unsafe impl DeviceOwned for GraphicsPipeline {
271     #[inline]
device(&self) -> &Arc<Device>272     fn device(&self) -> &Arc<Device> {
273         &self.device
274     }
275 }
276 
277 impl Debug for GraphicsPipeline {
fmt(&self, f: &mut Formatter<'_>) -> Result<(), FmtError>278     fn fmt(&self, f: &mut Formatter<'_>) -> Result<(), FmtError> {
279         write!(f, "<Vulkan graphics pipeline {:?}>", self.handle)
280     }
281 }
282 
283 unsafe impl VulkanObject for GraphicsPipeline {
284     type Handle = ash::vk::Pipeline;
285 
286     #[inline]
handle(&self) -> Self::Handle287     fn handle(&self) -> Self::Handle {
288         self.handle
289     }
290 }
291 
292 impl Drop for GraphicsPipeline {
293     #[inline]
drop(&mut self)294     fn drop(&mut self) {
295         unsafe {
296             let fns = self.device.fns();
297             (fns.v1_0.destroy_pipeline)(self.device.handle(), self.handle, ptr::null());
298         }
299     }
300 }
301 
302 impl_id_counter!(GraphicsPipeline);
303