1
  2
  3
  4
  5
  6
  7
  8
  9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
//! Utility for a texture view which can either be created by a [`TextureView`](wgpu::TextureView)
//! or [`SurfaceTexture`](wgpu::SurfaceTexture)

use crate::render::settings::Msaa;
use crate::render::util::HasChanged;
use std::ops::Deref;

/// Describes a [`TextureView`].
///
/// May be converted from a [`TextureView`](wgpu::TextureView) or [`SurfaceTexture`](wgpu::SurfaceTexture)
/// or dereferences to a wgpu [`TextureView`](wgpu::TextureView).
#[derive(Debug)]
pub enum TextureView {
    /// The value is an actual wgpu [`TextureView`](wgpu::TextureView).
    TextureView(wgpu::TextureView),

    /// The value is a wgpu [`SurfaceTexture`](wgpu::SurfaceTexture), but dereferences to
    /// a [`TextureView`](wgpu::TextureView).
    SurfaceTexture {
        // NOTE: The order of these fields is important because the view must be dropped before the
        // frame is dropped
        view: wgpu::TextureView,
        texture: wgpu::SurfaceTexture,
    },
}

impl TextureView {
    /// Returns the [`SurfaceTexture`](wgpu::SurfaceTexture) of the texture view if it is of that type.
    #[inline]
    pub fn take_surface_texture(self) -> Option<wgpu::SurfaceTexture> {
        match self {
            TextureView::TextureView(_) => None,
            TextureView::SurfaceTexture { texture, .. } => Some(texture),
        }
    }
}

impl From<wgpu::TextureView> for TextureView {
    fn from(value: wgpu::TextureView) -> Self {
        TextureView::TextureView(value)
    }
}

impl From<wgpu::SurfaceTexture> for TextureView {
    fn from(surface_texture: wgpu::SurfaceTexture) -> Self {
        let view = surface_texture.texture.create_view(&Default::default());

        TextureView::SurfaceTexture {
            texture: surface_texture,
            view,
        }
    }
}

impl Deref for TextureView {
    type Target = wgpu::TextureView;

    #[inline]
    fn deref(&self) -> &Self::Target {
        match &self {
            TextureView::TextureView(value) => value,
            TextureView::SurfaceTexture { view, .. } => view,
        }
    }
}

pub struct Texture {
    pub size: (u32, u32),
    pub texture: wgpu::Texture,
    pub view: TextureView,
}

impl Texture {
    pub fn new(
        label: wgpu::Label,
        device: &wgpu::Device,
        format: wgpu::TextureFormat,
        width: u32,
        height: u32,
        msaa: Msaa,
    ) -> Texture {
        let texture = device.create_texture(&wgpu::TextureDescriptor {
            label,
            size: wgpu::Extent3d {
                width,
                height,
                depth_or_array_layers: 1,
            },
            mip_level_count: 1,
            sample_count: msaa.samples,
            dimension: wgpu::TextureDimension::D2,
            format,
            usage: wgpu::TextureUsages::RENDER_ATTACHMENT,
        });
        let view = texture.create_view(&wgpu::TextureViewDescriptor::default());
        Self {
            size: (width, height),
            texture,
            view: TextureView::TextureView(view),
        }
    }
}

impl HasChanged for Texture {
    type Criteria = (u32, u32);

    fn has_changed(&self, criteria: &Self::Criteria) -> bool {
        !self.size.eq(criteria)
    }
}