mirror of
https://github.com/BinomialLLC/basis_universal.git
synced 2026-07-21 05:29:03 +00:00
441 lines
10 KiB
C++
441 lines
10 KiB
C++
// basisu_astc_ldr_fencode.h
|
|
#pragma once
|
|
#include "../transcoder/basisu.h"
|
|
#include "../transcoder/basisu_transcoder_internal.h"
|
|
#include "basisu_astc_ldr_common.h"
|
|
|
|
namespace basisu
|
|
{
|
|
|
|
namespace astc_ldrf
|
|
{
|
|
|
|
BASISU_FORCE_INLINE int popcount64(uint64_t x)
|
|
{
|
|
#if defined(__cplusplus) && (__cplusplus >= 202002L) && defined(__cpp_lib_bitops)
|
|
return static_cast<int>(std::popcount(x));
|
|
|
|
#elif defined(__EMSCRIPTEN__) || defined(__clang__) || defined(__GNUC__)
|
|
return __builtin_popcountll(static_cast<unsigned long long>(x));
|
|
|
|
#elif defined(_MSC_VER) && defined(_M_X64)
|
|
return static_cast<int>(__popcnt64(x));
|
|
|
|
#elif defined(_MSC_VER) && (defined(_M_IX86) || defined(_M_ARM64) || defined(_M_ARM))
|
|
return static_cast<int>(
|
|
__popcnt(static_cast<uint32_t>(x)) +
|
|
__popcnt(static_cast<uint32_t>(x >> 32))
|
|
);
|
|
|
|
#else
|
|
int count = 0;
|
|
while (x)
|
|
{
|
|
x &= (x - 1);
|
|
++count;
|
|
}
|
|
return count;
|
|
#endif
|
|
}
|
|
|
|
struct bitmask192
|
|
{
|
|
uint64_t m_a, m_b, m_c; // a=lowest qword (bits 0-63), b=middle (64-127), c=highest (128-191)
|
|
|
|
inline bitmask192() {}
|
|
|
|
constexpr inline bitmask192(const bitmask192& o) noexcept
|
|
: m_a(o.m_a), m_b(o.m_b), m_c(o.m_c)
|
|
{
|
|
}
|
|
|
|
inline bitmask192& operator=(const bitmask192& o) noexcept
|
|
{
|
|
m_a = o.m_a;
|
|
m_b = o.m_b;
|
|
m_c = o.m_c;
|
|
return *this;
|
|
}
|
|
|
|
constexpr inline bitmask192(uint64_t a, uint64_t b, uint64_t c) noexcept
|
|
: m_a(a), m_b(b), m_c(c)
|
|
{
|
|
}
|
|
|
|
static constexpr inline bitmask192 zero() noexcept
|
|
{
|
|
return bitmask192(0, 0, 0);
|
|
}
|
|
|
|
static constexpr inline bitmask192 all() noexcept
|
|
{
|
|
return bitmask192(UINT64_MAX, UINT64_MAX, UINT64_MAX);
|
|
}
|
|
|
|
inline void clear() noexcept
|
|
{
|
|
m_a = 0;
|
|
m_b = 0;
|
|
m_c = 0;
|
|
}
|
|
|
|
inline void set_all() noexcept
|
|
{
|
|
m_a = UINT64_MAX;
|
|
m_b = UINT64_MAX;
|
|
m_c = UINT64_MAX;
|
|
}
|
|
|
|
inline bool is_zero() const noexcept
|
|
{
|
|
return (m_a | m_b | m_c) == 0;
|
|
}
|
|
|
|
inline bool any() const noexcept
|
|
{
|
|
return (m_a | m_b | m_c) != 0;
|
|
}
|
|
|
|
inline bool none() const noexcept
|
|
{
|
|
return !any();
|
|
}
|
|
|
|
inline bool all_set() const noexcept
|
|
{
|
|
return (m_a == UINT64_MAX) && (m_b == UINT64_MAX) && (m_c == UINT64_MAX);
|
|
}
|
|
|
|
inline uint32_t popcount() const noexcept
|
|
{
|
|
return popcount64(m_a) + popcount64(m_b) + popcount64(m_c);
|
|
}
|
|
|
|
constexpr inline bitmask192 operator~() const noexcept
|
|
{
|
|
return bitmask192(~m_a, ~m_b, ~m_c);
|
|
}
|
|
|
|
constexpr inline bitmask192 operator&(const bitmask192& rhs) const noexcept
|
|
{
|
|
return bitmask192(m_a & rhs.m_a, m_b & rhs.m_b, m_c & rhs.m_c);
|
|
}
|
|
|
|
constexpr inline bitmask192 operator|(const bitmask192& rhs) const noexcept
|
|
{
|
|
return bitmask192(m_a | rhs.m_a, m_b | rhs.m_b, m_c | rhs.m_c);
|
|
}
|
|
|
|
constexpr inline bitmask192 operator^(const bitmask192& rhs) const noexcept
|
|
{
|
|
return bitmask192(m_a ^ rhs.m_a, m_b ^ rhs.m_b, m_c ^ rhs.m_c);
|
|
}
|
|
|
|
inline bitmask192& operator&=(const bitmask192& rhs) noexcept
|
|
{
|
|
m_a &= rhs.m_a;
|
|
m_b &= rhs.m_b;
|
|
m_c &= rhs.m_c;
|
|
return *this;
|
|
}
|
|
|
|
inline bitmask192& operator|=(const bitmask192& rhs) noexcept
|
|
{
|
|
m_a |= rhs.m_a;
|
|
m_b |= rhs.m_b;
|
|
m_c |= rhs.m_c;
|
|
return *this;
|
|
}
|
|
|
|
inline bitmask192& operator^=(const bitmask192& rhs) noexcept
|
|
{
|
|
m_a ^= rhs.m_a;
|
|
m_b ^= rhs.m_b;
|
|
m_c ^= rhs.m_c;
|
|
return *this;
|
|
}
|
|
|
|
constexpr inline bool operator==(const bitmask192& rhs) const noexcept
|
|
{
|
|
return (m_a == rhs.m_a) && (m_b == rhs.m_b) && (m_c == rhs.m_c);
|
|
}
|
|
|
|
constexpr inline bool operator!=(const bitmask192& rhs) const noexcept
|
|
{
|
|
return !(*this == rhs);
|
|
}
|
|
|
|
// m_a is the lowest qword, m_b highest
|
|
constexpr inline bool operator<(const bitmask192& rhs) const noexcept
|
|
{
|
|
if (m_c != rhs.m_c) return m_c < rhs.m_c;
|
|
if (m_b != rhs.m_b) return m_b < rhs.m_b;
|
|
return m_a < rhs.m_a;
|
|
}
|
|
|
|
constexpr inline bool operator>(const bitmask192& rhs) const noexcept
|
|
{
|
|
return rhs < *this;
|
|
}
|
|
|
|
constexpr inline bool operator<=(const bitmask192& rhs) const noexcept
|
|
{
|
|
return !(rhs < *this);
|
|
}
|
|
|
|
constexpr inline bool operator>=(const bitmask192& rhs) const noexcept
|
|
{
|
|
return !(*this < rhs);
|
|
}
|
|
|
|
explicit constexpr inline operator bool() const noexcept
|
|
{
|
|
return (m_a | m_b | m_c) != 0;
|
|
}
|
|
|
|
inline bool intersects(const bitmask192& rhs) const noexcept
|
|
{
|
|
return ((m_a & rhs.m_a) | (m_b & rhs.m_b) | (m_c & rhs.m_c)) != 0;
|
|
}
|
|
|
|
inline bool disjoint(const bitmask192& rhs) const noexcept
|
|
{
|
|
return !intersects(rhs);
|
|
}
|
|
|
|
constexpr inline bool contains_all(const bitmask192& rhs) const noexcept
|
|
{
|
|
return ((m_a & rhs.m_a) == rhs.m_a) &&
|
|
((m_b & rhs.m_b) == rhs.m_b) &&
|
|
((m_c & rhs.m_c) == rhs.m_c);
|
|
}
|
|
|
|
constexpr inline bool is_subset_of(const bitmask192& rhs) const noexcept
|
|
{
|
|
return rhs.contains_all(*this);
|
|
}
|
|
|
|
inline bool contains_any(const bitmask192& rhs) const noexcept
|
|
{
|
|
return intersects(rhs);
|
|
}
|
|
|
|
constexpr inline uint64_t low64() const noexcept
|
|
{
|
|
return m_a;
|
|
}
|
|
|
|
constexpr inline uint64_t mid64() const noexcept
|
|
{
|
|
return m_b;
|
|
}
|
|
|
|
constexpr inline uint64_t high64() const noexcept
|
|
{
|
|
return m_c;
|
|
}
|
|
|
|
inline void set_bit(uint32_t index) noexcept
|
|
{
|
|
assert(index < 192);
|
|
|
|
if (index < 64)
|
|
m_a |= uint64_t(1) << index;
|
|
else if (index < 128)
|
|
m_b |= uint64_t(1) << (index - 64);
|
|
else
|
|
m_c |= uint64_t(1) << (index - 128);
|
|
}
|
|
|
|
inline void set_bit(uint32_t index, uint32_t bit_val) noexcept
|
|
{
|
|
assert(index < 192);
|
|
assert(bit_val <= 1);
|
|
|
|
if (index < 64)
|
|
{
|
|
m_a &= ~(uint64_t(1) << index);
|
|
m_a |= uint64_t(bit_val) << index;
|
|
}
|
|
else if (index < 128)
|
|
{
|
|
m_b &= ~(uint64_t(1) << (index - 64));
|
|
m_b |= uint64_t(bit_val) << (index - 64);
|
|
}
|
|
else
|
|
{
|
|
m_c &= ~(uint64_t(1) << (index - 128));
|
|
m_c |= uint64_t(bit_val) << (index - 128);
|
|
}
|
|
}
|
|
|
|
inline bool is_bit_set(uint32_t index) const noexcept
|
|
{
|
|
assert(index < 192);
|
|
|
|
if (index < 64)
|
|
return ((m_a >> index) & 1) != 0;
|
|
else if (index < 128)
|
|
return ((m_b >> (index - 64)) & 1) != 0;
|
|
else
|
|
return ((m_c >> (index - 128)) & 1) != 0;
|
|
}
|
|
|
|
static inline bitmask192 lsb_mask(uint32_t num_bits) noexcept
|
|
{
|
|
assert(num_bits <= 192);
|
|
|
|
if (num_bits == 0)
|
|
return bitmask192(0, 0, 0);
|
|
|
|
if (num_bits < 64)
|
|
return bitmask192((uint64_t(1) << num_bits) - 1, 0, 0);
|
|
|
|
if (num_bits == 64)
|
|
return bitmask192(UINT64_MAX, 0, 0);
|
|
|
|
if (num_bits < 128)
|
|
{
|
|
return bitmask192(
|
|
UINT64_MAX,
|
|
(uint64_t(1) << (num_bits - 64)) - 1,
|
|
0);
|
|
}
|
|
|
|
if (num_bits == 128)
|
|
return bitmask192(UINT64_MAX, UINT64_MAX, 0);
|
|
|
|
if (num_bits < 192)
|
|
{
|
|
return bitmask192(
|
|
UINT64_MAX,
|
|
UINT64_MAX,
|
|
(uint64_t(1) << (num_bits - 128)) - 1);
|
|
}
|
|
|
|
return bitmask192(UINT64_MAX, UINT64_MAX, UINT64_MAX);
|
|
}
|
|
};
|
|
|
|
inline uint32_t popcount192(const bitmask192& a) { return a.popcount(); }
|
|
|
|
const uint32_t MAX_CANDIDATES = 512;
|
|
|
|
struct rgba32_image
|
|
{
|
|
const uint8_t* m_pPixels;
|
|
uint32_t m_width;
|
|
uint32_t m_height;
|
|
uint32_t m_row_pitch_in_texels; // pitch in pixels/texels, not bytes
|
|
};
|
|
|
|
struct single_subset_enc_context
|
|
{
|
|
uint32_t m_block_width, m_block_height;
|
|
uint32_t m_block_size_index;
|
|
uint32_t m_total_block_pixels;
|
|
|
|
uint32_t m_max_candidates;
|
|
uint32_t m_num_ls_iterations;
|
|
|
|
uint32_t m_chan_weights[4];
|
|
|
|
basist::astc_ldr_t::dct2f m_dct;
|
|
|
|
astc_helpers::decode_mode m_astc_decode_mode;
|
|
bool m_disable_dual_plane;
|
|
bool m_weight_polishing;
|
|
|
|
bool m_has_alpha;
|
|
|
|
bool m_try_base_ofs;
|
|
bool m_higher_effort_bc;
|
|
};
|
|
|
|
const uint32_t MAX_UNIQUE_2SUBSET_PATS = 838;
|
|
const uint32_t MAX_UNIQUE_3SUBSET_PATS = 626;
|
|
|
|
typedef basisu::vector<astc_helpers::log_astc_block> astc_lblock_vec;
|
|
|
|
// source pEndpoints[] = ASTC direct order: LR HR LG HG LB HB LA HA
|
|
bool cem_encode(uint32_t cem_index, const float pEndpoints[8], uint32_t endpoint_ise_range, uint8_t* pCEM_values, bool allow_bc = true, bool high_effort = true);
|
|
|
|
bool init_single_subset_context(
|
|
single_subset_enc_context& ctx,
|
|
uint32_t block_width, uint32_t block_height,
|
|
astc_helpers::decode_mode astc_decode_mode,
|
|
const uint32_t chan_weights[4],
|
|
uint32_t max_candidates, uint32_t num_ls_iterations, bool disable_dual_plane, bool has_alpha, bool weight_polishing);
|
|
|
|
// best_lblock will be in ise space (see is_lblock_ise() below), elements in array pointed to by pAll_candidates (which may be null) will be in rank space
|
|
double compress_single_subset(
|
|
single_subset_enc_context& ctx,
|
|
const uint8_t* pBlock_pixels,
|
|
astc_helpers::log_astc_block& best_lblock,
|
|
astc_lblock_vec* pAll_candidates,
|
|
bool always_compute_error);
|
|
|
|
static const uint32_t NUM_DOT_THRESH_FRACTS = 6;
|
|
|
|
struct subset_enc_context : single_subset_enc_context
|
|
{
|
|
subset_enc_context() {}
|
|
|
|
uint32_t m_max_subsets;
|
|
|
|
uint32_t m_num_carrier_candidates;
|
|
uint32_t m_num_pattern_candidates;
|
|
float m_two_subset_var_thresh;
|
|
float m_three_subset_var_thresh;
|
|
uint32_t m_two_subset_dot_thresh_fract_index;
|
|
|
|
bitmask192 m_two_subset_pat_bitmask[MAX_UNIQUE_2SUBSET_PATS];
|
|
|
|
uint32_t m_num_unique_two_subset_pats;
|
|
const uint16_t* m_pUnique_two_subset_pats;
|
|
|
|
bool m_use_method1;
|
|
bool m_use_method2;
|
|
|
|
astc_ldr::partitions_data* m_pPart_data_p2;
|
|
astc_ldr::partitions_data* m_pPart_data_p3;
|
|
};
|
|
|
|
// must have first called init_single_subset_context() on ctx
|
|
bool init_multi_subset_context(
|
|
subset_enc_context& ctx,
|
|
uint32_t max_subsets,
|
|
uint32_t num_carrier_candidates, uint32_t num_pattern_candidates,
|
|
float two_subset_var_thresh, uint32_t two_subset_dot_thresh_fract_index,
|
|
float three_subset_var_thresh,
|
|
astc_ldr::partitions_data* pPart_data_p2, astc_ldr::partitions_data* pPart_data_p3);
|
|
|
|
struct subset_enc_thread_context
|
|
{
|
|
astc_ldr::partition_pattern_vec m_pat_vec;
|
|
};
|
|
|
|
double compress_block_subsets(
|
|
const subset_enc_context& enc_context,
|
|
subset_enc_thread_context& enc_thread_context,
|
|
const uint8_t* pBlock_pixels,
|
|
astc_helpers::log_astc_block& best_lblock, astc_lblock_vec* pAll_candidates);
|
|
|
|
enum
|
|
{
|
|
cUserModeISEValues = 0,
|
|
cUserModeRankValues = 1
|
|
};
|
|
|
|
static inline bool is_lblock_ise(const astc_helpers::log_astc_block& log_blk)
|
|
{
|
|
// the default user mode value == ISE, 1 = ranks (which is the exceptional case for astc_helpers)
|
|
return log_blk.m_user_mode == cUserModeISEValues;
|
|
}
|
|
|
|
void convert_rank_lblock_to_ise(astc_helpers::log_astc_block& log_blk);
|
|
void convert_ise_lblock_to_rank(astc_helpers::log_astc_block& log_blk);
|
|
|
|
} // namespace astc_ldr_f
|
|
} // namespace basisu
|