wgpu_core/
conv.rs

1use wgt::TextureFormatFeatures;
2
3use crate::resource::{self, TextureDescriptor};
4
5// Some core-only texture format helpers. The helper methods on `TextureFormat`
6// defined in wgpu-types may need to be modified along with the ones here.
7
8#[cfg_attr(any(not(webgl)), expect(unused))]
9pub fn is_valid_external_image_copy_dst_texture_format(format: wgt::TextureFormat) -> bool {
10    use wgt::TextureFormat as Tf;
11    match format {
12        Tf::R8Unorm
13        | Tf::R16Float
14        | Tf::R32Float
15        | Tf::Rg8Unorm
16        | Tf::Rg16Float
17        | Tf::Rg32Float
18        | Tf::Rgba8Unorm
19        | Tf::Rgba8UnormSrgb
20        | Tf::Bgra8Unorm
21        | Tf::Bgra8UnormSrgb
22        | Tf::Rgb10a2Unorm
23        | Tf::Rgba16Float
24        | Tf::Rgba32Float => true,
25        _ => false,
26    }
27}
28
29pub fn map_buffer_usage(usage: wgt::BufferUsages) -> wgt::BufferUses {
30    let mut u = wgt::BufferUses::empty();
31    u.set(
32        wgt::BufferUses::MAP_READ,
33        usage.contains(wgt::BufferUsages::MAP_READ),
34    );
35    u.set(
36        wgt::BufferUses::MAP_WRITE,
37        usage.contains(wgt::BufferUsages::MAP_WRITE),
38    );
39    u.set(
40        wgt::BufferUses::COPY_SRC,
41        usage.contains(wgt::BufferUsages::COPY_SRC),
42    );
43    u.set(
44        wgt::BufferUses::COPY_DST,
45        usage.contains(wgt::BufferUsages::COPY_DST),
46    );
47    u.set(
48        wgt::BufferUses::INDEX,
49        usage.contains(wgt::BufferUsages::INDEX),
50    );
51    u.set(
52        wgt::BufferUses::VERTEX,
53        usage.contains(wgt::BufferUsages::VERTEX),
54    );
55    u.set(
56        wgt::BufferUses::UNIFORM,
57        usage.contains(wgt::BufferUsages::UNIFORM),
58    );
59    u.set(
60        wgt::BufferUses::STORAGE_READ_ONLY | wgt::BufferUses::STORAGE_READ_WRITE,
61        usage.contains(wgt::BufferUsages::STORAGE),
62    );
63    u.set(
64        wgt::BufferUses::INDIRECT,
65        usage.contains(wgt::BufferUsages::INDIRECT),
66    );
67    u.set(
68        wgt::BufferUses::QUERY_RESOLVE,
69        usage.contains(wgt::BufferUsages::QUERY_RESOLVE),
70    );
71    u.set(
72        wgt::BufferUses::BOTTOM_LEVEL_ACCELERATION_STRUCTURE_INPUT,
73        usage.contains(wgt::BufferUsages::BLAS_INPUT),
74    );
75    u.set(
76        wgt::BufferUses::TOP_LEVEL_ACCELERATION_STRUCTURE_INPUT,
77        usage.contains(wgt::BufferUsages::TLAS_INPUT),
78    );
79    u
80}
81
82pub fn map_texture_usage(
83    usage: wgt::TextureUsages,
84    aspect: hal::FormatAspects,
85    flags: wgt::TextureFormatFeatureFlags,
86) -> wgt::TextureUses {
87    let mut u = wgt::TextureUses::empty();
88    u.set(
89        wgt::TextureUses::COPY_SRC,
90        usage.contains(wgt::TextureUsages::COPY_SRC),
91    );
92    u.set(
93        wgt::TextureUses::COPY_DST,
94        usage.contains(wgt::TextureUsages::COPY_DST),
95    );
96    u.set(
97        wgt::TextureUses::RESOURCE,
98        usage.contains(wgt::TextureUsages::TEXTURE_BINDING),
99    );
100    if usage.contains(wgt::TextureUsages::STORAGE_BINDING) {
101        u.set(
102            wgt::TextureUses::STORAGE_READ_ONLY,
103            flags.contains(wgt::TextureFormatFeatureFlags::STORAGE_READ_ONLY),
104        );
105        u.set(
106            wgt::TextureUses::STORAGE_WRITE_ONLY,
107            flags.contains(wgt::TextureFormatFeatureFlags::STORAGE_WRITE_ONLY),
108        );
109        u.set(
110            wgt::TextureUses::STORAGE_READ_WRITE,
111            flags.contains(wgt::TextureFormatFeatureFlags::STORAGE_READ_WRITE),
112        );
113    }
114    let is_color = aspect.intersects(
115        hal::FormatAspects::COLOR
116            | hal::FormatAspects::PLANE_0
117            | hal::FormatAspects::PLANE_1
118            | hal::FormatAspects::PLANE_2,
119    );
120    u.set(
121        wgt::TextureUses::COLOR_TARGET,
122        usage.contains(wgt::TextureUsages::RENDER_ATTACHMENT) && is_color,
123    );
124    u.set(
125        wgt::TextureUses::DEPTH_WRITE
126            | wgt::TextureUses::DEPTH_READ
127            | wgt::TextureUses::STENCIL_WRITE
128            | wgt::TextureUses::STENCIL_READ,
129        usage.contains(wgt::TextureUsages::RENDER_ATTACHMENT) && !is_color,
130    );
131    u.set(
132        wgt::TextureUses::STORAGE_ATOMIC,
133        usage.contains(wgt::TextureUsages::STORAGE_ATOMIC),
134    );
135    u.set(
136        wgt::TextureUses::TRANSIENT,
137        usage.contains(wgt::TextureUsages::TRANSIENT_ATTACHMENT),
138    );
139    u
140}
141
142pub fn map_texture_usage_for_texture(
143    desc: &TextureDescriptor,
144    format_features: &TextureFormatFeatures,
145) -> wgt::TextureUses {
146    // Enforce having COPY_DST/DEPTH_WRITE/STENCIL_WRITE/COLOR_TARGET otherwise we
147    // wouldn't be able to initialize the texture.
148    map_texture_usage(desc.usage, desc.format.into(), format_features.flags)
149        | if desc.format.is_depth_stencil_format() {
150            wgt::TextureUses::DEPTH_WRITE | wgt::TextureUses::STENCIL_WRITE
151        } else if desc.usage.contains(wgt::TextureUsages::COPY_DST) {
152            wgt::TextureUses::COPY_DST // (set already)
153        } else {
154            // Use COPY_DST only if we can't use COLOR_TARGET
155            if format_features
156                .allowed_usages
157                .contains(wgt::TextureUsages::RENDER_ATTACHMENT)
158                && desc.dimension == wgt::TextureDimension::D2
159            // Render targets dimension must be 2d
160            {
161                wgt::TextureUses::COLOR_TARGET
162            } else {
163                wgt::TextureUses::COPY_DST
164            }
165        }
166}
167
168pub fn map_texture_usage_from_hal(uses: wgt::TextureUses) -> wgt::TextureUsages {
169    let mut u = wgt::TextureUsages::empty();
170    u.set(
171        wgt::TextureUsages::COPY_SRC,
172        uses.contains(wgt::TextureUses::COPY_SRC),
173    );
174    u.set(
175        wgt::TextureUsages::COPY_DST,
176        uses.contains(wgt::TextureUses::COPY_DST),
177    );
178    u.set(
179        wgt::TextureUsages::TEXTURE_BINDING,
180        uses.contains(wgt::TextureUses::RESOURCE),
181    );
182    u.set(
183        wgt::TextureUsages::STORAGE_BINDING,
184        uses.intersects(
185            wgt::TextureUses::STORAGE_READ_ONLY
186                | wgt::TextureUses::STORAGE_WRITE_ONLY
187                | wgt::TextureUses::STORAGE_READ_WRITE,
188        ),
189    );
190    u.set(
191        wgt::TextureUsages::RENDER_ATTACHMENT,
192        uses.contains(wgt::TextureUses::COLOR_TARGET),
193    );
194    u.set(
195        wgt::TextureUsages::STORAGE_ATOMIC,
196        uses.contains(wgt::TextureUses::STORAGE_ATOMIC),
197    );
198    u.set(
199        wgt::TextureUsages::TRANSIENT_ATTACHMENT,
200        uses.contains(wgt::TextureUses::TRANSIENT),
201    );
202    u
203}
204
205/// Check the requested texture size against the supported limits.
206///
207/// This function implements the texture size and sample count checks in [vtd
208/// dimension step]. The format checks are elsewhere in [`create_texture`]`.
209///
210/// Note that while there is some basic checking of the sample count here, there
211/// is an additional set of checks when `sample_count > 1` elsewhere in
212/// [`create_texture`]`.
213///
214/// [vtd dimension step]: https://www.w3.org/TR/2025/CRD-webgpu-20251120/#:~:text=or%204.-,If%20descriptor.dimension%20is
215/// [`create_texture`]: crate::device::Device::create_texture
216pub fn check_texture_dimension_size(
217    dimension: wgt::TextureDimension,
218    wgt::Extent3d {
219        width,
220        height,
221        depth_or_array_layers,
222    }: wgt::Extent3d,
223    sample_size: u32,
224    limits: &wgt::Limits,
225) -> Result<(), resource::TextureDimensionError> {
226    use resource::{TextureDimensionError as Tde, TextureErrorDimension as Ted};
227    use wgt::TextureDimension::*;
228
229    let (extent_limits, sample_limit) = match dimension {
230        D1 => ([limits.max_texture_dimension_1d, 1, 1], 1),
231        D2 => (
232            [
233                limits.max_texture_dimension_2d,
234                limits.max_texture_dimension_2d,
235                limits.max_texture_array_layers,
236            ],
237            32,
238        ),
239        D3 => (
240            [
241                limits.max_texture_dimension_3d,
242                limits.max_texture_dimension_3d,
243                limits.max_texture_dimension_3d,
244            ],
245            1,
246        ),
247    };
248
249    for (&dim, (&given, &limit)) in [Ted::X, Ted::Y, Ted::Z].iter().zip(
250        [width, height, depth_or_array_layers]
251            .iter()
252            .zip(extent_limits.iter()),
253    ) {
254        if given == 0 {
255            return Err(Tde::Zero(dim));
256        }
257        if given > limit {
258            return Err(Tde::LimitExceeded { dim, given, limit });
259        }
260    }
261    if sample_size == 0 || sample_size > sample_limit || !sample_size.is_power_of_two() {
262        return Err(Tde::InvalidSampleCount(sample_size));
263    }
264
265    Ok(())
266}
267
268pub fn bind_group_layout_flags(features: wgt::Features) -> hal::BindGroupLayoutFlags {
269    let mut flags = hal::BindGroupLayoutFlags::empty();
270    flags.set(
271        hal::BindGroupLayoutFlags::PARTIALLY_BOUND,
272        features.contains(wgt::Features::PARTIALLY_BOUND_BINDING_ARRAY),
273    );
274    flags
275}