Skip to content
This repository was archived by the owner on Sep 19, 2020. It is now read-only.

Commit 660322d

Browse files
Add compression support for ETC1S/ETC2AS encodings
Explanation: ETC1S encoding is a subset of ETC1, which is using only one color endpoint per 4x4 block. The base color is therefore is always encoded as RGB555 and there is no need to encode block flips. ETC2AS encoding is a subset of ETC2A encoding which is using ETC1S encoding for color and default ETC2A encoding for alpha. ETC1S/ETC2AS Crunch compression and decompression is based on ETC and DXT Crunch compression and decompression algorithms: - ETC1S/ETC2AS tiling is performed within the area of 8x8 pixels using DXT1/DXT5 tiling scheme - ETC1S color endpoints are generated using standard ETC1 optimization - ETC1S color codebook encoding is equivalent to ETC1 codebook encoding - ETC1S level encoding is equivalent to DXT1 level encoding - ETC2AS alpha codebook encoding is equivalent to ETC2A alpha codebook encoding - ETC2AS level encoding is equivalent to DXT5 level encoding Testing results suggest that ETC1S/ETC2AS encodings can be used to achieve lower bitrates than ETC1/ETC2A on the Kodak test set while providing equivalent image quality (estimated using PSNR). DXT Testing: The modified algorithm has been tested on the Kodak test set using 64-bit build with default settings (running on Windows 10, i7-4790, 3.6GHz). All the decompressed test images are identical to the images being compressed and decompressed using original version of Crunch (revision ea9b8d8). [Compressing Kodak set without mipmaps using DXT1 encoding] Original: 1582222 bytes / 28.854 sec Modified: 1468204 bytes / 5.473 sec Improvement: 7.21% (compression ratio) / 81.03% (compression time) [Compressing Kodak set with mipmaps using DXT1 encoding] Original: 2065243 bytes / 36.925 sec Modified: 1914805 bytes / 7.297 sec Improvement: 7.28% (compression ratio) / 80.24% (compression time) ETC Testing: The modified algorithm has been tested on the Kodak test set using 64-bit build with default settings (running on Windows 10, i7-4790, 3.6GHz). The ETC1 quantization parameters have been selected in such a way, so that ETC1 compression gives approximately the same average Luma PSNR as the corresponding DXT1 compression (which is equal to 34.044 dB for the Kodak test set compressed without mipmaps using DXT1 encoding and default quality settings). [Compressing Kodak set without mipmaps using ETC1 encoding] Total size: 1607858 bytes Total time: 12.842 sec Average bitrate: 1.363 bpp Average Luma PSNR: 34.050 dB ETCS Testing: The modified algorithm has been tested on the Kodak test set using 64-bit build with default settings (running on Windows 10, i7-4790, 3.6GHz). The ETC1S quantization parameters have been selected in such a way, so that ETC1S compression gives approximately the same average Luma PSNR as the corresponding DXT1 compression (which is equal to 34.044 dB for the Kodak test set compressed without mipmaps using DXT1 encoding and default quality settings). [Compressing Kodak set without mipmaps using ETC1S encoding] Total size: 1363676 bytes Total time: 15.586 sec Average bitrate: 1.156 bpp Average Luma PSNR: 34.047 dB
1 parent c1d8e8d commit 660322d

16 files changed

+216
-55
lines changed

bin/crunch_x64.exe

2 KB
Binary file not shown.

crnlib/crn_comp.cpp

Lines changed: 21 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -272,7 +272,7 @@ bool crn_comp::pack_blocks(
272272
uint block_width = m_levels[group].block_width;
273273
for (uint by = 0, b = m_levels[group].first_block, bEnd = b + m_levels[group].num_blocks; b < bEnd; by++) {
274274
for (uint bx = 0; bx < block_width; bx++, b++) {
275-
const bool secondary_etc_subblock = m_has_etc_color_blocks && bx & 1;
275+
const bool secondary_etc_subblock = m_has_subblocks && bx & 1;
276276
if (!(by & 1) && !(bx & 1)) {
277277
uint8 reference_group = m_endpoint_indices[b].reference | m_endpoint_indices[b + block_width].reference << 2 |
278278
m_endpoint_indices[b + 1].reference << 4 | m_endpoint_indices[b + block_width + 1].reference << 6;
@@ -336,7 +336,7 @@ bool crn_comp::alias_images() {
336336
m_total_blocks = 0;
337337
for (uint level = 0; level < m_pParams->m_levels; level++) {
338338
uint blockHeight = ((math::maximum(1U, m_pParams->m_height >> level) + 7) & ~7) >> 2;
339-
m_levels[level].block_width = ((math::maximum(1U, m_pParams->m_width >> level) + 7) & ~7) >> (m_has_etc_color_blocks ? 1 : 2);
339+
m_levels[level].block_width = ((math::maximum(1U, m_pParams->m_width >> level) + 7) & ~7) >> (m_has_subblocks ? 1 : 2);
340340
m_levels[level].first_block = m_total_blocks;
341341
m_levels[level].num_blocks = m_pParams->m_faces * m_levels[level].block_width * blockHeight;
342342
m_total_blocks += m_levels[level].num_blocks;
@@ -354,6 +354,7 @@ void crn_comp::clear() {
354354

355355
utils::zero_object(m_has_comp);
356356
m_has_etc_color_blocks = false;
357+
m_has_subblocks = false;
357358

358359
m_levels.clear();
359360

@@ -413,8 +414,8 @@ bool crn_comp::quantize_images() {
413414
float color_quality_power_mul = 1.0f;
414415
float alpha_quality_power_mul = 1.0f;
415416
if (m_has_etc_color_blocks) {
416-
color_quality_power_mul = 1.31f;
417-
params.m_adaptive_tile_color_psnr_derating = 5.0f;
417+
color_quality_power_mul = m_has_subblocks ? 1.31f : 0.7f;
418+
params.m_adaptive_tile_color_psnr_derating = m_has_subblocks ? 5.0f : 2.0f;
418419
}
419420
if (m_pParams->m_format == cCRNFmtDXT5_CCxY) {
420421
color_quality_power_mul = 3.5f;
@@ -530,6 +531,18 @@ bool crn_comp::quantize_images() {
530531
m_has_comp[cAlpha0] = true;
531532
break;
532533
}
534+
case cCRNFmtETC1S: {
535+
params.m_format = cETC1S;
536+
m_has_comp[cColor] = true;
537+
break;
538+
}
539+
case cCRNFmtETC2AS: {
540+
params.m_format = cETC2AS;
541+
params.m_alpha_component_indices[0] = m_pParams->m_alpha_component;
542+
m_has_comp[cColor] = true;
543+
m_has_comp[cAlpha0] = true;
544+
break;
545+
}
533546
default: {
534547
return false;
535548
}
@@ -695,7 +708,7 @@ void crn_comp::optimize_color_endpoints_task(uint64 data, void* pData_ptr) {
695708
for (uint level = 0; level < m_levels.size(); level++) {
696709
for (uint endpoint_index = 0, b = m_levels[level].first_block, bEnd = b + m_levels[level].num_blocks; b < bEnd; b++) {
697710
uint index = remapping[m_endpoint_indices[b].component[cColor]];
698-
if (m_has_etc_color_blocks && b & 1 ? m_endpoint_indices[b].reference : !m_endpoint_indices[b].reference) {
711+
if (m_has_subblocks && b & 1 ? m_endpoint_indices[b].reference : !m_endpoint_indices[b].reference) {
699712
int sym = index - endpoint_index;
700713
hist[sym < 0 ? sym + n : sym]++;
701714
}
@@ -773,7 +786,7 @@ void crn_comp::optimize_color() {
773786
crnlib::vector<uint> sum(n);
774787
for (uint i, i_prev = 0, b = 0; b < m_endpoint_indices.size(); b++, i_prev = i) {
775788
i = m_endpoint_indices[b].color;
776-
if ((m_has_etc_color_blocks && b & 1 ? m_endpoint_indices[b].reference : !m_endpoint_indices[b].reference) && i != i_prev) {
789+
if ((m_has_subblocks && b & 1 ? m_endpoint_indices[b].reference : !m_endpoint_indices[b].reference) && i != i_prev) {
777790
hist[i * n + i_prev]++;
778791
hist[i_prev * n + i]++;
779792
sum[i]++;
@@ -1279,7 +1292,8 @@ bool crn_comp::compress_pass(const crn_comp_params& params, float* pEffective_bi
12791292
*pEffective_bitrate = 0.0f;
12801293

12811294
m_pParams = &params;
1282-
m_has_etc_color_blocks = params.m_format == cCRNFmtETC1 || params.m_format == cCRNFmtETC2 || params.m_format == cCRNFmtETC2A;
1295+
m_has_etc_color_blocks = params.m_format == cCRNFmtETC1 || params.m_format == cCRNFmtETC2 || params.m_format == cCRNFmtETC2A || params.m_format == cCRNFmtETC1S || params.m_format == cCRNFmtETC2AS;
1296+
m_has_subblocks = params.m_format == cCRNFmtETC1 || params.m_format == cCRNFmtETC2 || params.m_format == cCRNFmtETC2A;
12831297

12841298
if ((math::minimum(m_pParams->m_width, m_pParams->m_height) < 1) || (math::maximum(m_pParams->m_width, m_pParams->m_height) > cCRNMaxLevelResolution))
12851299
return false;

crnlib/crn_comp.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -46,6 +46,7 @@ class crn_comp : public itexture_comp {
4646

4747
bool m_has_comp[cNumComps];
4848
bool m_has_etc_color_blocks;
49+
bool m_has_subblocks;
4950

5051
struct level_details {
5152
uint first_block;

crnlib/crn_dxt.cpp

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -41,6 +41,10 @@ const char* get_dxt_format_string(dxt_format fmt) {
4141
return "ETC2";
4242
case cETC2A:
4343
return "ETC2A";
44+
case cETC1S:
45+
return "ETC1S";
46+
case cETC2AS:
47+
return "ETC2AS";
4448
default:
4549
break;
4650
}
@@ -74,12 +78,14 @@ uint get_dxt_format_bits_per_pixel(dxt_format fmt) {
7478
case cDXT5A:
7579
case cETC1:
7680
case cETC2:
81+
case cETC1S:
7782
return 4;
7883
case cDXT3:
7984
case cDXT5:
8085
case cDXN_XY:
8186
case cDXN_YX:
8287
case cETC2A:
88+
case cETC2AS:
8389
return 8;
8490
default:
8591
break;
@@ -95,6 +101,7 @@ bool get_dxt_format_has_alpha(dxt_format fmt) {
95101
case cDXT5:
96102
case cDXT5A:
97103
case cETC2A:
104+
case cETC2AS:
98105
return true;
99106
default:
100107
break;

crnlib/crn_dxt.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -45,6 +45,8 @@ enum dxt_format {
4545
cETC1,
4646
cETC2,
4747
cETC2A,
48+
cETC1S,
49+
cETC2AS,
4850
};
4951

5052
const float cDXT1MaxLinearValue = 3.0f;

crnlib/crn_dxt_hc.cpp

Lines changed: 49 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,7 @@ dxt_hc::dxt_hc()
2727
: m_num_blocks(0),
2828
m_has_color_blocks(false),
2929
m_has_etc_color_blocks(false),
30+
m_has_subblocks(false),
3031
m_num_alpha_blocks(0),
3132
m_main_thread_id(crn_get_current_thread_id()),
3233
m_canceled(false),
@@ -78,9 +79,10 @@ bool dxt_hc::compress(
7879
const params& p
7980
) {
8081
clear();
81-
m_has_etc_color_blocks = p.m_format == cETC1 || p.m_format == cETC2 || p.m_format == cETC2A;
82+
m_has_etc_color_blocks = p.m_format == cETC1 || p.m_format == cETC2 || p.m_format == cETC2A || p.m_format == cETC1S || p.m_format == cETC2AS;
83+
m_has_subblocks = p.m_format == cETC1 || p.m_format == cETC2 || p.m_format == cETC2A;
8284
m_has_color_blocks = p.m_format == cDXT1 || p.m_format == cDXT5 || m_has_etc_color_blocks;
83-
m_num_alpha_blocks = p.m_format == cDXT5 || p.m_format == cDXT5A || p.m_format == cETC2A ? 1 : p.m_format == cDXN_XY || p.m_format == cDXN_YX ? 2 : 0;
85+
m_num_alpha_blocks = p.m_format == cDXT5 || p.m_format == cDXT5A || p.m_format == cETC2A || p.m_format == cETC2AS ? 1 : p.m_format == cDXN_XY || p.m_format == cDXN_YX ? 2 : 0;
8486
if (!m_has_color_blocks && !m_num_alpha_blocks)
8587
return false;
8688
m_blocks = blocks;
@@ -118,7 +120,7 @@ bool dxt_hc::compress(
118120
}
119121

120122
for (uint i = 0; i <= m_pTask_pool->get_num_threads(); i++)
121-
m_pTask_pool->queue_object_task(this, m_has_etc_color_blocks ? &dxt_hc::determine_tiles_task_etc : &dxt_hc::determine_tiles_task, i);
123+
m_pTask_pool->queue_object_task(this, m_has_subblocks ? &dxt_hc::determine_tiles_task_etc : &dxt_hc::determine_tiles_task, i);
122124
m_pTask_pool->join();
123125

124126
m_num_tiles = 0;
@@ -212,7 +214,7 @@ bool dxt_hc::compress(
212214
for (uint bx = 0; bx < block_width; bx++, b++) {
213215
bool top_match = by != 0;
214216
bool left_match = top_match || bx;
215-
bool diag_match = m_has_etc_color_blocks && top_match && bx;
217+
bool diag_match = m_has_subblocks && top_match && bx;
216218
for (uint c = m_has_color_blocks ? 0 : cAlpha0; c < cAlpha0 + m_num_alpha_blocks; c++) {
217219
uint16 endpoint_index = (c ? alpha_endpoints_remap : color_endpoints_remap)[m_endpoint_indices[b].component[c]];
218220
left_match = left_match && endpoint_index == endpoint_indices[b - 1].component[c];
@@ -222,7 +224,7 @@ bool dxt_hc::compress(
222224
uint16 selector_index = (c ? alpha_selectors_remap : color_selectors_remap)[m_selector_indices[b].component[c]];
223225
selector_indices[b].component[c] = selector_index;
224226
}
225-
endpoint_indices[b].reference = m_has_etc_color_blocks && b & 1 ? m_endpoint_indices[b].reference : left_match ? 1 : top_match ? 2 : diag_match ? 3 : 0;
227+
endpoint_indices[b].reference = m_has_subblocks && b & 1 ? m_endpoint_indices[b].reference : left_match ? 1 : top_match ? 2 : diag_match ? 3 : 0;
226228
}
227229
}
228230
}
@@ -290,6 +292,15 @@ void dxt_hc::determine_tiles_task(uint64 data, void*) {
290292
uint tile_error[3][9];
291293
uint total_error[3][8];
292294

295+
etc1_optimizer optimizer;
296+
etc1_optimizer::params params;
297+
params.m_use_color4 = false;
298+
params.m_constrain_against_base_color5 = false;
299+
etc1_optimizer::results results;
300+
results.m_pSelectors = selectors;
301+
int scan[] = {-1, 0, 1};
302+
int refine[] = {-3, -2, 2, 3};
303+
293304
for (uint level = 0; level < m_params.m_num_levels; level++) {
294305
float weight = m_params.m_levels[level].m_weight;
295306
uint width = m_params.m_levels[level].m_block_width;
@@ -318,7 +329,20 @@ void dxt_hc::determine_tiles_task(uint64 data, void*) {
318329
for (uint t = 0; t < 9; t++) {
319330
color_quad_u8* pixels = tilePixels + offsets[t];
320331
uint size = 16 << (t >> 2);
321-
if (m_has_color_blocks) {
332+
if (m_has_etc_color_blocks) {
333+
params.m_pSrc_pixels = pixels;
334+
params.m_num_src_pixels = results.m_n = size;
335+
optimizer.init(params, results);
336+
params.m_pScan_deltas = scan;
337+
params.m_scan_delta_size = sizeof(scan) / sizeof(*scan);
338+
optimizer.compute();
339+
if (results.m_error > 375 * params.m_num_src_pixels) {
340+
params.m_pScan_deltas = refine;
341+
params.m_scan_delta_size = sizeof(refine) / sizeof(*refine);
342+
optimizer.compute();
343+
}
344+
tile_error[cColor][t] = results.m_error;
345+
} else if (m_has_color_blocks) {
322346
uint low16, high16;
323347
dxt_fast::compress_color_block(size, pixels, low16, high16, selectors);
324348
color_quad_u8 block_colors[4];
@@ -605,23 +629,25 @@ void dxt_hc::determine_color_endpoint_codebook_task_etc(uint64 data, void*) {
605629
float endpoint_weight = powf(math::minimum((cluster.color_values[3].get_luma() - cluster.color_values[0].get_luma()) / 100.0f, 1.0f), 2.7f);
606630

607631
crnlib::vector<uint>& blocks = cluster.blocks[cColor];
632+
uint blockSize = m_has_subblocks ? 8 : 16;
608633
for (uint i = 0; i < blocks.size(); i++) {
609634
uint b = blocks[i];
635+
color_quad_u8* pixels = m_has_subblocks ? ((color_quad_u8(*)[8])m_blocks)[b] : m_blocks[b];
610636
uint weight = (uint)(math::clamp<uint>(0x8000 * endpoint_weight * m_block_weights[b] * (m_block_encodings[b] ? 0.972f : 1.0f), 1, 0xFFFF));
611637
uint32 selector = 0;
612-
for (uint p = 0; p < 8; p++) {
638+
for (uint p = 0; p < blockSize; p++) {
613639
uint error_best = cUINT32_MAX;
614640
uint8 s_best = 0;
615641
for (uint8 s = 0; s < 4; s++) {
616-
uint error = color::color_distance(m_params.m_perceptual, ((color_quad_u8(*)[8])m_blocks)[b][p], cluster.color_values[s], false);
642+
uint error = color::color_distance(m_params.m_perceptual, pixels[p], cluster.color_values[s], false);
617643
if (error < error_best) {
618644
s_best = s;
619645
error_best = error;
620646
}
621647
}
622648
selector = selector << 2 | s_best;
623649
}
624-
m_block_selectors[cColor][b] = (uint64)selector << ((b & 1) ? 32 : 48) | weight;
650+
m_block_selectors[cColor][b] = (uint64)selector << (!m_has_subblocks || (b & 1) ? 32 : 48) | weight;
625651
}
626652
}
627653
}
@@ -731,7 +757,7 @@ void dxt_hc::determine_color_endpoints() {
731757
uint cluster_index = m_tiles[m_tile_indices[b]].cluster_indices[cColor];
732758
m_endpoint_indices[b].component[cColor] = cluster_index;
733759
m_color_clusters[cluster_index].blocks[cColor].push_back(b);
734-
if (m_has_etc_color_blocks && m_endpoint_indices[b].reference && cluster_index == m_endpoint_indices[b - 1].component[cColor]) {
760+
if (m_has_subblocks && m_endpoint_indices[b].reference && cluster_index == m_endpoint_indices[b - 1].component[cColor]) {
735761
if (m_endpoint_indices[b].reference >> 1) {
736762
color_quad_u8 mirror[16];
737763
for (uint p = 0; p < 16; p++)
@@ -808,7 +834,7 @@ void dxt_hc::determine_alpha_endpoint_codebook_task(uint64 data, void*) {
808834
uint8 s_best = 0;
809835
for (uint8 t = 0; t < 8; t++) {
810836
uint8 s = m_has_etc_color_blocks ? t : results.m_reordered ? 7 - g_dxt5_to_linear[t] : g_dxt5_to_linear[t];
811-
int delta = m_blocks[m_has_etc_color_blocks ? b >> 1 : b][p][component_index] - alpha_values[s];
837+
int delta = m_blocks[m_has_subblocks ? b >> 1 : b][p][component_index] - alpha_values[s];
812838
uint error = delta >= 0 ? delta : -delta;
813839
if (error < error_best) {
814840
s_best = s;
@@ -946,7 +972,7 @@ void dxt_hc::determine_alpha_endpoints() {
946972
for (uint a = 0; a < m_num_alpha_blocks; a++) {
947973
uint cluster_index = m_tiles[m_tile_indices[b]].cluster_indices[cAlpha0 + a];
948974
m_endpoint_indices[b].component[cAlpha0 + a] = cluster_index;
949-
if (!(m_has_etc_color_blocks && b & 1))
975+
if (!(m_has_subblocks && b & 1))
950976
m_alpha_clusters[cluster_index].blocks[cAlpha0 + a].push_back(b);
951977
}
952978
}
@@ -968,12 +994,12 @@ void dxt_hc::create_color_selector_codebook_task(uint64 data, void* pData_ptr) {
968994
uint E2[16][4];
969995
uint E4[8][16];
970996
uint E8[4][256];
971-
for (uint n = m_has_etc_color_blocks ? m_num_blocks >> 1 : m_num_blocks, b = n * data / num_tasks, bEnd = n * (data + 1) / num_tasks; b < bEnd; b++) {
997+
for (uint n = m_has_subblocks ? m_num_blocks >> 1 : m_num_blocks, b = n * data / num_tasks, bEnd = n * (data + 1) / num_tasks; b < bEnd; b++) {
972998
color_cluster& cluster = m_color_clusters[m_endpoint_indices[b].color];
973999
color_quad_u8* endpoint_colors = cluster.color_values;
9741000
for (uint p = 0; p < 16; p++) {
9751001
for (uint s = 0; s < 4; s++)
976-
E2[p][s] = m_has_etc_color_blocks ? color::color_distance(m_params.m_perceptual, m_blocks[b][p], m_color_clusters[m_endpoint_indices[b << 1 | p >> 3].color].color_values[s], false) :
1002+
E2[p][s] = m_has_subblocks ? color::color_distance(m_params.m_perceptual, m_blocks[b][p], m_color_clusters[m_endpoint_indices[b << 1 | p >> 3].color].color_values[s], false) :
9771003
color::color_distance(m_params.m_perceptual, m_blocks[b][p], endpoint_colors[s], false);
9781004
}
9791005
for (uint p = 0; p < 8; p++) {
@@ -999,7 +1025,7 @@ void dxt_hc::create_color_selector_codebook_task(uint64 data, void* pData_ptr) {
9991025
total_errors[p][s] += E2[p][s];
10001026
}
10011027
selector_details[best_index].used = true;
1002-
m_selector_indices[m_has_etc_color_blocks ? b << 1 : b].color = best_index;
1028+
m_selector_indices[m_has_subblocks ? b << 1 : b].color = best_index;
10031029
}
10041030
}
10051031

@@ -1012,9 +1038,9 @@ struct SelectorNode {
10121038

10131039
void dxt_hc::create_color_selector_codebook() {
10141040
uint num_tasks = m_pTask_pool->get_num_threads() + 1;
1015-
crnlib::vector<uint64> selectors(m_has_etc_color_blocks ? m_num_blocks >> 1 : m_num_blocks);
1016-
for (uint i = 0, b = 0, step = m_has_etc_color_blocks ? 2 : 1; b < m_num_blocks; b += step)
1017-
selectors[i++] = m_block_selectors[cColor][b] + (m_has_etc_color_blocks ? m_block_selectors[cColor][b + 1] : 0);
1041+
crnlib::vector<uint64> selectors(m_has_subblocks ? m_num_blocks >> 1 : m_num_blocks);
1042+
for (uint i = 0, b = 0, step = m_has_subblocks ? 2 : 1; b < m_num_blocks; b += step)
1043+
selectors[i++] = m_block_selectors[cColor][b] + (m_has_subblocks ? m_block_selectors[cColor][b + 1] : 0);
10181044

10191045
crnlib::vector<SelectorNode> nodes;
10201046
SelectorNode node(0, selectors.get_ptr());
@@ -1115,10 +1141,10 @@ void dxt_hc::create_alpha_selector_codebook_task(uint64 data, void* pData_ptr) {
11151141
uint num_tasks = m_pTask_pool->get_num_threads() + 1;
11161142
uint E3[16][8];
11171143
uint E6[8][64];
1118-
for (uint n = m_has_etc_color_blocks ? m_num_blocks >> 1 : m_num_blocks, b = n * data / num_tasks, bEnd = n * (data + 1) / num_tasks; b < bEnd; b++) {
1144+
for (uint n = m_has_subblocks ? m_num_blocks >> 1 : m_num_blocks, b = n * data / num_tasks, bEnd = n * (data + 1) / num_tasks; b < bEnd; b++) {
11191145
for (uint c = cAlpha0; c < cAlpha0 + m_num_alpha_blocks; c++) {
11201146
const uint alpha_pixel_comp = m_params.m_alpha_component_indices[c - cAlpha0];
1121-
alpha_cluster& cluster = m_alpha_clusters[m_endpoint_indices[m_has_etc_color_blocks ? b << 1 : b].component[c]];
1147+
alpha_cluster& cluster = m_alpha_clusters[m_endpoint_indices[m_has_subblocks ? b << 1 : b].component[c]];
11221148
uint* block_values = cluster.alpha_values;
11231149
for (uint p = 0; p < 16; p++) {
11241150
for (uint s = 0; s < 8; s++) {
@@ -1161,16 +1187,16 @@ void dxt_hc::create_alpha_selector_codebook_task(uint64 data, void* pData_ptr) {
11611187
total_errors[p][s] += E3[p][s];
11621188
}
11631189
selector_details[best_index].used = true;
1164-
m_selector_indices[m_has_etc_color_blocks ? b << 1 : b].component[c] = best_index;
1190+
m_selector_indices[m_has_subblocks ? b << 1 : b].component[c] = best_index;
11651191
}
11661192
}
11671193
}
11681194

11691195
void dxt_hc::create_alpha_selector_codebook() {
11701196
uint num_tasks = m_pTask_pool->get_num_threads() + 1;
1171-
crnlib::vector<uint64> selectors(m_num_alpha_blocks * (m_has_etc_color_blocks ? m_num_blocks >> 1 : m_num_blocks));
1197+
crnlib::vector<uint64> selectors(m_num_alpha_blocks * (m_has_subblocks ? m_num_blocks >> 1 : m_num_blocks));
11721198
for (uint i = 0, c = cAlpha0; c < cAlpha0 + m_num_alpha_blocks; c++) {
1173-
for (uint b = 0, step = m_has_etc_color_blocks ? 2 : 1; b < m_num_blocks; b += step)
1199+
for (uint b = 0, step = m_has_subblocks ? 2 : 1; b < m_num_blocks; b += step)
11741200
selectors[i++] = m_block_selectors[c][b];
11751201
}
11761202

crnlib/crn_dxt_hc.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -149,6 +149,7 @@ class dxt_hc {
149149
uint m_num_alpha_blocks;
150150
bool m_has_color_blocks;
151151
bool m_has_etc_color_blocks;
152+
bool m_has_subblocks;
152153

153154
enum {
154155
cColor = 0,

0 commit comments

Comments
 (0)