• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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