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