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