wgpu_core/
conv.rs

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