sierra/
image.rs

1use crate::sealed::Sealed;
2
3pub use {
4    self::Samples::*,
5    crate::{
6        access::Access,
7        backend::Image,
8        encode::Encoder,
9        queue::{Ownership, QueueId},
10        stage::PipelineStages,
11    },
12};
13use {
14    crate::{
15        format::{AspectFlags, Format},
16        Extent2, Extent3, ImageSize, Offset3,
17    },
18    std::ops::Range,
19};
20
21bitflags::bitflags! {
22    /// Flags to specify allowed usages for image.
23    #[cfg_attr(feature = "serde-1", derive(serde::Serialize, serde::Deserialize))]
24    pub struct ImageUsage: u32 {
25        /// Image with this usage flag can be used as source for various transfer operations.
26        const TRANSFER_SRC =                0x001;
27
28        /// Image with this usage flag can be used as destination for various transfer operations.
29        const TRANSFER_DST =                0x002;
30
31        /// Image with this usage flag can be used as `SampledImage` descriptor.
32        const SAMPLED =                     0x004;
33
34        /// Image with this usage flag can be used as `StorageImage` descriptor.
35        const STORAGE =                     0x008;
36
37        /// Image with this usage flag can be used as color attachment in render passes.
38        const COLOR_ATTACHMENT =            0x010;
39
40        /// Image with this usage flag can be used as depth-stencil attachment in render passes.
41        const DEPTH_STENCIL_ATTACHMENT =    0x020;
42
43        /// Image with this usage flag can be used as input attachment in render passes.
44        const INPUT_ATTACHMENT =            0x080;
45    }
46}
47
48impl ImageUsage {
49    /// Returns `true` if image with this usage flags can be used as render target, either color or depth.
50    pub fn is_render_target(self) -> bool {
51        self.intersects(Self::COLOR_ATTACHMENT | Self::DEPTH_STENCIL_ATTACHMENT)
52    }
53
54    /// Returns `true` if image with this usage flags can be used as render target, either color or depth,
55    /// and no other usage is allowed.
56    pub fn is_render_target_only(self) -> bool {
57        self.is_render_target()
58            && !self.intersects(
59                Self::TRANSFER_SRC
60                    | Self::TRANSFER_DST
61                    | Self::SAMPLED
62                    | Self::STORAGE
63                    | Self::INPUT_ATTACHMENT,
64            )
65    }
66
67    /// Returns `true` if no mutable usages allowed.
68    /// Content still can be modified through memory mapping.
69    pub fn is_read_only(self) -> bool {
70        !self.intersects(
71            Self::TRANSFER_DST
72                | Self::STORAGE
73                | Self::COLOR_ATTACHMENT
74                | Self::DEPTH_STENCIL_ATTACHMENT,
75        )
76    }
77}
78
79/// Image layout defines how texel are placed in memory.
80/// Operations can be used in one or more layouts.
81/// User is responsible to insert layout transition commands to ensure
82/// that the image is in valid layout for each operation.
83/// Pipeline barriers can be used to change layouts.
84/// Additionally render pass can change layout of its attachments.
85#[derive(Clone, Copy, Debug, Hash, PartialEq, Eq)]
86#[cfg_attr(feature = "serde-1", derive(serde::Serialize, serde::Deserialize))]
87pub enum Layout {
88    /// Can be used with all device operations.
89    /// Only presentation is not possible in this layout.
90    /// Operations may perform slower in this layout.
91    General,
92
93    /// Can be used for color attachments.
94    ColorAttachmentOptimal,
95
96    /// Can be used for depth-stencil attachments.
97    DepthStencilAttachmentOptimal,
98
99    /// Can be used for depth-stencil attachments
100    /// without writes.
101    DepthStencilReadOnlyOptimal,
102
103    /// Can be used for images accessed from shaders
104    /// without writes.
105    ShaderReadOnlyOptimal,
106
107    /// Can be used for copy, blit and other transferring operations
108    /// on source image.
109    TransferSrcOptimal,
110
111    /// Can be used for copy, blit and other transferring operations
112    /// on destination image.
113    TransferDstOptimal,
114
115    /// Layout for swapchain images presentation.
116    /// Should not be used if presentation feature is not enabled.
117    Present,
118}
119
120impl Default for Layout {
121    fn default() -> Self {
122        Self::General
123    }
124}
125
126/// Extent of the image.
127#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)]
128#[cfg_attr(feature = "serde-1", derive(serde::Serialize, serde::Deserialize))]
129pub enum ImageExtent {
130    /// One dimensional extent.
131    D1 {
132        /// Width of the image
133        width: ImageSize,
134    },
135    /// Two dimensional extent.
136    D2 {
137        /// Width of the image
138        width: ImageSize,
139
140        /// Height of the image.
141        height: ImageSize,
142    },
143    /// Three dimensional extent.
144    D3 {
145        /// Width of the image
146        width: ImageSize,
147
148        /// Height of the image.
149        height: ImageSize,
150
151        /// Depth of the image.
152        depth: ImageSize,
153    },
154}
155
156impl From<Extent2> for ImageExtent {
157    fn from(extent: Extent2) -> Self {
158        ImageExtent::D2 {
159            width: extent.width,
160            height: extent.height,
161        }
162    }
163}
164
165impl From<Extent3> for ImageExtent {
166    fn from(extent: Extent3) -> Self {
167        ImageExtent::D3 {
168            width: extent.width,
169            height: extent.height,
170            depth: extent.depth,
171        }
172    }
173}
174
175impl ImageExtent {
176    /// Convert image extent (1,2 or 3 dimensional) into 3 dimensional extent.
177    /// If image doesn't have `height` or `depth`  they are set to 1.
178    pub fn into_3d(self) -> Extent3 {
179        match self {
180            Self::D1 { width } => Extent3::new(width, 1, 1),
181            Self::D2 { width, height } => Extent3::new(width, height, 1),
182            Self::D3 {
183                width,
184                height,
185                depth,
186            } => Extent3::new(width, height, depth),
187        }
188    }
189
190    /// Convert image extent (1,2 or 3 dimensional) into 2 dimensional extent.
191    /// If image doesn't have `height` it is set to 1.
192    /// `depth` is ignored.
193    pub fn into_2d(self) -> Extent2 {
194        match self {
195            Self::D1 { width } => Extent2::new(width, 1),
196            Self::D2 { width, height } => Extent2::new(width, height),
197            Self::D3 { width, height, .. } => Extent2::new(width, height),
198        }
199    }
200}
201
202impl PartialEq<Extent2> for ImageExtent {
203    fn eq(&self, rhs: &Extent2) -> bool {
204        match self {
205            ImageExtent::D2 { width, height } => *width == rhs.width && *height == rhs.height,
206            _ => false,
207        }
208    }
209}
210
211impl PartialEq<Extent3> for ImageExtent {
212    fn eq(&self, rhs: &Extent3) -> bool {
213        match self {
214            ImageExtent::D3 {
215                width,
216                height,
217                depth,
218            } => *width == rhs.width && *height == rhs.height && *depth == rhs.depth,
219            _ => false,
220        }
221    }
222}
223
224impl PartialEq<ImageExtent> for Extent2 {
225    fn eq(&self, rhs: &ImageExtent) -> bool {
226        match rhs {
227            ImageExtent::D2 { width, height } => self.width == *width && self.height == *height,
228            _ => false,
229        }
230    }
231}
232
233impl PartialEq<ImageExtent> for Extent3 {
234    fn eq(&self, rhs: &ImageExtent) -> bool {
235        match rhs {
236            ImageExtent::D3 {
237                width,
238                height,
239                depth,
240            } => self.width == *width && self.height == *height && self.depth == *depth,
241            _ => false,
242        }
243    }
244}
245
246/// Number of samples for an image.
247#[derive(Clone, Copy, Debug, Hash, PartialEq, Eq)]
248#[cfg_attr(feature = "serde-1", derive(serde::Serialize, serde::Deserialize))]
249pub enum Samples {
250    /// 1 sample.
251    Samples1,
252    /// 2 samples.
253    Samples2,
254    /// 4 samples.
255    Samples4,
256    /// 8 samples.
257    Samples8,
258    /// 16 samples.
259    Samples16,
260    /// 32 samples.
261    Samples32,
262    /// 64 samples.
263    Samples64,
264}
265
266impl Default for Samples {
267    fn default() -> Self {
268        Samples::Samples1
269    }
270}
271
272/// Information required to create an image.
273#[derive(Clone, Copy, Debug, Hash, PartialEq, Eq)]
274#[cfg_attr(feature = "serde-1", derive(serde::Serialize, serde::Deserialize))]
275pub struct ImageInfo {
276    /// Dimensionality and size of those dimensions.
277    pub extent: ImageExtent,
278
279    /// Format for image texels.
280    pub format: Format,
281
282    /// Number of MIP levels.
283    pub levels: u32,
284
285    /// Number of array layers.
286    pub layers: u32,
287
288    /// Number of samples per texel.
289    pub samples: Samples,
290
291    /// Usage types supported by image.
292    pub usage: ImageUsage,
293}
294/// Subresorce range of the image.
295/// Used to create `ImageView`s.
296#[derive(Clone, Copy, Debug, Hash, PartialEq, Eq)]
297#[cfg_attr(feature = "serde-1", derive(serde::Serialize, serde::Deserialize))]
298pub struct SubresourceRange {
299    pub aspect: AspectFlags,
300    pub first_level: u32,
301    pub level_count: u32,
302    pub first_layer: u32,
303    pub layer_count: u32,
304}
305
306impl SubresourceRange {
307    pub fn new(aspect: AspectFlags, levels: Range<u32>, layers: Range<u32>) -> Self {
308        assert!(levels.end >= levels.start);
309
310        assert!(layers.end >= layers.start);
311
312        SubresourceRange {
313            aspect,
314            first_level: levels.start,
315            level_count: levels.end - levels.start,
316            first_layer: layers.start,
317            layer_count: layers.end - layers.start,
318        }
319    }
320
321    pub fn subresource(subresource: Subresource) -> Self {
322        SubresourceRange {
323            aspect: subresource.aspect,
324            first_level: subresource.level,
325            level_count: 1,
326            first_layer: subresource.layer,
327            layer_count: 1,
328        }
329    }
330
331    pub fn layers(layers: SubresourceLayers) -> Self {
332        SubresourceRange {
333            aspect: layers.aspect,
334            first_level: layers.level,
335            level_count: 1,
336            first_layer: layers.first_layer,
337            layer_count: layers.layer_count,
338        }
339    }
340
341    pub fn whole(info: &ImageInfo) -> Self {
342        SubresourceRange {
343            aspect: info.format.aspect_flags(),
344            first_level: 0,
345            level_count: info.levels,
346            first_layer: 0,
347            layer_count: info.layers,
348        }
349    }
350
351    pub fn color(levels: Range<u32>, layers: Range<u32>) -> Self {
352        Self::new(AspectFlags::COLOR, levels, layers)
353    }
354
355    pub fn depth(levels: Range<u32>, layers: Range<u32>) -> Self {
356        Self::new(AspectFlags::DEPTH, levels, layers)
357    }
358
359    pub fn stencil(levels: Range<u32>, layers: Range<u32>) -> Self {
360        Self::new(AspectFlags::STENCIL, levels, layers)
361    }
362
363    pub fn depth_stencil(levels: Range<u32>, layers: Range<u32>) -> Self {
364        Self::new(AspectFlags::DEPTH | AspectFlags::STENCIL, levels, layers)
365    }
366}
367
368/// Subresorce layers of the image.
369/// Unlike `SubresourceRange` it specifies only single mip-level.
370/// Used in image copy operations.
371#[derive(Clone, Copy, Debug, Hash, PartialEq, Eq)]
372#[cfg_attr(feature = "serde-1", derive(serde::Serialize, serde::Deserialize))]
373pub struct SubresourceLayers {
374    pub aspect: AspectFlags,
375    pub level: u32,
376    pub first_layer: u32,
377    pub layer_count: u32,
378}
379
380impl SubresourceLayers {
381    pub fn new(aspect: AspectFlags, level: u32, layers: Range<u32>) -> Self {
382        assert!(layers.end >= layers.start);
383
384        SubresourceLayers {
385            aspect,
386            level,
387            first_layer: layers.start,
388            layer_count: layers.end - layers.start,
389        }
390    }
391
392    pub fn subresource(subresource: Subresource) -> Self {
393        SubresourceLayers {
394            aspect: subresource.aspect,
395            level: subresource.level,
396            first_layer: subresource.layer,
397            layer_count: 1,
398        }
399    }
400
401    pub fn all_layers(info: &ImageInfo, level: u32) -> Self {
402        assert!(level < info.levels);
403
404        SubresourceLayers {
405            aspect: info.format.aspect_flags(),
406            level,
407            first_layer: 0,
408            layer_count: info.layers,
409        }
410    }
411
412    pub fn color(level: u32, layers: Range<u32>) -> Self {
413        Self::new(AspectFlags::COLOR, level, layers)
414    }
415
416    pub fn depth(level: u32, layers: Range<u32>) -> Self {
417        Self::new(AspectFlags::DEPTH, level, layers)
418    }
419
420    pub fn stencil(level: u32, layers: Range<u32>) -> Self {
421        Self::new(AspectFlags::STENCIL, level, layers)
422    }
423
424    pub fn depth_stencil(level: u32, layers: Range<u32>) -> Self {
425        Self::new(AspectFlags::DEPTH | AspectFlags::STENCIL, level, layers)
426    }
427}
428
429impl From<SubresourceLayers> for SubresourceRange {
430    fn from(layers: SubresourceLayers) -> Self {
431        SubresourceRange::layers(layers)
432    }
433}
434
435/// Subresorce of the image.
436/// Unlike `SubresourceRange` it specifies only single mip-level and single
437/// array layer.
438#[derive(Clone, Copy, Debug, Hash, PartialEq, Eq)]
439#[cfg_attr(feature = "serde-1", derive(serde::Serialize, serde::Deserialize))]
440pub struct Subresource {
441    pub aspect: AspectFlags,
442    pub level: u32,
443    pub layer: u32,
444}
445
446impl Subresource {
447    pub fn new(aspect: AspectFlags, level: u32, layer: u32) -> Self {
448        Subresource {
449            aspect,
450            level,
451            layer,
452        }
453    }
454
455    pub fn from_info(info: &ImageInfo, level: u32, layer: u32) -> Self {
456        assert!(level < info.levels);
457
458        assert!(layer < info.layers);
459
460        Subresource {
461            aspect: info.format.aspect_flags(),
462            level,
463            layer,
464        }
465    }
466
467    pub fn color(level: u32, layer: u32) -> Self {
468        Self::new(AspectFlags::COLOR, level, layer)
469    }
470
471    pub fn depth(level: u32, layer: u32) -> Self {
472        Self::new(AspectFlags::DEPTH, level, layer)
473    }
474
475    pub fn stencil(level: u32, layer: u32) -> Self {
476        Self::new(AspectFlags::STENCIL, level, layer)
477    }
478
479    pub fn depth_stencil(level: u32, layer: u32) -> Self {
480        Self::new(AspectFlags::DEPTH | AspectFlags::STENCIL, level, layer)
481    }
482}
483
484impl From<Subresource> for SubresourceLayers {
485    fn from(subresource: Subresource) -> Self {
486        SubresourceLayers::subresource(subresource)
487    }
488}
489
490impl From<Subresource> for SubresourceRange {
491    fn from(subresource: Subresource) -> Self {
492        SubresourceRange::subresource(subresource)
493    }
494}
495
496#[derive(Clone, Copy, Debug, Hash, PartialEq, Eq)]
497#[cfg_attr(feature = "serde-1", derive(serde::Serialize, serde::Deserialize))]
498pub struct ImageBlit {
499    pub src_subresource: SubresourceLayers,
500    pub src_offsets: [Offset3; 2],
501    pub dst_subresource: SubresourceLayers,
502    pub dst_offsets: [Offset3; 2],
503}
504
505#[derive(Clone, Copy, Debug, Hash, PartialEq, Eq)]
506pub struct LayoutTransition<'a> {
507    pub image: &'a Image,
508    pub old_access: Access,
509    pub old_layout: Option<Layout>,
510    pub new_access: Access,
511    pub new_layout: Layout,
512    pub range: SubresourceRange,
513}
514
515#[derive(Clone, Copy, Debug, Hash, PartialEq, Eq)]
516pub struct ImageMemoryBarrier<'a> {
517    pub image: &'a Image,
518    pub old_access: Access,
519    pub old_layout: Option<Layout>,
520    pub new_access: Access,
521    pub new_layout: Layout,
522    pub family_transfer: Option<(u32, u32)>,
523    pub range: SubresourceRange,
524}
525
526impl<'a> ImageMemoryBarrier<'a> {
527    pub fn transition_whole(
528        image: &'a Image,
529        access: Range<Access>,
530        layout: Range<Layout>,
531    ) -> Self {
532        ImageMemoryBarrier {
533            range: SubresourceRange::whole(image.info()),
534            image,
535            old_access: access.start,
536            new_access: access.end,
537            old_layout: Some(layout.start),
538            new_layout: layout.end,
539            family_transfer: None,
540        }
541    }
542
543    pub fn initialize_whole(image: &'a Image, access: Access, layout: Layout) -> Self {
544        ImageMemoryBarrier {
545            range: SubresourceRange::whole(image.info()),
546            image,
547            old_access: Access::empty(),
548            old_layout: None,
549            new_access: access,
550            new_layout: layout,
551            family_transfer: None,
552        }
553    }
554}
555
556impl<'a> From<LayoutTransition<'a>> for ImageMemoryBarrier<'a> {
557    fn from(value: LayoutTransition<'a>) -> Self {
558        ImageMemoryBarrier {
559            image: value.image,
560            old_access: value.old_access,
561            old_layout: value.old_layout,
562            new_access: value.new_access,
563            new_layout: value.new_layout,
564            family_transfer: None,
565            range: value.range,
566        }
567    }
568}
569
570#[derive(Clone, Debug, PartialEq, Eq, Hash)]
571pub struct ImageSubresourceRange {
572    pub image: Image,
573    pub range: SubresourceRange,
574}
575
576/// Image region with access mask,
577/// specifying how it may be accessed "before".
578///
579/// Note that "before" is loosely defined,
580/// as whatever previous owners do.
581/// Which should be translated to "earlier GPU operations"
582/// but this crate doesn't attempt to enforce that.
583#[derive(Clone, Debug, PartialEq, Eq, Hash)]
584pub struct ImageSubresourceState {
585    pub subresource: ImageSubresourceRange,
586    pub access: Access,
587    pub stages: PipelineStages,
588    pub layout: Option<Layout>,
589    pub family: Ownership,
590}
591
592impl ImageSubresourceState {
593    ///
594    pub fn access<'a>(
595        &'a mut self,
596        access: Access,
597        stages: PipelineStages,
598        layout: Layout,
599        queue: QueueId,
600        encoder: &mut Encoder<'a>,
601    ) -> &'a Self {
602        match self.family {
603            Ownership::NotOwned => encoder.image_barriers(
604                self.stages,
605                stages,
606                encoder.scope().to_scope([ImageMemoryBarrier {
607                    image: &self.subresource.image,
608                    old_access: self.access,
609                    new_access: access,
610                    old_layout: self.layout,
611                    new_layout: layout,
612                    family_transfer: None,
613                    range: self.subresource.range,
614                }]),
615            ),
616            Ownership::Owned { family } => {
617                assert_eq!(family, queue.family, "Wrong queue family owns the buffer");
618
619                encoder.image_barriers(
620                    self.stages,
621                    stages,
622                    encoder.scope().to_scope([ImageMemoryBarrier {
623                        image: &self.subresource.image,
624                        old_access: self.access,
625                        new_access: access,
626                        old_layout: self.layout,
627                        new_layout: layout,
628                        family_transfer: None,
629                        range: self.subresource.range,
630                    }]),
631                )
632            }
633            Ownership::Transition { from, to } => {
634                assert_eq!(
635                    to, queue.family,
636                    "Image is being transitioned to wrong queue family"
637                );
638
639                encoder.image_barriers(
640                    self.stages,
641                    stages,
642                    encoder.scope().to_scope([ImageMemoryBarrier {
643                        image: &self.subresource.image,
644                        old_access: self.access,
645                        new_access: access,
646                        old_layout: self.layout,
647                        new_layout: layout,
648                        family_transfer: Some((from, to)),
649                        range: self.subresource.range,
650                    }]),
651                )
652            }
653        }
654        self.stages = stages;
655        self.access = access;
656        self.layout = Some(layout);
657        self
658    }
659
660    ///
661    pub fn overwrite<'a>(
662        &'a mut self,
663        access: Access,
664        stages: PipelineStages,
665        layout: Layout,
666        queue: QueueId,
667        encoder: &mut Encoder<'a>,
668    ) -> &'a ImageSubresourceRange {
669        encoder.image_barriers(
670            self.stages,
671            stages,
672            encoder.scope().to_scope([ImageMemoryBarrier {
673                image: &self.subresource.image,
674                old_access: Access::empty(),
675                new_access: access,
676                old_layout: None,
677                new_layout: layout,
678                family_transfer: None,
679                range: self.subresource.range,
680            }]),
681        );
682        self.family = Ownership::Owned {
683            family: queue.family,
684        };
685        self.stages = stages;
686        self.access = access;
687        self.layout = Some(layout);
688        &self.subresource
689    }
690}
691
692#[derive(Copy, Clone, Debug)]
693pub enum ColorAttachmentOptimal {}
694
695#[derive(Copy, Clone, Debug)]
696pub enum DepthStencilAttachmentOptimal {}
697
698#[derive(Copy, Clone, Debug)]
699pub enum DepthStencilReadOnlyOptimal {}
700
701#[derive(Copy, Clone, Debug)]
702pub enum ShaderReadOnlyOptimal {}
703
704#[derive(Copy, Clone, Debug)]
705pub enum TransferSrcOptimal {}
706
707#[derive(Copy, Clone, Debug)]
708pub enum TransferDstOptimal {}
709
710#[derive(Copy, Clone, Debug)]
711pub enum Present {}
712
713#[derive(Copy, Clone, Debug)]
714pub enum General {}
715
716pub trait StaticLayout {
717    const LAYOUT: Layout;
718}
719
720impl StaticLayout for ColorAttachmentOptimal {
721    const LAYOUT: Layout = Layout::ColorAttachmentOptimal;
722}
723impl StaticLayout for DepthStencilAttachmentOptimal {
724    const LAYOUT: Layout = Layout::DepthStencilAttachmentOptimal;
725}
726impl StaticLayout for DepthStencilReadOnlyOptimal {
727    const LAYOUT: Layout = Layout::DepthStencilReadOnlyOptimal;
728}
729impl StaticLayout for ShaderReadOnlyOptimal {
730    const LAYOUT: Layout = Layout::ShaderReadOnlyOptimal;
731}
732impl StaticLayout for TransferSrcOptimal {
733    const LAYOUT: Layout = Layout::TransferSrcOptimal;
734}
735impl StaticLayout for TransferDstOptimal {
736    const LAYOUT: Layout = Layout::TransferDstOptimal;
737}
738impl StaticLayout for Present {
739    const LAYOUT: Layout = Layout::Present;
740}
741impl StaticLayout for General {
742    const LAYOUT: Layout = Layout::General;
743}
744
745impl Sealed for (Image, Layout) {}