From 8cd870ed26489ebc1b3ef0f329064f4972bc18a5 Mon Sep 17 00:00:00 2001 From: drewcassidy Date: Thu, 1 Apr 2021 22:37:25 -0700 Subject: [PATCH] More block tweaks --- quicktex/Color.cpp | 22 ++++++---- quicktex/Color.h | 3 -- quicktex/s3tc/bc1/BC1Block.h | 71 +++++++++++++------------------- quicktex/s3tc/bc1/BC1Encoder.cpp | 67 +++++++++++++----------------- quicktex/s3tc/bc3/BC3Block.h | 3 +- quicktex/s3tc/bc4/BC4Block.h | 61 +++++++++++---------------- quicktex/s3tc/bc4/_bindings.cpp | 2 +- quicktex/s3tc/bc5/BC5Block.h | 3 +- quicktex/util.h | 10 ++++- 9 files changed, 107 insertions(+), 135 deletions(-) diff --git a/quicktex/Color.cpp b/quicktex/Color.cpp index 84b0b4a..242da76 100644 --- a/quicktex/Color.cpp +++ b/quicktex/Color.cpp @@ -18,7 +18,8 @@ */ #include "Color.h" -#include // for max, Min +#include +#include #include "Vector4.h" #include "Vector4Int.h" @@ -26,7 +27,17 @@ namespace quicktex { -Color::Color(Vector4Int v) { SetRGBA((uint8_t)v[0], (uint8_t)v[1], (uint8_t)v[2], (uint8_t)v[3]); } +Color::Color(Vector4Int v) { + if (v.MaxAbs() > 0xFF) throw std::invalid_argument("Vector members out of range"); + for (int i = 0; i < 4; i++) { + if (v[i] < 0) throw std::range_error("Color members cannot be negative"); + } + + r = static_cast(v[0]); + g = static_cast(v[1]); + b = static_cast(v[2]); + a = static_cast(v[3]); +} uint16_t Color::Pack565Unscaled(uint8_t r, uint8_t g, uint8_t b) { assert5bit(r); @@ -75,13 +86,6 @@ Color Color::PreciseRound565(Vector4 &v) { return Color(r, g, b); } -void Color::SetRGBA(uint8_t vr, uint8_t vg, uint8_t vb, uint8_t va = 0xFF) { - r = vr; - g = vg; - b = vb; - a = va; -} - void Color::SetRGB(uint8_t vr, uint8_t vg, uint8_t vb) { r = vr; g = vg; diff --git a/quicktex/Color.h b/quicktex/Color.h index 3d2fc8d..c9cf2f1 100644 --- a/quicktex/Color.h +++ b/quicktex/Color.h @@ -66,9 +66,6 @@ class Color { operator Vector4Int() const; friend Vector4Int operator-(const Color &lhs, const Color &rhs); - void SetRGBA(uint8_t vr, uint8_t vg, uint8_t vb, uint8_t va); - void SetRGBA(const Color &other) { SetRGBA(other.r, other.g, other.b, other.a); } - void SetRGB(uint8_t vr, uint8_t vg, uint8_t vb); void SetRGB(const Color &other) { SetRGB(other.r, other.g, other.b); } diff --git a/quicktex/s3tc/bc1/BC1Block.h b/quicktex/s3tc/bc1/BC1Block.h index 19f53e9..e58af8f 100644 --- a/quicktex/s3tc/bc1/BC1Block.h +++ b/quicktex/s3tc/bc1/BC1Block.h @@ -35,39 +35,40 @@ class alignas(8) BC1Block { static constexpr int Height = 4; using SelectorArray = std::array, Height>; - using ColorPair = std::tuple; + using ColorPair = std::pair; constexpr BC1Block() { static_assert(sizeof(BC1Block) == 8); static_assert(sizeof(std::array) == 8 * 10); - SetColor0Raw(0); - SetColor1Raw(0); - SetSelectorsSolid(0); + static_assert(alignof(BC1Block) >= 8); + _color0 = _color1 = {0, 0}; + _selectors = {0, 0, 0, 0}; } - constexpr BC1Block(Color color0, Color color1, const SelectorArray& selectors) { + BC1Block(Color color0, Color color1, const SelectorArray& selectors) { SetColor0(color0); SetColor1(color1); SetSelectors(selectors); } - constexpr BC1Block(Color color0, Color color1, uint8_t solid_mask) { - SetColor0(color0); - SetColor1(color1); - SetSelectorsSolid(solid_mask); + BC1Block(uint16_t ep0, uint16_t ep1, const SelectorArray& selectors) { + SetColor0Raw(ep0); + SetColor1Raw(ep1); + SetSelectors(selectors); } - uint16_t GetColor0Raw() const { return static_cast(_color_0[0] | (_color_0[1] << 8U)); } - uint16_t GetColor1Raw() const { return static_cast(_color_1[0] | (_color_1[1] << 8U)); } - void SetColor0Raw(uint16_t c) { - _color_0[0] = c & 0xFF; - _color_0[1] = (c >> 8) & 0xFF; - } - void SetColor1Raw(uint16_t c) { - _color_1[0] = c & 0xFF; - _color_1[1] = (c >> 8) & 0xFF; + BC1Block(uint16_t ep0, uint16_t ep1, uint8_t solid_mask) { + SetColor0Raw(ep0); + SetColor1Raw(ep1); + _selectors.fill(solid_mask); } + constexpr uint16_t GetColor0Raw() const { return Pack(_color0); } + constexpr uint16_t GetColor1Raw() const { return Pack(_color1); } + + void SetColor0Raw(uint16_t c) { _color0 = Unpack(c); } + void SetColor1Raw(uint16_t c) { _color1 = Unpack(c); } + Color GetColor0() const { return Color::Unpack565(GetColor0Raw()); } Color GetColor1() const { return Color::Unpack565(GetColor1Raw()); } ColorPair GetColors() const { return {GetColor0(), GetColor1()}; } @@ -75,37 +76,23 @@ class alignas(8) BC1Block { void SetColor0(Color c) { SetColor0Raw(c.Pack565()); } void SetColor1(Color c) { SetColor1Raw(c.Pack565()); } void SetColors(ColorPair cs) { - SetColor0(std::get<0>(cs)); - SetColor1(std::get<1>(cs)); + SetColor0(cs.first); + SetColor1(cs.second); } - bool Is3Color() const { return GetColor0Raw() <= GetColor1Raw(); } + constexpr SelectorArray GetSelectors() const { return MapArray(_selectors, Unpack); } - SelectorArray GetSelectors() const { - SelectorArray unpacked; - for (int i = 0; i < Height; i++) { unpacked[i] = Unpack(_selectors[i]); } - return unpacked; - } + void SetSelectors(const SelectorArray& unpacked) { _selectors = MapArray(unpacked, Pack); } - void SetSelectors(const SelectorArray& unpacked) { - for (int i = 0; i < Height; i++) { _selectors[i] = Pack(unpacked[i]); } - } + constexpr bool Is3Color() const { return GetColor0Raw() <= GetColor1Raw(); } - /** - * Set every row of selectors to the same 8-bit mask. useful for solid-color blocks - * @param mask the 8-bit mask to use for each row - */ - void SetSelectorsSolid(uint8_t mask) { - for (int i = 0; i < Height; i++) _selectors[i] = mask; - } - - constexpr static inline size_t EndpointSize = 2; // in bytes - constexpr static inline size_t SelectorSize = 4; // in bytes - constexpr static inline uint8_t SelectorBits = 2; // in bits + constexpr static inline size_t EndpointSize = 2; // in bytes + constexpr static inline size_t SelectorSize = 4; // in bytes + constexpr static inline uint8_t SelectorBits = 2; // in bits private: - std::array _color_0; - std::array _color_1; + std::array _color0; + std::array _color1; std::array _selectors; }; } // namespace quicktex::s3tc \ No newline at end of file diff --git a/quicktex/s3tc/bc1/BC1Encoder.cpp b/quicktex/s3tc/bc1/BC1Encoder.cpp index 742ccde..31974e9 100644 --- a/quicktex/s3tc/bc1/BC1Encoder.cpp +++ b/quicktex/s3tc/bc1/BC1Encoder.cpp @@ -43,9 +43,6 @@ namespace quicktex::s3tc { -using CBlock = ColorBlock<4, 4>; -using BlockMetrics = CBlock::Metrics; - // constructors BC1Encoder::BC1Encoder(unsigned int level, ColorMode color_mode, InterpolatorPtr interpolator) : _interpolator(interpolator), _color_mode(color_mode) { @@ -347,7 +344,6 @@ BC1Block BC1Encoder::EncodeBlock(const ColorBlock<4, 4> &pixels) const { // Private methods BC1Block BC1Encoder::WriteBlockSolid(Color color) const { - BC1Block block; uint8_t mask = 0xAA; // 2222 uint16_t min16, max16; @@ -394,17 +390,13 @@ BC1Block BC1Encoder::WriteBlockSolid(Color color) const { } } - block.SetColor0Raw(max16); - block.SetColor1Raw(min16); - block.SetSelectorsSolid(mask); - return block; + return BC1Block(max16, min16, mask); } BC1Block BC1Encoder::WriteBlock(EncodeResults &result) const { - BC1Block block; BC1Block::SelectorArray selectors; - uint16_t color1 = result.low.Pack565Unscaled(); - uint16_t color0 = result.high.Pack565Unscaled(); + uint16_t ep1 = result.low.Pack565Unscaled(); + uint16_t ep0 = result.high.Pack565Unscaled(); std::array lut; assert(result.color_mode != ColorMode::Incomplete); @@ -412,31 +404,31 @@ BC1Block BC1Encoder::WriteBlock(EncodeResults &result) const { if ((bool)(result.color_mode & ColorMode::FourColor)) { lut = {1, 3, 2, 0}; - if (color1 > color0) { - std::swap(color1, color0); + if (ep1 > ep0) { + std::swap(ep1, ep0); lut = {0, 2, 3, 1}; - } else if (color1 == color0) { - if (color1 > 0) { - color1--; + } else if (ep1 == ep0) { + if (ep1 > 0) { + ep1--; lut = {0, 0, 0, 0}; } else { - assert(color1 == 0 && color0 == 0); - color0 = 1; - color1 = 0; + assert(ep1 == 0 && ep0 == 0); + ep0 = 1; + ep1 = 0; lut = {1, 1, 1, 1}; } } - assert(color0 > color1); + assert(ep0 > ep1); } else { lut = {1, 2, 0, 3}; - if (color1 < color0) { - std::swap(color1, color0); + if (ep1 < ep0) { + std::swap(ep1, ep0); lut = {0, 2, 1, 3}; } - assert(color0 <= color1); + assert(ep0 <= ep1); } for (unsigned i = 0; i < 16; i++) { @@ -446,10 +438,7 @@ BC1Block BC1Encoder::WriteBlock(EncodeResults &result) const { if (result.color_mode == ColorMode::ThreeColor) { assert(selectors[y][x] != 3); } } - block.SetColor0Raw(color0); - block.SetColor1Raw(color1); - block.SetSelectors(selectors); - return block; + return BC1Block(ep0, ep1, selectors); } void BC1Encoder::FindEndpointsSingleColor(EncodeResults &result, Color color, bool is_3color) const { @@ -474,7 +463,7 @@ void BC1Encoder::FindEndpointsSingleColor(EncodeResults &result, const CBlock &p FindEndpointsSingleColor(result, color, is_3color); result.error = 0; - for (unsigned i = 0; i < 16; i++) { + for (int i = 0; i < 16; i++) { Vector4Int pixel_vector = (Vector4Int)pixels.Get(i); auto diff = pixel_vector - result_vector; result.error += diff.SqrMag(); @@ -521,7 +510,7 @@ void BC1Encoder::FindEndpoints(EncodeResults &result, const CBlock &pixels, cons std::array sums_xy; - for (unsigned i = 0; i < 16; i++) { + for (int i = 0; i < 16; i++) { auto val = pixels.Get(i); for (unsigned c = 0; c < 3; c++) { sums_xy[c] += val[chan0] * val[c]; } } @@ -579,7 +568,7 @@ void BC1Encoder::FindEndpoints(EncodeResults &result, const CBlock &pixels, cons // Select the correct diagonal across the bounding box int icov_xz = 0, icov_yz = 0; - for (unsigned i = 0; i < 16; i++) { + for (int i = 0; i < 16; i++) { int b = (int)pixels.Get(i).b - metrics.avg.b; icov_xz += b * (int)pixels.Get(i).r - metrics.avg.r; icov_yz += b * (int)pixels.Get(i).g - metrics.avg.g; @@ -604,7 +593,7 @@ void BC1Encoder::FindEndpoints(EncodeResults &result, const CBlock &pixels, cons } int icov_xz = 0, icov_yz = 0; - for (unsigned i = 0; i < 16; i++) { + for (int i = 0; i < 16; i++) { int b = (int)pixels.Get(i).b - metrics.avg.b; icov_xz += b * (int)pixels.Get(i).r - metrics.avg.r; icov_yz += b * (int)pixels.Get(i).g - metrics.avg.g; @@ -625,7 +614,7 @@ void BC1Encoder::FindEndpoints(EncodeResults &result, const CBlock &pixels, cons Vector4 axis = {306, 601, 117}; // Luma vector Matrix4x4 covariance = Matrix4x4::Identity(); - for (unsigned i = 0; i < 16; i++) { + for (int i = 0; i < 16; i++) { auto val = pixels.Get(i); if (ignore_black && val.IsBlack()) continue; @@ -661,9 +650,9 @@ void BC1Encoder::FindEndpoints(EncodeResults &result, const CBlock &pixels, cons float min_dot = INFINITY; float max_dot = -INFINITY; - unsigned min_index = 0, max_index = 0; + int min_index = 0, max_index = 0; - for (unsigned i = 0; i < 16; i++) { + for (int i = 0; i < 16; i++) { auto val = pixels.Get(i); if (ignore_black && val.IsBlack()) continue; @@ -709,11 +698,11 @@ template void BC1Encoder::FindSelectors(EncodeResults if (error_mode == ErrorMode::None || error_mode == ErrorMode::Faster) { Vector4Int axis = color_vectors[3] - color_vectors[0]; std::array dots; - for (unsigned i = 0; i < 4; i++) { dots[i] = axis.Dot(color_vectors[i]); } + for (int i = 0; i < 4; i++) { dots[i] = axis.Dot(color_vectors[i]); } int t0 = dots[0] + dots[1], t1 = dots[1] + dots[2], t2 = dots[2] + dots[3]; axis *= 2; - for (unsigned i = 0; i < 16; i++) { + for (int i = 0; i < 16; i++) { Vector4Int pixel_vector = Vector4Int::FromColorRGB(pixels.Get(i)); int dot = axis.Dot(pixel_vector); uint8_t level = (dot <= t0) + (dot < t1) + (dot < t2); @@ -734,7 +723,7 @@ template void BC1Encoder::FindSelectors(EncodeResults Vector4Int axis = color_vectors[3] - color_vectors[0]; const float f = 4.0f / ((float)axis.SqrMag() + .00000125f); - for (unsigned i = 0; i < 16; i++) { + for (int i = 0; i < 16; i++) { Vector4Int pixel_vector = Vector4Int::FromColorRGB(pixels.Get(i)); auto diff = pixel_vector - color_vectors[0]; float sel_f = (float)diff.Dot(axis) * f + 0.5f; @@ -762,7 +751,7 @@ template void BC1Encoder::FindSelectors(EncodeResults } else if (error_mode == ErrorMode::Full) { unsigned max_sel = (bool)(M == ColorMode::ThreeColor) ? 3 : 4; - for (unsigned i = 0; i < 16; i++) { + for (int i = 0; i < 16; i++) { unsigned best_error = UINT_MAX; uint8_t best_sel = 0; Vector4Int pixel_vector = Vector4Int::FromColorRGB(pixels.Get(i)); @@ -800,7 +789,7 @@ template bool BC1Encoder::RefineEndpointsLS(EncodeResu Vector4 q00 = {0, 0, 0}; Vector4 matrix = Vector4(0); - for (unsigned i = 0; i < 16; i++) { + for (int i = 0; i < 16; i++) { const Color color = pixels.Get(i); const uint8_t sel = result.selectors[i]; diff --git a/quicktex/s3tc/bc3/BC3Block.h b/quicktex/s3tc/bc3/BC3Block.h index e4be502..0dc8d98 100644 --- a/quicktex/s3tc/bc3/BC3Block.h +++ b/quicktex/s3tc/bc3/BC3Block.h @@ -32,11 +32,12 @@ class alignas(8) BC3Block { constexpr BC3Block() { static_assert(sizeof(BC3Block) == 16); static_assert(sizeof(std::array) == 16 * 10); + static_assert(alignof(BC3Block) >= 8); alpha_block = BC4Block(); color_block = BC1Block(); } - constexpr BC3Block(const BC4Block &alpha, const BC1Block &color) { + BC3Block(const BC4Block &alpha, const BC1Block &color) { alpha_block = alpha; color_block = color; } diff --git a/quicktex/s3tc/bc4/BC4Block.h b/quicktex/s3tc/bc4/BC4Block.h index c589232..caeec74 100644 --- a/quicktex/s3tc/bc4/BC4Block.h +++ b/quicktex/s3tc/bc4/BC4Block.h @@ -24,9 +24,7 @@ #include #include -#include "../../Color.h" #include "../../util.h" -#include "../bc1/BC1Block.h" namespace quicktex::s3tc { @@ -41,55 +39,50 @@ class alignas(8) BC4Block { constexpr BC4Block() { static_assert(sizeof(BC4Block) == 8); static_assert(sizeof(std::array) == 8 * 10); + static_assert(alignof(BC4Block) >= 8); alpha0 = alpha1 = 0; - SetSelectorBits(0); + _selectors = {0, 0, 0, 0, 0, 0}; } - constexpr BC4Block(uint8_t valpha0, uint8_t valpha1, const SelectorArray& selectors) { + BC4Block(uint8_t valpha0, uint8_t valpha1, const SelectorArray& selectors) { alpha0 = valpha0; alpha1 = valpha1; SetSelectors(selectors); } - inline bool Is6Value() const { return alpha0 <= alpha1; } - - AlphaPair GetAlphas() const { return AlphaPair(alpha0, alpha1); } + constexpr AlphaPair GetAlphas() const { return AlphaPair(alpha0, alpha1); } void SetAlphas(AlphaPair as) { alpha0 = as.first; alpha1 = as.second; } - inline uint64_t GetSelectorBits() const { - auto packed = Pack(selectors); - assert(packed <= SelectorBitsMax); + constexpr uint64_t GetSelectorBits() const { + auto packed = Pack(_selectors); + assert(packed <= SelectorsPackedMax); return packed; } void SetSelectorBits(uint64_t packed) { - assert(packed <= SelectorBitsMax); - selectors = Unpack(packed); + assert(packed <= SelectorsPackedMax); + _selectors = Unpack(packed); } - SelectorArray GetSelectors() const { - SelectorArray unpacked; - auto rows = Unpack(GetSelectorBits()); - for (unsigned i = 0; i < Height; i++) { - auto row = Unpack(rows[i]); - unpacked[i] = row; - } - + constexpr SelectorArray GetSelectors() const { + auto rows = Unpack(GetSelectorBits()); + auto unpacked = MapArray(rows, Unpack); return unpacked; } void SetSelectors(const SelectorArray& unpacked) { - std::array rows; - for (int i = 0; i < Height; i++) { rows[i] = Pack(unpacked[i]); } - auto packed = Pack(rows); + auto rows = MapArray(unpacked, Pack); + auto packed = Pack(rows); SetSelectorBits(packed); } - static inline std::array GetValues6(uint32_t l, uint32_t h) { + constexpr bool Is6Value() const { return alpha0 <= alpha1; } + + static constexpr std::array GetValues6(unsigned l, unsigned h) { return {static_cast(l), static_cast(h), static_cast((l * 4 + h) / 5), @@ -100,7 +93,7 @@ class alignas(8) BC4Block { 255}; } - static inline std::array GetValues8(uint32_t l, uint32_t h) { + static constexpr std::array GetValues8(unsigned l, unsigned h) { return {static_cast(l), static_cast(h), static_cast((l * 6 + h) / 7), @@ -111,24 +104,16 @@ class alignas(8) BC4Block { static_cast((l + h * 6) / 7)}; } - static inline std::array GetValues(uint32_t l, uint32_t h) { - if (l > h) - return GetValues8(l, h); - else - return GetValues6(l, h); - } + static constexpr std::array GetValues(unsigned l, unsigned h) { return l > h ? GetValues8(l, h) : GetValues6(l, h); } - constexpr static inline size_t EndpointSize = 1; - constexpr static inline size_t SelectorSize = 6; - constexpr static inline uint8_t SelectorBits = 3; - constexpr static inline uint8_t SelectorValues = 1 << SelectorBits; - constexpr static inline uint8_t SelectorMask = SelectorValues - 1; - constexpr static inline uint64_t SelectorBitsMax = (1ULL << (8U * SelectorSize)) - 1U; + static constexpr size_t SelectorSize = 6; + static constexpr uint8_t SelectorBits = 3; + static constexpr uint64_t SelectorsPackedMax = (1ULL << (8U * SelectorSize)) - 1U; uint8_t alpha0; uint8_t alpha1; private: - std::array selectors; + std::array _selectors; }; } // namespace quicktex::s3tc diff --git a/quicktex/s3tc/bc4/_bindings.cpp b/quicktex/s3tc/bc4/_bindings.cpp index 3c39dd8..b9e5c5f 100644 --- a/quicktex/s3tc/bc4/_bindings.cpp +++ b/quicktex/s3tc/bc4/_bindings.cpp @@ -47,7 +47,7 @@ void InitBC4(py::module_ &s3tc) { bc4_block.doc() = "A single BC4 block."; bc4_block.def(py::init<>()); - bc4_block.def(py::init(), "endpoint0"_a, "endpoint1"_a, "selectors"_a, R"doc( + bc4_block.def(py::init(), "endpoint0"_a, "endpoint1"_a, "selectors"_a, R"doc( __init__(self, endpoint0: int, endpoint1: int, selectors: List[List[int]]) -> None Create a new BC4Block with the specified endpoints and selectors. diff --git a/quicktex/s3tc/bc5/BC5Block.h b/quicktex/s3tc/bc5/BC5Block.h index c350194..6d0105c 100644 --- a/quicktex/s3tc/bc5/BC5Block.h +++ b/quicktex/s3tc/bc5/BC5Block.h @@ -31,10 +31,11 @@ class alignas(8) BC5Block { constexpr BC5Block() { static_assert(sizeof(BC5Block) == 16); static_assert(sizeof(std::array) == 16 * 10); + static_assert(alignof(BC5Block) >= 8); chan0_block = chan1_block = BC4Block(); } - constexpr BC5Block(const BC4Block &chan0, const BC4Block &chan1) { + BC5Block(const BC4Block &chan0, const BC4Block &chan1) { chan0_block = chan0; chan1_block = chan1; } diff --git a/quicktex/util.h b/quicktex/util.h index 2387d32..e001a06 100644 --- a/quicktex/util.h +++ b/quicktex/util.h @@ -100,6 +100,14 @@ template constexpr std::array ExpandAr return res; } +template constexpr auto MapArray(const std::array &input, Fn&& op) { + std::array, N> output; + for (unsigned i = 0; i < N; i++) { + output[i] = op(input[i]); + } + return output; +} + template constexpr S scale8To5(S v) { auto v2 = v * 31 + 128; return static_cast((v2 + (v2 >> 8)) >> 8); @@ -159,7 +167,7 @@ template std::string Format(const char *str, const Args &...a for (unsigned i = 0; i < values.size(); i++) { auto key = "{" + std::to_string(i) + "}"; auto value = values[i]; - while(true) { + while (true) { size_t where = output.find(key); if (where == output.npos) break; output.replace(where, key.length(), value);