1 // Copyright (c) 2016 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 use crate::format::ClearValue; 11 use crate::format::Format; 12 use crate::image::ImageLayout; 13 use crate::image::SampleCount; 14 use crate::pipeline::shader::ShaderInterface; 15 use crate::sync::AccessFlags; 16 use crate::sync::PipelineStages; 17 18 /// The description of a render pass. 19 #[derive(Clone, Debug)] 20 pub struct RenderPassDesc { 21 attachments: Vec<AttachmentDesc>, 22 subpasses: Vec<SubpassDesc>, 23 dependencies: Vec<SubpassDependencyDesc>, 24 multiview: Option<MultiviewDesc>, 25 } 26 27 impl RenderPassDesc { 28 /// Creates a description of a render pass. new( attachments: Vec<AttachmentDesc>, subpasses: Vec<SubpassDesc>, dependencies: Vec<SubpassDependencyDesc>, ) -> RenderPassDesc29 pub fn new( 30 attachments: Vec<AttachmentDesc>, 31 subpasses: Vec<SubpassDesc>, 32 dependencies: Vec<SubpassDependencyDesc>, 33 ) -> RenderPassDesc { 34 RenderPassDesc { 35 attachments, 36 subpasses, 37 dependencies, 38 multiview: None, 39 } 40 } 41 42 /// Creates a description of a render pass that uses the multiview feature. 43 /// See [`MultiviewDesc`] for an explanation of possible configuration options. with_multiview( attachments: Vec<AttachmentDesc>, subpasses: Vec<SubpassDesc>, dependencies: Vec<SubpassDependencyDesc>, multiview: MultiviewDesc, ) -> RenderPassDesc44 pub fn with_multiview( 45 attachments: Vec<AttachmentDesc>, 46 subpasses: Vec<SubpassDesc>, 47 dependencies: Vec<SubpassDependencyDesc>, 48 multiview: MultiviewDesc, 49 ) -> RenderPassDesc { 50 RenderPassDesc { 51 attachments, 52 subpasses, 53 dependencies, 54 multiview: Some(multiview), 55 } 56 } 57 58 /// Creates a description of an empty render pass, with one subpass and no attachments. empty() -> RenderPassDesc59 pub fn empty() -> RenderPassDesc { 60 RenderPassDesc { 61 attachments: vec![], 62 subpasses: vec![SubpassDesc { 63 color_attachments: vec![], 64 depth_stencil: None, 65 input_attachments: vec![], 66 resolve_attachments: vec![], 67 preserve_attachments: vec![], 68 }], 69 dependencies: vec![], 70 multiview: None, 71 } 72 } 73 74 // Returns the attachments of the description. 75 #[inline] attachments(&self) -> &[AttachmentDesc]76 pub fn attachments(&self) -> &[AttachmentDesc] { 77 &self.attachments 78 } 79 80 // Returns the subpasses of the description. 81 #[inline] subpasses(&self) -> &[SubpassDesc]82 pub fn subpasses(&self) -> &[SubpassDesc] { 83 &self.subpasses 84 } 85 86 // Returns the dependencies of the description. 87 #[inline] dependencies(&self) -> &[SubpassDependencyDesc]88 pub fn dependencies(&self) -> &[SubpassDependencyDesc] { 89 &self.dependencies 90 } 91 92 // Returns the multiview configuration of the description. 93 #[inline] multiview(&self) -> &Option<MultiviewDesc>94 pub fn multiview(&self) -> &Option<MultiviewDesc> { 95 &self.multiview 96 } 97 98 /// Decodes `I` into a list of clear values where each element corresponds 99 /// to an attachment. The size of the returned iterator must be the same as the number of 100 /// attachments. 101 /// 102 /// When the user enters a render pass, they need to pass a list of clear values to apply to 103 /// the attachments of the framebuffer. This method is then responsible for checking the 104 /// correctness of these values and turning them into a list that can be processed by vulkano. 105 /// 106 /// The format of the clear value **must** match the format of the attachment. Attachments 107 /// that are not loaded with `LoadOp::Clear` must have an entry equal to `ClearValue::None`. convert_clear_values<I>(&self, values: I) -> impl Iterator<Item = ClearValue> where I: IntoIterator<Item = ClearValue>,108 pub fn convert_clear_values<I>(&self, values: I) -> impl Iterator<Item = ClearValue> 109 where 110 I: IntoIterator<Item = ClearValue>, 111 { 112 // FIXME: safety checks 113 values.into_iter() 114 } 115 116 /// Returns `true` if the subpass of this description is compatible with the shader's fragment 117 /// output definition. is_compatible_with_shader( &self, subpass: u32, shader_interface: &ShaderInterface, ) -> bool118 pub fn is_compatible_with_shader( 119 &self, 120 subpass: u32, 121 shader_interface: &ShaderInterface, 122 ) -> bool { 123 let pass_descr = match self.subpasses.get(subpass as usize) { 124 Some(s) => s, 125 None => return false, 126 }; 127 128 for element in shader_interface.elements() { 129 for location in element.location.clone() { 130 let attachment_id = match pass_descr.color_attachments.get(location as usize) { 131 Some(a) => a.0, 132 None => return false, 133 }; 134 135 let attachment_desc = &self.attachments[attachment_id]; 136 137 // FIXME: compare formats depending on the number of components and data type 138 /*if attachment_desc.format != element.format { 139 return false; 140 }*/ 141 } 142 } 143 144 true 145 } 146 147 /// Returns `true` if this description is compatible with the other description, 148 /// as defined in the `Render Pass Compatibility` section of the Vulkan specs. 149 // TODO: return proper error is_compatible_with_desc(&self, other: &RenderPassDesc) -> bool150 pub fn is_compatible_with_desc(&self, other: &RenderPassDesc) -> bool { 151 if self.attachments().len() != other.attachments().len() { 152 return false; 153 } 154 155 for (my_atch, other_atch) in self.attachments.iter().zip(other.attachments.iter()) { 156 if !my_atch.is_compatible_with(&other_atch) { 157 return false; 158 } 159 } 160 161 return true; 162 163 // FIXME: finish 164 } 165 } 166 167 impl Default for RenderPassDesc { default() -> Self168 fn default() -> Self { 169 Self::empty() 170 } 171 } 172 173 /// Describes an attachment that will be used in a render pass. 174 #[derive(Debug, Clone, Copy)] 175 pub struct AttachmentDesc { 176 /// Format of the image that is going to be bound. 177 pub format: Format, 178 /// Number of samples of the image that is going to be bound. 179 pub samples: SampleCount, 180 181 /// What the implementation should do with that attachment at the start of the render pass. 182 pub load: LoadOp, 183 /// What the implementation should do with that attachment at the end of the render pass. 184 pub store: StoreOp, 185 186 /// Equivalent of `load` for the stencil component of the attachment, if any. Irrelevant if 187 /// there is no stencil component. 188 pub stencil_load: LoadOp, 189 /// Equivalent of `store` for the stencil component of the attachment, if any. Irrelevant if 190 /// there is no stencil component. 191 pub stencil_store: StoreOp, 192 193 /// Layout that the image is going to be in at the start of the renderpass. 194 /// 195 /// The vulkano library will automatically switch to the correct layout if necessary, but it 196 /// is more efficient to set this to the correct value. 197 pub initial_layout: ImageLayout, 198 199 /// Layout that the image will be transitioned to at the end of the renderpass. 200 pub final_layout: ImageLayout, 201 } 202 203 impl AttachmentDesc { 204 /// Returns true if this attachment is compatible with another attachment, as defined in the 205 /// `Render Pass Compatibility` section of the Vulkan specs. 206 #[inline] is_compatible_with(&self, other: &AttachmentDesc) -> bool207 pub fn is_compatible_with(&self, other: &AttachmentDesc) -> bool { 208 self.format == other.format && self.samples == other.samples 209 } 210 } 211 212 /// Describes one of the subpasses of a render pass. 213 /// 214 /// # Restrictions 215 /// 216 /// All these restrictions are checked when the `RenderPass` object is created. 217 /// TODO: that's not the case ^ 218 /// 219 /// - The number of color attachments must be less than the limit of the physical device. 220 /// - All the attachments in `color_attachments` and `depth_stencil` must have the same 221 /// samples count. 222 /// - If any attachment is used as both an input attachment and a color or 223 /// depth/stencil attachment, then each use must use the same layout. 224 /// - Elements of `preserve_attachments` must not be used in any of the other members. 225 /// - If `resolve_attachments` is not empty, then all the resolve attachments must be attachments 226 /// with 1 sample and all the color attachments must have more than 1 sample. 227 /// - If `resolve_attachments` is not empty, all the resolve attachments must have the same format 228 /// as the color attachments. 229 /// - If the first use of an attachment in this renderpass is as an input attachment and the 230 /// attachment is not also used as a color or depth/stencil attachment in the same subpass, 231 /// then the loading operation must not be `Clear`. 232 /// 233 // TODO: add tests for all these restrictions 234 // TODO: allow unused attachments (for example attachment 0 and 2 are used, 1 is unused) 235 #[derive(Debug, Clone)] 236 pub struct SubpassDesc { 237 /// Indices and layouts of attachments to use as color attachments. 238 pub color_attachments: Vec<(usize, ImageLayout)>, // TODO: Vec is slow 239 240 /// Index and layout of the attachment to use as depth-stencil attachment. 241 pub depth_stencil: Option<(usize, ImageLayout)>, 242 243 /// Indices and layouts of attachments to use as input attachments. 244 pub input_attachments: Vec<(usize, ImageLayout)>, // TODO: Vec is slow 245 246 /// If not empty, each color attachment will be resolved into each corresponding entry of 247 /// this list. 248 /// 249 /// If this value is not empty, it **must** be the same length as `color_attachments`. 250 pub resolve_attachments: Vec<(usize, ImageLayout)>, // TODO: Vec is slow 251 252 /// Indices of attachments that will be preserved during this pass. 253 pub preserve_attachments: Vec<usize>, // TODO: Vec is slow 254 } 255 256 /// Describes a dependency between two subpasses of a render pass. 257 /// 258 /// The implementation is allowed to change the order of the subpasses within a render pass, unless 259 /// you specify that there exists a dependency between two subpasses (ie. the result of one will be 260 /// used as the input of another one). 261 #[derive(Debug, Clone, Copy)] 262 pub struct SubpassDependencyDesc { 263 /// Index of the subpass that writes the data that `destination_subpass` is going to use. 264 pub source_subpass: usize, 265 266 /// Index of the subpass that reads the data that `source_subpass` wrote. 267 pub destination_subpass: usize, 268 269 /// The pipeline stages that must be finished on the previous subpass before the destination 270 /// subpass can start. 271 pub source_stages: PipelineStages, 272 273 /// The pipeline stages of the destination subpass that must wait for the source to be finished. 274 /// Stages that are earlier of the stages specified here can start before the source is 275 /// finished. 276 pub destination_stages: PipelineStages, 277 278 /// The way the source subpass accesses the attachments on which we depend. 279 pub source_access: AccessFlags, 280 281 /// The way the destination subpass accesses the attachments on which we depend. 282 pub destination_access: AccessFlags, 283 284 /// If false, then the whole subpass must be finished for the next one to start. If true, then 285 /// the implementation can start the new subpass for some given pixels as long as the previous 286 /// subpass is finished for these given pixels. 287 /// 288 /// In other words, if the previous subpass has some side effects on other parts of an 289 /// attachment, then you should set it to false. 290 /// 291 /// Passing `false` is always safer than passing `true`, but in practice you rarely need to 292 /// pass `false`. 293 pub by_region: bool, 294 } 295 296 /// Describes what the implementation should do with an attachment after all the subpasses have 297 /// completed. 298 #[derive(Debug, Copy, Clone, PartialEq, Eq, Hash)] 299 #[repr(i32)] 300 pub enum StoreOp { 301 /// The attachment will be stored. This is what you usually want. 302 /// 303 /// While this is the most intuitive option, it is also slower than `DontCare` because it can 304 /// take time to write the data back to memory. 305 Store = ash::vk::AttachmentStoreOp::STORE.as_raw(), 306 307 /// What happens is implementation-specific. 308 /// 309 /// This is purely an optimization compared to `Store`. The implementation doesn't need to copy 310 /// from the internal cache to the memory, which saves memory bandwidth. 311 /// 312 /// This doesn't mean that the data won't be copied, as an implementation is also free to not 313 /// use a cache and write the output directly in memory. In other words, the content of the 314 /// image will be undefined. 315 DontCare = ash::vk::AttachmentStoreOp::DONT_CARE.as_raw(), 316 } 317 318 impl From<StoreOp> for ash::vk::AttachmentStoreOp { 319 #[inline] from(val: StoreOp) -> Self320 fn from(val: StoreOp) -> Self { 321 Self::from_raw(val as i32) 322 } 323 } 324 325 /// Describes what the implementation should do with an attachment at the start of the subpass. 326 #[derive(Debug, Copy, Clone, PartialEq, Eq, Hash)] 327 #[repr(i32)] 328 pub enum LoadOp { 329 /// The content of the attachment will be loaded from memory. This is what you want if you want 330 /// to draw over something existing. 331 /// 332 /// While this is the most intuitive option, it is also the slowest because it uses a lot of 333 /// memory bandwidth. 334 Load = ash::vk::AttachmentLoadOp::LOAD.as_raw(), 335 336 /// The content of the attachment will be filled by the implementation with a uniform value 337 /// that you must provide when you start drawing. 338 /// 339 /// This is what you usually use at the start of a frame, in order to reset the content of 340 /// the color, depth and/or stencil buffers. 341 /// 342 /// See the `draw_inline` and `draw_secondary` methods of `PrimaryComputeBufferBuilder`. 343 Clear = ash::vk::AttachmentLoadOp::CLEAR.as_raw(), 344 345 /// The attachment will have undefined content. 346 /// 347 /// This is what you should use for attachments that you intend to entirely cover with draw 348 /// commands. 349 /// If you are going to fill the attachment with a uniform value, it is better to use `Clear` 350 /// instead. 351 DontCare = ash::vk::AttachmentLoadOp::DONT_CARE.as_raw(), 352 } 353 354 impl From<LoadOp> for ash::vk::AttachmentLoadOp { 355 #[inline] from(val: LoadOp) -> Self356 fn from(val: LoadOp) -> Self { 357 Self::from_raw(val as i32) 358 } 359 } 360 361 /// Describes the `multiview` configuration for the render pass which is used to draw 362 /// to multiple layers of a framebuffer inside of a single render pass. 363 #[derive(Debug, Clone)] 364 pub struct MultiviewDesc { 365 /// The view masks indicate which layers of the framebuffer should be rendered for each subpass. 366 /// Values are bit masks which means that for example `0b11` will draw to the first two layers 367 /// and `0b101` will draw to the first and third layer. 368 pub view_masks: Vec<u32>, 369 370 /// The correlation masks indicate sets of views that may be more efficient to render 371 /// concurrently (usually because they show the same geometry from almost the same perspective). 372 /// Values are bit masks which means that for example `0b11` means the first two layers are 373 /// highly correlated and `0b101` means the first and third layer are highly correlated. 374 pub correlation_masks: Vec<u32>, 375 376 /// The view offsets contain additional information for each subpass dependency that indicate 377 /// which views in the source subpass the views of the destination subpass depend on. 378 pub view_offsets: Vec<i32>, 379 } 380 381 impl MultiviewDesc { 382 /// Returns the index of the layer with the biggest index that is 383 /// referred to by a mask in the multiview description. highest_used_layer(&self) -> u32384 pub fn highest_used_layer(&self) -> u32 { 385 self.view_masks 386 .iter() 387 .chain(self.correlation_masks.iter()) 388 .map(|&mask| 32 - mask.leading_zeros()) // the highest set bit corresponds to the highest used layer 389 .max() 390 .unwrap_or(0) 391 } 392 393 /// Returns the amount of layers that are used in the multiview description. used_layer_count(&self) -> u32394 pub fn used_layer_count(&self) -> u32 { 395 self.view_masks 396 .iter() 397 .chain(self.correlation_masks.iter()) 398 .fold(0, |acc, &mask| acc | mask) 399 .count_ones() 400 } 401 } 402 403 /// Possible resolve modes for depth and stencil attachments. 404 #[derive(Clone, Copy, Debug, PartialEq, Eq)] 405 #[repr(u32)] 406 pub enum ResolveMode { 407 None = ash::vk::ResolveModeFlags::NONE.as_raw(), 408 SampleZero = ash::vk::ResolveModeFlags::SAMPLE_ZERO.as_raw(), 409 Average = ash::vk::ResolveModeFlags::AVERAGE.as_raw(), 410 Min = ash::vk::ResolveModeFlags::MIN.as_raw(), 411 Max = ash::vk::ResolveModeFlags::MAX.as_raw(), 412 } 413 414 #[derive(Clone, Copy, Debug)] 415 pub struct ResolveModes { 416 pub none: bool, 417 pub sample_zero: bool, 418 pub average: bool, 419 pub min: bool, 420 pub max: bool, 421 } 422 423 impl From<ash::vk::ResolveModeFlags> for ResolveModes { 424 #[inline] from(val: ash::vk::ResolveModeFlags) -> Self425 fn from(val: ash::vk::ResolveModeFlags) -> Self { 426 Self { 427 none: val.intersects(ash::vk::ResolveModeFlags::NONE), 428 sample_zero: val.intersects(ash::vk::ResolveModeFlags::SAMPLE_ZERO), 429 average: val.intersects(ash::vk::ResolveModeFlags::AVERAGE), 430 min: val.intersects(ash::vk::ResolveModeFlags::MIN), 431 max: val.intersects(ash::vk::ResolveModeFlags::MAX), 432 } 433 } 434 } 435