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}