Optimize selector quantization, assignment and refinement

This change significantly improves compression speed.

Explanation:
The main ideas used for selector computations optimization:
- possible pixel values for each endpoint can be cached
- the distances between the possible pixel values and the actual pixels values within a block can be cached for fast error computation during selector assignment
- selector refinement can be efficiently integrated with the selector assignment, as it is based on the same set of cached error values
- using block encoding instead of chunk encoding for both endpoints and selectors eliminates extra levels of indirection

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.

[Compressing Kodak set without mipmaps]
Original: 1582222 bytes / 28.953 sec
Modified: 1494501 bytes / 19.667 sec
Improvement: 5.54% (compression ratio) / 32.07% (compression time)

[Compressing Kodak set with mipmaps]
Original: 2065243 bytes / 36.998 sec
Modified: 1945365 bytes / 25.642 sec
Improvement: 5.80% (compression ratio) / 30.69% (compression time)
This commit is contained in:
Alexander Suvorov
2017-05-19 19:55:10 +02:00
parent b8349dfac8
commit 7b6f456399
3 changed files with 373 additions and 752 deletions
Binary file not shown.
+347 -724
View File
File diff suppressed because it is too large Load Diff
+26 -28
View File
@@ -50,9 +50,14 @@ class dxt_hc {
};
crnlib::vector<chunk_details> m_chunk_details;
crnlib::vector<uint64> m_block_selectors[3];
crnlib::vector<crnlib::vector<color_quad_u8>> m_blocks;
crnlib::vector<uint64> m_block_selectors[3];
crnlib::vector<uint32> m_color_selectors;
crnlib::vector<uint64> m_alpha_selectors;
crnlib::vector<bool> m_color_selectors_used;
crnlib::vector<bool> m_alpha_selectors_used;
crnlib::vector<endpoint_indices_details> m_endpoint_indices;
crnlib::vector<selector_indices_details> m_selector_indices;
struct pixel_chunk {
pixel_chunk() { clear(); }
@@ -186,9 +191,9 @@ class dxt_hc {
const crnlib::vector<uint>& get_color_endpoint_vec() const { return m_color_endpoints; }
// Color selectors
uint get_color_selector_codebook_size() const { return m_color_selectors.size(); }
const selectors& get_color_selectors(uint codebook_index) const { return m_color_selectors[codebook_index]; }
const crnlib::vector<selectors>& get_color_selectors_vec() const { return m_color_selectors; }
uint get_color_selector_codebook_size() const { return m_color_selectors_vec.size(); }
const selectors& get_color_selectors(uint codebook_index) const { return m_color_selectors_vec[codebook_index]; }
const crnlib::vector<selectors>& get_color_selectors_vec() const { return m_color_selectors_vec; }
// Alpha endpoints
inline uint get_alpha_endpoint_codebook_size() const { return m_alpha_endpoints.size(); }
@@ -196,9 +201,9 @@ class dxt_hc {
const crnlib::vector<uint>& get_alpha_endpoint_vec() const { return m_alpha_endpoints; }
// Alpha selectors
uint get_alpha_selector_codebook_size() const { return m_alpha_selectors.size(); }
const selectors& get_alpha_selectors(uint codebook_index) const { return m_alpha_selectors[codebook_index]; }
const crnlib::vector<selectors>& get_alpha_selectors_vec() const { return m_alpha_selectors; }
uint get_alpha_selector_codebook_size() const { return m_alpha_selectors_vec.size(); }
const selectors& get_alpha_selectors(uint codebook_index) const { return m_alpha_selectors_vec[codebook_index]; }
const crnlib::vector<selectors>& get_alpha_selectors_vec() const { return m_alpha_selectors_vec; }
private:
params m_params;
@@ -230,7 +235,6 @@ class dxt_hc {
uint8 m_num_tiles;
compressed_tile m_tiles[cChunkMaxTiles];
compressed_tile m_quantized_tiles[cChunkMaxTiles];
uint16 m_endpoint_cluster_index[cChunkMaxTiles];
uint16 m_selector_cluster_index[cChunkBlockHeight][cChunkBlockWidth];
@@ -265,23 +269,21 @@ class dxt_hc {
struct tile_cluster {
tile_cluster()
: m_first_endpoint(0), m_second_endpoint(0), m_error(0) {}
: m_first_endpoint(0), m_second_endpoint(0) {}
// first = chunk, second = tile
// if an alpha tile, second's upper 16 bits contains the alpha index (0 or 1)
crnlib::vector<std::pair<uint, uint> > m_tiles;
crnlib::vector<color_quad_u8> m_pixels;
crnlib::vector<uint8> m_selectors;
struct {
bool result;
uint first_endpoint;
uint second_endpoint;
uint64 error;
} m_refined;
uint m_first_endpoint;
uint m_second_endpoint;
uint64 m_error;
color_quad_u8 m_color_values[4];
uint m_alpha_values[8];
bool m_refined_result;
uint m_refined_first_endpoint;
uint m_refined_second_endpoint;
uint m_refined_alpha_values[8];
};
typedef crnlib::vector<tile_cluster> tile_cluster_vec;
@@ -289,8 +291,8 @@ class dxt_hc {
tile_cluster_vec m_color_clusters;
tile_cluster_vec m_alpha_clusters;
selectors_vec m_color_selectors;
selectors_vec m_alpha_selectors;
selectors_vec m_alpha_selectors_vec;
selectors_vec m_color_selectors_vec;
// For each selector, this array indicates every chunk/tile/tile block that use this color selector.
struct block_id {
@@ -307,8 +309,6 @@ class dxt_hc {
};
typedef crnlib::vector<crnlib::vector<block_id> > chunk_blocks_using_selectors_vec;
chunk_blocks_using_selectors_vec m_chunk_blocks_using_color_selectors;
chunk_blocks_using_selectors_vec m_chunk_blocks_using_alpha_selectors; // second's upper 16 bits contain alpha index!
crnlib::vector<uint> m_color_endpoints; // not valid until end, only for user access
crnlib::vector<uint> m_alpha_endpoints; // not valid until end, only for user access
@@ -377,17 +377,15 @@ class dxt_hc {
void determine_alpha_endpoint_codebook_task(uint64 data, void* pData_ptr);
bool determine_alpha_endpoint_codebook();
void create_selector_codebook_task(uint64 data, void* pData_ptr);
bool create_selector_codebook(bool alpha_blocks);
void create_color_selector_codebook_task(uint64 data, void* pData_ptr);
bool create_color_selector_codebook();
void create_alpha_selector_codebook_task(uint64 data, void* pData_ptr);
bool create_alpha_selector_codebook();
bool refine_quantized_color_endpoints();
bool refine_quantized_color_selectors();
bool refine_quantized_alpha_endpoints();
bool refine_quantized_alpha_selectors();
bool initialize_blocks(const params& p);
bool create_block_encodings(const params& p);
bool update_progress(uint phase_index, uint subphase_index, uint subphase_total);
bool compress_internal(const params& p, uint num_chunks, const pixel_chunk* pChunks);
};
CRNLIB_DEFINE_BITWISE_COPYABLE(dxt_hc::pixel_chunk);