Saturday, February 6, 2021

Simple and fast ways to reduce BC7's output entropy (and increase LZ matches)

 It's relatively easy to reduce the output entropy of BC7 by around 5-10%, without slowing down encoding or even speeding it up. I'll be adding this stuff to the bc7e ispc encoder soon. I've been testing these tricks in bc7enc_rdo:

- Weight the mode errors: For example weight mode 1 and 6's errors way lower than the other modes. This shifts the encoder to use modes 1 and 6 more often, which reduces the output data's entropy. This requires the other modes to make a truly significant difference in reducing distortion before the encoder switches to using them.

- Biased p-bits: When deciding which p-bits to use (0 vs. 1), weight the error from using p-bit 1 slightly lower (or the opposite). This will cause the encoder to favor one of the p-bits more than the other, reducing the block output data's entropy.

- Partition pattern weighting: Weight the error from using the lower frequency partitions [0,15] or [0,33] slightly lower vs. the other patterns. This reduces the output entropy of the first or second byte of BC7 modes with partitions.

- Quantize mode 6's endpoints and force its p-bits to [0,1]: Mode 6 uses 7-bit endpoint components. Use 6-bits instead, with fixed [0,1] p-bits. You'll need to do this in combination with reducing mode 6's error weight, or a multi-mode encoder won't use mode 6 as much. 

- Don't use mode 4/5 component rotations, or the index flag. 

In practice these options aren't particularly useful, and just increase the output entropy. The component rotation feature can also cause odd looking color artifacts.

- Don't use mode 0,2,3, possibly 4: These modes are less useful, at least on albedo/specular/etc. maps, sRGB content, and photos/images. Almost all BC7 encoders, including ispc_texcomp's, can't even handle mode 0 correctly anyway.

Mode 4 is useful on decorrelated alpha. If your content doesn't have much of that, just always use mode 5.


More RDO BC7 encoder progress

I finally sat down and added a simple LZ4-like simulator to my in-progress soon to be open source RDO BC7 encoder. You can add blocks in, query it to find the longest/nearest match, and give it some bytes and ask it how many bits it would take to code (up to 128 for BC7, less if it finds matches). It's definitely the right path forward for RDO encoders. It looks like, for BC7 modes 1 and 6, that it's accurate vs. Deflate within around 1.5-7%. It predicts on the high side vs. Deflate, because it doesn't have a Huffman model. Mode 1's predictions tend to be more accurate, I think because this mode has encoded endpoints nicely aligned on byte boundaries.

With BC7 RDO encoding, you really need an LZ simulator of some sort. Or you need decent approximations. Once you can simulate how many bits a block compresses to, you can then have the encoder try replacing byte aligned sequences within each block (with sequences that appear in previous blocks). This is the key magic that makes this method work so well. You need to "talk" to the LZ compressor in the primary language it understands: 2+ or 3+ length byte matches.

For example, with mode 6, the selectors are 4-bits per texel, and are aligned at the end of the block. So each byte has 2 texels. If your p-bits are always [0,1] (mine are in RDO mode), then it's easy to substitute various regions of bytes from previously encoded mode 6 blocks, and see what LZ does.

This is pretty awesome because it allows the encoder to escape from being forced to always using an entire previous block's selectors, greatly reducing block artifacts.

In one experiment, around 40% of the blocks that got selector byte substitutions from previous blocks are from plugging in 3 or 4 byte matches and evaluating the Lagrangian.

40% is ridiculously high - which means this technique works well. It'll work with BC1 too. The downside (as usual) is encoding performance.

I've implemented byte replacement trials for 3-8 byte matches. All are heavily used, especially 7 and 8 byte matches. I may try other combinations, like trying two 3 byte matches with 2 literals, etc. You can also do byte replacement in two passes, by trying 3 or 4 byte sequences from 2 previously encoded blocks.

Making this go fast will be a perf. optimization challenge. I'm convinced that you need to do something like this otherwise you're always stuck replacing entire block's worth of selectors, which can be way uglier.

Example encodings (non-RDO modes 1+6 is 42.253 dB, 6.84 bits/texel):

- RDO BC7 mode 1+6, lambda .1, 8KB max search distance, match replacements taken from up to 2 previous blocks
41.765 RGB dB, 6.13 bits/texel (Deflate - miniz library max compression)



- RDO BC7 mode 1+6, lambda .25, 8KB max search distance, match replacements taken from up to 2 previous blocks
41.496 RGB dB, 5.78 bits/texel (Deflate - miniz library max compression)



- RDO BC7 mode 1+6, lambda .5, 8KB max search distance, match replacements taken from up to 2 previous blocks
40.830 RGB dB, 5.36 bits/texel (Deflate - miniz library max compression)



- RDO BC7 mode 1+6, lambda 1.0, 4KB max search distance
39.507 RGB dB, 4.97 bits/texel (Deflate - miniz library max compression)



Mode 6 byte replacement histogram (lengths of matches, in bytes):
14752 0 5000 3688 3833 3975 4632 0 0 0 0 0 0 0 0 0
8       3    4    5    6    7

- RDO BC7 mode 1+6, lambda 3.0, 2KB max search distance
36.161 dB, 4.59 bits/texel




- RDO BC7 mode 1+6, lambda 4.0, 2KB max search distance
35.035 dB, 4.47 bits/texel



- RDO BC7 mode 1+6, lambda 5.0, 4KB max search distance, match replacements taken from up to 2 previous blocks
33.760 dB, 3.96 bits/texel



- RDO BC7 mode 1+6, lambda 8.0, 4KB max search distance, match replacements taken from up to 2 previous blocks
32.072 dB, 3.47 bits/texel



-RDO BC7 mode 1+6, lambda 10.0, 4KB max search distance, match replacements taken from up to 2 previous blocks
31.318 dB, 3.32 bits/texel


- RDO BC7 mode 1+6, lambda 10.0, 8KB max search distance, match replacements taken from up to 2 previous blocks
31.279 dB, 3.21 bits/texel

- RDO BC7 mode 1+6, lambda 12.0, 8KB max search distance, match replacements taken from up to 2 previous blocks
30.675 db, 3.07 bits/texel


- RDO BC7 mode 1+6, lambda 20.0, 8KB max search distance, match replacements taken from up to 2 previous blocks
29.179 dB, 2.68 bits/texel



- Non-RDO mode 1+6 (bc7enc level 4)
42.253 dB, 6.84 bits/texel:



- Original 1024x1024 image:



Wednesday, February 3, 2021

RDO BC1-BC7 progress

I've been making progress on my first RDO BC7 encoder. I started working on RDO BC1-7 years ago, but I put this work on hold to open source Basis Universal. BasisU was way more important from a business perspective. (Games are fun and all, but the game business doesn't pay and web and mapping are where the eyeballs are at.)

RDO BC1-5 are done and already checked into the bc7enc_rdo repo. The test app in this repo only currently supports RDO BC1 and BC4, but I'll add in BC3/5 very soon (they are just trivial variations of BC1/4). I'm hoping the KTX2 guys will add this encoder to their repo, so I don't have to create yet another command line tool that supports mipmaps, reading/writing DDS/KTX, etc. RDO BC1-5 are implemented as post-processors, so they are compatible with any other non-RDO BC1-5 encoder. 

For my first RDO BC7 encoder, I've modified bc7enc's BC7 encoder (which purposely only supports 4 modes: 1/5/6/7) to support optional per-mode error weights, and 6-bit endpoint components with fixed 0/1 p-bits in mode 6. These two simple changes immediately reduce LZ compressed file sizes by around 5-10% with Deflate, with no perf. impact. I may support doing something like this for the other modes. I also implemented Castano's optimal endpoint rounding method, because why not.

The next step is creating a post-processor that accepts an array of encoded BC7 blocks, and modifies them for higher quality per compressed bit by increasing LZ matches. The post-processor function will support all the modes, although I'm testing primarily with bc7enc at the moment. Merging selector bits with previously encoded blocks is the simplest thing to do, which I just got working for any mode. 

I'm using the usual Langrangian multiplier method (j=D+l*R, where D=MSE, R=predicted bits, l=lambda). Here's a good but dense article on rate distortion methods and theory: Rate-distortion methods for image and video compression, by Ortego and Ramchandran (1998). I first read this years ago while working on Halo Wars 1's texture compression system, which was like crunch's .CRN mode but simpler. None of this stuff is new, and the image and video folks have been doing it for decades.

I first implemented the Langrangian multiplier method in 2017, as a postprocess on top of crunch's BC1 RDO mode which we sent to a few companies. The Langrangian multiplier method itself is easy, but estimating LZ bitrate and especially handling smooth blocks is tricky. The current smooth block method I'm using computes the maximum of the standard deviation of any component in each block, and from that scalar it computes a per-block MSE error scale. This artificially amplifies computed errors on smooth blocks, which is a hack, but it does seem to work. This hurts R-D performance but something must be done or smooth blocks turn to shit.

Some RDO BC1 and BC7 examples on kodim23, which has lots of smooth blocks:

RDO BC1: 8KB dictionary, lambda=1.0, max smooth block MSE scale=10.2, max std dev=18.0, linear metrics
38.763 RGB dB, 2.72 bits/texel (Deflate, miniz max compression)


RDO BC7 modes 1+6: 8KB dictionary, lambda=1.0, max smooth block MSE scale=19.2, max std dev=18.0, -u4, linear metrics
42.659 RGB dB, 5.05 bits/texel (Deflate, miniz max compression)
Mode 1: 1920 blocks
Mode 6: 22656 blocks



RDO BC7 modes 1+6: 8KB dictionary, lambda=2.0, max smooth block MSE scale=20.4, max std dev=18.0, -u4, linear metrics
40.876 RGB dB, 4.41 bits/texel (Deflate, miniz max compression)
Mode 1: 1920 blocks
Mode 6: 22656 blocks


To get an idea how bad things can get if you don't do anything to handle smooth blocks, here's BC7 modes 1+6: lambda=1.0, no smooth block error scaling (max MSE scale=1.0):
38.469 RGB dB, 3.49 bits/texel


I'm showing kodim23 because how you handle smooth blocks in this method is paramount. 92% of kodim23's blocks are treated as smooth blocks (because the max component standard deviation of any block is <= 18). This means that most of the MSE errors being computed and plugged into the Langrangian calculation are being artificially scaled up. There must be a better way, but at least it's simple. (By comparison, crunch's clusterization-based method didn't do anything special for smooth blocks - it just worked.)

I'm still tuning how smooth blocks are handled. Being too conservative with smooth blocks can cause very noticeable block artifacts at higher lambdas. Being too liberal with smooth blocks causes the R-D efficiency (quality per LZ bit) to go down:


Here are some R-D curves from my early BC1 RDO results. rgbcx.h's RDO BC1 is clearly beating crunch's 13 year old RDO BC1 implementation, achieving higher quality per LZ compressed bit. crunch is based off endpoint/selector clusterization+refinement with no direct awareness of what LZ is going to do with the output data, so this isn't surprising. 


(These images are way too big, but I'm too tired to resize them.)

For some historical background the crunch library (which also supports RDO BC1-5) has always computed and displayed LZMA statistics on the compressed texture's output data. (As a side note, there's no point using Unity's crunch repo for RDO BC1-5 - they didn't optimize RDO, just .CRN.) The entire goal of crunch, from the beginning, was RDO BC1-5. I remember being very excited by RDO texture encoders in 2009, because I realized how useful they would be to video game developers. It achieved this indirectly by causing many blocks, especially nearby ones, to use the same endpoint/selector bits, increasing the ratio of LZ matches vs. literals. For a fun but practical Windows demo I wrote years ago of crunch's RDO encoder (written using managed C++ of all things), check out ddsexport.

Anyhow, the next step is to further enhance RDO BC7 opaque, then dive into alpha. I'll be open sourcing the RDO BC7 postprocessor within a week. After this I'm going to write a second stronger version.

I suspect everybody will switch to RDO texture encoders at some point. Selector RDO with optional endpoint refinement is very easy to do on all the GPU texture formats, even PVRTC1.

I recently went back and updated the UASTC RDO encoder to use the same basic options (lambda and smooth block settings) as my RDO BC1-7 encoders. The original UASTC RDO encoder controlled quality vs. bitrate in a different way. These changes will be in basisu v1.13, which should be released on github hopefully by next week (once we get approval from the company we're working with).

Saturday, January 23, 2021

How to benchmark or use the UASTC encoder in the Basis Universal library

UASTC is a subset of LDR ASTC 4x4, 4x4 block size, always 8bpp, and very high quality. If your engine/product/benchmark supports BC7 or LDR ASTC 4x4, trying out our UASTC encoder/transcoder (without using .basis or .KTX2 at all) is pretty simple:

Compile/link in the Basis Universal encoder and transcoder .cpp files (or put them into libs). Call basisu_encoder_init() at startup.

To encode 4x4 blocks to the 8bpp UASTC format, call encode_uastc():
https://github.com/BinomialLLC/basis_universal/blob/master/encoder/basisu_uastc_enc.h

To decode UASTC blocks to raw 32bpp pixels, call

bool unpack_uastc(const uastc_block& blk, color32* pPixels, bool srgb);

Set the "srgb" flag to always false right now, because that's what the UASTC encoder assumes it will be set to. (We're fixing this for the Feb. release.)

Or you can call transcode_uastc_to_bc7() or transcode_uastc_to_astc(), then unpack those blocks yourself (ASTC will always be equal or higher quality than BC7 because UASTC is a pure subset of LDR 4x4 ASTC):

https://github.com/BinomialLLC/basis_universal/blob/master/transcoder/basisu_transcoder_uastc.h

There's an optional RDO post processor in there too that you can call on arrays of UASTC blocks, but it's pretty basic right now. See uastc_rdo().

The advantage of UASTC is that you can transcode it at run-time to basically any texture format. There are very high quality transcoders to BC1-5, ETC1/2, BC7, etc. It even supports PVRTC1. The disadvantage is a slight drop in quality vs. best BC7/ASTC, but not much, and slower encoding. We even throw in a free RDO encoder (as a simple post processor) for UASTC.

Tuesday, September 15, 2020

LZHAM and crunch are now Public Domain software

As of 9/15/2020, acting as the full legal owner of the LZHAM and crunch data compression libraries, I (acting as an individual) have placed these libraries into the Public Domain. For jurisdictions that don't recognize releasing Public Domain software, there are unlicense-style fallback clauses:


Thanks to Cowles & Thompson, a law firm in Dallas, TX for making this Public Domain release possible.

Wednesday, August 26, 2020

LZHAM and "crunch" IP will be placed into the Public Domain on 9/15/2020

As the owner of the "LZHAM" and "crunch" free open source software IP, I have decided to place these two works into the Public Domain in the United States, expressly waiving copyright protection. Once this is done this software will no longer by my or anyone's IP (i.e. it will NOT BE INTELLECTUAL PROPERTY, OR ANYONE'S PROPERTY). The upload placing these works into the Public Domain will occur on 9/15/2020 around noon EST.

This public domain declaration and anti-copyright waiver (somewhat derived from the unlicense and CC0) will be distributed along with the software:

THIS SOFTWARE IS IN THE PUBLIC DOMAIN

THIS IS FREE AND UNENCUMBERED SOFTWARE EXPLICITLY AND OVERTLY RELEASED AND CONTRIBUTED TO THE PUBLIC DOMAIN, PERMANENTLY, IRREVOCABLY AND UNCONDITIONALLY WAIVING ANY AND ALL CLAIM OF COPYRIGHT, IN PERPETUITY ON SEPTEMBER 15, 2020.

1. FALLBACK CLAUSES

THIS SOFTWARE MAY BE FREELY USED, DERIVED FROM, EXECUTED, LINKED WITH, MODIFIED AND DISTRIBUTED FOR ANY PURPOSE, COMMERCIAL OR NON-COMMERCIAL, BY ANYONE, FOR ANY REASON, WITH NO ATTRIBUTION, IN PERPETUITY.

THE AUTHOR OR AUTHORS OF THIS WORK HEREBY OVERTLY, FULLY, PERMANENTLY, IRREVOCABLY AND UNCONDITIONALLY FORFEITS AND WAIVES ALL CLAIM OF COPYRIGHT (ECONOMIC AND MORAL), ANY AND ALL RIGHTS OF INTEGRITY, AND ANY AND ALL RIGHTS OF ATTRIBUTION. ANYONE IS FREE TO COPY, MODIFY, ENHANCE, OPTIMIZE, PUBLISH, USE, COMPILE, DECOMPILE, ASSEMBLE, DISASSEMBLE, DOWNLOAD, UPLOAD, TRANSMIT, RECEIVE, SELL, FORK, DERIVE FROM, LINK, LINK TO, CALL, REFERENCE, WRAP, THUNK, ENCODE, ENCRYPT, TRANSFORM, STORE, RETRIEVE, DISTORT, DESTROY, RENAME, DELETE, BROADCAST, OR DISTRIBUTE THIS SOFTWARE, EITHER IN SOURCE CODE FORM, IN A TRANSLATED FORM, AS A LIBRARY, AS TEXT, IN PRINT, OR AS A COMPILED BINARY OR EXECUTABLE PROGRAM, OR IN DIGITAL FORM, OR IN ANALOG FORM, OR IN PHYSICAL FORM, OR IN ANY OTHER REPRESENTATION, FOR ANY PURPOSE, COMMERCIAL OR NON-COMMERCIAL, AND BY ANY MEANS, WITH NO ATTRIBUTION, IN PERPETUITY.

2. ANTI-COPYRIGHT WAIVER AND STATEMENT OF INTENT

IN JURISDICTIONS THAT RECOGNIZE COPYRIGHT LAWS, THE AUTHOR OR AUTHORS OF THIS SOFTWARE OVERTLY, FULLY, PERMANENTLY, IRREVOCABLY AND UNCONDITIONALLY DEDICATE, FORFEIT, AND WAIVE ANY AND ALL COPYRIGHT INTEREST IN THE SOFTWARE TO THE PUBLIC DOMAIN. WE MAKE THIS DEDICATION AND WAIVER FOR THE BENEFIT OF THE PUBLIC AT LARGE AND TO THE DETRIMENT OF OUR HEIRS AND SUCCESSORS. WE INTEND THIS DEDICATION AND WAIVER TO BE AN OVERT ACT OF RELINQUISHMENT IN PERPETUITY OF ALL PRESENT AND FUTURE RIGHTS TO THIS SOFTWARE UNDER COPYRIGHT LAW. WE INTEND THIS SOFTWARE TO BE FREELY USED, COMPILED, EXECUTED, MODIFIED, PUBLISHED, DERIVED FROM, OR DISTRIBUTED BY ANYONE, FOR ANY COMMERCIAL OR NON-COMMERCIAL USE, WITH NO ATTRIBUTION, IN PERPETUITY.

3. NO WARRANTY CLAUSE

THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHOR OR AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE, OR DERIVING FROM THE SOFTWARE, OR LINKING WITH THE SOFTWARE, OR CALLING THE SOFTWARE, OR EXECUTING THE SOFTWARE, OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 

4. FINAL ANTI-COPYRIGHT AND INTENT FALLBACK CLAUSE

SHOULD ANY PART OF THIS PUBLIC DOMAIN DECLARATION, OR THE FALLBACK CLAUSES, OR THE ANTI-COPYRIGHT WAIVER FOR ANY REASON BE JUDGED LEGALLY INVALID OR INEFFECTIVE UNDER APPLICABLE LAW, THEN THE PUBLIC DOMAIN DECLARATION, THE 
FALLBACK CLAUSES, AND ANTI-COPYRIGHT WAIVER SHALL BE PRESERVED TO THE MAXIMUM EXTENT PERMITTED BY LAW TAKING INTO ACCOUNT THE ABOVE STATEMENT OF INTENT.

Thursday, April 16, 2020

Yet another BC1 encoder benchmark

stb_dxt v1.09, icbc, rgbcx v1.12, original crunch, and Unity's optimized variant of crunch. Both 4 and 3 color blocks can be used, but transparent texels are not utilized to get black/dark texels in this benchmark. Across a diverse assortment of 100 textures (not just images).



Same benchmark except this time with 3-color transparent texels used for black or dark texels in rgbcx (purple samples):


Here's an update, now with nvdxt.exe (black sample) and ispc_texcomp (brown sample). Note that the nvdxt.exe time is approximate because I had to spawn nvdxt.exe and it loads a .png and saves a .dds file. I did spawn it twice, once without timing it, then immediately again timing it.


nvdxt.exe command line:

nvdxt.exe -nomipmap -quality_highest -rms_threshold 50 -file image.png -output nvcompressed.dds -dxt1c -weight 1.0 1.0 1.0


Thursday, April 9, 2020

BC1 encoding initial endpoint determination benchmark

Benchmark of BC1 encoders using different methods to determine the initial endpoints: 

stb_dxt.h PCA: 35.754 dB, .551 us/block 
rgbcx.h PCA: 35.794, .651 
rgbcx.h PCA+inset: 35.925, .640 
rgbcx.h 2D LS+inset+opt round: 35.920 dB, .541 
rgbcx.h bounds+inset+XY covar: 35.836 dB, .472

This is across 100 textures, so even small avg. improvements are significant. Amazingly, the inset method (a few lines of code) buys rgbcx.h PCA .131 dB! All encoders should be doing this. You *must* pay attention to every little detail in these texture encoders.

Quality is performance in competitive texture block encoding, so even small boosts in quality allow us to dial down the # of total orders to check for the same average quality. This leads to a more competitive encoder.

Methods:

- bounds+inset+XY covar method is Castano's/van Waveren's. 
All encoders should be applying the "inset" method describes in this paper, because from a quantization perspective it makes perfect sense.

- 2D LS is Humus's method, ported to mostly integer math, with added inset+optimal rounding to 565: 

- stb_dxt.h and rgbcx.h PCA is 3D integer PCA (3x3 covar+4 power iters, pick 2 colors along principle axis). 

- PCA+inset+optimal rounding does PCA, picks 2 colors, then lerps the 2 colors by 1/16 or 15/16, then optimal rounds to 565.

Wednesday, April 8, 2020

AMD GPU BC1 decoding lookup tables

Here are the lookup tables you can use to determine how AMD GPU's decode BC1 textures: https://pastebin.com/raw/LSgn0ent

These tables were gathered straight from a Radeon RX 580 by using a small D3D9 app that rendered a textured BC1 quad with point sampling and did a CPU readback. I used this same D3D9 app on an NVidia 1080 and the pixels I read back exactly matched what the NV BC1 formulas on the web predicted, so I'm confident in the approach.

For selectors 0 and 1, the 5->8 and 6->8 endpoint conversion just uses bitshifts/OR's (same as ideal BC1). For 4-color selector 2, use the tables. For selector 3, just invert the low/high endpoints. (I've verified you can do this.) For 3-color selector 2, use the tables.

To access the tables, use [color0_component*32+color1_component], or *64 for 6-bits:
Block Compression (Direct3D 10) - Win32 appsdocs.microsoft.com

Converting the tables to formulas sounds like an interesting puzzle.

Example showing exactly how to use the tables to decode AMD BC1:


Tuesday, April 7, 2020

CPU BC1 Encoding Pareto Frontier

rgbcx.h now defines the BC1 Pareto Frontier for high quality CPU BC1 encoding (i.e. it's stronger than all other available practical high quality CPU encoders for both performance and quality):


Data:

Image

I didn't include AMD Compressonator's encoder because in previous benchmarks (conducted by others) it was beaten by a weaker version of rgbcx.h for both perf. and quality.

The overall CPU BC1 Pareto frontier is defined by ispc_texcomp (at low quality: ~33.1 dB) and rgbcx for any higher quality level. We're going to need SIMD to compete against ispc_texcomp BC1 (a weak stb_dxt clone), which is my next major goal.

To get rgbcx to compete against icbc for max. quality I had to add prioritized cluster fit support for 3-color blocks (not just 4).

It's possible to permit rgbcx to go to even higher quality levels by enlarging the total ordering tables. They're currently limited to 32 entries per total ordering.

I think rgbcx.h's max quality is slightly higher than icbc's HQ mode because prioritized cluster fit can afford to do optimal rounding and evaluate accurate MSE errors in every trial. Regular cluster fit can't afford to do so because it has to evaluate so many total orderings.

Links:
rgbcx: https://github.com/richgel999/bc7enc
libsquish: https://github.com/richgel999/libsquish
icbc: https://github.com/castano/icbc/blob/master/icbc.h

Saturday, April 4, 2020

New BC1 benchmark

Optimizing BC1 encoding is still useful and interesting because the same core algorithms are used in BC7 and ASTC/UASTC encoders. Most improvements made to BC1 encoding carry over nicely to the 2-bit and 3-bit selector modes of other formats.

Here's my latest benchmark:



The highest performing samples (above 37 dB) are rgbcx in 3-color block mode, where it can use transparent black colors (selector 3) for opaque black or very dark texels. (The only other BC1 encoder that might support this mode is the one in NVidia Texture Tools, but I'm not sure.) This technically turns opaque textures into textures with a useless alpha channel, but if the engine or shader just ignores alpha then this mode performs exceptionally well in the average case. The flags are cEncodeBC1Use3ColorBlocksForBlackPixels | cEncodeBC1Use3ColorBlocks

This mode is super useful because it allows the 3-color block encoder to focus the endpoints on the brighter texels within the block, potentially greatly increasing quality. Blocks with very dark or black texels are common in practice.

If your engine supports ignoring the alpha channel in sampled BC1 textures then everyone using BC1 should be using encoders that support this.

Data:

rgbcx.h flags:

- h is cEncodeBC1HighQuality
- ut is cEncodeBC1UseLikelyTotalOrderings
- ub is cEncodeBC1Use3ColorBlocksForBlackPixels
- 3 is cEncodeBC1Use3ColorBlocks

From the benchmarks I've seen it appears NVidia Texture Tools BC1 is around the same perf. as libsquish at slightly higher quality:


I believe this was rgbcx using 10 total orderings (the default setting). The max is 32, and every additional total ordering increases average quality. So at higher settings rgbcx is likely competitive against nvtt while being faster.

I'm currently working on integrating NVTT into my test app.

Friday, February 28, 2020

UASTC benchmark

RGB PSNR over a 1,048,576 4x4 block compression torture test (random blocks from 81 test textures):
                                     
    Near-opt BC7 (BC7E slower):   41.743
    astcenc_thorough:             40.892
    UASTC (veryslow)->ASTC        40.373
    UASTC (veryslow)->BC7         39.965
    UASTC (slower)->ASTC          40.163
    UASTC (slower)->BC7:          39.782
    UASTC (default)->ASTC         39.372
    UASTC (default)->BC7:         39.171
    UASTC (faster)->ASTC          39.269
    UASTC (fastest)->ASTC         34.654
    UASTC (fastest)->BC7          34.554
    ispc_texcomp ASTC alpha_slow: 39.768
    stb_dxt BC1 HIGHQUAL:         32.479
    UASTC (slower)->BC1:          32.148
    UASTC (fastest)->BC1          32.256
    UASTC (slower)->ETC1:         30.956
    UASTC (fastest)->ETC1:        30.113
    UASTC (slower)->R11:          37.942

The 4096x4096 .PNG is here.

The EAC R11 format is R PSNR, and is included for comparison purposes.

Notice that the UASTC->BC1 quality actually increased when going from "slower" to "fastest" mode. This is because in "fastest" mode, almost all the blocks used UASTC mode 0, which is more compatible with BC1. (UASTC has 1-2 bits of BC1 hints per block that allow the UASTC block to be converted directly to BC1 blocks, skipping real-time encoding.)


Monday, February 24, 2020

LDR ASTC mode list (all CEM's the same)

ASTC is a very complex format. There are 407 valid 4x4 LDR ASTC encodings (or configurations?) that meet the following criteria:

- LDR only, 4x4 block size
- Planes: 1 or 2
- Subsets: 1-4 (one plane) or 1-3 (dual plane)
- CEM's: LDR only (0, 1, 4, 5, 6, 8, 9, 10, 12, 13), all CEM's the same for each subset
- Weight Ranges: 0-11
- Endpoint Ranges: 0-19

If the "all CEM's the same" rule was relaxed there would be a ridiculous number of modes to list (in the thousands).

Here's the list. I generated it by iterating through all the various configurations and trying to encode each to a valid ASTC block. To double check I used an open source ASTC decompressor to ensure the block was decodable without errors. I went through this list to determine the 18 modes UASTC uses.

DualPlane: 0, Subsets: 1, WeightRange: 1 (3 levels), CEM: 0 (L Direct     ), EndpointRange: 20 (256 levels)
DualPlane: 0, Subsets: 1, WeightRange: 1 (3 levels), CEM: 1 (L Base+Ofs   ), EndpointRange: 20 (256 levels)
DualPlane: 0, Subsets: 1, WeightRange: 1 (3 levels), CEM: 4 (LA Direct    ), EndpointRange: 20 (256 levels)
DualPlane: 0, Subsets: 1, WeightRange: 1 (3 levels), CEM: 5 (LA Base+Ofs  ), EndpointRange: 20 (256 levels)
DualPlane: 0, Subsets: 1, WeightRange: 1 (3 levels), CEM: 6 (RGB Base+Sc  ), EndpointRange: 20 (256 levels)
DualPlane: 0, Subsets: 1, WeightRange: 1 (3 levels), CEM: 8 (RGB Direct   ), EndpointRange: 20 (256 levels)
DualPlane: 0, Subsets: 1, WeightRange: 1 (3 levels), CEM: 9 (RGB Base+Ofs ), EndpointRange: 20 (256 levels)
DualPlane: 0, Subsets: 1, WeightRange: 1 (3 levels), CEM: 10 (RGB Base+Sc2A), EndpointRange: 20 (256 levels)
DualPlane: 0, Subsets: 1, WeightRange: 1 (3 levels), CEM: 12 (RGBA Direct  ), EndpointRange: 20 (256 levels)
DualPlane: 0, Subsets: 1, WeightRange: 1 (3 levels), CEM: 13 (RGBA Base+Ofs), EndpointRange: 20 (256 levels)
DualPlane: 0, Subsets: 1, WeightRange: 2 (4 levels), CEM: 0 (L Direct     ), EndpointRange: 20 (256 levels)
DualPlane: 0, Subsets: 1, WeightRange: 2 (4 levels), CEM: 1 (L Base+Ofs   ), EndpointRange: 20 (256 levels)
DualPlane: 0, Subsets: 1, WeightRange: 2 (4 levels), CEM: 4 (LA Direct    ), EndpointRange: 20 (256 levels)
DualPlane: 0, Subsets: 1, WeightRange: 2 (4 levels), CEM: 5 (LA Base+Ofs  ), EndpointRange: 20 (256 levels)
DualPlane: 0, Subsets: 1, WeightRange: 2 (4 levels), CEM: 6 (RGB Base+Sc  ), EndpointRange: 20 (256 levels)
DualPlane: 0, Subsets: 1, WeightRange: 2 (4 levels), CEM: 8 (RGB Direct   ), EndpointRange: 20 (256 levels)
DualPlane: 0, Subsets: 1, WeightRange: 2 (4 levels), CEM: 9 (RGB Base+Ofs ), EndpointRange: 20 (256 levels)
DualPlane: 0, Subsets: 1, WeightRange: 2 (4 levels), CEM: 10 (RGB Base+Sc2A), EndpointRange: 20 (256 levels)
DualPlane: 0, Subsets: 1, WeightRange: 2 (4 levels), CEM: 12 (RGBA Direct  ), EndpointRange: 20 (256 levels)
DualPlane: 0, Subsets: 1, WeightRange: 2 (4 levels), CEM: 13 (RGBA Base+Ofs), EndpointRange: 20 (256 levels)
DualPlane: 0, Subsets: 1, WeightRange: 3 (5 levels), CEM: 0 (L Direct     ), EndpointRange: 20 (256 levels)
DualPlane: 0, Subsets: 1, WeightRange: 3 (5 levels), CEM: 1 (L Base+Ofs   ), EndpointRange: 20 (256 levels)
DualPlane: 0, Subsets: 1, WeightRange: 3 (5 levels), CEM: 4 (LA Direct    ), EndpointRange: 20 (256 levels)
DualPlane: 0, Subsets: 1, WeightRange: 3 (5 levels), CEM: 5 (LA Base+Ofs  ), EndpointRange: 20 (256 levels)
DualPlane: 0, Subsets: 1, WeightRange: 3 (5 levels), CEM: 6 (RGB Base+Sc  ), EndpointRange: 20 (256 levels)
DualPlane: 0, Subsets: 1, WeightRange: 3 (5 levels), CEM: 8 (RGB Direct   ), EndpointRange: 20 (256 levels)
DualPlane: 0, Subsets: 1, WeightRange: 3 (5 levels), CEM: 9 (RGB Base+Ofs ), EndpointRange: 20 (256 levels)
DualPlane: 0, Subsets: 1, WeightRange: 3 (5 levels), CEM: 10 (RGB Base+Sc2A), EndpointRange: 20 (256 levels)
DualPlane: 0, Subsets: 1, WeightRange: 3 (5 levels), CEM: 12 (RGBA Direct  ), EndpointRange: 20 (256 levels)
DualPlane: 0, Subsets: 1, WeightRange: 3 (5 levels), CEM: 13 (RGBA Base+Ofs), EndpointRange: 20 (256 levels)
DualPlane: 0, Subsets: 1, WeightRange: 4 (6 levels), CEM: 0 (L Direct     ), EndpointRange: 20 (256 levels)
DualPlane: 0, Subsets: 1, WeightRange: 4 (6 levels), CEM: 1 (L Base+Ofs   ), EndpointRange: 20 (256 levels)
DualPlane: 0, Subsets: 1, WeightRange: 4 (6 levels), CEM: 4 (LA Direct    ), EndpointRange: 20 (256 levels)
DualPlane: 0, Subsets: 1, WeightRange: 4 (6 levels), CEM: 5 (LA Base+Ofs  ), EndpointRange: 20 (256 levels)
DualPlane: 0, Subsets: 1, WeightRange: 4 (6 levels), CEM: 6 (RGB Base+Sc  ), EndpointRange: 20 (256 levels)
DualPlane: 0, Subsets: 1, WeightRange: 4 (6 levels), CEM: 8 (RGB Direct   ), EndpointRange: 20 (256 levels)
DualPlane: 0, Subsets: 1, WeightRange: 4 (6 levels), CEM: 9 (RGB Base+Ofs ), EndpointRange: 20 (256 levels)
DualPlane: 0, Subsets: 1, WeightRange: 4 (6 levels), CEM: 10 (RGB Base+Sc2A), EndpointRange: 20 (256 levels)
DualPlane: 0, Subsets: 1, WeightRange: 4 (6 levels), CEM: 12 (RGBA Direct  ), EndpointRange: 20 (256 levels)
DualPlane: 0, Subsets: 1, WeightRange: 4 (6 levels), CEM: 13 (RGBA Base+Ofs), EndpointRange: 20 (256 levels)
DualPlane: 0, Subsets: 1, WeightRange: 5 (8 levels), CEM: 0 (L Direct     ), EndpointRange: 20 (256 levels)
DualPlane: 0, Subsets: 1, WeightRange: 5 (8 levels), CEM: 1 (L Base+Ofs   ), EndpointRange: 20 (256 levels)
DualPlane: 0, Subsets: 1, WeightRange: 5 (8 levels), CEM: 4 (LA Direct    ), EndpointRange: 20 (256 levels)
DualPlane: 0, Subsets: 1, WeightRange: 5 (8 levels), CEM: 5 (LA Base+Ofs  ), EndpointRange: 20 (256 levels)
DualPlane: 0, Subsets: 1, WeightRange: 5 (8 levels), CEM: 6 (RGB Base+Sc  ), EndpointRange: 20 (256 levels)
DualPlane: 0, Subsets: 1, WeightRange: 5 (8 levels), CEM: 8 (RGB Direct   ), EndpointRange: 20 (256 levels)
DualPlane: 0, Subsets: 1, WeightRange: 5 (8 levels), CEM: 9 (RGB Base+Ofs ), EndpointRange: 20 (256 levels)
DualPlane: 0, Subsets: 1, WeightRange: 5 (8 levels), CEM: 10 (RGB Base+Sc2A), EndpointRange: 20 (256 levels)
DualPlane: 0, Subsets: 1, WeightRange: 5 (8 levels), CEM: 12 (RGBA Direct  ), EndpointRange: 19 (192 levels)
DualPlane: 0, Subsets: 1, WeightRange: 5 (8 levels), CEM: 13 (RGBA Base+Ofs), EndpointRange: 19 (192 levels)
DualPlane: 0, Subsets: 1, WeightRange: 6 (10 levels), CEM: 0 (L Direct     ), EndpointRange: 20 (256 levels)
DualPlane: 0, Subsets: 1, WeightRange: 6 (10 levels), CEM: 1 (L Base+Ofs   ), EndpointRange: 20 (256 levels)
DualPlane: 0, Subsets: 1, WeightRange: 6 (10 levels), CEM: 4 (LA Direct    ), EndpointRange: 20 (256 levels)
DualPlane: 0, Subsets: 1, WeightRange: 6 (10 levels), CEM: 5 (LA Base+Ofs  ), EndpointRange: 20 (256 levels)
DualPlane: 0, Subsets: 1, WeightRange: 6 (10 levels), CEM: 6 (RGB Base+Sc  ), EndpointRange: 20 (256 levels)
DualPlane: 0, Subsets: 1, WeightRange: 6 (10 levels), CEM: 8 (RGB Direct   ), EndpointRange: 20 (256 levels)
DualPlane: 0, Subsets: 1, WeightRange: 6 (10 levels), CEM: 9 (RGB Base+Ofs ), EndpointRange: 20 (256 levels)
DualPlane: 0, Subsets: 1, WeightRange: 6 (10 levels), CEM: 10 (RGB Base+Sc2A), EndpointRange: 20 (256 levels)
DualPlane: 0, Subsets: 1, WeightRange: 6 (10 levels), CEM: 12 (RGBA Direct  ), EndpointRange: 17 (128 levels)
DualPlane: 0, Subsets: 1, WeightRange: 6 (10 levels), CEM: 13 (RGBA Base+Ofs), EndpointRange: 17 (128 levels)
DualPlane: 0, Subsets: 1, WeightRange: 7 (12 levels), CEM: 0 (L Direct     ), EndpointRange: 20 (256 levels)
DualPlane: 0, Subsets: 1, WeightRange: 7 (12 levels), CEM: 1 (L Base+Ofs   ), EndpointRange: 20 (256 levels)
DualPlane: 0, Subsets: 1, WeightRange: 7 (12 levels), CEM: 4 (LA Direct    ), EndpointRange: 20 (256 levels)
DualPlane: 0, Subsets: 1, WeightRange: 7 (12 levels), CEM: 5 (LA Base+Ofs  ), EndpointRange: 20 (256 levels)
DualPlane: 0, Subsets: 1, WeightRange: 7 (12 levels), CEM: 6 (RGB Base+Sc  ), EndpointRange: 20 (256 levels)
DualPlane: 0, Subsets: 1, WeightRange: 7 (12 levels), CEM: 8 (RGB Direct   ), EndpointRange: 20 (256 levels)
DualPlane: 0, Subsets: 1, WeightRange: 7 (12 levels), CEM: 9 (RGB Base+Ofs ), EndpointRange: 20 (256 levels)
DualPlane: 0, Subsets: 1, WeightRange: 7 (12 levels), CEM: 10 (RGB Base+Sc2A), EndpointRange: 20 (256 levels)
DualPlane: 0, Subsets: 1, WeightRange: 7 (12 levels), CEM: 12 (RGBA Direct  ), EndpointRange: 16 (96 levels)
DualPlane: 0, Subsets: 1, WeightRange: 7 (12 levels), CEM: 13 (RGBA Base+Ofs), EndpointRange: 16 (96 levels)
DualPlane: 0, Subsets: 1, WeightRange: 8 (16 levels), CEM: 0 (L Direct     ), EndpointRange: 20 (256 levels)
DualPlane: 0, Subsets: 1, WeightRange: 8 (16 levels), CEM: 1 (L Base+Ofs   ), EndpointRange: 20 (256 levels)
DualPlane: 0, Subsets: 1, WeightRange: 8 (16 levels), CEM: 4 (LA Direct    ), EndpointRange: 20 (256 levels)
DualPlane: 0, Subsets: 1, WeightRange: 8 (16 levels), CEM: 5 (LA Base+Ofs  ), EndpointRange: 20 (256 levels)
DualPlane: 0, Subsets: 1, WeightRange: 8 (16 levels), CEM: 6 (RGB Base+Sc  ), EndpointRange: 20 (256 levels)
DualPlane: 0, Subsets: 1, WeightRange: 8 (16 levels), CEM: 8 (RGB Direct   ), EndpointRange: 19 (192 levels)
DualPlane: 0, Subsets: 1, WeightRange: 8 (16 levels), CEM: 9 (RGB Base+Ofs ), EndpointRange: 19 (192 levels)
DualPlane: 0, Subsets: 1, WeightRange: 8 (16 levels), CEM: 10 (RGB Base+Sc2A), EndpointRange: 19 (192 levels)
DualPlane: 0, Subsets: 1, WeightRange: 8 (16 levels), CEM: 12 (RGBA Direct  ), EndpointRange: 13 (48 levels)
DualPlane: 0, Subsets: 1, WeightRange: 8 (16 levels), CEM: 13 (RGBA Base+Ofs), EndpointRange: 13 (48 levels)
DualPlane: 0, Subsets: 1, WeightRange: 9 (20 levels), CEM: 0 (L Direct     ), EndpointRange: 20 (256 levels)
DualPlane: 0, Subsets: 1, WeightRange: 9 (20 levels), CEM: 1 (L Base+Ofs   ), EndpointRange: 20 (256 levels)
DualPlane: 0, Subsets: 1, WeightRange: 9 (20 levels), CEM: 4 (LA Direct    ), EndpointRange: 20 (256 levels)
DualPlane: 0, Subsets: 1, WeightRange: 9 (20 levels), CEM: 5 (LA Base+Ofs  ), EndpointRange: 20 (256 levels)
DualPlane: 0, Subsets: 1, WeightRange: 9 (20 levels), CEM: 6 (RGB Base+Sc  ), EndpointRange: 20 (256 levels)
DualPlane: 0, Subsets: 1, WeightRange: 9 (20 levels), CEM: 8 (RGB Direct   ), EndpointRange: 16 (96 levels)
DualPlane: 0, Subsets: 1, WeightRange: 9 (20 levels), CEM: 9 (RGB Base+Ofs ), EndpointRange: 16 (96 levels)
DualPlane: 0, Subsets: 1, WeightRange: 9 (20 levels), CEM: 10 (RGB Base+Sc2A), EndpointRange: 16 (96 levels)
DualPlane: 0, Subsets: 1, WeightRange: 9 (20 levels), CEM: 12 (RGBA Direct  ), EndpointRange: 11 (32 levels)
DualPlane: 0, Subsets: 1, WeightRange: 9 (20 levels), CEM: 13 (RGBA Base+Ofs), EndpointRange: 11 (32 levels)
DualPlane: 0, Subsets: 1, WeightRange: 10 (24 levels), CEM: 0 (L Direct     ), EndpointRange: 20 (256 levels)
DualPlane: 0, Subsets: 1, WeightRange: 10 (24 levels), CEM: 1 (L Base+Ofs   ), EndpointRange: 20 (256 levels)
DualPlane: 0, Subsets: 1, WeightRange: 10 (24 levels), CEM: 4 (LA Direct    ), EndpointRange: 20 (256 levels)
DualPlane: 0, Subsets: 1, WeightRange: 10 (24 levels), CEM: 5 (LA Base+Ofs  ), EndpointRange: 20 (256 levels)
DualPlane: 0, Subsets: 1, WeightRange: 10 (24 levels), CEM: 6 (RGB Base+Sc  ), EndpointRange: 20 (256 levels)
DualPlane: 0, Subsets: 1, WeightRange: 10 (24 levels), CEM: 8 (RGB Direct   ), EndpointRange: 14 (64 levels)
DualPlane: 0, Subsets: 1, WeightRange: 10 (24 levels), CEM: 9 (RGB Base+Ofs ), EndpointRange: 14 (64 levels)
DualPlane: 0, Subsets: 1, WeightRange: 10 (24 levels), CEM: 10 (RGB Base+Sc2A), EndpointRange: 14 (64 levels)
DualPlane: 0, Subsets: 1, WeightRange: 10 (24 levels), CEM: 12 (RGBA Direct  ), EndpointRange: 10 (24 levels)
DualPlane: 0, Subsets: 1, WeightRange: 10 (24 levels), CEM: 13 (RGBA Base+Ofs), EndpointRange: 10 (24 levels)
DualPlane: 0, Subsets: 1, WeightRange: 11 (32 levels), CEM: 0 (L Direct     ), EndpointRange: 20 (256 levels)
DualPlane: 0, Subsets: 1, WeightRange: 11 (32 levels), CEM: 1 (L Base+Ofs   ), EndpointRange: 20 (256 levels)
DualPlane: 0, Subsets: 1, WeightRange: 11 (32 levels), CEM: 4 (LA Direct    ), EndpointRange: 19 (192 levels)
DualPlane: 0, Subsets: 1, WeightRange: 11 (32 levels), CEM: 5 (LA Base+Ofs  ), EndpointRange: 19 (192 levels)
DualPlane: 0, Subsets: 1, WeightRange: 11 (32 levels), CEM: 6 (RGB Base+Sc  ), EndpointRange: 19 (192 levels)
DualPlane: 0, Subsets: 1, WeightRange: 11 (32 levels), CEM: 8 (RGB Direct   ), EndpointRange: 11 (32 levels)
DualPlane: 0, Subsets: 1, WeightRange: 11 (32 levels), CEM: 9 (RGB Base+Ofs ), EndpointRange: 11 (32 levels)
DualPlane: 0, Subsets: 1, WeightRange: 11 (32 levels), CEM: 10 (RGB Base+Sc2A), EndpointRange: 11 (32 levels)
DualPlane: 0, Subsets: 1, WeightRange: 11 (32 levels), CEM: 12 (RGBA Direct  ), EndpointRange: 7 (12 levels)
DualPlane: 0, Subsets: 1, WeightRange: 11 (32 levels), CEM: 13 (RGBA Base+Ofs), EndpointRange: 7 (12 levels)
DualPlane: 0, Subsets: 2, WeightRange: 1 (3 levels), CEM: 0 (L Direct     ), EndpointRange: 20 (256 levels)
DualPlane: 0, Subsets: 2, WeightRange: 1 (3 levels), CEM: 1 (L Base+Ofs   ), EndpointRange: 20 (256 levels)
DualPlane: 0, Subsets: 2, WeightRange: 1 (3 levels), CEM: 4 (LA Direct    ), EndpointRange: 20 (256 levels)
DualPlane: 0, Subsets: 2, WeightRange: 1 (3 levels), CEM: 5 (LA Base+Ofs  ), EndpointRange: 20 (256 levels)
DualPlane: 0, Subsets: 2, WeightRange: 1 (3 levels), CEM: 6 (RGB Base+Sc  ), EndpointRange: 20 (256 levels)
DualPlane: 0, Subsets: 2, WeightRange: 1 (3 levels), CEM: 8 (RGB Direct   ), EndpointRange: 14 (64 levels)
DualPlane: 0, Subsets: 2, WeightRange: 1 (3 levels), CEM: 9 (RGB Base+Ofs ), EndpointRange: 14 (64 levels)
DualPlane: 0, Subsets: 2, WeightRange: 1 (3 levels), CEM: 10 (RGB Base+Sc2A), EndpointRange: 14 (64 levels)
DualPlane: 0, Subsets: 2, WeightRange: 1 (3 levels), CEM: 12 (RGBA Direct  ), EndpointRange: 9 (20 levels)
DualPlane: 0, Subsets: 2, WeightRange: 1 (3 levels), CEM: 13 (RGBA Base+Ofs), EndpointRange: 9 (20 levels)
DualPlane: 0, Subsets: 2, WeightRange: 2 (4 levels), CEM: 0 (L Direct     ), EndpointRange: 20 (256 levels)
DualPlane: 0, Subsets: 2, WeightRange: 2 (4 levels), CEM: 1 (L Base+Ofs   ), EndpointRange: 20 (256 levels)
DualPlane: 0, Subsets: 2, WeightRange: 2 (4 levels), CEM: 4 (LA Direct    ), EndpointRange: 20 (256 levels)
DualPlane: 0, Subsets: 2, WeightRange: 2 (4 levels), CEM: 5 (LA Base+Ofs  ), EndpointRange: 20 (256 levels)
DualPlane: 0, Subsets: 2, WeightRange: 2 (4 levels), CEM: 6 (RGB Base+Sc  ), EndpointRange: 20 (256 levels)
DualPlane: 0, Subsets: 2, WeightRange: 2 (4 levels), CEM: 8 (RGB Direct   ), EndpointRange: 12 (40 levels)
DualPlane: 0, Subsets: 2, WeightRange: 2 (4 levels), CEM: 9 (RGB Base+Ofs ), EndpointRange: 12 (40 levels)
DualPlane: 0, Subsets: 2, WeightRange: 2 (4 levels), CEM: 10 (RGB Base+Sc2A), EndpointRange: 12 (40 levels)
DualPlane: 0, Subsets: 2, WeightRange: 2 (4 levels), CEM: 12 (RGBA Direct  ), EndpointRange: 8 (16 levels)
DualPlane: 0, Subsets: 2, WeightRange: 2 (4 levels), CEM: 13 (RGBA Base+Ofs), EndpointRange: 8 (16 levels)
DualPlane: 0, Subsets: 2, WeightRange: 3 (5 levels), CEM: 0 (L Direct     ), EndpointRange: 20 (256 levels)
DualPlane: 0, Subsets: 2, WeightRange: 3 (5 levels), CEM: 1 (L Base+Ofs   ), EndpointRange: 20 (256 levels)
DualPlane: 0, Subsets: 2, WeightRange: 3 (5 levels), CEM: 4 (LA Direct    ), EndpointRange: 19 (192 levels)
DualPlane: 0, Subsets: 2, WeightRange: 3 (5 levels), CEM: 5 (LA Base+Ofs  ), EndpointRange: 19 (192 levels)
DualPlane: 0, Subsets: 2, WeightRange: 3 (5 levels), CEM: 6 (RGB Base+Sc  ), EndpointRange: 19 (192 levels)
DualPlane: 0, Subsets: 2, WeightRange: 3 (5 levels), CEM: 8 (RGB Direct   ), EndpointRange: 11 (32 levels)
DualPlane: 0, Subsets: 2, WeightRange: 3 (5 levels), CEM: 9 (RGB Base+Ofs ), EndpointRange: 11 (32 levels)
DualPlane: 0, Subsets: 2, WeightRange: 3 (5 levels), CEM: 10 (RGB Base+Sc2A), EndpointRange: 11 (32 levels)
DualPlane: 0, Subsets: 2, WeightRange: 3 (5 levels), CEM: 12 (RGBA Direct  ), EndpointRange: 7 (12 levels)
DualPlane: 0, Subsets: 2, WeightRange: 3 (5 levels), CEM: 13 (RGBA Base+Ofs), EndpointRange: 7 (12 levels)
DualPlane: 0, Subsets: 2, WeightRange: 4 (6 levels), CEM: 0 (L Direct     ), EndpointRange: 20 (256 levels)
DualPlane: 0, Subsets: 2, WeightRange: 4 (6 levels), CEM: 1 (L Base+Ofs   ), EndpointRange: 20 (256 levels)
DualPlane: 0, Subsets: 2, WeightRange: 4 (6 levels), CEM: 4 (LA Direct    ), EndpointRange: 17 (128 levels)
DualPlane: 0, Subsets: 2, WeightRange: 4 (6 levels), CEM: 5 (LA Base+Ofs  ), EndpointRange: 17 (128 levels)
DualPlane: 0, Subsets: 2, WeightRange: 4 (6 levels), CEM: 6 (RGB Base+Sc  ), EndpointRange: 17 (128 levels)
DualPlane: 0, Subsets: 2, WeightRange: 4 (6 levels), CEM: 8 (RGB Direct   ), EndpointRange: 10 (24 levels)
DualPlane: 0, Subsets: 2, WeightRange: 4 (6 levels), CEM: 9 (RGB Base+Ofs ), EndpointRange: 10 (24 levels)
DualPlane: 0, Subsets: 2, WeightRange: 4 (6 levels), CEM: 10 (RGB Base+Sc2A), EndpointRange: 10 (24 levels)
DualPlane: 0, Subsets: 2, WeightRange: 4 (6 levels), CEM: 12 (RGBA Direct  ), EndpointRange: 6 (10 levels)
DualPlane: 0, Subsets: 2, WeightRange: 4 (6 levels), CEM: 13 (RGBA Base+Ofs), EndpointRange: 6 (10 levels)
DualPlane: 0, Subsets: 2, WeightRange: 5 (8 levels), CEM: 0 (L Direct     ), EndpointRange: 20 (256 levels)
DualPlane: 0, Subsets: 2, WeightRange: 5 (8 levels), CEM: 1 (L Base+Ofs   ), EndpointRange: 20 (256 levels)
DualPlane: 0, Subsets: 2, WeightRange: 5 (8 levels), CEM: 4 (LA Direct    ), EndpointRange: 15 (80 levels)
DualPlane: 0, Subsets: 2, WeightRange: 5 (8 levels), CEM: 5 (LA Base+Ofs  ), EndpointRange: 15 (80 levels)
DualPlane: 0, Subsets: 2, WeightRange: 5 (8 levels), CEM: 6 (RGB Base+Sc  ), EndpointRange: 15 (80 levels)
DualPlane: 0, Subsets: 2, WeightRange: 5 (8 levels), CEM: 8 (RGB Direct   ), EndpointRange: 8 (16 levels)
DualPlane: 0, Subsets: 2, WeightRange: 5 (8 levels), CEM: 9 (RGB Base+Ofs ), EndpointRange: 8 (16 levels)
DualPlane: 0, Subsets: 2, WeightRange: 5 (8 levels), CEM: 10 (RGB Base+Sc2A), EndpointRange: 8 (16 levels)
DualPlane: 0, Subsets: 2, WeightRange: 5 (8 levels), CEM: 12 (RGBA Direct  ), EndpointRange: 5 (8 levels)
DualPlane: 0, Subsets: 2, WeightRange: 5 (8 levels), CEM: 13 (RGBA Base+Ofs), EndpointRange: 5 (8 levels)
DualPlane: 0, Subsets: 2, WeightRange: 6 (10 levels), CEM: 0 (L Direct     ), EndpointRange: 20 (256 levels)
DualPlane: 0, Subsets: 2, WeightRange: 6 (10 levels), CEM: 1 (L Base+Ofs   ), EndpointRange: 20 (256 levels)
DualPlane: 0, Subsets: 2, WeightRange: 6 (10 levels), CEM: 4 (LA Direct    ), EndpointRange: 13 (48 levels)
DualPlane: 0, Subsets: 2, WeightRange: 6 (10 levels), CEM: 5 (LA Base+Ofs  ), EndpointRange: 13 (48 levels)
DualPlane: 0, Subsets: 2, WeightRange: 6 (10 levels), CEM: 6 (RGB Base+Sc  ), EndpointRange: 13 (48 levels)
DualPlane: 0, Subsets: 2, WeightRange: 6 (10 levels), CEM: 8 (RGB Direct   ), EndpointRange: 7 (12 levels)
DualPlane: 0, Subsets: 2, WeightRange: 6 (10 levels), CEM: 9 (RGB Base+Ofs ), EndpointRange: 7 (12 levels)
DualPlane: 0, Subsets: 2, WeightRange: 6 (10 levels), CEM: 10 (RGB Base+Sc2A), EndpointRange: 7 (12 levels)
DualPlane: 0, Subsets: 2, WeightRange: 6 (10 levels), CEM: 12 (RGBA Direct  ), EndpointRange: 4 (6 levels)
DualPlane: 0, Subsets: 2, WeightRange: 6 (10 levels), CEM: 13 (RGBA Base+Ofs), EndpointRange: 4 (6 levels)
DualPlane: 0, Subsets: 2, WeightRange: 7 (12 levels), CEM: 0 (L Direct     ), EndpointRange: 20 (256 levels)
DualPlane: 0, Subsets: 2, WeightRange: 7 (12 levels), CEM: 1 (L Base+Ofs   ), EndpointRange: 20 (256 levels)
DualPlane: 0, Subsets: 2, WeightRange: 7 (12 levels), CEM: 4 (LA Direct    ), EndpointRange: 11 (32 levels)
DualPlane: 0, Subsets: 2, WeightRange: 7 (12 levels), CEM: 5 (LA Base+Ofs  ), EndpointRange: 11 (32 levels)
DualPlane: 0, Subsets: 2, WeightRange: 7 (12 levels), CEM: 6 (RGB Base+Sc  ), EndpointRange: 11 (32 levels)
DualPlane: 0, Subsets: 2, WeightRange: 7 (12 levels), CEM: 8 (RGB Direct   ), EndpointRange: 6 (10 levels)
DualPlane: 0, Subsets: 2, WeightRange: 7 (12 levels), CEM: 9 (RGB Base+Ofs ), EndpointRange: 6 (10 levels)
DualPlane: 0, Subsets: 2, WeightRange: 7 (12 levels), CEM: 10 (RGB Base+Sc2A), EndpointRange: 6 (10 levels)
DualPlane: 0, Subsets: 2, WeightRange: 8 (16 levels), CEM: 0 (L Direct     ), EndpointRange: 20 (256 levels)
DualPlane: 0, Subsets: 2, WeightRange: 8 (16 levels), CEM: 1 (L Base+Ofs   ), EndpointRange: 20 (256 levels)
DualPlane: 0, Subsets: 2, WeightRange: 8 (16 levels), CEM: 4 (LA Direct    ), EndpointRange: 9 (20 levels)
DualPlane: 0, Subsets: 2, WeightRange: 8 (16 levels), CEM: 5 (LA Base+Ofs  ), EndpointRange: 9 (20 levels)
DualPlane: 0, Subsets: 2, WeightRange: 8 (16 levels), CEM: 6 (RGB Base+Sc  ), EndpointRange: 9 (20 levels)
DualPlane: 0, Subsets: 2, WeightRange: 8 (16 levels), CEM: 8 (RGB Direct   ), EndpointRange: 4 (6 levels)
DualPlane: 0, Subsets: 2, WeightRange: 8 (16 levels), CEM: 9 (RGB Base+Ofs ), EndpointRange: 4 (6 levels)
DualPlane: 0, Subsets: 2, WeightRange: 8 (16 levels), CEM: 10 (RGB Base+Sc2A), EndpointRange: 4 (6 levels)
DualPlane: 0, Subsets: 2, WeightRange: 9 (20 levels), CEM: 0 (L Direct     ), EndpointRange: 17 (128 levels)
DualPlane: 0, Subsets: 2, WeightRange: 9 (20 levels), CEM: 1 (L Base+Ofs   ), EndpointRange: 17 (128 levels)
DualPlane: 0, Subsets: 2, WeightRange: 9 (20 levels), CEM: 4 (LA Direct    ), EndpointRange: 7 (12 levels)
DualPlane: 0, Subsets: 2, WeightRange: 9 (20 levels), CEM: 5 (LA Base+Ofs  ), EndpointRange: 7 (12 levels)
DualPlane: 0, Subsets: 2, WeightRange: 9 (20 levels), CEM: 6 (RGB Base+Sc  ), EndpointRange: 7 (12 levels)
DualPlane: 0, Subsets: 2, WeightRange: 10 (24 levels), CEM: 0 (L Direct     ), EndpointRange: 14 (64 levels)
DualPlane: 0, Subsets: 2, WeightRange: 10 (24 levels), CEM: 1 (L Base+Ofs   ), EndpointRange: 14 (64 levels)
DualPlane: 0, Subsets: 2, WeightRange: 10 (24 levels), CEM: 4 (LA Direct    ), EndpointRange: 5 (8 levels)
DualPlane: 0, Subsets: 2, WeightRange: 10 (24 levels), CEM: 5 (LA Base+Ofs  ), EndpointRange: 5 (8 levels)
DualPlane: 0, Subsets: 2, WeightRange: 10 (24 levels), CEM: 6 (RGB Base+Sc  ), EndpointRange: 5 (8 levels)
DualPlane: 0, Subsets: 2, WeightRange: 11 (32 levels), CEM: 0 (L Direct     ), EndpointRange: 10 (24 levels)
DualPlane: 0, Subsets: 2, WeightRange: 11 (32 levels), CEM: 1 (L Base+Ofs   ), EndpointRange: 10 (24 levels)
DualPlane: 0, Subsets: 3, WeightRange: 1 (3 levels), CEM: 0 (L Direct     ), EndpointRange: 20 (256 levels)
DualPlane: 0, Subsets: 3, WeightRange: 1 (3 levels), CEM: 1 (L Base+Ofs   ), EndpointRange: 20 (256 levels)
DualPlane: 0, Subsets: 3, WeightRange: 1 (3 levels), CEM: 4 (LA Direct    ), EndpointRange: 14 (64 levels)
DualPlane: 0, Subsets: 3, WeightRange: 1 (3 levels), CEM: 5 (LA Base+Ofs  ), EndpointRange: 14 (64 levels)
DualPlane: 0, Subsets: 3, WeightRange: 1 (3 levels), CEM: 6 (RGB Base+Sc  ), EndpointRange: 14 (64 levels)
DualPlane: 0, Subsets: 3, WeightRange: 1 (3 levels), CEM: 8 (RGB Direct   ), EndpointRange: 8 (16 levels)
DualPlane: 0, Subsets: 3, WeightRange: 1 (3 levels), CEM: 9 (RGB Base+Ofs ), EndpointRange: 8 (16 levels)
DualPlane: 0, Subsets: 3, WeightRange: 1 (3 levels), CEM: 10 (RGB Base+Sc2A), EndpointRange: 8 (16 levels)
DualPlane: 0, Subsets: 3, WeightRange: 2 (4 levels), CEM: 0 (L Direct     ), EndpointRange: 20 (256 levels)
DualPlane: 0, Subsets: 3, WeightRange: 2 (4 levels), CEM: 1 (L Base+Ofs   ), EndpointRange: 20 (256 levels)
DualPlane: 0, Subsets: 3, WeightRange: 2 (4 levels), CEM: 4 (LA Direct    ), EndpointRange: 12 (40 levels)
DualPlane: 0, Subsets: 3, WeightRange: 2 (4 levels), CEM: 5 (LA Base+Ofs  ), EndpointRange: 12 (40 levels)
DualPlane: 0, Subsets: 3, WeightRange: 2 (4 levels), CEM: 6 (RGB Base+Sc  ), EndpointRange: 12 (40 levels)
DualPlane: 0, Subsets: 3, WeightRange: 2 (4 levels), CEM: 8 (RGB Direct   ), EndpointRange: 7 (12 levels)
DualPlane: 0, Subsets: 3, WeightRange: 2 (4 levels), CEM: 9 (RGB Base+Ofs ), EndpointRange: 7 (12 levels)
DualPlane: 0, Subsets: 3, WeightRange: 2 (4 levels), CEM: 10 (RGB Base+Sc2A), EndpointRange: 7 (12 levels)
DualPlane: 0, Subsets: 3, WeightRange: 3 (5 levels), CEM: 0 (L Direct     ), EndpointRange: 20 (256 levels)
DualPlane: 0, Subsets: 3, WeightRange: 3 (5 levels), CEM: 1 (L Base+Ofs   ), EndpointRange: 20 (256 levels)
DualPlane: 0, Subsets: 3, WeightRange: 3 (5 levels), CEM: 4 (LA Direct    ), EndpointRange: 11 (32 levels)
DualPlane: 0, Subsets: 3, WeightRange: 3 (5 levels), CEM: 5 (LA Base+Ofs  ), EndpointRange: 11 (32 levels)
DualPlane: 0, Subsets: 3, WeightRange: 3 (5 levels), CEM: 6 (RGB Base+Sc  ), EndpointRange: 11 (32 levels)
DualPlane: 0, Subsets: 3, WeightRange: 3 (5 levels), CEM: 8 (RGB Direct   ), EndpointRange: 6 (10 levels)
DualPlane: 0, Subsets: 3, WeightRange: 3 (5 levels), CEM: 9 (RGB Base+Ofs ), EndpointRange: 6 (10 levels)
DualPlane: 0, Subsets: 3, WeightRange: 3 (5 levels), CEM: 10 (RGB Base+Sc2A), EndpointRange: 6 (10 levels)
DualPlane: 0, Subsets: 3, WeightRange: 4 (6 levels), CEM: 0 (L Direct     ), EndpointRange: 20 (256 levels)
DualPlane: 0, Subsets: 3, WeightRange: 4 (6 levels), CEM: 1 (L Base+Ofs   ), EndpointRange: 20 (256 levels)
DualPlane: 0, Subsets: 3, WeightRange: 4 (6 levels), CEM: 4 (LA Direct    ), EndpointRange: 10 (24 levels)
DualPlane: 0, Subsets: 3, WeightRange: 4 (6 levels), CEM: 5 (LA Base+Ofs  ), EndpointRange: 10 (24 levels)
DualPlane: 0, Subsets: 3, WeightRange: 4 (6 levels), CEM: 6 (RGB Base+Sc  ), EndpointRange: 10 (24 levels)
DualPlane: 0, Subsets: 3, WeightRange: 4 (6 levels), CEM: 8 (RGB Direct   ), EndpointRange: 5 (8 levels)
DualPlane: 0, Subsets: 3, WeightRange: 4 (6 levels), CEM: 9 (RGB Base+Ofs ), EndpointRange: 5 (8 levels)
DualPlane: 0, Subsets: 3, WeightRange: 4 (6 levels), CEM: 10 (RGB Base+Sc2A), EndpointRange: 5 (8 levels)
DualPlane: 0, Subsets: 3, WeightRange: 5 (8 levels), CEM: 0 (L Direct     ), EndpointRange: 20 (256 levels)
DualPlane: 0, Subsets: 3, WeightRange: 5 (8 levels), CEM: 1 (L Base+Ofs   ), EndpointRange: 20 (256 levels)
DualPlane: 0, Subsets: 3, WeightRange: 5 (8 levels), CEM: 4 (LA Direct    ), EndpointRange: 8 (16 levels)
DualPlane: 0, Subsets: 3, WeightRange: 5 (8 levels), CEM: 5 (LA Base+Ofs  ), EndpointRange: 8 (16 levels)
DualPlane: 0, Subsets: 3, WeightRange: 5 (8 levels), CEM: 6 (RGB Base+Sc  ), EndpointRange: 8 (16 levels)
DualPlane: 0, Subsets: 3, WeightRange: 5 (8 levels), CEM: 8 (RGB Direct   ), EndpointRange: 4 (6 levels)
DualPlane: 0, Subsets: 3, WeightRange: 5 (8 levels), CEM: 9 (RGB Base+Ofs ), EndpointRange: 4 (6 levels)
DualPlane: 0, Subsets: 3, WeightRange: 5 (8 levels), CEM: 10 (RGB Base+Sc2A), EndpointRange: 4 (6 levels)
DualPlane: 0, Subsets: 3, WeightRange: 6 (10 levels), CEM: 0 (L Direct     ), EndpointRange: 18 (160 levels)
DualPlane: 0, Subsets: 3, WeightRange: 6 (10 levels), CEM: 1 (L Base+Ofs   ), EndpointRange: 18 (160 levels)
DualPlane: 0, Subsets: 3, WeightRange: 6 (10 levels), CEM: 4 (LA Direct    ), EndpointRange: 7 (12 levels)
DualPlane: 0, Subsets: 3, WeightRange: 6 (10 levels), CEM: 5 (LA Base+Ofs  ), EndpointRange: 7 (12 levels)
DualPlane: 0, Subsets: 3, WeightRange: 6 (10 levels), CEM: 6 (RGB Base+Sc  ), EndpointRange: 7 (12 levels)
DualPlane: 0, Subsets: 3, WeightRange: 7 (12 levels), CEM: 0 (L Direct     ), EndpointRange: 16 (96 levels)
DualPlane: 0, Subsets: 3, WeightRange: 7 (12 levels), CEM: 1 (L Base+Ofs   ), EndpointRange: 16 (96 levels)
DualPlane: 0, Subsets: 3, WeightRange: 7 (12 levels), CEM: 4 (LA Direct    ), EndpointRange: 6 (10 levels)
DualPlane: 0, Subsets: 3, WeightRange: 7 (12 levels), CEM: 5 (LA Base+Ofs  ), EndpointRange: 6 (10 levels)
DualPlane: 0, Subsets: 3, WeightRange: 7 (12 levels), CEM: 6 (RGB Base+Sc  ), EndpointRange: 6 (10 levels)
DualPlane: 0, Subsets: 3, WeightRange: 8 (16 levels), CEM: 0 (L Direct     ), EndpointRange: 13 (48 levels)
DualPlane: 0, Subsets: 3, WeightRange: 8 (16 levels), CEM: 1 (L Base+Ofs   ), EndpointRange: 13 (48 levels)
DualPlane: 0, Subsets: 3, WeightRange: 8 (16 levels), CEM: 4 (LA Direct    ), EndpointRange: 4 (6 levels)
DualPlane: 0, Subsets: 3, WeightRange: 8 (16 levels), CEM: 5 (LA Base+Ofs  ), EndpointRange: 4 (6 levels)
DualPlane: 0, Subsets: 3, WeightRange: 8 (16 levels), CEM: 6 (RGB Base+Sc  ), EndpointRange: 4 (6 levels)
DualPlane: 0, Subsets: 3, WeightRange: 9 (20 levels), CEM: 0 (L Direct     ), EndpointRange: 10 (24 levels)
DualPlane: 0, Subsets: 3, WeightRange: 9 (20 levels), CEM: 1 (L Base+Ofs   ), EndpointRange: 10 (24 levels)
DualPlane: 0, Subsets: 3, WeightRange: 10 (24 levels), CEM: 0 (L Direct     ), EndpointRange: 8 (16 levels)
DualPlane: 0, Subsets: 3, WeightRange: 10 (24 levels), CEM: 1 (L Base+Ofs   ), EndpointRange: 8 (16 levels)
DualPlane: 0, Subsets: 3, WeightRange: 11 (32 levels), CEM: 0 (L Direct     ), EndpointRange: 5 (8 levels)
DualPlane: 0, Subsets: 3, WeightRange: 11 (32 levels), CEM: 1 (L Base+Ofs   ), EndpointRange: 5 (8 levels)
DualPlane: 0, Subsets: 4, WeightRange: 1 (3 levels), CEM: 0 (L Direct     ), EndpointRange: 20 (256 levels)
DualPlane: 0, Subsets: 4, WeightRange: 1 (3 levels), CEM: 1 (L Base+Ofs   ), EndpointRange: 20 (256 levels)
DualPlane: 0, Subsets: 4, WeightRange: 1 (3 levels), CEM: 4 (LA Direct    ), EndpointRange: 9 (20 levels)
DualPlane: 0, Subsets: 4, WeightRange: 1 (3 levels), CEM: 5 (LA Base+Ofs  ), EndpointRange: 9 (20 levels)
DualPlane: 0, Subsets: 4, WeightRange: 1 (3 levels), CEM: 6 (RGB Base+Sc  ), EndpointRange: 9 (20 levels)
DualPlane: 0, Subsets: 4, WeightRange: 2 (4 levels), CEM: 0 (L Direct     ), EndpointRange: 20 (256 levels)
DualPlane: 0, Subsets: 4, WeightRange: 2 (4 levels), CEM: 1 (L Base+Ofs   ), EndpointRange: 20 (256 levels)
DualPlane: 0, Subsets: 4, WeightRange: 2 (4 levels), CEM: 4 (LA Direct    ), EndpointRange: 8 (16 levels)
DualPlane: 0, Subsets: 4, WeightRange: 2 (4 levels), CEM: 5 (LA Base+Ofs  ), EndpointRange: 8 (16 levels)
DualPlane: 0, Subsets: 4, WeightRange: 2 (4 levels), CEM: 6 (RGB Base+Sc  ), EndpointRange: 8 (16 levels)
DualPlane: 0, Subsets: 4, WeightRange: 3 (5 levels), CEM: 0 (L Direct     ), EndpointRange: 19 (192 levels)
DualPlane: 0, Subsets: 4, WeightRange: 3 (5 levels), CEM: 1 (L Base+Ofs   ), EndpointRange: 19 (192 levels)
DualPlane: 0, Subsets: 4, WeightRange: 3 (5 levels), CEM: 4 (LA Direct    ), EndpointRange: 7 (12 levels)
DualPlane: 0, Subsets: 4, WeightRange: 3 (5 levels), CEM: 5 (LA Base+Ofs  ), EndpointRange: 7 (12 levels)
DualPlane: 0, Subsets: 4, WeightRange: 3 (5 levels), CEM: 6 (RGB Base+Sc  ), EndpointRange: 7 (12 levels)
DualPlane: 0, Subsets: 4, WeightRange: 4 (6 levels), CEM: 0 (L Direct     ), EndpointRange: 17 (128 levels)
DualPlane: 0, Subsets: 4, WeightRange: 4 (6 levels), CEM: 1 (L Base+Ofs   ), EndpointRange: 17 (128 levels)
DualPlane: 0, Subsets: 4, WeightRange: 4 (6 levels), CEM: 4 (LA Direct    ), EndpointRange: 6 (10 levels)
DualPlane: 0, Subsets: 4, WeightRange: 4 (6 levels), CEM: 5 (LA Base+Ofs  ), EndpointRange: 6 (10 levels)
DualPlane: 0, Subsets: 4, WeightRange: 4 (6 levels), CEM: 6 (RGB Base+Sc  ), EndpointRange: 6 (10 levels)
DualPlane: 0, Subsets: 4, WeightRange: 5 (8 levels), CEM: 0 (L Direct     ), EndpointRange: 15 (80 levels)
DualPlane: 0, Subsets: 4, WeightRange: 5 (8 levels), CEM: 1 (L Base+Ofs   ), EndpointRange: 15 (80 levels)
DualPlane: 0, Subsets: 4, WeightRange: 5 (8 levels), CEM: 4 (LA Direct    ), EndpointRange: 5 (8 levels)
DualPlane: 0, Subsets: 4, WeightRange: 5 (8 levels), CEM: 5 (LA Base+Ofs  ), EndpointRange: 5 (8 levels)
DualPlane: 0, Subsets: 4, WeightRange: 5 (8 levels), CEM: 6 (RGB Base+Sc  ), EndpointRange: 5 (8 levels)
DualPlane: 0, Subsets: 4, WeightRange: 6 (10 levels), CEM: 0 (L Direct     ), EndpointRange: 13 (48 levels)
DualPlane: 0, Subsets: 4, WeightRange: 6 (10 levels), CEM: 1 (L Base+Ofs   ), EndpointRange: 13 (48 levels)
DualPlane: 0, Subsets: 4, WeightRange: 6 (10 levels), CEM: 4 (LA Direct    ), EndpointRange: 4 (6 levels)
DualPlane: 0, Subsets: 4, WeightRange: 6 (10 levels), CEM: 5 (LA Base+Ofs  ), EndpointRange: 4 (6 levels)
DualPlane: 0, Subsets: 4, WeightRange: 6 (10 levels), CEM: 6 (RGB Base+Sc  ), EndpointRange: 4 (6 levels)
DualPlane: 0, Subsets: 4, WeightRange: 7 (12 levels), CEM: 0 (L Direct     ), EndpointRange: 11 (32 levels)
DualPlane: 0, Subsets: 4, WeightRange: 7 (12 levels), CEM: 1 (L Base+Ofs   ), EndpointRange: 11 (32 levels)
DualPlane: 0, Subsets: 4, WeightRange: 8 (16 levels), CEM: 0 (L Direct     ), EndpointRange: 9 (20 levels)
DualPlane: 0, Subsets: 4, WeightRange: 8 (16 levels), CEM: 1 (L Base+Ofs   ), EndpointRange: 9 (20 levels)
DualPlane: 0, Subsets: 4, WeightRange: 9 (20 levels), CEM: 0 (L Direct     ), EndpointRange: 7 (12 levels)
DualPlane: 0, Subsets: 4, WeightRange: 9 (20 levels), CEM: 1 (L Base+Ofs   ), EndpointRange: 7 (12 levels)
DualPlane: 0, Subsets: 4, WeightRange: 10 (24 levels), CEM: 0 (L Direct     ), EndpointRange: 5 (8 levels)
DualPlane: 0, Subsets: 4, WeightRange: 10 (24 levels), CEM: 1 (L Base+Ofs   ), EndpointRange: 5 (8 levels)
DualPlane: 1, Subsets: 1, WeightRange: 0 (2 levels), CEM: 0 (L Direct     ), EndpointRange: 20 (256 levels)
DualPlane: 1, Subsets: 1, WeightRange: 0 (2 levels), CEM: 1 (L Base+Ofs   ), EndpointRange: 20 (256 levels)
DualPlane: 1, Subsets: 1, WeightRange: 0 (2 levels), CEM: 4 (LA Direct    ), EndpointRange: 20 (256 levels)
DualPlane: 1, Subsets: 1, WeightRange: 0 (2 levels), CEM: 5 (LA Base+Ofs  ), EndpointRange: 20 (256 levels)
DualPlane: 1, Subsets: 1, WeightRange: 0 (2 levels), CEM: 6 (RGB Base+Sc  ), EndpointRange: 20 (256 levels)
DualPlane: 1, Subsets: 1, WeightRange: 0 (2 levels), CEM: 8 (RGB Direct   ), EndpointRange: 20 (256 levels)
DualPlane: 1, Subsets: 1, WeightRange: 0 (2 levels), CEM: 9 (RGB Base+Ofs ), EndpointRange: 20 (256 levels)
DualPlane: 1, Subsets: 1, WeightRange: 0 (2 levels), CEM: 10 (RGB Base+Sc2A), EndpointRange: 20 (256 levels)
DualPlane: 1, Subsets: 1, WeightRange: 0 (2 levels), CEM: 12 (RGBA Direct  ), EndpointRange: 20 (256 levels)
DualPlane: 1, Subsets: 1, WeightRange: 0 (2 levels), CEM: 13 (RGBA Base+Ofs), EndpointRange: 20 (256 levels)
DualPlane: 1, Subsets: 1, WeightRange: 1 (3 levels), CEM: 0 (L Direct     ), EndpointRange: 20 (256 levels)
DualPlane: 1, Subsets: 1, WeightRange: 1 (3 levels), CEM: 1 (L Base+Ofs   ), EndpointRange: 20 (256 levels)
DualPlane: 1, Subsets: 1, WeightRange: 1 (3 levels), CEM: 4 (LA Direct    ), EndpointRange: 20 (256 levels)
DualPlane: 1, Subsets: 1, WeightRange: 1 (3 levels), CEM: 5 (LA Base+Ofs  ), EndpointRange: 20 (256 levels)
DualPlane: 1, Subsets: 1, WeightRange: 1 (3 levels), CEM: 6 (RGB Base+Sc  ), EndpointRange: 20 (256 levels)
DualPlane: 1, Subsets: 1, WeightRange: 1 (3 levels), CEM: 8 (RGB Direct   ), EndpointRange: 20 (256 levels)
DualPlane: 1, Subsets: 1, WeightRange: 1 (3 levels), CEM: 9 (RGB Base+Ofs ), EndpointRange: 20 (256 levels)
DualPlane: 1, Subsets: 1, WeightRange: 1 (3 levels), CEM: 10 (RGB Base+Sc2A), EndpointRange: 20 (256 levels)
DualPlane: 1, Subsets: 1, WeightRange: 1 (3 levels), CEM: 12 (RGBA Direct  ), EndpointRange: 17 (128 levels)
DualPlane: 1, Subsets: 1, WeightRange: 1 (3 levels), CEM: 13 (RGBA Base+Ofs), EndpointRange: 17 (128 levels)
DualPlane: 1, Subsets: 1, WeightRange: 2 (4 levels), CEM: 0 (L Direct     ), EndpointRange: 20 (256 levels)
DualPlane: 1, Subsets: 1, WeightRange: 2 (4 levels), CEM: 1 (L Base+Ofs   ), EndpointRange: 20 (256 levels)
DualPlane: 1, Subsets: 1, WeightRange: 2 (4 levels), CEM: 4 (LA Direct    ), EndpointRange: 20 (256 levels)
DualPlane: 1, Subsets: 1, WeightRange: 2 (4 levels), CEM: 5 (LA Base+Ofs  ), EndpointRange: 20 (256 levels)
DualPlane: 1, Subsets: 1, WeightRange: 2 (4 levels), CEM: 6 (RGB Base+Sc  ), EndpointRange: 20 (256 levels)
DualPlane: 1, Subsets: 1, WeightRange: 2 (4 levels), CEM: 8 (RGB Direct   ), EndpointRange: 18 (160 levels)
DualPlane: 1, Subsets: 1, WeightRange: 2 (4 levels), CEM: 9 (RGB Base+Ofs ), EndpointRange: 18 (160 levels)
DualPlane: 1, Subsets: 1, WeightRange: 2 (4 levels), CEM: 10 (RGB Base+Sc2A), EndpointRange: 18 (160 levels)
DualPlane: 1, Subsets: 1, WeightRange: 2 (4 levels), CEM: 12 (RGBA Direct  ), EndpointRange: 13 (48 levels)
DualPlane: 1, Subsets: 1, WeightRange: 2 (4 levels), CEM: 13 (RGBA Base+Ofs), EndpointRange: 13 (48 levels)
DualPlane: 1, Subsets: 1, WeightRange: 3 (5 levels), CEM: 0 (L Direct     ), EndpointRange: 20 (256 levels)
DualPlane: 1, Subsets: 1, WeightRange: 3 (5 levels), CEM: 1 (L Base+Ofs   ), EndpointRange: 20 (256 levels)
DualPlane: 1, Subsets: 1, WeightRange: 3 (5 levels), CEM: 4 (LA Direct    ), EndpointRange: 20 (256 levels)
DualPlane: 1, Subsets: 1, WeightRange: 3 (5 levels), CEM: 5 (LA Base+Ofs  ), EndpointRange: 20 (256 levels)
DualPlane: 1, Subsets: 1, WeightRange: 3 (5 levels), CEM: 6 (RGB Base+Sc  ), EndpointRange: 20 (256 levels)
DualPlane: 1, Subsets: 1, WeightRange: 3 (5 levels), CEM: 8 (RGB Direct   ), EndpointRange: 13 (48 levels)
DualPlane: 1, Subsets: 1, WeightRange: 3 (5 levels), CEM: 9 (RGB Base+Ofs ), EndpointRange: 13 (48 levels)
DualPlane: 1, Subsets: 1, WeightRange: 3 (5 levels), CEM: 10 (RGB Base+Sc2A), EndpointRange: 13 (48 levels)
DualPlane: 1, Subsets: 1, WeightRange: 3 (5 levels), CEM: 12 (RGBA Direct  ), EndpointRange: 8 (16 levels)
DualPlane: 1, Subsets: 1, WeightRange: 3 (5 levels), CEM: 13 (RGBA Base+Ofs), EndpointRange: 8 (16 levels)
DualPlane: 1, Subsets: 1, WeightRange: 4 (6 levels), CEM: 0 (L Direct     ), EndpointRange: 20 (256 levels)
DualPlane: 1, Subsets: 1, WeightRange: 4 (6 levels), CEM: 1 (L Base+Ofs   ), EndpointRange: 20 (256 levels)
DualPlane: 1, Subsets: 1, WeightRange: 4 (6 levels), CEM: 4 (LA Direct    ), EndpointRange: 14 (64 levels)
DualPlane: 1, Subsets: 1, WeightRange: 4 (6 levels), CEM: 5 (LA Base+Ofs  ), EndpointRange: 14 (64 levels)
DualPlane: 1, Subsets: 1, WeightRange: 4 (6 levels), CEM: 6 (RGB Base+Sc  ), EndpointRange: 14 (64 levels)
DualPlane: 1, Subsets: 1, WeightRange: 4 (6 levels), CEM: 8 (RGB Direct   ), EndpointRange: 8 (16 levels)
DualPlane: 1, Subsets: 1, WeightRange: 4 (6 levels), CEM: 9 (RGB Base+Ofs ), EndpointRange: 8 (16 levels)
DualPlane: 1, Subsets: 1, WeightRange: 4 (6 levels), CEM: 10 (RGB Base+Sc2A), EndpointRange: 8 (16 levels)
DualPlane: 1, Subsets: 1, WeightRange: 4 (6 levels), CEM: 12 (RGBA Direct  ), EndpointRange: 5 (8 levels)
DualPlane: 1, Subsets: 1, WeightRange: 4 (6 levels), CEM: 13 (RGBA Base+Ofs), EndpointRange: 5 (8 levels)
DualPlane: 1, Subsets: 1, WeightRange: 5 (8 levels), CEM: 0 (L Direct     ), EndpointRange: 15 (80 levels)
DualPlane: 1, Subsets: 1, WeightRange: 5 (8 levels), CEM: 1 (L Base+Ofs   ), EndpointRange: 15 (80 levels)
DualPlane: 1, Subsets: 1, WeightRange: 5 (8 levels), CEM: 4 (LA Direct    ), EndpointRange: 5 (8 levels)
DualPlane: 1, Subsets: 1, WeightRange: 5 (8 levels), CEM: 5 (LA Base+Ofs  ), EndpointRange: 5 (8 levels)
DualPlane: 1, Subsets: 1, WeightRange: 5 (8 levels), CEM: 6 (RGB Base+Sc  ), EndpointRange: 5 (8 levels)
DualPlane: 1, Subsets: 2, WeightRange: 0 (2 levels), CEM: 0 (L Direct     ), EndpointRange: 20 (256 levels)
DualPlane: 1, Subsets: 2, WeightRange: 0 (2 levels), CEM: 1 (L Base+Ofs   ), EndpointRange: 20 (256 levels)
DualPlane: 1, Subsets: 2, WeightRange: 0 (2 levels), CEM: 4 (LA Direct    ), EndpointRange: 20 (256 levels)
DualPlane: 1, Subsets: 2, WeightRange: 0 (2 levels), CEM: 5 (LA Base+Ofs  ), EndpointRange: 20 (256 levels)
DualPlane: 1, Subsets: 2, WeightRange: 0 (2 levels), CEM: 6 (RGB Base+Sc  ), EndpointRange: 20 (256 levels)
DualPlane: 1, Subsets: 2, WeightRange: 0 (2 levels), CEM: 8 (RGB Direct   ), EndpointRange: 12 (40 levels)
DualPlane: 1, Subsets: 2, WeightRange: 0 (2 levels), CEM: 9 (RGB Base+Ofs ), EndpointRange: 12 (40 levels)
DualPlane: 1, Subsets: 2, WeightRange: 0 (2 levels), CEM: 10 (RGB Base+Sc2A), EndpointRange: 12 (40 levels)
DualPlane: 1, Subsets: 2, WeightRange: 0 (2 levels), CEM: 12 (RGBA Direct  ), EndpointRange: 8 (16 levels)
DualPlane: 1, Subsets: 2, WeightRange: 0 (2 levels), CEM: 13 (RGBA Base+Ofs), EndpointRange: 8 (16 levels)
DualPlane: 1, Subsets: 2, WeightRange: 1 (3 levels), CEM: 0 (L Direct     ), EndpointRange: 20 (256 levels)
DualPlane: 1, Subsets: 2, WeightRange: 1 (3 levels), CEM: 1 (L Base+Ofs   ), EndpointRange: 20 (256 levels)
DualPlane: 1, Subsets: 2, WeightRange: 1 (3 levels), CEM: 4 (LA Direct    ), EndpointRange: 13 (48 levels)
DualPlane: 1, Subsets: 2, WeightRange: 1 (3 levels), CEM: 5 (LA Base+Ofs  ), EndpointRange: 13 (48 levels)
DualPlane: 1, Subsets: 2, WeightRange: 1 (3 levels), CEM: 6 (RGB Base+Sc  ), EndpointRange: 13 (48 levels)
DualPlane: 1, Subsets: 2, WeightRange: 1 (3 levels), CEM: 8 (RGB Direct   ), EndpointRange: 7 (12 levels)
DualPlane: 1, Subsets: 2, WeightRange: 1 (3 levels), CEM: 9 (RGB Base+Ofs ), EndpointRange: 7 (12 levels)
DualPlane: 1, Subsets: 2, WeightRange: 1 (3 levels), CEM: 10 (RGB Base+Sc2A), EndpointRange: 7 (12 levels)
DualPlane: 1, Subsets: 2, WeightRange: 1 (3 levels), CEM: 12 (RGBA Direct  ), EndpointRange: 4 (6 levels)
DualPlane: 1, Subsets: 2, WeightRange: 1 (3 levels), CEM: 13 (RGBA Base+Ofs), EndpointRange: 4 (6 levels)
DualPlane: 1, Subsets: 2, WeightRange: 2 (4 levels), CEM: 0 (L Direct     ), EndpointRange: 20 (256 levels)
DualPlane: 1, Subsets: 2, WeightRange: 2 (4 levels), CEM: 1 (L Base+Ofs   ), EndpointRange: 20 (256 levels)
DualPlane: 1, Subsets: 2, WeightRange: 2 (4 levels), CEM: 4 (LA Direct    ), EndpointRange: 8 (16 levels)
DualPlane: 1, Subsets: 2, WeightRange: 2 (4 levels), CEM: 5 (LA Base+Ofs  ), EndpointRange: 8 (16 levels)
DualPlane: 1, Subsets: 2, WeightRange: 2 (4 levels), CEM: 6 (RGB Base+Sc  ), EndpointRange: 8 (16 levels)
DualPlane: 1, Subsets: 2, WeightRange: 2 (4 levels), CEM: 8 (RGB Direct   ), EndpointRange: 4 (6 levels)
DualPlane: 1, Subsets: 2, WeightRange: 2 (4 levels), CEM: 9 (RGB Base+Ofs ), EndpointRange: 4 (6 levels)
DualPlane: 1, Subsets: 2, WeightRange: 2 (4 levels), CEM: 10 (RGB Base+Sc2A), EndpointRange: 4 (6 levels)
DualPlane: 1, Subsets: 2, WeightRange: 3 (5 levels), CEM: 0 (L Direct     ), EndpointRange: 12 (40 levels)
DualPlane: 1, Subsets: 2, WeightRange: 3 (5 levels), CEM: 1 (L Base+Ofs   ), EndpointRange: 12 (40 levels)
DualPlane: 1, Subsets: 2, WeightRange: 3 (5 levels), CEM: 4 (LA Direct    ), EndpointRange: 4 (6 levels)
DualPlane: 1, Subsets: 2, WeightRange: 3 (5 levels), CEM: 5 (LA Base+Ofs  ), EndpointRange: 4 (6 levels)
DualPlane: 1, Subsets: 2, WeightRange: 3 (5 levels), CEM: 6 (RGB Base+Sc  ), EndpointRange: 4 (6 levels)
DualPlane: 1, Subsets: 2, WeightRange: 4 (6 levels), CEM: 0 (L Direct     ), EndpointRange: 5 (8 levels)
DualPlane: 1, Subsets: 2, WeightRange: 4 (6 levels), CEM: 1 (L Base+Ofs   ), EndpointRange: 5 (8 levels)
DualPlane: 1, Subsets: 3, WeightRange: 0 (2 levels), CEM: 0 (L Direct     ), EndpointRange: 20 (256 levels)
DualPlane: 1, Subsets: 3, WeightRange: 0 (2 levels), CEM: 1 (L Base+Ofs   ), EndpointRange: 20 (256 levels)
DualPlane: 1, Subsets: 3, WeightRange: 0 (2 levels), CEM: 4 (LA Direct    ), EndpointRange: 12 (40 levels)
DualPlane: 1, Subsets: 3, WeightRange: 0 (2 levels), CEM: 5 (LA Base+Ofs  ), EndpointRange: 12 (40 levels)
DualPlane: 1, Subsets: 3, WeightRange: 0 (2 levels), CEM: 6 (RGB Base+Sc  ), EndpointRange: 12 (40 levels)
DualPlane: 1, Subsets: 3, WeightRange: 0 (2 levels), CEM: 8 (RGB Direct   ), EndpointRange: 7 (12 levels)
DualPlane: 1, Subsets: 3, WeightRange: 0 (2 levels), CEM: 9 (RGB Base+Ofs ), EndpointRange: 7 (12 levels)
DualPlane: 1, Subsets: 3, WeightRange: 0 (2 levels), CEM: 10 (RGB Base+Sc2A), EndpointRange: 7 (12 levels)
DualPlane: 1, Subsets: 3, WeightRange: 1 (3 levels), CEM: 0 (L Direct     ), EndpointRange: 18 (160 levels)
DualPlane: 1, Subsets: 3, WeightRange: 1 (3 levels), CEM: 1 (L Base+Ofs   ), EndpointRange: 18 (160 levels)
DualPlane: 1, Subsets: 3, WeightRange: 1 (3 levels), CEM: 4 (LA Direct    ), EndpointRange: 7 (12 levels)
DualPlane: 1, Subsets: 3, WeightRange: 1 (3 levels), CEM: 5 (LA Base+Ofs  ), EndpointRange: 7 (12 levels)
DualPlane: 1, Subsets: 3, WeightRange: 1 (3 levels), CEM: 6 (RGB Base+Sc  ), EndpointRange: 7 (12 levels)
DualPlane: 1, Subsets: 3, WeightRange: 2 (4 levels), CEM: 0 (L Direct     ), EndpointRange: 12 (40 levels)
DualPlane: 1, Subsets: 3, WeightRange: 2 (4 levels), CEM: 1 (L Base+Ofs   ), EndpointRange: 12 (40 levels)
DualPlane: 1, Subsets: 3, WeightRange: 2 (4 levels), CEM: 4 (LA Direct    ), EndpointRange: 4 (6 levels)
DualPlane: 1, Subsets: 3, WeightRange: 2 (4 levels), CEM: 5 (LA Base+Ofs  ), EndpointRange: 4 (6 levels)
DualPlane: 1, Subsets: 3, WeightRange: 2 (4 levels), CEM: 6 (RGB Base+Sc  ), EndpointRange: 4 (6 levels)
DualPlane: 1, Subsets: 3, WeightRange: 3 (5 levels), CEM: 0 (L Direct     ), EndpointRange: 7 (12 levels)
DualPlane: 1, Subsets: 3, WeightRange: 3 (5 levels), CEM: 1 (L Base+Ofs   ), EndpointRange: 7 (12 levels)