1use alloc::vec::Vec;
2use core::num::NonZeroU8;
3
4use crate::dfd::{Basic, ChannelTypeQualifiers, DataFormatFlags, SampleInformation};
5use crate::{ColorModel, ColorPrimaries, Format, TransferFunction};
6
7const CHANNEL_R: u8 = 0;
9const CHANNEL_G: u8 = 1;
10const CHANNEL_B: u8 = 2;
11const CHANNEL_STENCIL: u8 = 13;
12const CHANNEL_DEPTH: u8 = 14;
13const CHANNEL_ALPHA: u8 = 15;
14
15const CHANNEL_Y: u8 = 0;
17const CHANNEL_U: u8 = 1;
18const CHANNEL_V: u8 = 2;
19
20const BC_COLOR: u8 = 0;
23const BC1A_ALPHA: u8 = 1;
25const BC5_RED: u8 = 0;
26const BC5_GREEN: u8 = 1;
27const BC_ALPHA: u8 = 15;
28
29const ETC2_RED: u8 = 0;
31const ETC2_GREEN: u8 = 1;
32const ETC2_COLOR: u8 = 2;
33const ETC2_ALPHA: u8 = 15;
34
35const ASTC_DATA: u8 = 0;
37
38const PVRTC_COLOR: u8 = 0;
40
41const RGB9E5_MANTISSA_BITS: u8 = 9;
43const RGB9E5_EXPONENT_BITS: u8 = 5;
44const RGB9E5_EXPONENT_OFFSET: u16 = 27;
45const RGB9E5_EXPONENT_BIAS: u32 = 15;
46const RGB9E5_EXPONENT_MAX: u32 = (1 << RGB9E5_EXPONENT_BITS) - 1;
47const RGB9E5_MANTISSA_UPPER: u32 = 8448;
51
52const SAMPLE_POS_ORIGIN: [u8; 4] = [0, 0, 0, 0];
54const HALF_TEXEL: u8 = 128;
57
58#[derive(Debug, Clone, Copy, PartialEq, Eq)]
60pub enum Datatype {
61 Unorm,
63 Snorm,
65 Uint,
67 Sint,
69 Sfloat,
71 Ufloat,
73 Sfixed5,
75}
76
77#[derive(Debug, Clone, Copy, PartialEq, Eq)]
79pub enum ChromaSubsamplingSampleOrder {
80 Gbgr,
82 Bgrg,
84}
85
86#[derive(Debug, Clone, Copy, PartialEq, Eq)]
92pub(super) enum FormatInherentTransferFunction {
93 Linear,
96 LinearWithSrgbCounterpart,
100 Srgb,
102}
103
104#[derive(Debug)]
106#[non_exhaustive]
107pub enum BuildError {
108 UnsupportedFormat,
110 DepthStencilPremultipliedAlpha,
113 DepthStencilTransferFunction,
116 DepthStencilColorPrimaries,
119 DepthStencilColorModel,
122 CompressedColorModel,
125 SrgbTransferNotAllowed,
128 SrgbTransferRequired,
131}
132
133impl core::fmt::Display for BuildError {
134 fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
135 let str = match self {
136 Self::UnsupportedFormat => "format is not recognized by the DFD generation table",
137 Self::DepthStencilPremultipliedAlpha => {
138 "premultiplied alpha is not supported for depth-stencil formats (no alpha channel)"
139 }
140 Self::DepthStencilTransferFunction => {
141 "transfer function override is not supported for depth-stencil formats (always linear)"
142 }
143 Self::DepthStencilColorPrimaries => {
144 "color primaries override is not supported for depth-stencil formats (always BT.709)"
145 }
146 Self::DepthStencilColorModel => {
147 "color model override is not supported for depth-stencil formats (always RGBSDA)"
148 }
149 Self::CompressedColorModel => {
150 "color model override is not supported for compressed formats (must use intrinsic model)"
151 }
152 Self::SrgbTransferNotAllowed => {
153 "sRGB transfer function is not allowed for this format; use the dedicated sRGB variant instead"
154 }
155 Self::SrgbTransferRequired => "this format is an sRGB variant and must use sRGB transfer function",
156 };
157
158 f.pad(str)
159 }
160}
161
162#[cfg(feature = "std")]
163impl std::error::Error for BuildError {}
164
165#[derive(Debug, Clone, Copy, PartialEq, Eq)]
167pub(super) enum Builder {
168 Standard {
170 datatype: Datatype,
172 srgb: FormatInherentTransferFunction,
174 bytes_per_texel: u8,
176 type_size: u8,
185 bit_count: &'static [u8],
187 bit_offset: &'static [u8],
189 channel_ids: &'static [u8],
191 },
192 DepthStencil {
194 depth_bits: u8,
196 depth_datatype: Datatype,
198 },
199 Rgb9e5,
201 Compressed {
203 color_model: ColorModel,
205 srgb: FormatInherentTransferFunction,
207 block_dimensions: [u8; 3],
209 bytes_per_block: u8,
211 datatype: Datatype,
213 channel_types: &'static [u8],
217 },
218 Subsampled422 {
220 sample_order: ChromaSubsamplingSampleOrder,
222 bit_width: u8,
224 },
225}
226
227impl Builder {
228 pub fn type_size(&self) -> u32 {
233 let type8 = match *self {
234 Builder::Standard { type_size, .. } => type_size,
235 Builder::Compressed { .. } => 1,
236 Builder::DepthStencil { depth_bits, .. } => match depth_bits {
239 16 => 2,
240 24 => 4, 32 => 4,
242 _ => unreachable!("unsupported depth bit width: {depth_bits}"),
243 },
244 Builder::Rgb9e5 => 4, Builder::Subsampled422 { bit_width, .. } => (bit_width + 7) / 8, };
247 type8 as u32
248 }
249
250 pub fn from_format(format: Format) -> Option<Builder> {
260 use ColorModel as Cm;
261 use Datatype as Dt;
262 use Format as F;
263 use FormatInherentTransferFunction::{Linear, LinearWithSrgbCounterpart as Counterpart, Srgb};
264
265 const R: u8 = CHANNEL_R;
266 const G: u8 = CHANNEL_G;
267 const B: u8 = CHANNEL_B;
268 const A: u8 = CHANNEL_ALPHA;
269 const D: u8 = CHANNEL_DEPTH;
270 const S: u8 = CHANNEL_STENCIL;
271
272 fn s(
273 datatype: Datatype,
274 srgb: FormatInherentTransferFunction,
275 bytes_per_texel: u8,
276 type_size: u8,
277 bit_count: &'static [u8],
278 bit_offset: &'static [u8],
279 channel_ids: &'static [u8],
280 ) -> Builder {
281 Builder::Standard {
282 datatype,
283 srgb,
284 bytes_per_texel,
285 type_size,
286 bit_count,
287 bit_offset,
288 channel_ids,
289 }
290 }
291
292 fn ds(depth_bits: u8, depth_datatype: Datatype) -> Builder {
293 Builder::DepthStencil {
294 depth_bits,
295 depth_datatype,
296 }
297 }
298
299 fn c422(sample_order: ChromaSubsamplingSampleOrder, bit_width: u8) -> Builder {
300 Builder::Subsampled422 {
301 sample_order,
302 bit_width,
303 }
304 }
305
306 #[allow(clippy::too_many_arguments)]
307 fn c(
308 color_model: ColorModel,
309 srgb: FormatInherentTransferFunction,
310 block_dimensions: [u8; 3],
311 bytes_per_block: u8,
312 datatype: Datatype,
313 channel_types: &'static [u8],
314 ) -> Builder {
315 Builder::Compressed {
316 color_model,
317 srgb,
318 block_dimensions,
319 bytes_per_block,
320 datatype,
321 channel_types,
322 }
323 }
324
325 #[rustfmt::skip]
332 let res = match format {
333 F::R4G4_UNORM_PACK8 => s(Dt::Unorm, Linear, 1, 1, &[4, 4], &[0, 4], &[G, R]),
335
336 F::R4G4B4A4_UNORM_PACK16 => s(Dt::Unorm, Linear, 2, 2, &[4, 4, 4, 4], &[0, 4, 8, 12], &[A, B, G, R]),
339 F::B4G4R4A4_UNORM_PACK16 => s(Dt::Unorm, Linear, 2, 2, &[4, 4, 4, 4], &[0, 4, 8, 12], &[A, R, G, B]),
340 F::R5G6B5_UNORM_PACK16 => s(Dt::Unorm, Linear, 2, 2, &[5, 6, 5], &[0, 5, 11], &[B, G, R]),
341 F::B5G6R5_UNORM_PACK16 => s(Dt::Unorm, Linear, 2, 2, &[5, 6, 5], &[0, 5, 11], &[R, G, B]),
342 F::R5G5B5A1_UNORM_PACK16 => s(Dt::Unorm, Linear, 2, 2, &[1, 5, 5, 5], &[0, 1, 6, 11], &[A, B, G, R]),
343 F::B5G5R5A1_UNORM_PACK16 => s(Dt::Unorm, Linear, 2, 2, &[1, 5, 5, 5], &[0, 1, 6, 11], &[A, R, G, B]),
344 F::A1R5G5B5_UNORM_PACK16 => s(Dt::Unorm, Linear, 2, 2, &[5, 5, 5, 1], &[0, 5, 10, 15], &[B, G, R, A]),
345
346 F::R8_UNORM => s(Dt::Unorm, Counterpart, 1, 1, &[8], &[0], &[R]),
348 F::R8_SNORM => s(Dt::Snorm, Linear, 1, 1, &[8], &[0], &[R]),
349 F::R8_UINT => s(Dt::Uint, Linear, 1, 1, &[8], &[0], &[R]),
350 F::R8_SINT => s(Dt::Sint, Linear, 1, 1, &[8], &[0], &[R]),
351 F::R8_SRGB => s(Dt::Unorm, Srgb, 1, 1, &[8], &[0], &[R]),
352
353 F::R8G8_UNORM => s(Dt::Unorm, Counterpart, 2, 1, &[8, 8], &[0, 8], &[R, G]),
355 F::R8G8_SNORM => s(Dt::Snorm, Linear, 2, 1, &[8, 8], &[0, 8], &[R, G]),
356 F::R8G8_UINT => s(Dt::Uint, Linear, 2, 1, &[8, 8], &[0, 8], &[R, G]),
357 F::R8G8_SINT => s(Dt::Sint, Linear, 2, 1, &[8, 8], &[0, 8], &[R, G]),
358 F::R8G8_SRGB => s(Dt::Unorm, Srgb, 2, 1, &[8, 8], &[0, 8], &[R, G]),
359
360 F::R8G8B8_UNORM => s(Dt::Unorm, Counterpart, 3, 1, &[8, 8, 8], &[0, 8, 16], &[R, G, B]),
362 F::R8G8B8_SNORM => s(Dt::Snorm, Linear, 3, 1, &[8, 8, 8], &[0, 8, 16], &[R, G, B]),
363 F::R8G8B8_UINT => s(Dt::Uint, Linear, 3, 1, &[8, 8, 8], &[0, 8, 16], &[R, G, B]),
364 F::R8G8B8_SINT => s(Dt::Sint, Linear, 3, 1, &[8, 8, 8], &[0, 8, 16], &[R, G, B]),
365 F::R8G8B8_SRGB => s(Dt::Unorm, Srgb, 3, 1, &[8, 8, 8], &[0, 8, 16], &[R, G, B]),
366
367 F::B8G8R8_UNORM => s(Dt::Unorm, Counterpart, 3, 1, &[8, 8, 8], &[0, 8, 16], &[B, G, R]),
369 F::B8G8R8_SNORM => s(Dt::Snorm, Linear, 3, 1, &[8, 8, 8], &[0, 8, 16], &[B, G, R]),
370 F::B8G8R8_UINT => s(Dt::Uint, Linear, 3, 1, &[8, 8, 8], &[0, 8, 16], &[B, G, R]),
371 F::B8G8R8_SINT => s(Dt::Sint, Linear, 3, 1, &[8, 8, 8], &[0, 8, 16], &[B, G, R]),
372 F::B8G8R8_SRGB => s(Dt::Unorm, Srgb, 3, 1, &[8, 8, 8], &[0, 8, 16], &[B, G, R]),
373
374 F::R8G8B8A8_UNORM => s(Dt::Unorm, Counterpart, 4, 1, &[8, 8, 8, 8], &[0, 8, 16, 24], &[R, G, B, A]),
376 F::R8G8B8A8_SNORM => s(Dt::Snorm, Linear, 4, 1, &[8, 8, 8, 8], &[0, 8, 16, 24], &[R, G, B, A]),
377 F::R8G8B8A8_UINT => s(Dt::Uint, Linear, 4, 1, &[8, 8, 8, 8], &[0, 8, 16, 24], &[R, G, B, A]),
378 F::R8G8B8A8_SINT => s(Dt::Sint, Linear, 4, 1, &[8, 8, 8, 8], &[0, 8, 16, 24], &[R, G, B, A]),
379 F::R8G8B8A8_SRGB => s(Dt::Unorm, Srgb, 4, 1, &[8, 8, 8, 8], &[0, 8, 16, 24], &[R, G, B, A]),
380
381 F::B8G8R8A8_UNORM => s(Dt::Unorm, Counterpart, 4, 1, &[8, 8, 8, 8], &[0, 8, 16, 24], &[B, G, R, A]),
383 F::B8G8R8A8_SNORM => s(Dt::Snorm, Linear, 4, 1, &[8, 8, 8, 8], &[0, 8, 16, 24], &[B, G, R, A]),
384 F::B8G8R8A8_UINT => s(Dt::Uint, Linear, 4, 1, &[8, 8, 8, 8], &[0, 8, 16, 24], &[B, G, R, A]),
385 F::B8G8R8A8_SINT => s(Dt::Sint, Linear, 4, 1, &[8, 8, 8, 8], &[0, 8, 16, 24], &[B, G, R, A]),
386 F::B8G8R8A8_SRGB => s(Dt::Unorm, Srgb, 4, 1, &[8, 8, 8, 8], &[0, 8, 16, 24], &[B, G, R, A]),
387
388 F::A8B8G8R8_UNORM_PACK32 => s(Dt::Unorm, Counterpart, 4, 4, &[8, 8, 8, 8], &[0, 8, 16, 24], &[R, G, B, A]),
390 F::A8B8G8R8_SNORM_PACK32 => s(Dt::Snorm, Linear, 4, 4, &[8, 8, 8, 8], &[0, 8, 16, 24], &[R, G, B, A]),
391 F::A8B8G8R8_UINT_PACK32 => s(Dt::Uint, Linear, 4, 4, &[8, 8, 8, 8], &[0, 8, 16, 24], &[R, G, B, A]),
392 F::A8B8G8R8_SINT_PACK32 => s(Dt::Sint, Linear, 4, 4, &[8, 8, 8, 8], &[0, 8, 16, 24], &[R, G, B, A]),
393 F::A8B8G8R8_SRGB_PACK32 => s(Dt::Unorm, Srgb, 4, 4, &[8, 8, 8, 8], &[0, 8, 16, 24], &[R, G, B, A]),
394
395 F::A2R10G10B10_UNORM_PACK32 => s(Dt::Unorm, Linear, 4, 4, &[10, 10, 10, 2], &[0, 10, 20, 30], &[B, G, R, A]),
397 F::A2R10G10B10_SNORM_PACK32 => s(Dt::Snorm, Linear, 4, 4, &[10, 10, 10, 2], &[0, 10, 20, 30], &[B, G, R, A]),
398 F::A2R10G10B10_UINT_PACK32 => s(Dt::Uint, Linear, 4, 4, &[10, 10, 10, 2], &[0, 10, 20, 30], &[B, G, R, A]),
399 F::A2R10G10B10_SINT_PACK32 => s(Dt::Sint, Linear, 4, 4, &[10, 10, 10, 2], &[0, 10, 20, 30], &[B, G, R, A]),
400
401 F::A2B10G10R10_UNORM_PACK32 => s(Dt::Unorm, Linear, 4, 4, &[10, 10, 10, 2], &[0, 10, 20, 30], &[R, G, B, A]),
403 F::A2B10G10R10_SNORM_PACK32 => s(Dt::Snorm, Linear, 4, 4, &[10, 10, 10, 2], &[0, 10, 20, 30], &[R, G, B, A]),
404 F::A2B10G10R10_UINT_PACK32 => s(Dt::Uint, Linear, 4, 4, &[10, 10, 10, 2], &[0, 10, 20, 30], &[R, G, B, A]),
405 F::A2B10G10R10_SINT_PACK32 => s(Dt::Sint, Linear, 4, 4, &[10, 10, 10, 2], &[0, 10, 20, 30], &[R, G, B, A]),
406
407 F::R16_UNORM => s(Dt::Unorm, Linear, 2, 2, &[16], &[0], &[R]),
409 F::R16_SNORM => s(Dt::Snorm, Linear, 2, 2, &[16], &[0], &[R]),
410 F::R16_UINT => s(Dt::Uint, Linear, 2, 2, &[16], &[0], &[R]),
411 F::R16_SINT => s(Dt::Sint, Linear, 2, 2, &[16], &[0], &[R]),
412 F::R16_SFLOAT => s(Dt::Sfloat, Linear, 2, 2, &[16], &[0], &[R]),
413
414 F::R16G16_UNORM => s(Dt::Unorm, Linear, 4, 2, &[16, 16], &[0, 16], &[R, G]),
416 F::R16G16_SNORM => s(Dt::Snorm, Linear, 4, 2, &[16, 16], &[0, 16], &[R, G]),
417 F::R16G16_UINT => s(Dt::Uint, Linear, 4, 2, &[16, 16], &[0, 16], &[R, G]),
418 F::R16G16_SINT => s(Dt::Sint, Linear, 4, 2, &[16, 16], &[0, 16], &[R, G]),
419 F::R16G16_SFLOAT => s(Dt::Sfloat, Linear, 4, 2, &[16, 16], &[0, 16], &[R, G]),
420
421 F::R16G16B16_UNORM => s(Dt::Unorm, Linear, 6, 2, &[16, 16, 16], &[0, 16, 32], &[R, G, B]),
423 F::R16G16B16_SNORM => s(Dt::Snorm, Linear, 6, 2, &[16, 16, 16], &[0, 16, 32], &[R, G, B]),
424 F::R16G16B16_UINT => s(Dt::Uint, Linear, 6, 2, &[16, 16, 16], &[0, 16, 32], &[R, G, B]),
425 F::R16G16B16_SINT => s(Dt::Sint, Linear, 6, 2, &[16, 16, 16], &[0, 16, 32], &[R, G, B]),
426 F::R16G16B16_SFLOAT => s(Dt::Sfloat, Linear, 6, 2, &[16, 16, 16], &[0, 16, 32], &[R, G, B]),
427
428 F::R16G16B16A16_UNORM => s(Dt::Unorm, Linear, 8, 2, &[16, 16, 16, 16], &[0, 16, 32, 48], &[R, G, B, A]),
430 F::R16G16B16A16_SNORM => s(Dt::Snorm, Linear, 8, 2, &[16, 16, 16, 16], &[0, 16, 32, 48], &[R, G, B, A]),
431 F::R16G16B16A16_UINT => s(Dt::Uint, Linear, 8, 2, &[16, 16, 16, 16], &[0, 16, 32, 48], &[R, G, B, A]),
432 F::R16G16B16A16_SINT => s(Dt::Sint, Linear, 8, 2, &[16, 16, 16, 16], &[0, 16, 32, 48], &[R, G, B, A]),
433 F::R16G16B16A16_SFLOAT => s(Dt::Sfloat, Linear, 8, 2, &[16, 16, 16, 16], &[0, 16, 32, 48], &[R, G, B, A]),
434
435 F::R32_UINT => s(Dt::Uint, Linear, 4, 4, &[32], &[0], &[R]),
437 F::R32_SINT => s(Dt::Sint, Linear, 4, 4, &[32], &[0], &[R]),
438 F::R32_SFLOAT => s(Dt::Sfloat, Linear, 4, 4, &[32], &[0], &[R]),
439
440 F::R32G32_UINT => s(Dt::Uint, Linear, 8, 4, &[32, 32], &[0, 32], &[R, G]),
442 F::R32G32_SINT => s(Dt::Sint, Linear, 8, 4, &[32, 32], &[0, 32], &[R, G]),
443 F::R32G32_SFLOAT => s(Dt::Sfloat, Linear, 8, 4, &[32, 32], &[0, 32], &[R, G]),
444
445 F::R32G32B32_UINT => s(Dt::Uint, Linear, 12, 4, &[32, 32, 32], &[0, 32, 64], &[R, G, B]),
447 F::R32G32B32_SINT => s(Dt::Sint, Linear, 12, 4, &[32, 32, 32], &[0, 32, 64], &[R, G, B]),
448 F::R32G32B32_SFLOAT => s(Dt::Sfloat, Linear, 12, 4, &[32, 32, 32], &[0, 32, 64], &[R, G, B]),
449
450 F::R32G32B32A32_UINT => s(Dt::Uint, Linear, 16, 4, &[32, 32, 32, 32], &[0, 32, 64, 96], &[R, G, B, A]),
452 F::R32G32B32A32_SINT => s(Dt::Sint, Linear, 16, 4, &[32, 32, 32, 32], &[0, 32, 64, 96], &[R, G, B, A]),
453 F::R32G32B32A32_SFLOAT => s(Dt::Sfloat, Linear, 16, 4, &[32, 32, 32, 32], &[0, 32, 64, 96], &[R, G, B, A]),
454
455 F::R64_UINT => s(Dt::Uint, Linear, 8, 8, &[64], &[0], &[R]),
457 F::R64_SINT => s(Dt::Sint, Linear, 8, 8, &[64], &[0], &[R]),
458 F::R64_SFLOAT => s(Dt::Sfloat, Linear, 8, 8, &[64], &[0], &[R]),
459
460 F::R64G64_UINT => s(Dt::Uint, Linear, 16, 8, &[64, 64], &[0, 64], &[R, G]),
462 F::R64G64_SINT => s(Dt::Sint, Linear, 16, 8, &[64, 64], &[0, 64], &[R, G]),
463 F::R64G64_SFLOAT => s(Dt::Sfloat, Linear, 16, 8, &[64, 64], &[0, 64], &[R, G]),
464
465 F::R64G64B64_UINT => s(Dt::Uint, Linear, 24, 8, &[64, 64, 64], &[0, 64, 128], &[R, G, B]),
467 F::R64G64B64_SINT => s(Dt::Sint, Linear, 24, 8, &[64, 64, 64], &[0, 64, 128], &[R, G, B]),
468 F::R64G64B64_SFLOAT => s(Dt::Sfloat, Linear, 24, 8, &[64, 64, 64], &[0, 64, 128], &[R, G, B]),
469
470 F::R64G64B64A64_UINT => s(Dt::Uint, Linear, 32, 8, &[64, 64, 64, 64], &[0, 64, 128, 192], &[R, G, B, A]),
472 F::R64G64B64A64_SINT => s(Dt::Sint, Linear, 32, 8, &[64, 64, 64, 64], &[0, 64, 128, 192], &[R, G, B, A]),
473 F::R64G64B64A64_SFLOAT => s(Dt::Sfloat, Linear, 32, 8, &[64, 64, 64, 64], &[0, 64, 128, 192], &[R, G, B, A]),
474
475 F::B10G11R11_UFLOAT_PACK32 => s(Dt::Ufloat, Linear, 4, 4, &[11, 11, 10], &[0, 11, 22], &[R, G, B]),
477
478 F::D16_UNORM => s(Dt::Unorm, Linear, 2, 2, &[16], &[0], &[D]),
480 F::X8_D24_UNORM_PACK32 => s(Dt::Unorm, Linear, 4, 4, &[24], &[0], &[D]),
481 F::D32_SFLOAT => s(Dt::Sfloat, Linear, 4, 4, &[32], &[0], &[D]),
482 F::S8_UINT => s(Dt::Uint, Linear, 1, 1, &[8], &[0], &[S]),
483
484 F::A4R4G4B4_UNORM_PACK16 => s(Dt::Unorm, Linear, 2, 2, &[4, 4, 4, 4], &[0, 4, 8, 12], &[B, G, R, A]),
486 F::A4B4G4R4_UNORM_PACK16 => s(Dt::Unorm, Linear, 2, 2, &[4, 4, 4, 4], &[0, 4, 8, 12], &[R, G, B, A]),
487 F::A1B5G5R5_UNORM_PACK16 => s(Dt::Unorm, Linear, 2, 2, &[5, 5, 5, 1], &[0, 5, 10, 15], &[R, G, B, A]),
488
489 F::R16G16_SFIXED5 => s(Dt::Sfixed5, Linear, 4, 2, &[16, 16], &[0, 16], &[R, G]),
491 F::A8_UNORM => s(Dt::Unorm, Linear, 1, 1, &[8], &[0], &[A]),
492
493 F::R10X6_UNORM_PACK16 => s(Dt::Unorm, Linear, 2, 2, &[10], &[6], &[R]),
498 F::R10X6G10X6_UNORM_2PACK16 => s(Dt::Unorm, Linear, 4, 2, &[10, 10], &[6, 22], &[R, G]),
499 F::R10X6G10X6B10X6A10X6_UNORM_4PACK16 => s(Dt::Unorm, Linear, 8, 2, &[10, 10, 10, 10], &[6, 22, 38, 54], &[R, G, B, A]),
500 F::R10X6_UINT_PACK16 => s(Dt::Uint, Linear, 2, 2, &[10], &[6], &[R]),
501 F::R10X6G10X6_UINT_2PACK16 => s(Dt::Uint, Linear, 4, 2, &[10, 10], &[6, 22], &[R, G]),
502 F::R10X6G10X6B10X6A10X6_UINT_4PACK16 => s(Dt::Uint, Linear, 8, 2, &[10, 10, 10, 10], &[6, 22, 38, 54], &[R, G, B, A]),
503
504 F::R12X4_UNORM_PACK16 => s(Dt::Unorm, Linear, 2, 2, &[12], &[4], &[R]),
506 F::R12X4G12X4_UNORM_2PACK16 => s(Dt::Unorm, Linear, 4, 2, &[12, 12], &[4, 20], &[R, G]),
507 F::R12X4G12X4B12X4A12X4_UNORM_4PACK16 => s(Dt::Unorm, Linear, 8, 2, &[12, 12, 12, 12], &[4, 20, 36, 52], &[R, G, B, A]),
508 F::R12X4_UINT_PACK16 => s(Dt::Uint, Linear, 2, 2, &[12], &[4], &[R]),
509 F::R12X4G12X4_UINT_2PACK16 => s(Dt::Uint, Linear, 4, 2, &[12, 12], &[4, 20], &[R, G]),
510 F::R12X4G12X4B12X4A12X4_UINT_4PACK16 => s(Dt::Uint, Linear, 8, 2, &[12, 12, 12, 12], &[4, 20, 36, 52], &[R, G, B, A]),
511
512 F::R14X2_UNORM_PACK16 => s(Dt::Unorm, Linear, 2, 2, &[14], &[2], &[R]),
514 F::R14X2G14X2_UNORM_2PACK16 => s(Dt::Unorm, Linear, 4, 2, &[14, 14], &[2, 18], &[R, G]),
515 F::R14X2G14X2B14X2A14X2_UNORM_4PACK16 => s(Dt::Unorm, Linear, 8, 2, &[14, 14, 14, 14], &[2, 18, 34, 50], &[R, G, B, A]),
516 F::R14X2_UINT_PACK16 => s(Dt::Uint, Linear, 2, 2, &[14], &[2], &[R]),
517 F::R14X2G14X2_UINT_2PACK16 => s(Dt::Uint, Linear, 4, 2, &[14, 14], &[2, 18], &[R, G]),
518 F::R14X2G14X2B14X2A14X2_UINT_4PACK16 => s(Dt::Uint, Linear, 8, 2, &[14, 14, 14, 14], &[2, 18, 34, 50], &[R, G, B, A]),
519
520 F::E5B9G9R9_UFLOAT_PACK32 => Builder::Rgb9e5,
522
523 F::D16_UNORM_S8_UINT => ds(16, Dt::Unorm),
526 F::D24_UNORM_S8_UINT => ds(24, Dt::Unorm),
527 F::D32_SFLOAT_S8_UINT => ds(32, Dt::Sfloat),
528
529 F::G8B8G8R8_422_UNORM => c422(ChromaSubsamplingSampleOrder::Gbgr, 8),
532 F::B8G8R8G8_422_UNORM => c422(ChromaSubsamplingSampleOrder::Bgrg, 8),
533 F::G10X6B10X6G10X6R10X6_422_UNORM_4PACK16 => c422(ChromaSubsamplingSampleOrder::Gbgr, 10),
534 F::B10X6G10X6R10X6G10X6_422_UNORM_4PACK16 => c422(ChromaSubsamplingSampleOrder::Bgrg, 10),
535 F::G12X4B12X4G12X4R12X4_422_UNORM_4PACK16 => c422(ChromaSubsamplingSampleOrder::Gbgr, 12),
536 F::B12X4G12X4R12X4G12X4_422_UNORM_4PACK16 => c422(ChromaSubsamplingSampleOrder::Bgrg, 12),
537 F::G16B16G16R16_422_UNORM => c422(ChromaSubsamplingSampleOrder::Gbgr, 16),
538 F::B16G16R16G16_422_UNORM => c422(ChromaSubsamplingSampleOrder::Bgrg, 16),
539
540 F::BC1_RGB_UNORM_BLOCK => c(Cm::BC1A, Counterpart, [4, 4, 1], 8, Dt::Unorm, &[BC_COLOR]),
543 F::BC1_RGB_SRGB_BLOCK => c(Cm::BC1A, Srgb, [4, 4, 1], 8, Dt::Unorm, &[BC_COLOR]),
544 F::BC1_RGBA_UNORM_BLOCK => c(Cm::BC1A, Counterpart, [4, 4, 1], 8, Dt::Unorm, &[BC1A_ALPHA]),
545 F::BC1_RGBA_SRGB_BLOCK => c(Cm::BC1A, Srgb, [4, 4, 1], 8, Dt::Unorm, &[BC1A_ALPHA]),
546 F::BC2_UNORM_BLOCK => c(Cm::BC2, Counterpart, [4, 4, 1], 16, Dt::Unorm, &[BC_ALPHA, BC_COLOR]),
547 F::BC2_SRGB_BLOCK => c(Cm::BC2, Srgb, [4, 4, 1], 16, Dt::Unorm, &[BC_ALPHA, BC_COLOR]),
548 F::BC3_UNORM_BLOCK => c(Cm::BC3, Counterpart, [4, 4, 1], 16, Dt::Unorm, &[BC_ALPHA, BC_COLOR]),
549 F::BC3_SRGB_BLOCK => c(Cm::BC3, Srgb, [4, 4, 1], 16, Dt::Unorm, &[BC_ALPHA, BC_COLOR]),
550 F::BC4_UNORM_BLOCK => c(Cm::BC4, Linear, [4, 4, 1], 8, Dt::Unorm, &[BC_COLOR]),
551 F::BC4_SNORM_BLOCK => c(Cm::BC4, Linear, [4, 4, 1], 8, Dt::Snorm, &[BC_COLOR]),
552 F::BC5_UNORM_BLOCK => c(Cm::BC5, Linear, [4, 4, 1], 16, Dt::Unorm, &[BC5_RED, BC5_GREEN]),
553 F::BC5_SNORM_BLOCK => c(Cm::BC5, Linear, [4, 4, 1], 16, Dt::Snorm, &[BC5_RED, BC5_GREEN]),
554 F::BC6H_UFLOAT_BLOCK => c(Cm::BC6H, Linear, [4, 4, 1], 16, Dt::Ufloat, &[BC_COLOR]),
555 F::BC6H_SFLOAT_BLOCK => c(Cm::BC6H, Linear, [4, 4, 1], 16, Dt::Sfloat, &[BC_COLOR]),
556 F::BC7_UNORM_BLOCK => c(Cm::BC7, Counterpart, [4, 4, 1], 16, Dt::Unorm, &[BC_COLOR]),
557 F::BC7_SRGB_BLOCK => c(Cm::BC7, Srgb, [4, 4, 1], 16, Dt::Unorm, &[BC_COLOR]),
558
559 F::ETC2_R8G8B8_UNORM_BLOCK => c(Cm::ETC2, Counterpart, [4, 4, 1], 8, Dt::Unorm, &[ETC2_COLOR]),
561 F::ETC2_R8G8B8_SRGB_BLOCK => c(Cm::ETC2, Srgb, [4, 4, 1], 8, Dt::Unorm, &[ETC2_COLOR]),
562 F::ETC2_R8G8B8A1_UNORM_BLOCK => c(Cm::ETC2, Counterpart, [4, 4, 1], 8, Dt::Unorm, &[ETC2_COLOR, ETC2_ALPHA]),
563 F::ETC2_R8G8B8A1_SRGB_BLOCK => c(Cm::ETC2, Srgb, [4, 4, 1], 8, Dt::Unorm, &[ETC2_COLOR, ETC2_ALPHA]),
564 F::ETC2_R8G8B8A8_UNORM_BLOCK => c(Cm::ETC2, Counterpart, [4, 4, 1], 16, Dt::Unorm, &[ETC2_ALPHA, ETC2_COLOR]),
565 F::ETC2_R8G8B8A8_SRGB_BLOCK => c(Cm::ETC2, Srgb, [4, 4, 1], 16, Dt::Unorm, &[ETC2_ALPHA, ETC2_COLOR]),
566 F::EAC_R11_UNORM_BLOCK => c(Cm::ETC2, Linear, [4, 4, 1], 8, Dt::Unorm, &[ETC2_RED]),
567 F::EAC_R11_SNORM_BLOCK => c(Cm::ETC2, Linear, [4, 4, 1], 8, Dt::Snorm, &[ETC2_RED]),
568 F::EAC_R11G11_UNORM_BLOCK => c(Cm::ETC2, Linear, [4, 4, 1], 16, Dt::Unorm, &[ETC2_RED, ETC2_GREEN]),
569 F::EAC_R11G11_SNORM_BLOCK => c(Cm::ETC2, Linear, [4, 4, 1], 16, Dt::Snorm, &[ETC2_RED, ETC2_GREEN]),
570
571 F::ASTC_4x4_UNORM_BLOCK => c(Cm::ASTC, Counterpart, [4, 4, 1], 16, Dt::Unorm, &[ASTC_DATA]),
573 F::ASTC_4x4_SRGB_BLOCK => c(Cm::ASTC, Srgb, [4, 4, 1], 16, Dt::Unorm, &[ASTC_DATA]),
574 F::ASTC_4x4_SFLOAT_BLOCK => c(Cm::ASTC, Linear, [4, 4, 1], 16, Dt::Sfloat, &[ASTC_DATA]),
575 F::ASTC_5x4_UNORM_BLOCK => c(Cm::ASTC, Counterpart, [5, 4, 1], 16, Dt::Unorm, &[ASTC_DATA]),
576 F::ASTC_5x4_SRGB_BLOCK => c(Cm::ASTC, Srgb, [5, 4, 1], 16, Dt::Unorm, &[ASTC_DATA]),
577 F::ASTC_5x4_SFLOAT_BLOCK => c(Cm::ASTC, Linear, [5, 4, 1], 16, Dt::Sfloat, &[ASTC_DATA]),
578 F::ASTC_5x5_UNORM_BLOCK => c(Cm::ASTC, Counterpart, [5, 5, 1], 16, Dt::Unorm, &[ASTC_DATA]),
579 F::ASTC_5x5_SRGB_BLOCK => c(Cm::ASTC, Srgb, [5, 5, 1], 16, Dt::Unorm, &[ASTC_DATA]),
580 F::ASTC_5x5_SFLOAT_BLOCK => c(Cm::ASTC, Linear, [5, 5, 1], 16, Dt::Sfloat, &[ASTC_DATA]),
581 F::ASTC_6x5_UNORM_BLOCK => c(Cm::ASTC, Counterpart, [6, 5, 1], 16, Dt::Unorm, &[ASTC_DATA]),
582 F::ASTC_6x5_SRGB_BLOCK => c(Cm::ASTC, Srgb, [6, 5, 1], 16, Dt::Unorm, &[ASTC_DATA]),
583 F::ASTC_6x5_SFLOAT_BLOCK => c(Cm::ASTC, Linear, [6, 5, 1], 16, Dt::Sfloat, &[ASTC_DATA]),
584 F::ASTC_6x6_UNORM_BLOCK => c(Cm::ASTC, Counterpart, [6, 6, 1], 16, Dt::Unorm, &[ASTC_DATA]),
585 F::ASTC_6x6_SRGB_BLOCK => c(Cm::ASTC, Srgb, [6, 6, 1], 16, Dt::Unorm, &[ASTC_DATA]),
586 F::ASTC_6x6_SFLOAT_BLOCK => c(Cm::ASTC, Linear, [6, 6, 1], 16, Dt::Sfloat, &[ASTC_DATA]),
587 F::ASTC_8x5_UNORM_BLOCK => c(Cm::ASTC, Counterpart, [8, 5, 1], 16, Dt::Unorm, &[ASTC_DATA]),
588 F::ASTC_8x5_SRGB_BLOCK => c(Cm::ASTC, Srgb, [8, 5, 1], 16, Dt::Unorm, &[ASTC_DATA]),
589 F::ASTC_8x5_SFLOAT_BLOCK => c(Cm::ASTC, Linear, [8, 5, 1], 16, Dt::Sfloat, &[ASTC_DATA]),
590 F::ASTC_8x6_UNORM_BLOCK => c(Cm::ASTC, Counterpart, [8, 6, 1], 16, Dt::Unorm, &[ASTC_DATA]),
591 F::ASTC_8x6_SRGB_BLOCK => c(Cm::ASTC, Srgb, [8, 6, 1], 16, Dt::Unorm, &[ASTC_DATA]),
592 F::ASTC_8x6_SFLOAT_BLOCK => c(Cm::ASTC, Linear, [8, 6, 1], 16, Dt::Sfloat, &[ASTC_DATA]),
593 F::ASTC_8x8_UNORM_BLOCK => c(Cm::ASTC, Counterpart, [8, 8, 1], 16, Dt::Unorm, &[ASTC_DATA]),
594 F::ASTC_8x8_SRGB_BLOCK => c(Cm::ASTC, Srgb, [8, 8, 1], 16, Dt::Unorm, &[ASTC_DATA]),
595 F::ASTC_8x8_SFLOAT_BLOCK => c(Cm::ASTC, Linear, [8, 8, 1], 16, Dt::Sfloat, &[ASTC_DATA]),
596 F::ASTC_10x5_UNORM_BLOCK => c(Cm::ASTC, Counterpart, [10, 5, 1], 16, Dt::Unorm, &[ASTC_DATA]),
597 F::ASTC_10x5_SRGB_BLOCK => c(Cm::ASTC, Srgb, [10, 5, 1], 16, Dt::Unorm, &[ASTC_DATA]),
598 F::ASTC_10x5_SFLOAT_BLOCK => c(Cm::ASTC, Linear, [10, 5, 1], 16, Dt::Sfloat, &[ASTC_DATA]),
599 F::ASTC_10x6_UNORM_BLOCK => c(Cm::ASTC, Counterpart, [10, 6, 1], 16, Dt::Unorm, &[ASTC_DATA]),
600 F::ASTC_10x6_SRGB_BLOCK => c(Cm::ASTC, Srgb, [10, 6, 1], 16, Dt::Unorm, &[ASTC_DATA]),
601 F::ASTC_10x6_SFLOAT_BLOCK => c(Cm::ASTC, Linear, [10, 6, 1], 16, Dt::Sfloat, &[ASTC_DATA]),
602 F::ASTC_10x8_UNORM_BLOCK => c(Cm::ASTC, Counterpart, [10, 8, 1], 16, Dt::Unorm, &[ASTC_DATA]),
603 F::ASTC_10x8_SRGB_BLOCK => c(Cm::ASTC, Srgb, [10, 8, 1], 16, Dt::Unorm, &[ASTC_DATA]),
604 F::ASTC_10x8_SFLOAT_BLOCK => c(Cm::ASTC, Linear, [10, 8, 1], 16, Dt::Sfloat, &[ASTC_DATA]),
605 F::ASTC_10x10_UNORM_BLOCK => c(Cm::ASTC, Counterpart, [10, 10, 1], 16, Dt::Unorm, &[ASTC_DATA]),
606 F::ASTC_10x10_SRGB_BLOCK => c(Cm::ASTC, Srgb, [10, 10, 1], 16, Dt::Unorm, &[ASTC_DATA]),
607 F::ASTC_10x10_SFLOAT_BLOCK => c(Cm::ASTC, Linear, [10, 10, 1], 16, Dt::Sfloat, &[ASTC_DATA]),
608 F::ASTC_12x10_UNORM_BLOCK => c(Cm::ASTC, Counterpart, [12, 10, 1], 16, Dt::Unorm, &[ASTC_DATA]),
609 F::ASTC_12x10_SRGB_BLOCK => c(Cm::ASTC, Srgb, [12, 10, 1], 16, Dt::Unorm, &[ASTC_DATA]),
610 F::ASTC_12x10_SFLOAT_BLOCK => c(Cm::ASTC, Linear, [12, 10, 1], 16, Dt::Sfloat, &[ASTC_DATA]),
611 F::ASTC_12x12_UNORM_BLOCK => c(Cm::ASTC, Counterpart, [12, 12, 1], 16, Dt::Unorm, &[ASTC_DATA]),
612 F::ASTC_12x12_SRGB_BLOCK => c(Cm::ASTC, Srgb, [12, 12, 1], 16, Dt::Unorm, &[ASTC_DATA]),
613 F::ASTC_12x12_SFLOAT_BLOCK => c(Cm::ASTC, Linear, [12, 12, 1], 16, Dt::Sfloat, &[ASTC_DATA]),
614
615 F::ASTC_3x3x3_UNORM_BLOCK => c(Cm::ASTC, Counterpart, [3, 3, 3], 16, Dt::Unorm, &[ASTC_DATA]),
617 F::ASTC_3x3x3_SRGB_BLOCK => c(Cm::ASTC, Srgb, [3, 3, 3], 16, Dt::Unorm, &[ASTC_DATA]),
618 F::ASTC_3x3x3_SFLOAT_BLOCK => c(Cm::ASTC, Linear, [3, 3, 3], 16, Dt::Sfloat, &[ASTC_DATA]),
619 F::ASTC_4x3x3_UNORM_BLOCK => c(Cm::ASTC, Counterpart, [4, 3, 3], 16, Dt::Unorm, &[ASTC_DATA]),
620 F::ASTC_4x3x3_SRGB_BLOCK => c(Cm::ASTC, Srgb, [4, 3, 3], 16, Dt::Unorm, &[ASTC_DATA]),
621 F::ASTC_4x3x3_SFLOAT_BLOCK => c(Cm::ASTC, Linear, [4, 3, 3], 16, Dt::Sfloat, &[ASTC_DATA]),
622 F::ASTC_4x4x3_UNORM_BLOCK => c(Cm::ASTC, Counterpart, [4, 4, 3], 16, Dt::Unorm, &[ASTC_DATA]),
623 F::ASTC_4x4x3_SRGB_BLOCK => c(Cm::ASTC, Srgb, [4, 4, 3], 16, Dt::Unorm, &[ASTC_DATA]),
624 F::ASTC_4x4x3_SFLOAT_BLOCK => c(Cm::ASTC, Linear, [4, 4, 3], 16, Dt::Sfloat, &[ASTC_DATA]),
625 F::ASTC_4x4x4_UNORM_BLOCK => c(Cm::ASTC, Counterpart, [4, 4, 4], 16, Dt::Unorm, &[ASTC_DATA]),
626 F::ASTC_4x4x4_SRGB_BLOCK => c(Cm::ASTC, Srgb, [4, 4, 4], 16, Dt::Unorm, &[ASTC_DATA]),
627 F::ASTC_4x4x4_SFLOAT_BLOCK => c(Cm::ASTC, Linear, [4, 4, 4], 16, Dt::Sfloat, &[ASTC_DATA]),
628 F::ASTC_5x4x4_UNORM_BLOCK => c(Cm::ASTC, Counterpart, [5, 4, 4], 16, Dt::Unorm, &[ASTC_DATA]),
629 F::ASTC_5x4x4_SRGB_BLOCK => c(Cm::ASTC, Srgb, [5, 4, 4], 16, Dt::Unorm, &[ASTC_DATA]),
630 F::ASTC_5x4x4_SFLOAT_BLOCK => c(Cm::ASTC, Linear, [5, 4, 4], 16, Dt::Sfloat, &[ASTC_DATA]),
631 F::ASTC_5x5x4_UNORM_BLOCK => c(Cm::ASTC, Counterpart, [5, 5, 4], 16, Dt::Unorm, &[ASTC_DATA]),
632 F::ASTC_5x5x4_SRGB_BLOCK => c(Cm::ASTC, Srgb, [5, 5, 4], 16, Dt::Unorm, &[ASTC_DATA]),
633 F::ASTC_5x5x4_SFLOAT_BLOCK => c(Cm::ASTC, Linear, [5, 5, 4], 16, Dt::Sfloat, &[ASTC_DATA]),
634 F::ASTC_5x5x5_UNORM_BLOCK => c(Cm::ASTC, Counterpart, [5, 5, 5], 16, Dt::Unorm, &[ASTC_DATA]),
635 F::ASTC_5x5x5_SRGB_BLOCK => c(Cm::ASTC, Srgb, [5, 5, 5], 16, Dt::Unorm, &[ASTC_DATA]),
636 F::ASTC_5x5x5_SFLOAT_BLOCK => c(Cm::ASTC, Linear, [5, 5, 5], 16, Dt::Sfloat, &[ASTC_DATA]),
637 F::ASTC_6x5x5_UNORM_BLOCK => c(Cm::ASTC, Counterpart, [6, 5, 5], 16, Dt::Unorm, &[ASTC_DATA]),
638 F::ASTC_6x5x5_SRGB_BLOCK => c(Cm::ASTC, Srgb, [6, 5, 5], 16, Dt::Unorm, &[ASTC_DATA]),
639 F::ASTC_6x5x5_SFLOAT_BLOCK => c(Cm::ASTC, Linear, [6, 5, 5], 16, Dt::Sfloat, &[ASTC_DATA]),
640 F::ASTC_6x6x5_UNORM_BLOCK => c(Cm::ASTC, Counterpart, [6, 6, 5], 16, Dt::Unorm, &[ASTC_DATA]),
641 F::ASTC_6x6x5_SRGB_BLOCK => c(Cm::ASTC, Srgb, [6, 6, 5], 16, Dt::Unorm, &[ASTC_DATA]),
642 F::ASTC_6x6x5_SFLOAT_BLOCK => c(Cm::ASTC, Linear, [6, 6, 5], 16, Dt::Sfloat, &[ASTC_DATA]),
643 F::ASTC_6x6x6_UNORM_BLOCK => c(Cm::ASTC, Counterpart, [6, 6, 6], 16, Dt::Unorm, &[ASTC_DATA]),
644 F::ASTC_6x6x6_SRGB_BLOCK => c(Cm::ASTC, Srgb, [6, 6, 6], 16, Dt::Unorm, &[ASTC_DATA]),
645 F::ASTC_6x6x6_SFLOAT_BLOCK => c(Cm::ASTC, Linear, [6, 6, 6], 16, Dt::Sfloat, &[ASTC_DATA]),
646
647 F::PVRTC1_2BPP_UNORM_BLOCK => c(Cm::PVRTC, Counterpart, [8, 4, 1], 8, Dt::Unorm, &[PVRTC_COLOR]),
649 F::PVRTC1_2BPP_SRGB_BLOCK => c(Cm::PVRTC, Srgb, [8, 4, 1], 8, Dt::Unorm, &[PVRTC_COLOR]),
650 F::PVRTC1_4BPP_UNORM_BLOCK => c(Cm::PVRTC, Counterpart, [4, 4, 1], 8, Dt::Unorm, &[PVRTC_COLOR]),
651 F::PVRTC1_4BPP_SRGB_BLOCK => c(Cm::PVRTC, Srgb, [4, 4, 1], 8, Dt::Unorm, &[PVRTC_COLOR]),
652 F::PVRTC2_2BPP_UNORM_BLOCK => c(Cm::PVRTC2, Counterpart, [8, 4, 1], 8, Dt::Unorm, &[PVRTC_COLOR]),
653 F::PVRTC2_2BPP_SRGB_BLOCK => c(Cm::PVRTC2, Srgb, [8, 4, 1], 8, Dt::Unorm, &[PVRTC_COLOR]),
654 F::PVRTC2_4BPP_UNORM_BLOCK => c(Cm::PVRTC2, Counterpart, [4, 4, 1], 8, Dt::Unorm, &[PVRTC_COLOR]),
655 F::PVRTC2_4BPP_SRGB_BLOCK => c(Cm::PVRTC2, Srgb, [4, 4, 1], 8, Dt::Unorm, &[PVRTC_COLOR]),
656
657 _ => return None,
659 };
660 Some(res)
661 }
662
663 pub fn build(
681 &self,
682 alpha_premultiplied: bool,
683 transfer_function: Option<TransferFunction>,
684 color_primaries: Option<ColorPrimaries>,
685 color_model: Option<ColorModel>,
686 ) -> Result<Basic, BuildError> {
687 match *self {
688 Builder::Standard {
689 datatype,
690 srgb,
691 bytes_per_texel,
692 bit_count,
693 bit_offset,
694 channel_ids,
695 ..
696 } => {
697 let color_model = color_model.unwrap_or(ColorModel::RGBSDA);
698 let color_primaries = color_primaries.unwrap_or(ColorPrimaries::BT709);
699 let transfer_function = resolve_transfer_function(srgb, transfer_function)?;
700 let flags = if alpha_premultiplied {
701 DataFormatFlags::ALPHA_PREMULTIPLIED
702 } else {
703 DataFormatFlags::STRAIGHT_ALPHA
704 };
705
706 let mut sample_information = Vec::with_capacity(channel_ids.len());
710 for i in 0..channel_ids.len() {
711 let (lower, upper) = lower_upper(datatype, bit_count[i]);
712 sample_information.push(SampleInformation {
713 bit_offset: bit_offset[i] as u16,
714 bit_length: NonZeroU8::new(bit_count[i]).unwrap(),
715 channel_type: channel_ids[i],
716 channel_type_qualifiers: sample_qualifiers(datatype, srgb, channel_ids[i]),
717 sample_positions: SAMPLE_POS_ORIGIN,
718 lower,
719 upper,
720 });
721 }
722
723 let mut bytes_planes = [0u8; 8];
724 bytes_planes[0] = bytes_per_texel;
725
726 Ok(Basic {
727 color_model: Some(color_model),
728 color_primaries: Some(color_primaries),
729 transfer_function: Some(transfer_function),
730 flags,
731 texel_block_dimensions: [NonZeroU8::new(1).unwrap(); 4],
732 bytes_planes,
733 sample_information,
734 })
735 }
736
737 Builder::DepthStencil {
738 depth_bits,
739 depth_datatype,
740 } => {
741 if alpha_premultiplied {
742 return Err(BuildError::DepthStencilPremultipliedAlpha);
743 }
744 if transfer_function.is_some() {
745 return Err(BuildError::DepthStencilTransferFunction);
746 }
747 if color_primaries.is_some() {
748 return Err(BuildError::DepthStencilColorPrimaries);
749 }
750 if color_model.is_some() {
751 return Err(BuildError::DepthStencilColorModel);
752 }
753
754 let bytes_plane0: u8 = match depth_bits {
759 16 => 4,
760 24 => 4,
761 32 => 8,
762 _ => unreachable!("unsupported depth bit width: {depth_bits}"),
763 };
764
765 let mut bytes_planes = [0u8; 8];
766 bytes_planes[0] = bytes_plane0;
767
768 let depth_quals = qualifiers(depth_datatype);
769 let (depth_lower, depth_upper) = lower_upper(depth_datatype, depth_bits);
770 let (stencil_lower, stencil_upper) = lower_upper(Datatype::Uint, 8);
771
772 let (depth_offset, stencil_offset) = match depth_bits {
776 16 => (0u16, 16u16),
777 24 => (8, 0),
778 32 => (0, 32),
779 _ => unreachable!("unsupported depth bit width: {depth_bits}"),
780 };
781
782 let mut sample_information = Vec::from([
784 SampleInformation {
785 bit_offset: depth_offset,
786 bit_length: NonZeroU8::new(depth_bits).unwrap(),
787 channel_type: CHANNEL_DEPTH,
788 channel_type_qualifiers: depth_quals,
789 sample_positions: SAMPLE_POS_ORIGIN,
790 lower: depth_lower,
791 upper: depth_upper,
792 },
793 SampleInformation {
794 bit_offset: stencil_offset,
795 bit_length: NonZeroU8::new(8).unwrap(),
796 channel_type: CHANNEL_STENCIL,
797 channel_type_qualifiers: ChannelTypeQualifiers::empty(),
798 sample_positions: SAMPLE_POS_ORIGIN,
799 lower: stencil_lower,
800 upper: stencil_upper,
801 },
802 ]);
803
804 sample_information.sort_unstable_by_key(|s| s.bit_offset);
805
806 Ok(Basic {
807 color_model: Some(ColorModel::RGBSDA),
808 color_primaries: Some(ColorPrimaries::BT709),
809 transfer_function: Some(TransferFunction::Linear),
810 flags: DataFormatFlags::empty(),
811 texel_block_dimensions: [NonZeroU8::new(1).unwrap(); 4],
812 bytes_planes,
813 sample_information,
814 })
815 }
816
817 Builder::Rgb9e5 => {
818 let color_model = color_model.unwrap_or(ColorModel::RGBSDA);
819 let color_primaries = color_primaries.unwrap_or(ColorPrimaries::BT709);
820 let transfer_function = transfer_function.unwrap_or(TransferFunction::Linear);
821 let flags = if alpha_premultiplied {
822 DataFormatFlags::ALPHA_PREMULTIPLIED
823 } else {
824 DataFormatFlags::STRAIGHT_ALPHA
825 };
826
827 let mut bytes_planes = [0u8; 8];
828 bytes_planes[0] = 4;
829
830 const CHANNELS: [u8; 3] = [CHANNEL_R, CHANNEL_G, CHANNEL_B];
835 const BASE_OFFSETS: [u16; 3] = [0, 9, 18];
836
837 let mut sample_information = Vec::with_capacity(6);
838 for i in 0..3 {
839 sample_information.push(SampleInformation {
840 bit_offset: BASE_OFFSETS[i],
841 bit_length: NonZeroU8::new(RGB9E5_MANTISSA_BITS).unwrap(),
842 channel_type: CHANNELS[i],
843 channel_type_qualifiers: ChannelTypeQualifiers::empty(),
844 sample_positions: SAMPLE_POS_ORIGIN,
845 lower: 0,
846 upper: RGB9E5_MANTISSA_UPPER,
847 });
848 sample_information.push(SampleInformation {
849 bit_offset: RGB9E5_EXPONENT_OFFSET,
850 bit_length: NonZeroU8::new(RGB9E5_EXPONENT_BITS).unwrap(),
851 channel_type: CHANNELS[i],
852 channel_type_qualifiers: ChannelTypeQualifiers::EXPONENT,
853 sample_positions: SAMPLE_POS_ORIGIN,
854 lower: RGB9E5_EXPONENT_BIAS,
855 upper: RGB9E5_EXPONENT_MAX,
856 });
857 }
858
859 Ok(Basic {
860 color_model: Some(color_model),
861 color_primaries: Some(color_primaries),
862 transfer_function: Some(transfer_function),
863 flags,
864 texel_block_dimensions: [NonZeroU8::new(1).unwrap(); 4],
865 bytes_planes,
866 sample_information,
867 })
868 }
869
870 Builder::Compressed {
871 color_model: model,
872 srgb,
873 block_dimensions,
874 bytes_per_block,
875 datatype,
876 channel_types,
877 } => {
878 if color_model.is_some() {
879 return Err(BuildError::CompressedColorModel);
880 }
881 let color_primaries = color_primaries.unwrap_or(ColorPrimaries::BT709);
882 let transfer_function = resolve_transfer_function(srgb, transfer_function)?;
883 let flags = if alpha_premultiplied {
884 DataFormatFlags::ALPHA_PREMULTIPLIED
885 } else {
886 DataFormatFlags::STRAIGHT_ALPHA
887 };
888
889 let (lower, upper) = compressed_lower_upper(datatype);
890
891 let sample_bits = if channel_types.len() == 1 {
896 bytes_per_block * 8
897 } else {
898 64
899 };
900 let sample_stride: u16 = if channel_types.len() > 1 && bytes_per_block > 8 {
901 64
902 } else {
903 0
904 };
905
906 let mut sample_information = Vec::with_capacity(channel_types.len());
907 for (i, &ch) in channel_types.iter().enumerate() {
908 sample_information.push(SampleInformation {
909 bit_offset: (i as u16) * sample_stride,
910 bit_length: NonZeroU8::new(sample_bits).unwrap(),
911 channel_type: ch,
912 channel_type_qualifiers: sample_qualifiers(datatype, srgb, ch),
913 sample_positions: SAMPLE_POS_ORIGIN,
914 lower,
915 upper,
916 });
917 }
918
919 let mut bytes_planes = [0u8; 8];
920 bytes_planes[0] = bytes_per_block;
921
922 Ok(Basic {
923 color_model: Some(model),
924 color_primaries: Some(color_primaries),
925 transfer_function: Some(transfer_function),
926 flags,
927 texel_block_dimensions: [
928 NonZeroU8::new(block_dimensions[0]).unwrap(),
929 NonZeroU8::new(block_dimensions[1]).unwrap(),
930 NonZeroU8::new(block_dimensions[2]).unwrap(),
931 NonZeroU8::new(1).unwrap(),
932 ],
933 bytes_planes,
934 sample_information,
935 })
936 }
937
938 Builder::Subsampled422 {
939 sample_order,
940 bit_width,
941 } => {
942 let color_model = color_model.unwrap_or(ColorModel::YUVSDA);
943 let color_primaries = color_primaries.unwrap_or(ColorPrimaries::BT709);
944 let transfer_function = transfer_function.unwrap_or(TransferFunction::Linear);
945 let flags = if alpha_premultiplied {
946 DataFormatFlags::ALPHA_PREMULTIPLIED
947 } else {
948 DataFormatFlags::STRAIGHT_ALPHA
949 };
950
951 let (lower, upper) = lower_upper(Datatype::Unorm, bit_width);
952
953 let word_bits = (bit_width as u16).next_power_of_two().max(8);
956 let pad_bits = word_bits - bit_width as u16;
957 let bytes_per_block = (word_bits * 4 / 8) as u8;
958
959 let layout: [(u8, u8); 4] = if sample_order == ChromaSubsamplingSampleOrder::Gbgr {
963 [(CHANNEL_Y, 0), (CHANNEL_U, 0), (CHANNEL_Y, 1), (CHANNEL_V, 0)]
964 } else {
965 [(CHANNEL_U, 0), (CHANNEL_Y, 0), (CHANNEL_V, 0), (CHANNEL_Y, 1)]
966 };
967
968 let sample_information = layout
969 .iter()
970 .enumerate()
971 .map(|(i, &(channel, pos_x))| SampleInformation {
972 bit_offset: (i as u16) * word_bits + pad_bits,
973 bit_length: NonZeroU8::new(bit_width).unwrap(),
974 channel_type: channel,
975 channel_type_qualifiers: ChannelTypeQualifiers::empty(),
976 sample_positions: [pos_x, HALF_TEXEL, 0, 0],
977 lower,
978 upper,
979 })
980 .collect();
981
982 let mut bytes_planes = [0u8; 8];
983 bytes_planes[0] = bytes_per_block;
984
985 Ok(Basic {
986 color_model: Some(color_model),
987 color_primaries: Some(color_primaries),
988 transfer_function: Some(transfer_function),
989 flags,
990 texel_block_dimensions: [
991 NonZeroU8::new(2).unwrap(),
992 NonZeroU8::new(1).unwrap(),
993 NonZeroU8::new(1).unwrap(),
994 NonZeroU8::new(1).unwrap(),
995 ],
996 bytes_planes,
997 sample_information,
998 })
999 }
1000 }
1001 }
1002}
1003
1004fn qualifiers(datatype: Datatype) -> ChannelTypeQualifiers {
1006 match datatype {
1007 Datatype::Unorm => ChannelTypeQualifiers::empty(),
1008 Datatype::Snorm => ChannelTypeQualifiers::SIGNED,
1009 Datatype::Uint => ChannelTypeQualifiers::empty(),
1010 Datatype::Sint => ChannelTypeQualifiers::SIGNED,
1011 Datatype::Sfloat => ChannelTypeQualifiers::SIGNED | ChannelTypeQualifiers::FLOAT,
1012 Datatype::Ufloat => ChannelTypeQualifiers::FLOAT,
1013 Datatype::Sfixed5 => ChannelTypeQualifiers::SIGNED,
1014 }
1015}
1016
1017fn sample_qualifiers(
1024 datatype: Datatype,
1025 srgb: FormatInherentTransferFunction,
1026 channel_id: u8,
1027) -> ChannelTypeQualifiers {
1028 let mut quals = qualifiers(datatype);
1029 if srgb == FormatInherentTransferFunction::Srgb && channel_id == CHANNEL_ALPHA {
1030 quals |= ChannelTypeQualifiers::LINEAR;
1031 }
1032 quals
1033}
1034
1035fn lower_upper(datatype: Datatype, bits: u8) -> (u32, u32) {
1037 match datatype {
1038 Datatype::Unorm => (0, (1u32 << bits) - 1),
1039 Datatype::Snorm => {
1040 let max = (1u32 << (bits - 1)) - 1;
1041 let min = (-(max as i32)) as u32;
1042 (min, max)
1043 }
1044 Datatype::Uint => (0, 1),
1047 Datatype::Sint => ((-1i32) as u32, 1),
1048 Datatype::Sfloat => ((-1.0f32).to_bits(), (1.0f32).to_bits()),
1049 Datatype::Ufloat => (0, (1.0f32).to_bits()),
1050 Datatype::Sfixed5 => ((-32i32) as u32, 32),
1053 }
1054}
1055
1056fn compressed_lower_upper(datatype: Datatype) -> (u32, u32) {
1061 match datatype {
1062 Datatype::Unorm => (0, 0xFFFFFFFF),
1063 Datatype::Snorm => (i32::MIN as u32, i32::MAX as u32),
1066 Datatype::Sfloat => ((-1.0f32).to_bits(), (1.0f32).to_bits()),
1067 Datatype::Ufloat => (0, (1.0f32).to_bits()),
1068 _ => unreachable!("unsupported compressed datatype"),
1069 }
1070}
1071
1072#[rustfmt::skip]
1077fn resolve_transfer_function(
1078 srgb: FormatInherentTransferFunction,
1079 requested: Option<TransferFunction>,
1080) -> Result<TransferFunction, BuildError> {
1081 match (srgb, requested) {
1082 (FormatInherentTransferFunction::Srgb, None) => Ok(TransferFunction::SRGB),
1084 (FormatInherentTransferFunction::Srgb, Some(TransferFunction::SRGB)) => Ok(TransferFunction::SRGB),
1085 (FormatInherentTransferFunction::Srgb, Some(_)) => Err(BuildError::SrgbTransferRequired),
1086 (FormatInherentTransferFunction::LinearWithSrgbCounterpart, None) => Ok(TransferFunction::Linear),
1088 (FormatInherentTransferFunction::LinearWithSrgbCounterpart, Some(TransferFunction::SRGB)) => Err(BuildError::SrgbTransferNotAllowed),
1089 (FormatInherentTransferFunction::LinearWithSrgbCounterpart, Some(tf)) => Ok(tf),
1090 (FormatInherentTransferFunction::Linear, None) => Ok(TransferFunction::Linear),
1092 (FormatInherentTransferFunction::Linear, Some(tf)) => Ok(tf),
1093 }
1094}