Skip to main content

pebble/wgpu/
texture_view.rs

1use crate::wgpu::backend::WGPUBackend;
2use crate::wgpu::flags::TextureUsages;
3use crate::wgpu::texture_format::TextureFormat;
4use crate::wgpu::textures::check_texture_dimensions;
5
6/// A `wgpu::TextureView`, opaque — the [`FrameOperations::Attachment`](crate::rendering::backend::FrameOperations::Attachment)/
7/// [`DepthAttachment`](crate::rendering::backend::FrameOperations::DepthAttachment)
8/// type for [`WGPUBackend`], and [`TextureBuilder::build`]'s return type.
9/// Bundles the backing `wgpu::Texture` alongside the view (kept alive,
10/// never otherwise accessed) — the view alone isn't enough to keep the
11/// underlying resource alive for as long as it's needed.
12pub struct TextureView {
13    view: wgpu::TextureView,
14    _texture: wgpu::Texture,
15}
16
17impl TextureView {
18    pub(crate) fn raw(&self) -> &wgpu::TextureView {
19        &self.view
20    }
21
22    /// Wraps an already-created `wgpu::TextureView` onto an existing
23    /// texture (a `wgpu::Texture` is a cheap, `Arc`-backed handle, so
24    /// `texture` is typically `.clone()`d off whatever already owns it) —
25    /// used by [`GPUCubemap::face_attachment`](super::cubemap::GPUCubemap::face_attachment)
26    /// for a render target into one face of an existing texture, as
27    /// opposed to [`TextureBuilder::build`] which allocates a brand new one.
28    pub(crate) fn from_raw(view: wgpu::TextureView, texture: wgpu::Texture) -> Self {
29        Self { view, _texture: texture }
30    }
31}
32
33/// Builds a one-off GPU-side texture with no source data — a depth buffer,
34/// an off-screen render target — and hands back its
35/// [`TextureView`]. Unlike [`Texture`](super::textures::Texture),
36/// which loads pixel data from a file/bytes through the asset pipeline,
37/// this allocates an empty texture directly; there's nothing to upload.
38///
39/// ```ignore
40/// let depth_view = TextureBuilder::new(backend.surface_width(), backend.surface_height(), TextureFormat::Depth16Unorm)
41///     .usage(TextureUsages::RENDER_ATTACHMENT)
42///     .build(backend);
43/// ```
44pub struct TextureBuilder<'a> {
45    label: Option<&'a str>,
46    width: u32,
47    height: u32,
48    format: TextureFormat,
49    usage: TextureUsages,
50    mip_level_count: u32,
51    sample_count: u32,
52}
53
54impl<'a> TextureBuilder<'a> {
55    pub fn new(width: u32, height: u32, format: TextureFormat) -> Self {
56        Self {
57            label: None,
58            width,
59            height,
60            format,
61            usage: TextureUsages::empty(),
62            mip_level_count: 1,
63            sample_count: 1,
64        }
65    }
66
67    pub fn label(mut self, label: impl Into<Option<&'a str>>) -> Self {
68        self.label = label.into();
69        self
70    }
71
72    pub fn usage(mut self, usage: TextureUsages) -> Self {
73        self.usage = usage;
74        self
75    }
76
77    pub fn mip_level_count(mut self, count: u32) -> Self {
78        self.mip_level_count = count;
79        self
80    }
81
82    /// Multisample count — must match whatever this texture is used
83    /// alongside (a depth attachment paired with an MSAA color target needs
84    /// the same count as [`WGPUBackend::sample_count`], say). `1` (no
85    /// multisampling) by default.
86    pub fn sample_count(mut self, count: u32) -> Self {
87        self.sample_count = count;
88        self
89    }
90
91    pub fn build(self, backend: &WGPUBackend) -> TextureView {
92        check_texture_dimensions(&backend.device, "TextureBuilder", self.width, self.height);
93
94        let texture = backend.device.create_texture(&wgpu::TextureDescriptor {
95            label: self.label,
96            size: wgpu::Extent3d { width: self.width, height: self.height, depth_or_array_layers: 1 },
97            mip_level_count: self.mip_level_count,
98            sample_count: self.sample_count,
99            dimension: wgpu::TextureDimension::D2,
100            format: self.format.into(),
101            usage: self.usage.into(),
102            view_formats: &[],
103        });
104        let view = texture.create_view(&wgpu::TextureViewDescriptor::default());
105        TextureView { view, _texture: texture }
106    }
107}