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