mirror of
https://github.com/drewcassidy/quicktex.git
synced 2024-09-13 06:37:34 +00:00
3-color refinement
This commit is contained in:
parent
645549978d
commit
f65008ccc3
@ -59,7 +59,8 @@ BC1Encoder::BC1Encoder(InterpolatorPtr interpolator) : _interpolator(interpolato
|
||||
_flags = Flags::UseFullMSEEval | Flags::TwoLeastSquaresPasses | Flags::UseLikelyTotalOrderings | Flags::Use3ColorBlocks;
|
||||
_error_mode = ErrorMode::Full;
|
||||
_endpoint_mode = EndpointMode::PCA;
|
||||
_orderings4 = 8;
|
||||
_orderings4 = 16;
|
||||
_orderings3 = 8;
|
||||
|
||||
// generate lookup tables
|
||||
order_table_mutex.lock();
|
||||
@ -96,80 +97,50 @@ void BC1Encoder::EncodeBlock(Color4x4 pixels, BC1Block *dest) const {
|
||||
needs_block_error |= metrics.has_black && ((_flags & Flags::Use3ColorBlocksForBlackPixels) != Flags::None);
|
||||
ErrorMode error_mode = needs_block_error ? _error_mode : ErrorMode::None;
|
||||
|
||||
unsigned total_ls_passes = (_flags & Flags::TwoLeastSquaresPasses) != Flags::None ? 2 : 1;
|
||||
unsigned total_ep_rounds = needs_block_error && ((_flags & Flags::TryAllInitialEndpoints) != Flags::None) ? 2 : 1;
|
||||
const unsigned total_ls_passes = (_flags & Flags::TwoLeastSquaresPasses) != Flags::None ? 2 : 1;
|
||||
const unsigned total_ep_rounds = needs_block_error && ((_flags & Flags::TryAllInitialEndpoints) != Flags::None) ? 2 : 1;
|
||||
const unsigned total_cf_iters = (_flags & Flags::Iterative) != Flags::None ? 2 : 1;
|
||||
|
||||
// Initial block generation
|
||||
EncodeResults orig;
|
||||
EncodeResults result;
|
||||
for (unsigned round = 0; round < total_ep_rounds; round++) {
|
||||
EndpointMode endpoint_mode = (round == 1) ? EndpointMode::BoundingBox : _endpoint_mode;
|
||||
|
||||
EncodeResults round_result;
|
||||
FindEndpoints(pixels, round_result, metrics, endpoint_mode);
|
||||
FindSelectors<ColorMode::FourColor>(pixels, round_result, error_mode);
|
||||
EncodeResults trial_orig;
|
||||
FindEndpoints(pixels, trial_orig, metrics, endpoint_mode);
|
||||
|
||||
RefineBlockLS<ColorMode::FourColor>(pixels, round_result, metrics, error_mode, total_ls_passes);
|
||||
EncodeResults trial_result = trial_orig;
|
||||
|
||||
if (!needs_block_error || round_result.error < result.error) { result = round_result; }
|
||||
FindSelectors<ColorMode::FourColor>(pixels, trial_result, error_mode);
|
||||
RefineBlockLS<ColorMode::FourColor>(pixels, trial_result, metrics, error_mode, total_ls_passes);
|
||||
|
||||
if (!needs_block_error || trial_result.error < result.error) {
|
||||
result = trial_result;
|
||||
orig = trial_orig;
|
||||
}
|
||||
}
|
||||
|
||||
// First refinement pass using ordered cluster fit
|
||||
if (result.error > 0 && (bool)(_flags & Flags::UseLikelyTotalOrderings)) {
|
||||
const unsigned total_iters = (_flags & Flags::Iterative) != Flags::None ? 2 : 1;
|
||||
for (unsigned iter = 0; iter < total_iters; iter++) {
|
||||
EncodeResults orig = result;
|
||||
Hist4 h(orig.selectors);
|
||||
|
||||
const Hash start_hash = order_table4->GetHash(h);
|
||||
|
||||
Vector4 axis = orig.high.ScaleFrom565() - orig.low.ScaleFrom565();
|
||||
std::array<Vector4, 16> color_vectors;
|
||||
std::array<uint32_t, 16> dots;
|
||||
|
||||
for (unsigned i = 0; i < 16; i++) {
|
||||
color_vectors[i] = Vector4::FromColorRGB(pixels.Get(i));
|
||||
int dot = 0x1000000 + (int)color_vectors[i].Dot(axis);
|
||||
assert(dot >= 0);
|
||||
dots[i] = (uint32_t)(dot << 4) | i;
|
||||
}
|
||||
|
||||
std::sort(dots.begin(), dots.end());
|
||||
|
||||
// we now have a list of indices and their dot products along the primary axis
|
||||
std::array<Vector4, 17> sums;
|
||||
for (unsigned i = 0; i < 16; i++) {
|
||||
const unsigned p = dots[i] & 0xF;
|
||||
sums[i + 1] = sums[i] + color_vectors[p];
|
||||
}
|
||||
|
||||
const Hash q_total = ((_flags & Flags::Exhaustive) != Flags::None) ? order_table4->UniqueOrderings
|
||||
: (Hash)clamp(_orderings4, MIN_TOTAL_ORDERINGS, MAX_TOTAL_ORDERINGS4);
|
||||
for (Hash q = 0; q < q_total; q++) {
|
||||
Hash trial_hash = ((_flags & Flags::Exhaustive) != Flags::None) ? q : g_best_total_orderings4[start_hash][q];
|
||||
Vector4 trial_matrix = order_table4->GetFactors(trial_hash);
|
||||
|
||||
EncodeResults trial_result = orig;
|
||||
Vector4 low, high;
|
||||
if (order_table4->IsSingleColor(trial_hash)) {
|
||||
FindEndpointsSingleColor(trial_result, pixels, metrics.avg, false);
|
||||
} else {
|
||||
RefineEndpointsLS<ColorMode::FourColor>(sums, trial_result, trial_matrix, trial_hash);
|
||||
FindSelectors<ColorMode::FourColor>(pixels, trial_result, _error_mode);
|
||||
}
|
||||
|
||||
if (trial_result.error < result.error) { result = trial_result; }
|
||||
if (trial_result.error == 0) break;
|
||||
}
|
||||
for (unsigned iter = 0; iter < total_cf_iters; iter++) { RefineBlockCF<ColorMode::FourColor>(pixels, result, metrics, _error_mode, _orderings4);
|
||||
}
|
||||
}
|
||||
|
||||
// try for 3-color block
|
||||
if (result.error > 0 && (bool)(_flags & Flags::Use3ColorBlocks)) {
|
||||
EncodeResults trial_result = result;
|
||||
FindSelectors<ColorMode::ThreeColor>(pixels, trial_result, ErrorMode::Full);
|
||||
EncodeResults trial_result = orig;
|
||||
|
||||
FindSelectors<ColorMode::ThreeColor>(pixels, trial_result, ErrorMode::Full);
|
||||
RefineBlockLS<ColorMode::ThreeColor>(pixels, trial_result, metrics, ErrorMode::Full, total_ls_passes);
|
||||
|
||||
// First refinement pass using ordered cluster fit
|
||||
if (trial_result.error > 0 && (bool)(_flags & Flags::UseLikelyTotalOrderings)) {
|
||||
for (unsigned iter = 0; iter < total_cf_iters; iter++) {
|
||||
RefineBlockCF<ColorMode::ThreeColor>(pixels, trial_result, metrics, ErrorMode::Full, _orderings3);
|
||||
}
|
||||
}
|
||||
|
||||
if (trial_result.error < result.error) { result = trial_result; };
|
||||
}
|
||||
|
||||
@ -274,12 +245,10 @@ void BC1Encoder::WriteBlock(EncodeResults &block, BC1Block *dest) const {
|
||||
unsigned x = i % 4;
|
||||
unsigned y = i / 4;
|
||||
selectors[y][x] = lut[block.selectors[i]];
|
||||
if (block.color_mode == ColorMode::ThreeColor) {
|
||||
assert(selectors[y][x] != 3);
|
||||
}
|
||||
if (block.color_mode == ColorMode::ThreeColor) { assert(selectors[y][x] != 3); }
|
||||
}
|
||||
|
||||
// if (block.color_mode != ColorMode::ThreeColor) return;
|
||||
// if (block.color_mode != ColorMode::ThreeColor) return;
|
||||
|
||||
dest->SetLowColor(color0);
|
||||
dest->SetHighColor(color1);
|
||||
@ -721,5 +690,74 @@ void BC1Encoder::RefineBlockLS(Color4x4 &pixels, EncodeResults &block, BlockMetr
|
||||
}
|
||||
}
|
||||
}
|
||||
template <ColorMode M>
|
||||
void BC1Encoder::RefineBlockCF(Color4x4 &pixels, EncodeResults &block, BlockMetrics &metrics, ErrorMode error_mode, unsigned orderings) const {
|
||||
const int color_count = (unsigned)M & 0x0F;
|
||||
static_assert(color_count == 3 || color_count == 4);
|
||||
static_assert(!(bool)(M & ColorMode::Solid));
|
||||
assert(block.color_mode != ColorMode::Incomplete);
|
||||
|
||||
using OrderTable = OrderTable<color_count>;
|
||||
using Hist = typename OrderTable::Histogram;
|
||||
|
||||
EncodeResults orig = block;
|
||||
Hist h = Hist(orig.selectors);
|
||||
|
||||
Hash start_hash;
|
||||
|
||||
if constexpr (color_count == 4) {
|
||||
start_hash = order_table4->GetHash(h);
|
||||
}
|
||||
else {
|
||||
start_hash = order_table3->GetHash(h);
|
||||
}
|
||||
|
||||
Vector4 axis = orig.high.ScaleFrom565() - orig.low.ScaleFrom565();
|
||||
std::array<Vector4, 16> color_vectors;
|
||||
std::array<uint32_t, 16> dots;
|
||||
|
||||
for (unsigned i = 0; i < 16; i++) {
|
||||
color_vectors[i] = Vector4::FromColorRGB(pixels.Get(i));
|
||||
int dot = 0x1000000 + (int)color_vectors[i].Dot(axis);
|
||||
assert(dot >= 0);
|
||||
dots[i] = (uint32_t)(dot << 4) | i;
|
||||
}
|
||||
|
||||
std::sort(dots.begin(), dots.end());
|
||||
|
||||
// we now have a list of indices and their dot products along the primary axis
|
||||
std::array<Vector4, 17> sums;
|
||||
for (unsigned i = 0; i < 16; i++) {
|
||||
const unsigned p = dots[i] & 0xF;
|
||||
sums[i + 1] = sums[i] + color_vectors[p];
|
||||
}
|
||||
|
||||
const Hash q_total =
|
||||
((_flags & Flags::Exhaustive) != Flags::None) ? OrderTable::UniqueOrderings : orderings;
|
||||
for (Hash q = 0; q < q_total; q++) {
|
||||
Hash trial_hash;
|
||||
Vector4 trial_matrix;
|
||||
|
||||
if (color_count == 4) {
|
||||
trial_hash = ((_flags & Flags::Exhaustive) != Flags::None) ? q : g_best_total_orderings4[start_hash][q];
|
||||
trial_matrix = order_table4->GetFactors(trial_hash);
|
||||
} else {
|
||||
trial_hash = ((_flags & Flags::Exhaustive) != Flags::None) ? q : g_best_total_orderings3[start_hash][q];
|
||||
trial_matrix = order_table3->GetFactors(trial_hash);
|
||||
}
|
||||
|
||||
EncodeResults trial_result = orig;
|
||||
Vector4 low, high;
|
||||
if (OrderTable::IsSingleColor(trial_hash)) {
|
||||
FindEndpointsSingleColor(trial_result, pixels, metrics.avg, (color_count == 3));
|
||||
} else {
|
||||
RefineEndpointsLS<M>(sums, trial_result, trial_matrix, trial_hash);
|
||||
FindSelectors<M>(pixels, trial_result, _error_mode);
|
||||
}
|
||||
|
||||
if (trial_result.error < block.error) { block = trial_result; }
|
||||
if (trial_result.error == 0) break;
|
||||
}
|
||||
}
|
||||
|
||||
} // namespace rgbcx
|
@ -167,5 +167,7 @@ class BC1Encoder final : public BlockEncoder<BC1Block, 4, 4> {
|
||||
template <ColorMode M> void RefineEndpointsLS(std::array<Vector4, 17> &sums, EncodeResults &block, Vector4 &matrix, Hash hash) const;
|
||||
|
||||
template <ColorMode M> void RefineBlockLS(Color4x4 &pixels, EncodeResults &block, BlockMetrics &metrics, ErrorMode error_mode, unsigned passes) const;
|
||||
|
||||
template<ColorMode M> void RefineBlockCF(Color4x4 &pixels, EncodeResults &block, BlockMetrics &metrics, ErrorMode error_mode, unsigned orderings) const;
|
||||
};
|
||||
} // namespace rgbcx
|
||||
|
@ -128,7 +128,7 @@ template <size_t N> class OrderTable {
|
||||
Vector4 GetFactors(Hash hash) { return Vector4(_factors[hash][0], _factors[hash][1], _factors[hash][1], _factors[hash][2]); }
|
||||
|
||||
static inline constexpr std::array<Hash, N> GetSingleColorHashes() {
|
||||
if (N == 4) { return {15, 700, 753, 515}; }
|
||||
if constexpr (N == 4) { return {15, 700, 753, 515}; }
|
||||
return {12, 15, 89};
|
||||
}
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user