-
Notifications
You must be signed in to change notification settings - Fork 6
/
astc.txt
2135 lines (1737 loc) · 82.9 KB
/
astc.txt
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
737
738
739
740
741
742
743
744
745
746
747
748
749
750
751
752
753
754
755
756
757
758
759
760
761
762
763
764
765
766
767
768
769
770
771
772
773
774
775
776
777
778
779
780
781
782
783
784
785
786
787
788
789
790
791
792
793
794
795
796
797
798
799
800
801
802
803
804
805
806
807
808
809
810
811
812
813
814
815
816
817
818
819
820
821
822
823
824
825
826
827
828
829
830
831
832
833
834
835
836
837
838
839
840
841
842
843
844
845
846
847
848
849
850
851
852
853
854
855
856
857
858
859
860
861
862
863
864
865
866
867
868
869
870
871
872
873
874
875
876
877
878
879
880
881
882
883
884
885
886
887
888
889
890
891
892
893
894
895
896
897
898
899
900
901
902
903
904
905
906
907
908
909
910
911
912
913
914
915
916
917
918
919
920
921
922
923
924
925
926
927
928
929
930
931
932
933
934
935
936
937
938
939
940
941
942
943
944
945
946
947
948
949
950
951
952
953
954
955
956
957
958
959
960
961
962
963
964
965
966
967
968
969
970
971
972
973
974
975
976
977
978
979
980
981
982
983
984
985
986
987
988
989
990
991
992
993
994
995
996
997
998
999
1000
// Copyright (c) 2014-2019 The Khronos Group Inc.
// Copyright notice at https://www.khronos.org/registry/speccopyright.html
[[ASTC]]
== ASTC Compressed Texture Image Formats
_This description is derived from the Khronos
link:https://www.khronos.org/registry/gles/extensions/OES/OES_texture_compression_astc.txt[OES_texture_compression_astc]
OpenGL extension._
=== What is ASTC?
ASTC stands for Adaptive Scalable Texture Compression.
The ASTC formats form a family of related compressed texture image
formats. They are all derived from a common set of definitions.
ASTC textures may be either 2D or 3D.
ASTC textures may be encoded using either high or low dynamic range.
Low dynamic range images may optionally be specified using the sRGB
transfer function for the _RGB_ channels.
Two sub-profiles (``LDR Profile'' and ``HDR Profile'') may be implemented,
which support only 2D images at low or high dynamic range respectively.
ASTC textures may be encoded as 1, 2, 3 or 4 components, but they are
all decoded into _RGBA_. ASTC has a variable block size.
<<<
=== Design Goals
The design goals for the format are as follows:
* Random access. This is a must for any texture compression format.
* Bit exact decode. This is a must for conformance testing and
reproducibility.
* Suitable for mobile use. The format should be suitable for both
desktop and mobile GPU environments. It should be low bandwidth
and low in area.
* Flexible choice of bit rate. Current formats only offer a few bit
rates, leaving content developers with only coarse control over
the size/quality tradeoff.
* Scalable and long-lived. The format should support existing _R_, _RG_,
_RGB_ and _RGBA_ image types, and also have high ``headroom'', allowing
continuing use for several years and the ability to innovate in
encoders. Part of this is the choice to include HDR and 3D.
* Feature orthogonality. The choices for the various features of the
format are all orthogonal to each other. This has three effects:
first, it allows a large, flexible configuration space; second,
it makes that space easier to understand; and third, it makes
verification easier.
* Best in class at given bit rate. It should beat or match the current
best in class for peak signal-to-noise ratio (PSNR) at all bit rates.
* Fast decode. Texel throughput for a cached texture should be one
texel decode per clock cycle per decoder. Parallel decoding of several
texels from the same block should be possible at incremental cost.
* Low bandwidth. The encoding scheme should ensure that memory access
is kept to a minimum, cache reuse is high and memory bandwidth for
the format is low.
* Low area. It must occupy comparable die size to competing formats.
=== Basic Concepts
ASTC is a block-based lossy compression format. The compressed image
is divided into a number of blocks of uniform size, which makes it
possible to quickly determine which block a given texel resides in.
Each block has a fixed memory footprint of 128 bits, but these bits
can represent varying numbers of texels (the block ``footprint'').
NOTE: The term ``block footprint'' in ASTC refers to the same concept
as ``compressed texel block dimensions'' elsewhere in the Data Format
Specification.
Block footprint sizes are not confined to powers-of-two, and are
also not confined to be square. They may be 2D, in which case the
block dimensions range from 4 to 12 texels, or 3D, in which case
the block dimensions range from 3 to 6 texels.
Decoding one texel requires only the data from a single block. This
simplifies cache design, reduces bandwidth and improves encoder throughput.
<<<
=== Block Encoding
To understand how the blocks are stored and decoded, it is useful to start
with a simple example, and then introduce additional features.
The simplest block encoding starts by defining two color ``endpoints''. The
endpoints define two colors, and a number of additional colors are generated
by interpolating between them. We can define these colors using 1, 2, 3,
or 4 components (usually corresponding to _R_, _RG_, _RGB_ and _RGBA_ textures),
and using low or high dynamic range.
We then store a color interpolant weight for each texel in the image, which
specifies how to calculate the color to use. From this, a weighted average
of the two endpoint colors is used to generate the intermediate color,
which is the returned color for this texel.
There are several different ways of specifying the endpoint colors, and the
weights, but once they have been defined, calculation of the texel colors
proceeds identically for all of them. Each block is free to choose whichever
encoding scheme best represents its color endpoints, within the constraint
that all the data fits within the 128 bit block.
For blocks which have a large number of texels (e.g. a 12{times}12 block), there is
not enough space to explicitly store a weight for every texel. In this case,
a sparser grid with fewer weights is stored, and interpolation is used to
determine the effective weight to be used for each texel position. This allows
very low bit rates to be used with acceptable quality. This can also be used
to more efficiently encode blocks with low detail, or with strong vertical
or horizontal features.
For blocks which have a mixture of disparate colors, a single line in the
color space is not a good fit to the colors of the pixels in the original
image. It is therefore possible to partition the texels into multiple sets,
the pixels within each set having similar colors. For each of these
``partitions'', we specify separate endpoint pairs, and choose which pair of
endpoints to use for a particular texel by looking up the partition index
from a partitioning pattern table. In ASTC, this partition table is actually
implemented as a function.
The endpoint encoding for each partition is independent.
For blocks which have uncorrelated channels -- for example an image with a
transparency mask, or an image used as a normal map -- it may be necessary
to specify two weights for each texel. Interpolation between the components
of the endpoint colors can then proceed independently for each ``plane'' of
the image. The assignment of channels to planes is selectable.
Since each of the above options is independent, it is possible to specify any
combination of channels, endpoint color encoding, weight encoding,
interpolation, multiple partitions and single or dual planes.
Since these values are specified per block, it is important that they are
represented with the minimum possible number of bits. As a result, these
values are packed together in ways which can be difficult to read, but
which are nevertheless highly amenable to hardware decode.
All of the values used as weights and color endpoint values can be specified
with a variable number of bits. The encoding scheme used allows a fine-grained
tradeoff between weight bits and color endpoint bits using ``integer
sequence encoding''. This can pack adjacent values together, allowing us to
use fractional numbers of bits per value.
Finally, a block may be just a single color. This is a so-called ``void
extent block'' and has a special coding which also allows it to identify
nearby regions of single color. This may be used to short-circuit fetching of
what would be identical blocks, and further reduce memory bandwidth.
<<<
=== LDR and HDR Modes
The decoding process for LDR content can be simplified if it is known in
advance that sRGB output is required. This selection is therefore included
as part of the global configuration.
The two modes differ in various ways, as shown in <<astc-differences-between-ldr-and-hdr-modes>>.
[[astc-differences-between-ldr-and-hdr-modes]]
.ASTC differences between LDR and HDR modes
[options="header"]
|======================
| Operation | LDR mode | HDR mode
| Returned Value 2+| Determined by decoding mode
| sRGB compatible | Yes | No
| LDR endpoint decoding precision | 16 bits, or 8 bits for sRGB | 16 bits
| HDR endpoint mode results | Error color | As decoded
| Error results | Error color | Vector of NaNs (0xFFFF)
|======================
The type of the values returned by the decoding process is determined by
the decoding mode as shown in <<astc_decoding_modes>>.
[[astc_decoding_modes]]
.ASTC decoding modes
[options="header"]
|================
| Decode mode | LDR mode | HDR mode
| decode_float16 2+| Vector of FP16 values
| decode_unorm8 | Vector of 8-bit unsigned normalized values | invalid
| decode_rgb9e5 2+| Vector using a shared exponent format
|================
Using the decode_unorm8 decoding mode in HDR mode gives undefined results.
For sRGB, the decoding mode is ignored, ad the decoding always returns
a vector of 8-bit unsigned normalized values.
The error color is opaque fully-saturated magenta
(_R_,_G_,_B_,_A_) = (0xFF, 0x00, 0xFF, 0xFF).
This has been chosen as it is much more noticeable than black or white, and occurs
far less often in valid images.
For linear _RGB_ decode, the error color may be either opaque fully-saturated
magenta (_R_,_G_,_B_,_A_) = (1.0, 0.0, 1.0, 1.0) or a vector of four _NaNs_
(_R_,_G_,_B_,_A_) = (_NaN_, _NaN_, _NaN_, _NaN_). In the latter case, the recommended
_NaN_ value returned is 0xFFFF.
When using the decode_rgb9e5 decoding mode in HDR mode, error results
will return the error color because NaN cannot be represented.
The error color is returned as an informative response to invalid
conditions, including invalid block encodings or use of reserved endpoint
modes.
Future, forward-compatible extensions to ASTC
may define valid interpretations of these conditions, which will decode to
some other color. Therefore, encoders and applications must not rely on
invalid encodings as a way of generating the error color.
<<<
=== Configuration Summary
The global configuration data for the format are as follows:
* Block dimension (2D or 3D)
* Block footprint size
* sRGB output enabled or not
The data specified per block are as follows:
* Texel weight grid size
* Texel weight range
* Texel weight values
* Number of partitions
* Partition pattern index
* Color endpoint modes (includes LDR or HDR selection)
* Color endpoint data
* Number of planes
* Plane-to-channel assignment
=== Decode Procedure
To decode one texel:
-------------------
(Optimization: If within known void-extent, immediately return single color)
Find block containing texel
Read block mode
If void-extent block, store void extent and immediately return single color
For each plane in image
If block mode requires infill
Find and decode stored weights adjacent to texel, unquantize and interpolate
Else
Find and decode weight for texel, and unquantize
Read number of partitions
If number of partitions > 1
Read partition table pattern index
Look up partition number from pattern
Read color endpoint mode and endpoint data for selected partition
Unquantize color endpoints
Interpolate color endpoints using weight (or weights in dual-plane mode)
Return interpolated color
-------------------
<<<
=== Block Determination and Bit Rates
The block footprint is a global setting for any given texture, and is
therefore not encoded in the individual blocks.
For 2D textures, the block footprint's width and height are selectable
from a number of predefined sizes, namely 4, 5, 6, 8, 10 and 12 pixels.
For square and nearly-square blocks, this gives the bit rates in
<<astc_footprint_2D>>.
[[astc_footprint_2D]]
.ASTC 2D footprint and bit rates
[cols="1,1,1,1",width="50%"]
|======================
2+^| *Footprint* .2+^.^| *Bit Rate* .2+^.^| *Increment*
^| *Width* ^| *Height*
^| 4 ^| 4 ^| 8.00 ^| 125%
^| 5 ^| 4 ^| 6.40 ^| 125%
^| 5 ^| 5 ^| 5.12 ^| 120%
^| 6 ^| 5 ^| 4.27 ^| 120%
^| 6 ^| 6 ^| 3.56 ^| 114%
^| 8 ^| 5 ^| 3.20 ^| 120%
^| 8 ^| 6 ^| 2.67 ^| 105%
^| 10 ^| 5 ^| 2.56 ^| 120%
^| 10 ^| 6 ^| 2.13 ^| 107%
^| 8 ^| 8 ^| 2.00 ^| 125%
^| 10 ^| 8 ^| 1.60 ^| 125%
^| 10 ^| 10 ^| 1.28 ^| 120%
^| 12 ^| 10 ^| 1.07 ^| 120%
^| 12 ^| 12 ^| 0.89 ^|
|=============
The ``Increment'' column indicates the ratio of bit rate against the next
lower available rate. A consistent value in this column indicates an even
spread of bit rates.
For 3D textures, the block footprint's width, height and depth are
selectable from a number of predefined sizes, namely 3, 4, 5, and 6 pixels.
For cubic and near-cubic blocks, this gives the bit rates in
<<astc_footprint_3D>>.
[[astc_footprint_3D]]
.ASTC 3D footprint and bit rates
[cols="1,1,1,1,1",width="60%"]
|======================
3+^| *Block Footprint* .2+^.^| *Bit Rate* .2+^.^| *Increment*
^| *Width* ^| *Height* ^| *Depth*
^| 3 ^| 3 ^| 3 ^| 4.74 ^| 133%
^| 4 ^| 3 ^| 3 ^| 3.56 ^| 133%
^| 4 ^| 4 ^| 3 ^| 2.67 ^| 133%
^| 4 ^| 4 ^| 4 ^| 2.00 ^| 125%
^| 5 ^| 4 ^| 4 ^| 1.60 ^| 125%
^| 5 ^| 5 ^| 4 ^| 1.28 ^| 125%
^| 5 ^| 5 ^| 5 ^| 1.02 ^| 120%
^| 6 ^| 5 ^| 5 ^| 0.85 ^| 120%
^| 6 ^| 6 ^| 5 ^| 0.71 ^| 120%
^| 6 ^| 6 ^| 6 ^| 0.59 ^|
|======================
The full profile supports only those block footprints listed in
<<astc_footprint_2D>> and <<astc_footprint_3D>>. Other block sizes are not supported.
For images which are not an integer multiple of the block size, additional
texels are added to the edges with maximum X and Y (and Z for 3D textures).
These texels may be any color, as they will not be accessed.
Although these are not all powers of two, it is possible to calculate block
addresses and pixel addresses within the block, for legal image sizes,
without undue complexity.
Given an image which is _W_ {times} _H_ {times} _D_ pixels in size, with block size
_w_ {times} _h_ {times} _d_, the size of the image in blocks is:
[latexmath]
++++++++++++++++++++++
\begin{align*}
\textrm{B}_\textrm{w} & = \left\lceil { W \over w } \right\rceil \\
\textrm{B}_\textrm{h} & = \left\lceil { H \over h } \right\rceil \\
\textrm{B}_\textrm{d} & = \left\lceil { D \over d } \right\rceil
\end{align*}
++++++++++++++++++++++
For a 3D image built from 2D slices, each 2D slice is a single texel thick,
so that for an image which is _W_ {times} _H_ {times} _D_ pixels in size, with block size
_w_ {times} _h_, the size of the image in blocks is:
[latexmath]
++++++++++++++++++++++
\begin{align*}
\textrm{B}_\textrm{w} & = \left\lceil { W \over w } \right\rceil \\
\textrm{B}_\textrm{h} & = \left\lceil { H \over h } \right\rceil \\
\textrm{B}_\textrm{d} & = D
\end{align*}
++++++++++++++++++++++
=== Block Layout
Each block in the image is stored as a single 128-bit block in memory. These
blocks are laid out in raster order, starting with the block at (0, 0, 0), then
ordered sequentially by X, Y and finally Z (if present). They are aligned to
128-bit boundaries in memory.
The bits in the block are labeled in little-endian order -- the byte at the
lowest address contains bits 0..7. Bit 0 is the least significant bit in the
byte.
Each block has the same basic layout, shown in <<astc-block-layout>>.
[[astc-block-layout]]
.ASTC block layout
[width="97%",cols="1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1"]
|====================
^| ~127~ ^| ~126~ ^| ~125~ ^| ~124~ ^| ~123~ ^| ~122~ ^| ~121~ ^| ~120~ ^| ~119~ ^| ~118~ ^| ~117~ ^| ~116~ ^| ~115~ ^| ~114~ ^| ~113~ ^| ~112~
12+| Texel weight data (variable width) 4+| Fill direction latexmath:[$\rightarrow$]
^| ~111~ ^| ~110~ ^| ~109~ ^| ~108~ ^| ~107~ ^| ~106~ ^| ~105~ ^| ~104~ ^| ~103~ ^| ~102~ ^| ~101~ ^| ~100~ ^| ~99~ ^| ~98~ ^| ~97~ ^| ~96~
16+| Texel weight data
^| ~95~ ^| ~94~ ^| ~93~ ^| ~92~ ^| ~91~ ^| ~90~ ^| ~89~ ^| ~88~ ^| ~87~ ^| ~86~ ^| ~85~ ^| ~84~ ^| ~83~ ^| ~82~ ^| ~81~ ^| ~80~
16+| Texel weight data
^| ~79~ ^| ~78~ ^| ~77~ ^| ~76~ ^| ~75~ ^| ~74~ ^| ~73~ ^| ~72~ ^| ~71~ ^| ~70~ ^| ~69~ ^| ~68~ ^| ~67~ ^| ~66~ ^| ~65~ ^| ~64~
16+| Texel weight data
^| ~63~ ^| ~62~ ^| ~61~ ^| ~60~ ^| ~59~ ^| ~58~ ^| ~57~ ^| ~56~ ^| ~55~ ^| ~54~ ^| ~53~ ^| ~52~ ^| ~51~ ^| ~50~ ^| ~49~ ^| ~48~
5+| 6+| More config data 5+|
^| ~47~ ^| ~46~ ^| ~45~ ^| ~44~ ^| ~43~ ^| ~42~ ^| ~41~ ^| ~40~ ^| ~39~ ^| ~38~ ^| ~37~ ^| ~36~ ^| ~35~ ^| ~34~ ^| ~33~ ^| ~32~
8+| latexmath:[$\leftarrow$] Fill direction 8+| Color endpoint data
^| ~31~ ^| ~30~ ^| ~29~ ^| ~28~ ^| ~27~ ^| ~26~ ^| ~25~ ^| ~24~ ^| ~23~ ^| ~22~ ^| ~21~ ^| ~20~ ^| ~19~ ^| ~18~ ^| ~17~ ^| ~16~
4+| 12+| Extra configuration data
^| ~15~ ^| ~14~ ^| ~13~ ^| ~12~ ^| ~11~ ^| ~10~ ^| ~9~ ^| ~8~ ^| ~7~ ^| ~6~ ^| ~5~ ^| ~4~ ^| ~3~ ^| ~2~ ^| ~1~ ^| ~0~
3+| Extra 2+| Part 11+| Block mode
|====================
Since the size of the ``texel weight data'' field is variable, the
positions shown for the ``more config data'' field and ``color endpoint
data'' field are only representative and not fixed.
The ``Block mode'' field specifies how the Texel Weight Data is encoded.
The ``Part'' field specifies the number of partitions, minus one. If dual
plane mode is enabled, the number of partitions must be 3 or fewer.
If 4 partitions are specified, the error value is returned for all
texels in the block.
The size and layout of the extra configuration data depends on the
number of partitions, and the number of planes in the image, as shown
in <<astc-single-partition-layout>> (only the bottom 32 bits are shown).
[[astc-single-partition-layout]]
.ASTC single-partition block layout
[width="97%",cols="1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1"]
|====================
^| ~31~ ^| ~30~ ^| ~29~ ^| ~28~ ^| ~27~ ^| ~26~ ^| ~25~ ^| ~24~ ^| ~23~ ^| ~22~ ^| ~21~ ^| ~20~ ^| ~19~ ^| ~18~ ^| ~17~ ^| ~16~
15+| Color endpoint data ^| CEM
^| ~15~ ^| ~14~ ^| ~13~ ^| ~12~ ^| ~11~ ^| ~10~ ^| ~9~ ^| ~8~ ^| ~7~ ^| ~6~ ^| ~5~ ^| ~4~ ^| ~3~ ^| ~2~ ^| ~1~ ^| ~0~
3+| CEM ^| 0 ^| 0 11+| Block mode
|====================
CEM is the color endpoint mode field, which determines how the Color
Endpoint Data is encoded.
If dual-plane mode is active, the color component selector bits appear
directly below the weight bits, as shown in <<astc-multi-partition-layout>>.
[[astc-multi-partition-layout]]
.ASTC multi-partition block layout
[width="97%",cols="1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1"]
|====================
^| ~31~ ^| ~30~ ^| ~29~ ^| ~28~ ^| ~27~ ^| ~26~ ^| ~25~ ^| ~24~ ^| ~23~ ^| ~22~ ^| ~21~ ^| ~20~ ^| ~19~ ^| ~18~ ^| ~17~ ^| ~16~
3+| 6+| CEM 7+| Partition index
^| ~15~ ^| ~14~ ^| ~13~ ^| ~12~ ^| ~11~ ^| ~10~ ^| ~9~ ^| ~8~ ^| ~7~ ^| ~6~ ^| ~5~ ^| ~4~ ^| ~3~ ^| ~2~ ^| ~1~ ^| ~0~
3+| Partition index 2+| Part 11+| Block mode
|====================
The Partition Index field specifies which partition layout to use. CEM is
the first 6 bits of color endpoint mode information for the various
partitions. For modes which require more than 6 bits of CEM data, the
additional bits appear at a variable position directly beneath the texel
weight data.
If dual-plane mode is active, the color component selector bits then appear
directly below the additional CEM bits.
The final special case is that if bits [8..0] of the block are ``111111100'',
then the block is a void-extent block, which has a separate encoding
described in <<astc-void-extent-blocks>>.
<<<
=== Block mode
The _block mode_ field specifies the width, height and depth of the grid of
weights, what range of values they use, and whether dual weight planes are
present. Since some these are not represented using powers of two (there
are 12 possible weight widths, for example), and not all combinations are
allowed, this is not a simple bit packing. However, it can be unpacked
quickly in hardware.
The weight ranges are encoded using a 3-bit range value {rho}, which is
interpreted together with a low/high-precision bit _P_, as shown in
<<astc-weight-range-encodings>>.
Each weight value is encoded using the specified number of Trits, Quints
and Bits. The details of this encoding can be found in
<<astc-integer-sequence-encoding>>.
[[astc-weight-range-encodings]]
.ASTC weight range encodings
[width="97%",cols="1,2,1,1,1,2,1,1,1"]
|====================
1.2+^.^| *{rho}^2..0^* 4+^.^| *Low-precision range (_P_=0)* 4+^.^| *High-precision range (_P_=1)*
^.^| *Weight range* ^.^| *Trits* ^.^| *Quints* ^.^| *Bits* ^.^| *Weight range* ^.^| *Trits* ^.^| *Quints* ^.^| *Bits*
^| 000 4+^| Invalid 4+^| Invalid
^| 001 4+^| Invalid 4+^| Invalid
^| 010 ^| 0..1 ^| ^| ^| 1 ^| 0..9 ^| ^| 1 ^| 1
^| 011 ^| 0..2 ^| 1 ^| ^| ^| 0..11 ^| 1 ^| ^| 2
^| 100 ^| 0..3 ^| ^| ^| 2 ^| 0..15 ^| ^| ^| 4
^| 101 ^| 0..4 ^| ^| 1 ^| ^| 0..19 ^| ^| 1 ^| 2
^| 110 ^| 0..5 ^| 1 ^| ^| 1 ^| 0..23 ^| 1 ^| ^| 3
^| 111 ^| 0..7 ^| ^| ^| 3 ^| 0..31 ^| ^| ^| 5
|====================
For 2D blocks, the Block Mode field is laid out as shown in
<<astc-2d-block-mode-layout>>.
[[astc-2d-block-mode-layout]]
.ASTC 2D block mode layout, weight grid width and height
[width="97%",cols="1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1"]
|====================
^| ~10~ ^| ~9~ ^| ~8~ ^| ~7~ ^| ~6~ ^| ~5~ ^| ~4~ ^| ~3~ ^| ~2~ ^| ~1~ ^| ~0~ 2+^| *W~width~* 2+^| *W~height~* 3+^| *Notes*
^| _D~P~_ ^| _P_ 2+^| _W_ 2+^| _H_ ^| {rho}^0^ ^| 0 ^| 0 ^| {rho}^2^ ^| {rho}^1^ 2+^| _W_+4 2+^| _H_+2 3+|
^| _D~P~_ ^| _P_ 2+^| _W_ 2+^| _H_ ^| {rho}^0^ ^| 0 ^| 1 ^| {rho}^2^ ^| {rho}^1^ 2+^| _W_+8 2+^| _H_+2 3+|
^| _D~P~_ ^| _P_ 2+^| _H_ 2+^| _W_ ^| {rho}^0^ ^| 1 ^| 0 ^| {rho}^2^ ^| {rho}^1^ 2+^| _W_+2 2+^| _H_+8 3+|
^| _D~P~_ ^| _P_ ^| 0 ^| _H_ 2+^| _W_ ^| {rho}^0^ ^| 1 ^| 1 ^| {rho}^2^ ^| {rho}^1^ 2+^| _W_+2 2+^| _H_+6 3+|
^| _D~P~_ ^| _P_ ^| 1 ^| _W_ 2+^| _H_ ^| {rho}^0^ ^| 1 ^| 1 ^| {rho}^2^ ^| {rho}^1^ 2+^| _W_+2 2+^| _H_+2 3+|
^| _D~P~_ ^| _P_ ^| 0 ^| 0 2+^| _H_ ^| {rho}^0^ ^| {rho}^2^ ^| {rho}^1^ ^| 0 ^| 0 2+^| 12 2+^| _H_+2 3+|
^| _D~P~_ ^| _P_ ^| 0 ^| 1 2+^| _W_ ^| {rho}^0^ ^| {rho}^2^ ^| {rho}^1^ ^| 0 ^| 0 2+^| _W_+2 2+^| 12 3+|
^| _D~P~_ ^| _P_ ^| 1 ^| 1 ^| 0 ^| 0 ^| {rho}^0^ ^| {rho}^2^ ^| {rho}^1^ ^| 0 ^| 0 2+^| 6 2+^| 10 3+|
^| _D~P~_ ^| _P_ ^| 1 ^| 1 ^| 0 ^| 1 ^| {rho}^0^ ^| {rho}^2^ ^| {rho}^1^ ^| 0 ^| 0 2+^| 10 2+^| 6 3+|
2+^| _H_ ^| 1 ^| 0 2+^| _W_ ^| {rho}^0^ ^| {rho}^2^ ^| {rho}^1^ ^| 0 ^| 0 2+^| _W_+6 2+^| _H_+6 3+^| _D~P~_=0, _P_=0
^| x ^| x ^| 1 ^| 1 ^| 1 ^| 1 ^| 1 ^| 1 ^| 1 ^| 0 ^| 0 2+^| - 2+^| - 3+^| Void-extent
^| x ^| x ^| 1 ^| 1 ^| 1 ^| x ^| x ^| x ^| x ^| 0 ^| 0 2+^| - 2+^| - 3+^| Reserved*
^| x ^| x ^| x ^| x ^| x ^| x ^| x ^| 0 ^| 0 ^| 0 ^| 0 2+^| - 2+^| - 3+^| Reserved
|====================
Note that, due to the encoding of the {rho} field, as described in the
previous page, bits {rho}^2^ and {rho}^1^ cannot both be zero, which disambiguates
the first five rows from the rest of the table.
Bit positions with a value of x are ignored for purposes of determining
if a block is a void-extent block or reserved, but may have defined
encodings for specific void-extent blocks.
The penultimate row of <<astc-2d-block-mode-layout>> is reserved only if
bits [5..2] are not all 1, in which case it encodes a void-extent block
(as shown in the previous row).
<<<
For 3D blocks, the Block Mode field is laid out as shown in <<astc-3d-block-mode-layout>>.
[[astc-3d-block-mode-layout]]
.ASTC 3D block mode layout, weight grid width, height and depth
[width="97%",cols="1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1"]
|====================
^| ~10~ ^| ~9~ ^| ~8~ ^| ~7~ ^| ~6~ ^| ~5~ ^| ~4~ ^| ~3~ ^| ~2~ ^| ~1~ ^| ~0~ 2+^| *W~width~* 2+^| *W~height~* 2+^| *W~depth~* 3+^| *Notes*
^| _D~P~_ ^| _P_ 2+^| _H_ 2+^| _W_ ^| {rho}^0^ 2+^| _D_ ^| {rho}^2^ ^| {rho}^1^ 2+^| _W_+2 2+^| _H_+2 2+^| _D_+2 3+^|
2+^| _H_ ^| 0 ^| 0 2+^| _D_ ^| {rho}^0^ ^| {rho}^2^ ^| {rho}^1^ ^| 0 ^| 0 2+^| 6 2+^| _H_+2 2+^| _D_+2 3+^| _D~P~_=0, _P_=0
2+^| _D_ ^| 0 ^| 1 2+^| _W_ ^| {rho}^0^ ^| {rho}^2^ ^| {rho}^1^ ^| 0 ^| 0 2+^| _W_+2 2+^| 6 2+^| _D_+2 3+^| _D~P~_=0, _P_=0
2+^| _H_ ^| 1 ^| 0 2+^| _W_ ^| {rho}^0^ ^| {rho}^2^ ^| {rho}^1^ ^| 0 ^| 0 2+^| _W_+2 2+^| _H_+2 2+^| 6 3+^| _D~P~_=0, _P_=0
^| _D~P~_ ^| _P_ ^| 1 ^| 1 ^| 0 ^| 0 ^| {rho}^0^ ^| {rho}^2^ ^| {rho}^1^ ^| 0 ^| 0 2+^| 6 2+^| 2 2+^| 2 3+^|
^| _D~P~_ ^| _P_ ^| 1 ^| 1 ^| 0 ^| 1 ^| {rho}^0^ ^| {rho}^2^ ^| {rho}^1^ ^| 0 ^| 0 2+^| 2 2+^| 6 2+^| 2 3+^|
^| _D~P~_ ^| _P_ ^| 1 ^| 1 ^| 1 ^| 0 ^| {rho}^0^ ^| {rho}^2^ ^| {rho}^1^ ^| 0 ^| 0 2+^| 2 2+^| 2 2+^| 6 3+^|
^| x ^| x ^| 1 ^| 1 ^| 1 ^| 1 ^| 1 ^| 1 ^| 1 ^| 0 ^| 0 2+^| - 2+^| - 2+^| - 3+^| Void-extent
^| x ^| x ^| 1 ^| 1 ^| 1 ^| 1 ^| x ^| x ^| x ^| 0 ^| 0 2+^| - 2+^| - 2+^| - 3+^| Reserved*
^| x ^| x ^| x ^| x ^| x ^| x ^| x ^| 0 ^| 0 ^| 0 ^| 0 2+^| - 2+^| - 2+^| - 3+^| Reserved
|====================
The _D~P~_ bit is set to indicate dual-plane mode. In this mode, the maximum
allowed number of partitions is 3.
The penultimate row of <<astc-3d-block-mode-layout>> is reserved only
if bits [4..2] are not all 1, in which case it encodes a void-extent
block (as shown in the previous row).
The size of the weight grid in each dimension must be less than or equal
to the corresponding dimension of the block footprint.
If the grid size is greater than the footprint dimension in any axis, then
this is an illegal block encoding and all texels will decode to the error
color.
=== Color Endpoint Mode
In single-partition mode, the Color Endpoint Mode (CEM) field stores one
of 16 possible values. Each of these specifies how many raw data values
are encoded, and how to convert these raw values into two _RGBA_ color
endpoints. They can be summarized as shown in <<astc-color-endpoint-modes>>.
[[astc-color-endpoint-modes]]
.ASTC color endpoint modes
[cols="2,11,2",options="header",width="55%"]
|====================
^| CEM | Description ^| Class
>| 0 | LDR Luminance, direct ^| 0
>| 1 | LDR Luminance, base+offset ^| 0
>| 2 | HDR Luminance, large range ^| 0
>| 3 | HDR Luminance, small range ^| 0
>| 4 | LDR Luminance+Alpha, direct ^| 1
>| 5 | LDR Luminance+Alpha, base+offset ^| 1
>| 6 | LDR _RGB_, base+scale ^| 1
>| 7 | HDR _RGB_, base+scale ^| 1
>| 8 | LDR _RGB_, direct ^| 2
>| 9 | LDR _RGB_, base+offset ^| 2
>| 10 | LDR _RGB_, base+scale plus two _A_ ^| 2
>| 11 | HDR _RGB_, direct ^| 2
>| 12 | LDR _RGBA_, direct ^| 3
>| 13 | LDR _RGBA_, base+offset ^| 3
>| 14 | HDR _RGB_, direct + LDR Alpha ^| 3
>| 15 | HDR _RGB_, direct + HDR Alpha ^| 3
|====================
In multi-partition mode, the CEM field is of variable width, from 6 to 14
bits. The lowest 2 bits of the CEM field specify how the endpoint mode
for each partition is calculated as shown in <<astc-multi-partition-color-endpoint-modes>>.
[[astc-multi-partition-color-endpoint-modes]]
.ASTC Multi-Partition Color Endpoint Modes
[cols="1,5",options="header",width="45%"]
|====================
^| Value | Meaning
^| 00 | All color endpoint pairs are of the same
type; a full 4-bit CEM is stored in block
bits [28..25]
and is used for all partitions
^| 01 | All endpoint pairs are of class 0 or 1
^| 10 | All endpoint pairs are of class 1 or 2
^| 11 | All endpoint pairs are of class 2 or 3
|====================
If the CEM selector value in bits [24..23] is not 00,
then data layout is as shown in <<astc-multi-partition-color-endpoint-mode-layout>>
and <<astc-multi-partition-color-endpoint-mode-layout-2>>.
[[astc-multi-partition-color-endpoint-mode-layout]]
.ASTC multi-partition color endpoint mode layout
[cols="2,1,2,1,1,1,1,1,1,1,1,1",width="90%"]
|====================
^| *Part* ^| ^| ^| ~n~ ^| ~m~ ^| ~l~ ^| ~k~ ^| ~j~ ^| ~i~ ^| ~h~ ^| ~g~ ^|
^| 2 ^| ... ^| Weight 2+^| M~1~ 6+| | ...
^| 3 ^| ... ^| Weight 2+^| M~2~ 2+^| M~1~ ^| M~0~ 3+| | ...
^| 4 ^| ... ^| Weight 2+^| M~3~ 2+^| M~2~ 2+^| M~1~ 2+^| M~0~ | ...
|====================
[[astc-multi-partition-color-endpoint-mode-layout-2]]
.ASTC multi-partition color endpoint mode layout (2)
[cols="2,1,1,1,1,1,1",width="60%"]
|====================
^| *Part* ^| ~28~ ^| ~27~ ^| ~26~ ^| ~25~ ^| ~24~ ^| ~23~
^| 2 2+^| M~0~ ^| C~1~ ^| C~0~ 2+^| CEM
^| 3 ^| M~0~ ^| C~2~ ^| C~1~ ^| C~0~ 2+^| CEM
^| 4 ^| C~3~ ^| C~2~ ^| C~1~ ^| C~0~ 2+^| CEM
|====================
In this view, each partition _i_ has two fields. C~_i_~ is the class selector
bit, choosing between the two possible CEM classes (0 indicates the
lower of the two classes), and M~_i_~ is a two-bit field specifying the low
bits of the color endpoint mode within that class. The additional bits
appear at a variable bit position, immediately below the texel weight
data.
The ranges used for the data values are not explicitly specified.
Instead, they are derived from the number of available bits remaining
after the configuration data and weight data have been specified.
Details of the decoding procedure for Color Endpoints can be found in
<<astc-endpoint-unquantization>>.
<<<
[[astc-integer-sequence-encoding]]
=== Integer Sequence Encoding
Both the weight data and the endpoint color data are variable width, and
are specified using a sequence of integer values. The range of each
value in a sequence (e.g. a color weight) is constrained.
Since it is often the case that the most efficient range for these
values is not a power of two, each value sequence is encoded using a
technique known as ``integer sequence encoding''. This allows efficient,
hardware-friendly packing and unpacking of values with non-power-of-two
ranges.
In a sequence, each value has an identical range. The range is specified
in one of the forms shown in <<astc-range-forms>> and
<<astc-range-encodings>>.
[[astc-range-forms]]
.ASTC range forms
[options="header",width="65%",cols="2,3,3"]
|====================
| Value range | MSB encoding | LSB encoding
| latexmath:[$0 \dots 2^n-1$] | - | _n_-bit value _m_ (_n_ {leq} 8)
| latexmath:[$0 \dots (3 \times 2^n)-1$] | Base-3 ``trit'' value _t_ | _n_-bit value _m_ (_n_ {leq} 6)
| latexmath:[$0 \dots (5 \times 2^n)-1$] | Base-5 ``quint'' value _q_ | _n_-bit value _m_ (_n_ {leq} 5)
|====================
[[astc-range-encodings]]
.ASTC encoding for different ranges
[options="header",width="60%",cols="4,3,2,5"]
|====================
| Value range | Value | Block | Packed block size
| latexmath:[$0 \dots 2^n-1$] | _m_ | 1 | _n_
| latexmath:[$0 \dots (3 \times 2^n)-1$] | latexmath:[$t \times 2^n + m$] | 5 | 8 {plus} 5 {times} _n_
| latexmath:[$0 \dots (5 \times 2^n)-1$] | latexmath:[$q \times 2^n + m$] | 3 | 7 {plus} 3 {times} _n_
|====================
Since 3^5^ is 243, it is possible to pack five trits into 8 bits (which has
256 possible values), so a trit can effectively be encoded as 1.6 bits.
Similarly, since 5^3^ is 125, it is possible to pack three quints into
7 bits (which has 128 possible values), so a quint can be encoded as
2.33 bits.
The encoding scheme packs the trits or quints, and then interleaves the _n_
additional bits in positions that satisfy the requirements of an
arbitrary-length stream. This makes it possible to correctly specify
lists of values whose length is not an integer multiple of 3 or 5 values.
It also makes it possible to easily select a value at random within the stream.
If there are insufficient bits in the stream to fill the final block, then
unused (higher-order) bits are assumed to be 0 when decoding.
To decode the bits for value number _i_ in a sequence of bits _b_, both
indexed from 0, perform the following:
If the range is encoded as _n_ bits per value, then the value is bits
latexmath:[$b^{i\times n + n - 1 .. i \times n}$] -- a simple multiplexing operation.
If the range is encoded using a trit, then each block contains 5 values
(v~0~ to v~4~), each of which contains a trit (t~0~ to t~4~) and a corresponding
LSB value (m~0~ to m~4~). The first bit of the packed block is bit
latexmath:[$\left\lfloor {i\over 5} \right\rfloor \times (8 + 5 \times n)$]. The bits in the
block are packed as shown in <<astc-trit-based-packing>> (in this example, _n_ is 4).
[[astc-trit-based-packing]]
.ASTC trit-based packing
[width="80%"]
|===========================================
4+^| ^| ~27~ ^| ~26~ ^| ~25~ ^| ~24~ ^| ~23~ ^| ~22~ ^| ~21~ ^| ~20~ ^| ~19~ ^| ~18~ ^| ~17~ ^| ~16~
4+^| ^| T^7^ 4+^| m~4~ ^| T^6^ ^| T^5^ 4+^| m~3~ ^| T^4^
^| ~15~ ^| ~14~ ^| ~13~ ^| ~12~ ^| ~11~ ^| ~10~ ^| ~9~ ^| ~8~ ^| ~7~ ^| ~6~ ^| ~5~ ^| ~4~ ^| ~3~ ^| ~2~ ^| ~1~ ^| ~0~
4+^| m~2~ ^| T^3^ ^| T^2^ 4+^| m~1~ ^| T^1^ ^| T^0^ 4+^| m~0~ ^|
|===========================================
<<<
The five trits t~0~ to t~4~ are obtained by bit manipulations of the 8 bits
T^7..0^ as follows:
-----
if T[4:2] = 111
C = { T[7:5], T[1:0] }; t4 = t3 = 2
else
C = T[4:0]
if T[6:5] = 11
t4 = 2; t3 = T[7]
else
t4 = T[7]; t3 = T[6:5]
if C[1:0] = 11
t2 = 2; t1 = C[4]; t0 = { C[3], C[2]&~C[3] }
else if C[3:2] = 11
t2 = 2; t1 = 2; t0 = C[1:0]
else
t2 = C[4]; t1 = C[3:2]; t0 = { C[1], C[0]&~C[1] }
-----
If the range is encoded using a quint, then each block contains 3 values
(v~0~ to v~2~), each of which contains a quint (q~0~ to q~2~) and a corresponding
LSB value (m~0~ to m~2~). The first bit of the packed block is bit
latexmath:[$ \left\lfloor {i\over 3} \right\rfloor \times (7+3 \times n)$].
The bits in the block are packed as described in <<astc-quint-based-packing>> and
<<astc-quint-based-packing-2>> (in this example, _n_ is 4).
[[astc-quint-based-packing]]
.ASTC quint-based packing
[width="20%"]
|===========
^| ~18~ ^| ~17~ ^| ~16~
^| Q^6^ ^| Q^5^ ^| m~2~
|===========
[[astc-quint-based-packing-2]]
.ASTC quint-based packing (2)
[width="80%"]
|===========
^| ~15~ ^| ~14~ ^| ~13~ ^| ~12~ ^| ~11~ ^| ~10~ ^| ~9~ ^| ~8~ ^| ~7~ ^| ~6~ ^| ~5~ ^| ~4~ ^| ~3~ ^| ~2~ ^| ~1~ ^| ~0~
3+^| m~2~ ^| Q^4^ ^| Q^3^ 4+^| m~1~ ^| Q^2^ ^| Q^1^ ^| Q^0^ 4+^| m~0~
|===========
The three quints q~0~ to q~2~ are obtained by bit manipulations of the 7 bits
Q^6..0^ as follows:
-----
if Q[2:1] = 11 and Q[6:5] = 00
q2 = { Q[0], Q[4]&~Q[0], Q[3]&~Q[0] }; q1 = q0 = 4
else
if Q[2:1] = 11
q2 = 4; C = { Q[4:3], ~Q[6:5], Q[0] }
else
q2 = Q[6:5]; C = Q[4:0]
if C[2:0] = 101
q1 = 4; q0 = C[4:3]
else
q1 = C[4:3]; q0 = C[2:0]
-----
Both these procedures ensure a valid decoding for all 128 possible values
(even though a few are duplicates). They can also be implemented
efficiently in software using small tables.
Encoding methods are not specified here, although table-based mechanisms
work well.
<<<
[[astc-endpoint-unquantization]]
=== Endpoint Unquantization
Each color endpoint is specified as a sequence of integers in a given
range. These values are packed using integer sequence encoding, as a
stream of bits stored from just above the configuration data, and
growing upwards.
Once unpacked, the values must be unquantized from their storage range,
returning them to a standard range of 0..255.
For bit-only representations, this is simple bit replication from the
most significant bit of the value.
For trit or quint-based representations, this involves a set of bit
manipulations and adjustments to avoid the expense of full-width
multipliers. This procedure ensures correct scaling, but scrambles
the order of the decoded values relative to the encoded values.
This must be compensated for using a table in the encoder.
The initial inputs to the procedure are denoted ++A++ (9 bits), ++B++
(9 bits), ++C++ (9 bits) and ++D++ (3 bits), and are decoded using the
range as described in <<astc-color-unquantization-parameters>>.
[[astc-color-unquantization-parameters]]
.ASTC color unquantization parameters
[cols="4,3,4,3,5,6,6,3,8",width="95%",options="header"]
|============
^| Range ^| #Trits ^| #Quints ^| #Bits ^| Bit layout ^| ++A++ ^| ++B++ ^| ++C++ ^| ++D++
^| 0..5 ^| 1 ^| ^| 1 ^| a ^| aaaaaaaaa ^| 000000000 ^| 204 ^| Trit value
^| 0..9 ^| ^| 1 ^| 1 ^| a ^| aaaaaaaaa ^| 000000000 ^| 113 ^| Quint value
^| 0..11 ^| 1 ^| ^| 2 ^| ba ^| aaaaaaaaa ^| b000b0bb0 ^| 93 ^| Trit value
^| 0..19 ^| ^| 1 ^| 2 ^| ba ^| aaaaaaaaa ^| b0000bb00 ^| 54 ^| Quint value
^| 0..23 ^| 1 ^| ^| 3 ^| cba ^| aaaaaaaaa ^| cb000cbcb ^| 44 ^| Trit value
^| 0..39 ^| ^| 1 ^| 3 ^| cba ^| aaaaaaaaa ^| cb0000cbc ^| 26 ^| Quint value
^| 0..47 ^| 1 ^| ^| 4 ^| dcba ^| aaaaaaaaa ^| dcb000dcb ^| 22 ^| Trit value
^| 0..79 ^| ^| 1 ^| 4 ^| dcba ^| aaaaaaaaa ^| dcb0000dc ^| 13 ^| Quint value
^| 0..95 ^| 1 ^| ^| 5 ^| edcba ^| aaaaaaaaa ^| edcb000ed ^| 11 ^| Trit value
^| 0..159 ^| ^| 1 ^| 5 ^| edcba ^| aaaaaaaaa ^| edcb0000e ^| 6 ^| Quint value
^| 0..191 ^| 1 ^| ^| 6 ^| fedcba ^| aaaaaaaaa ^| fedcb000f ^| 5 ^| Trit value
|============
These are then processed as follows:
-----
unq = D * C + B;
unq = unq ^ A;
unq = (A & 0x80) | (unq >> 2);
-----
Note that the multiply in the first line is nearly trivial as it only
needs to multiply by 0, 1, 2, 3 or 4.
<<<
=== LDR Endpoint Decoding
The decoding method used depends on the Color Endpoint Mode (CEM) field,
which specifies how many values are used to represent the endpoint.
The CEM field also specifies how to take the _n_ unquantized color endpoint
values v~0~ to v~n-1~ and convert them into two _RGBA_ color endpoints e~0~
and e~1~.
The HDR Modes are more complex and do not fit neatly into this section.
They are documented in following section.
The methods can be summarized as shown in <<astc-ldr-color-endpoint-modes>>.
[[astc-ldr-color-endpoint-modes]]
.ASTC LDR color endpoint modes
[options="header",cols="2,3,11,1",width="55%"]
|==============
^| CEM ^| Range | Description ^| _n_
>| 0 ^| LDR | Luminance, direct ^| 2
>| 1 ^| LDR | Luminance, base+offset ^| 2
>| 2 ^| HDR | Luminance, large range ^| 2
>| 3 ^| HDR | Luminance, small range ^| 2
>| 4 ^| LDR | Luminance+Alpha, direct ^| 4
>| 5 ^| LDR | Luminance+Alpha, base+offset ^| 4
>| 6 ^| LDR | _RGB_, base+scale ^| 4
>| 7 ^| HDR | _RGB_, base+scale ^| 4
>| 8 ^| LDR | _RGB_, direct ^| 6
>| 9 ^| LDR | _RGB_, base+offset ^| 6
>| 10 ^| LDR | _RGB_, base+scale plus two _A_ ^| 6
>| 11 ^| HDR | _RGB_ ^| 6
>| 12 ^| LDR | _RGBA_, direct ^| 8
>| 13 ^| LDR | _RGBA_, base+offset ^| 8
>| 14 ^| HDR | _RGB_ + LDR Alpha ^| 8
>| 15 ^| HDR | _RGB_ + HDR Alpha ^| 8
|==============
Mode 14 is special in that the alpha values are interpolated linearly,
but the color components are interpolated logarithmically. This is the
only endpoint format with mixed-mode operation, and will return the
error value if encountered in LDR mode.
Decode the different LDR endpoint modes as follows:
==== Mode 0 LDR Luminance, direct
-----
e0=(v0,v0,v0,0xFF); e1=(v1,v1,v1,0xFF);
-----
==== Mode 1 LDR Luminance, base+offset
-----
L0 = (v0>>2)|(v1&0xC0); L1=L0+(v1&0x3F);
if (L1>0xFF) { L1=0xFF; }
e0=(L0,L0,L0,0xFF); e1=(L1,L1,L1,0xFF);
-----
==== Mode 4 LDR Luminance+Alpha,direct
-----
e0=(v0,v0,v0,v2);
e1=(v1,v1,v1,v3);
-----
==== Mode 5 LDR Luminance+Alpha, base+offset
-----
bit_transfer_signed(v1,v0); bit_transfer_signed(v3,v2);
e0=(v0,v0,v0,v2); e1=(v0+v1,v0+v1,v0+v1,v2+v3);
clamp_unorm8(e0); clamp_unorm8(e1);
-----
==== Mode 6 LDR _RGB_, base+scale
-----
e0=(v0*v3>>8,v1*v3>>8,v2*v3>>8, 0xFF);
e1=(v0,v1,v2,0xFF);
-----
==== Mode 8 LDR _RGB_, Direct
-----
s0= v0+v2+v4; s1= v1+v3+v5;
if (s1>=s0){e0=(v0,v2,v4,0xFF);
e1=(v1,v3,v5,0xFF); }
else { e0=blue_contract(v1,v3,v5,0xFF);
e1=blue_contract(v0,v2,v4,0xFF); }
-----
==== Mode 9 LDR _RGB_, base+offset
-----
bit_transfer_signed(v1,v0);
bit_transfer_signed(v3,v2);
bit_transfer_signed(v5,v4);
if(v1+v3+v5 >= 0)
{ e0=(v0,v2,v4,0xFF); e1=(v0+v1,v2+v3,v4+v5,0xFF); }
else
{ e0=blue_contract(v0+v1,v2+v3,v4+v5,0xFF);
e1=blue_contract(v0,v2,v4,0xFF); }
clamp_unorm8(e0); clamp_unorm8(e1);
-----
==== Mode 10 LDR _RGB_, base+scale plus two _A_
-----
e0=(v0*v3>>8,v1*v3>>8,v2*v3>>8, v4);
e1=(v0,v1,v2, v5);
-----
==== Mode 12 LDR _RGBA_, direct
-----
s0= v0+v2+v4; s1= v1+v3+v5;
if (s1>=s0){e0=(v0,v2,v4,v6);
e1=(v1,v3,v5,v7); }
else { e0=blue_contract(v1,v3,v5,v7);
e1=blue_contract(v0,v2,v4,v6); }
-----
==== Mode 13 LDR _RGBA_, base+offset
-----
bit_transfer_signed(v1,v0);
bit_transfer_signed(v3,v2);
bit_transfer_signed(v5,v4);
bit_transfer_signed(v7,v6);
if(v1+v3+v5>=0) { e0=(v0,v2,v4,v6);
e1=(v0+v1,v2+v3,v4+v5,v6+v7); }
else { e0=blue_contract(v0+v1,v2+v3,v4+v5,v6+v7);
e1=blue_contract(v0,v2,v4,v6); }
clamp_unorm8(e0); clamp_unorm8(e1);
-----
The `bit_transfer_signed()` procedure transfers a bit from one value (_a_)
to another (_b_). Initially, both _a_ and _b_ are in the range 0..255.
After calling this procedure, _a_'s range becomes -32..31, and _b_ remains
in the range 0..255. Note that, as is often the case, this is easier to
express in hardware than in C:
-----
bit_transfer_signed(int& a, int& b)
{
b >>= 1;
b |= a & 0x80;
a >>= 1;
a &= 0x3F;
if( (a&0x20)!=0 ) a-=0x40;
}
-----
The `blue_contract()` procedure is used to give additional precision to
_RGB_ colors near gray:
-----