diff options
Diffstat (limited to 'thirdparty/basis_universal/encoder/basisu_astc_hdr_enc.h')
-rw-r--r-- | thirdparty/basis_universal/encoder/basisu_astc_hdr_enc.h | 224 |
1 files changed, 224 insertions, 0 deletions
diff --git a/thirdparty/basis_universal/encoder/basisu_astc_hdr_enc.h b/thirdparty/basis_universal/encoder/basisu_astc_hdr_enc.h new file mode 100644 index 0000000000..ee122ff7ce --- /dev/null +++ b/thirdparty/basis_universal/encoder/basisu_astc_hdr_enc.h @@ -0,0 +1,224 @@ +// basisu_astc_hdr_enc.h +#pragma once +#include "basisu_enc.h" +#include "basisu_gpu_texture.h" +#include "../transcoder/basisu_astc_helpers.h" +#include "../transcoder/basisu_astc_hdr_core.h" + +namespace basisu +{ + // This MUST be called before encoding any blocks. + void astc_hdr_enc_init(); + + const uint32_t MODE11_FIRST_ISE_RANGE = astc_helpers::BISE_3_LEVELS, MODE11_LAST_ISE_RANGE = astc_helpers::BISE_16_LEVELS; + const uint32_t MODE7_PART1_FIRST_ISE_RANGE = astc_helpers::BISE_3_LEVELS, MODE7_PART1_LAST_ISE_RANGE = astc_helpers::BISE_16_LEVELS; + const uint32_t MODE7_PART2_FIRST_ISE_RANGE = astc_helpers::BISE_3_LEVELS, MODE7_PART2_LAST_ISE_RANGE = astc_helpers::BISE_8_LEVELS; + const uint32_t MODE11_PART2_FIRST_ISE_RANGE = astc_helpers::BISE_3_LEVELS, MODE11_PART2_LAST_ISE_RANGE = astc_helpers::BISE_4_LEVELS; + const uint32_t MODE11_TOTAL_SUBMODES = 8; // plus an extra hidden submode, directly encoded, for direct, so really 9 (see tables 99/100 of the ASTC spec) + const uint32_t MODE7_TOTAL_SUBMODES = 6; + + struct astc_hdr_codec_options + { + float m_bc6h_err_weight; + + bool m_use_solid; + + bool m_use_mode11; + bool m_mode11_uber_mode; + uint32_t m_first_mode11_weight_ise_range; + uint32_t m_last_mode11_weight_ise_range; + bool m_mode11_direct_only; + int32_t m_first_mode11_submode; + int32_t m_last_mode11_submode; + + bool m_use_mode7_part1; + uint32_t m_first_mode7_part1_weight_ise_range; + uint32_t m_last_mode7_part1_weight_ise_range; + + bool m_use_mode7_part2; + uint32_t m_mode7_part2_part_masks; + uint32_t m_first_mode7_part2_weight_ise_range; + uint32_t m_last_mode7_part2_weight_ise_range; + + bool m_use_mode11_part2; + uint32_t m_mode11_part2_part_masks; + uint32_t m_first_mode11_part2_weight_ise_range; + uint32_t m_last_mode11_part2_weight_ise_range; + + float m_r_err_scale, m_g_err_scale; + + bool m_refine_weights; + + uint32_t m_level; + + bool m_use_estimated_partitions; + uint32_t m_max_estimated_partitions; + + // If true, the ASTC HDR compressor is allowed to more aggressively vary weight indices for slightly higher compression in non-fastest mode. This will hurt BC6H quality, however. + bool m_allow_uber_mode; + + astc_hdr_codec_options(); + + void init(); + + // TODO: set_quality_level() is preferred to configure the codec for transcoding purposes. + static const int cMinLevel = 0; + static const int cMaxLevel = 4; + static const int cDefaultLevel = 1; + void set_quality_level(int level); + + private: + void set_quality_best(); + void set_quality_normal(); + void set_quality_fastest(); + }; + + struct astc_hdr_pack_results + { + double m_best_block_error; + double m_bc6h_block_error; // note this is not used/set by the encoder, here for convienance + + // Encoder results (logical ASTC block) + astc_helpers::log_astc_block m_best_blk; + + // For statistical use + uint32_t m_best_submodes[2]; + uint32_t m_best_pat_index; + bool m_constrained_weights; + + bool m_improved_via_refinement_flag; + + // Only valid if the block is solid + basist::astc_blk m_solid_blk; + + // The BC6H transcoded block + basist::bc6h_block m_bc6h_block; + + // Solid color/void extent flag + bool m_is_solid; + + void clear() + { + m_best_block_error = 1e+30f; + m_bc6h_block_error = 1e+30f; + + m_best_blk.clear(); + m_best_blk.m_grid_width = 4; + m_best_blk.m_grid_height = 4; + m_best_blk.m_endpoint_ise_range = 20; // 0-255 + + clear_obj(m_best_submodes); + + m_best_pat_index = 0; + m_constrained_weights = false; + + clear_obj(m_bc6h_block); + + m_is_solid = false; + m_improved_via_refinement_flag = false; + } + }; + + void interpolate_qlog12_colors( + const int e[2][3], + basist::half_float* pDecoded_half, + vec3F* pDecoded_float, + uint32_t n, uint32_t ise_weight_range); + + bool get_astc_hdr_mode_11_block_colors( + const uint8_t* pEndpoints, + basist::half_float* pDecoded_half, + vec3F* pDecoded_float, + uint32_t n, uint32_t ise_weight_range, uint32_t ise_endpoint_range); + + bool get_astc_hdr_mode_7_block_colors( + const uint8_t* pEndpoints, + basist::half_float* pDecoded_half, + vec3F* pDecoded_float, + uint32_t n, uint32_t ise_weight_range, uint32_t ise_endpoint_range); + + double eval_selectors( + uint32_t num_pixels, + uint8_t* pWeights, + const basist::half_float* pBlock_pixels_half, + uint32_t num_weight_levels, + const basist::half_float* pDecoded_half, + const astc_hdr_codec_options& coptions, + uint32_t usable_selector_bitmask = UINT32_MAX); + + double compute_block_error(const basist::half_float* pOrig_block, const basist::half_float* pPacked_block, const astc_hdr_codec_options& coptions); + + // Encodes a 4x4 ASTC HDR block given a 4x4 array of source block pixels/texels. + // Supports solid color blocks, mode 11 (all submodes), mode 7/1 partition (all submodes), + // and mode 7/2 partitions (all submodes) - 30 patterns, only the ones also in common with the BC6H format. + // The packed ASTC weight grid dimensions are currently always 4x4 texels, but may be also 3x3 in the future. + // This function is thread safe, i.e. it may be called from multiple encoding threads simultanously with different blocks. + // + // Parameters: + // pRGBPixels - An array of 48 (16 RGB) floats: the 4x4 block to pack + // pPacked_block - A pointer to the packed ASTC HDR block + // coptions - Codec options + // pInternal_results - An optional pointer to details about how the block was packed, for statistics/debugging purposes. May be nullptr. + // + // Requirements: + // astc_hdr_enc_init() MUST have been called first to initialized the codec. + // Input pixels are checked and cannot be NaN's, Inf's, signed, or too large (greater than MAX_HALF_FLOAT, or 65504). + // Normal values and denormals are okay. + bool astc_hdr_enc_block( + const float* pRGBPixels, + const astc_hdr_codec_options& coptions, + basisu::vector<astc_hdr_pack_results> &all_results); + + bool astc_hdr_pack_results_to_block(basist::astc_blk& dst_blk, const astc_hdr_pack_results& results); + + bool astc_hdr_refine_weights(const basist::half_float* pSource_block, astc_hdr_pack_results& cur_results, const astc_hdr_codec_options& coptions, float bc6h_weight, bool* pImproved_flag); + + struct astc_hdr_block_stats + { + std::mutex m_mutex; + + uint32_t m_total_blocks; + uint32_t m_total_2part, m_total_solid; + uint32_t m_total_mode7_1part, m_total_mode7_2part; + uint32_t m_total_mode11_1part, m_total_mode11_2part; + uint32_t m_total_mode11_1part_constrained_weights; + + uint32_t m_weight_range_hist_7[11]; + uint32_t m_weight_range_hist_7_2part[11]; + uint32_t m_mode7_submode_hist[6]; + + uint32_t m_weight_range_hist_11[11]; + uint32_t m_weight_range_hist_11_2part[11]; + uint32_t m_mode11_submode_hist[9]; + + uint32_t m_part_hist[32]; + + uint32_t m_total_refined; + + astc_hdr_block_stats() { clear(); } + + void clear() + { + std::lock_guard<std::mutex> lck(m_mutex); + + m_total_blocks = 0; + m_total_mode7_1part = 0, m_total_mode7_2part = 0, m_total_mode11_1part = 0, m_total_2part = 0, m_total_solid = 0, m_total_mode11_2part = 0; + m_total_mode11_1part_constrained_weights = 0; + m_total_refined = 0; + + clear_obj(m_weight_range_hist_11); + clear_obj(m_weight_range_hist_11_2part); + clear_obj(m_weight_range_hist_7); + clear_obj(m_weight_range_hist_7_2part); + clear_obj(m_mode7_submode_hist); + clear_obj(m_mode11_submode_hist); + clear_obj(m_part_hist); + } + + void update(const astc_hdr_pack_results& log_blk); + + void print(); + }; + +} // namespace basisu + |