diff --git a/CMakeLists.txt b/CMakeLists.txt index 2a5395f..cae5f43 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -34,6 +34,8 @@ target_compile_features(test_rgbcx PUBLIC cxx_std_20 c_std_11) set_project_warnings(python_rgbcx) set_project_warnings(test_rgbcx) +set(CMAKE_CXX_FLAGS_RELEASE "${CMAKE_CXX_FLAGS_RELEASE} -O3") + if (CMAKE_CXX_COMPILER_ID MATCHES ".*Clang") set(CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} -stdlib=libc++ -lc++abi") set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -stdlib=libc++ -fsanitize=undefined") diff --git a/src/BC1/BC1Decoder.cpp b/src/BC1/BC1Decoder.cpp index 4b395f6..34bda12 100644 --- a/src/BC1/BC1Decoder.cpp +++ b/src/BC1/BC1Decoder.cpp @@ -24,9 +24,9 @@ #include +#include "../BlockView.h" #include "../Color.h" -#include "../ColorBlock.h" -#include "../interpolator.h" +#include "../Interpolator.h" #include "../ndebug.h" #include "BC1Block.h" @@ -44,9 +44,9 @@ void BC1Decoder::DecodeBlock(Color4x4 dest, BC1Block *const block) const noexcep assert(selector < 4); assert((color.a == 0 && selector == 3 && l <= h) || color.a == UINT8_MAX); if (_write_alpha) { - dest[y][x].SetRGBA(color); + dest.get(x, y).SetRGBA(color); } else { - dest[y][x].SetRGB(color); + dest.get(x, y).SetRGB(color); } } } diff --git a/src/BC1/BC1Decoder.h b/src/BC1/BC1Decoder.h index deca5bc..72be6ac 100644 --- a/src/BC1/BC1Decoder.h +++ b/src/BC1/BC1Decoder.h @@ -22,8 +22,8 @@ #include #include "../BlockDecoder.h" -#include "../ColorBlock.h" -#include "../interpolator.h" +#include "../BlockView.h" +#include "../Interpolator.h" #include "../ndebug.h" #include "BC1Block.h" diff --git a/src/BC3/BC3Decoder.cpp b/src/BC3/BC3Decoder.cpp index 5ac24e1..51fd888 100644 --- a/src/BC3/BC3Decoder.cpp +++ b/src/BC3/BC3Decoder.cpp @@ -21,7 +21,7 @@ #include "../BC1/BC1Decoder.h" #include "../BC4/BC4Decoder.h" -#include "../ColorBlock.h" +#include "../BlockView.h" #include "../ndebug.h" namespace rgbcx { diff --git a/src/BC3/BC3Decoder.h b/src/BC3/BC3Decoder.h index 40c478e..71f546d 100644 --- a/src/BC3/BC3Decoder.h +++ b/src/BC3/BC3Decoder.h @@ -24,8 +24,8 @@ #include "../BC1/BC1Decoder.h" #include "../BC4/BC4Decoder.h" #include "../BlockDecoder.h" -#include "../ColorBlock.h" -#include "../interpolator.h" +#include "../BlockView.h" +#include "../Interpolator.h" #include "../ndebug.h" #include "BC3Block.h" diff --git a/src/BC4/BC4Decoder.cpp b/src/BC4/BC4Decoder.cpp index ca54a31..b64e81d 100644 --- a/src/BC4/BC4Decoder.cpp +++ b/src/BC4/BC4Decoder.cpp @@ -23,12 +23,12 @@ #include // for array -#include "../Color.h" // for Color -#include "../ColorBlock.h" // for ColorBlock -#include "../ndebug.h" // for ndebug +#include "../BlockView.h" // for ColorBlock +#include "../Color.h" // for Color +#include "../ndebug.h" // for ndebug #include "BC4Block.h" -void rgbcx::BC4Decoder::DecodeBlock(Color4x4 dest, BC4Block *const block, size_t channel) const noexcept(ndebug) { +void rgbcx::BC4Decoder::DecodeBlock(Byte4x4 dest, BC4Block *const block) const noexcept(ndebug) { auto l = block->GetLowAlpha(); auto h = block->GetHighAlpha(); @@ -39,7 +39,7 @@ void rgbcx::BC4Decoder::DecodeBlock(Color4x4 dest, BC4Block *const block, size_t for (unsigned x = 0; x < 4; x++) { const auto selector = selectors[y][x]; assert(selector < 8); - dest[y][x][channel] = values[selector]; + dest.set(x, y, values[selector]); } } } diff --git a/src/BC4/BC4Decoder.h b/src/BC4/BC4Decoder.h index 5509de9..1316c16 100644 --- a/src/BC4/BC4Decoder.h +++ b/src/BC4/BC4Decoder.h @@ -22,21 +22,23 @@ #include #include "../BlockDecoder.h" -#include "../ColorBlock.h" +#include "../BlockView.h" #include "../ndebug.h" #include "BC4Block.h" namespace rgbcx { class BC4Decoder : public BlockDecoder { public: - BC4Decoder(size_t channel = 3) : _channel(channel) {} + using Byte4x4 = BlockView; + BC4Decoder(uint8_t channel = 3) : _channel(channel) { assert(channel < 4U); } - void DecodeBlock(Color4x4 dest, BC4Block *const block) const noexcept(ndebug) override { DecodeBlock(dest, block, _channel); } - void DecodeBlock(Color4x4 dest, BC4Block *const block, size_t channel) const noexcept(ndebug); + void DecodeBlock(Color4x4 dest, BC4Block *const block) const noexcept(ndebug) override { DecodeBlock(dest.GetChannel(_channel), block); } + void DecodeBlock(Color4x4 dest, BC4Block *const block, uint8_t channel) const noexcept(ndebug) { DecodeBlock(dest.GetChannel(channel), block); } + void DecodeBlock(Byte4x4 dest, BC4Block *const block) const noexcept(ndebug); - constexpr size_t GetChannel() const { return _channel; } + constexpr uint8_t GetChannel() const { return _channel; } private: - const size_t _channel; + const uint8_t _channel; }; } // namespace rgbcx diff --git a/src/BC4/BC4Encoder.cpp b/src/BC4/BC4Encoder.cpp new file mode 100644 index 0000000..295184e --- /dev/null +++ b/src/BC4/BC4Encoder.cpp @@ -0,0 +1,22 @@ +/* Python-rgbcx Texture Compression Library + Copyright (C) 2021 Andrew Cassidy + Partially derived from rgbcx.h written by Richard Geldreich + and licenced under the public domain + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU Lesser General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public License + along with this program. If not, see . + */ + +#include "BC4Encoder.h" + +namespace rgbcx {} // namespace rgbcx \ No newline at end of file diff --git a/src/BC4/BC4Encoder.h b/src/BC4/BC4Encoder.h new file mode 100644 index 0000000..624939b --- /dev/null +++ b/src/BC4/BC4Encoder.h @@ -0,0 +1,25 @@ +/* Python-rgbcx Texture Compression Library + Copyright (C) 2021 Andrew Cassidy + Partially derived from rgbcx.h written by Richard Geldreich + and licenced under the public domain + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU Lesser General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public License + along with this program. If not, see . + */ + +#pragma once + +namespace rgbcx { + +class BC4Encoder {}; +} // namespace rgbcx diff --git a/src/BC5/BC5Decoder.cpp b/src/BC5/BC5Decoder.cpp index 2f4a43d..0e21c76 100644 --- a/src/BC5/BC5Decoder.cpp +++ b/src/BC5/BC5Decoder.cpp @@ -20,7 +20,7 @@ #include "BC5Decoder.h" #include "../BC4/BC4Decoder.h" -#include "../ColorBlock.h" +#include "../BlockView.h" #include "../ndebug.h" namespace rgbcx { diff --git a/src/BC5/BC5Decoder.h b/src/BC5/BC5Decoder.h index bf70b52..8feaf44 100644 --- a/src/BC5/BC5Decoder.h +++ b/src/BC5/BC5Decoder.h @@ -20,11 +20,12 @@ #pragma once #include + #include #include "../BC4/BC4Decoder.h" #include "../BlockDecoder.h" -#include "../ColorBlock.h" +#include "../BlockView.h" #include "../ndebug.h" #include "BC5Block.h" @@ -33,8 +34,12 @@ class BC5Decoder : public BlockDecoder { public: using BC4DecoderPtr = std::shared_ptr; - BC5Decoder(size_t chan0 = 0, size_t chan1 = 1) : BC5Decoder(std::make_shared(), chan0, chan1) {} - BC5Decoder(BC4DecoderPtr bc4_decoder, size_t chan0 = 0, size_t chan1 = 1) : _bc4_decoder(bc4_decoder), _chan0(chan0), _chan1(chan1) {} + BC5Decoder(uint8_t chan0 = 0, uint8_t chan1 = 1) : BC5Decoder(std::make_shared(), chan0, chan1) {} + BC5Decoder(BC4DecoderPtr bc4_decoder, uint8_t chan0 = 0, uint8_t chan1 = 1) : _bc4_decoder(bc4_decoder), _chan0(chan0), _chan1(chan1) { + assert(chan0 < 4U); + assert(chan1 < 4U); + assert(chan0 != chan1); + } void DecodeBlock(Color4x4 dest, BC5Block *const block) const noexcept(ndebug) override; @@ -43,7 +48,7 @@ class BC5Decoder : public BlockDecoder { private: const BC4DecoderPtr _bc4_decoder; - const size_t _chan0; - const size_t _chan1; + const uint8_t _chan0; + const uint8_t _chan1; }; } // namespace rgbcx diff --git a/src/BlockDecoder.h b/src/BlockDecoder.h index a3825a9..c1582c5 100644 --- a/src/BlockDecoder.h +++ b/src/BlockDecoder.h @@ -24,19 +24,20 @@ #include #include -#include "ColorBlock.h" -#include "util.h" +#include "BlockView.h" #include "ndebug.h" +#include "util.h" namespace rgbcx { template class BlockDecoder { public: - using DecodedBlock = ColorBlock; + using DecodedBlock = ColorBlockView; using EncodedBlock = B; BlockDecoder() noexcept = default; virtual ~BlockDecoder() noexcept = default; + virtual void DecodeBlock(DecodedBlock dest, EncodedBlock *const block) const noexcept(ndebug) = 0; void DecodeRow(std::span dests, std::span blocks) { @@ -69,8 +70,9 @@ template class BlockDecoder { auto rows = std::array(); for (unsigned i = 0; i < M; i++) { rows[i] = reinterpret_cast(&image[top_left + i * image_width]); } - // auto dest = DecodedBlock(image, image_width, image_height, x, y); - DecodeBlock(DecodedBlock(rows), &blocks[x + block_width * y]); + auto dest = DecodedBlock(&image[top_left],image_width); + + DecodeBlock(dest, &blocks[x + block_width * y]); } } } diff --git a/src/BlockEncoder.h b/src/BlockEncoder.h index 7f462a4..9966055 100644 --- a/src/BlockEncoder.h +++ b/src/BlockEncoder.h @@ -21,13 +21,13 @@ #include -#include "ColorBlock.h" +#include "BlockView.h" namespace rgbcx { template class BlockEncoder { public: - using DecodedBlock = ColorBlock; + using DecodedBlock = BlockView; using EncodedBlock = B; virtual void EncodeBlock(EncodedBlock *dest, DecodedBlock *const pixels) const = 0; }; diff --git a/src/BlockView.h b/src/BlockView.h new file mode 100644 index 0000000..6193631 --- /dev/null +++ b/src/BlockView.h @@ -0,0 +1,118 @@ +/* Python-rgbcx Texture Compression Library + Copyright (C) 2021 Andrew Cassidy + Partially derived from rgbcx.h written by Richard Geldreich + and licenced under the public domain + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU Lesser General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public License + along with this program. If not, see . + */ + +#pragma once + +#include +#include +#include +#include +#include + +#include "Color.h" +#include "ndebug.h" + +namespace rgbcx { +template class RowView { + public: + RowView(S *start, int pixel_stride = 1) : start(start), pixel_stride(pixel_stride) {} + + constexpr S &operator[](size_t index) noexcept(ndebug) { + assert(index < N); + return start[index * pixel_stride]; + } + constexpr const S &operator[](size_t index) const noexcept(ndebug) { + assert(index < N); + return start[index * pixel_stride]; + } + + constexpr int size() noexcept { return N; } + + S *const start; + const int pixel_stride; +}; + +template class BlockView { + public: + using Row = RowView; + + BlockView(S *start, int row_stride = N, int pixel_stride = 1) : start(start), row_stride(row_stride), pixel_stride(pixel_stride) {} + + constexpr Row operator[](size_t index) noexcept(ndebug) { + assert(index < M); + return RowView(&start[index * row_stride], pixel_stride); + } + + constexpr int width() noexcept { return N; } + constexpr int height() noexcept { return M; } + constexpr int size() noexcept { return N * M; } + + constexpr S &get(unsigned x, unsigned y) noexcept(ndebug) { + assert(x < N); + assert(y < M); + return start[(row_stride * y) + (pixel_stride * x)]; + } + + constexpr S get(unsigned x, unsigned y) const noexcept(ndebug) { + assert(x < N); + assert(y < M); + return start[(row_stride * y) + (pixel_stride * x)]; + } + + constexpr void set(unsigned x, unsigned y, S value) noexcept(ndebug) { + assert(x < N); + assert(y < M); + start[(row_stride * y) + (pixel_stride * x)] = value; + } + + constexpr std::array flatten() noexcept { + std::array result; + for (unsigned x = 0; x < N; x++) { + for (unsigned y = 0; y < M; y++) { result[x + (N * y)] = start[(row_stride * y) + (pixel_stride * x)]; } + } + return result; + } + + S *const start; + const int row_stride; + const int pixel_stride; +}; + +template class ColorBlockView : public BlockView { + public: + using Base = BlockView; + using ChannelView = BlockView; + + ColorBlockView(Color *start, int row_stride = N, int pixel_stride = 1) : Base(start, row_stride, pixel_stride) {} + + constexpr ChannelView GetChannel(uint8_t index) noexcept(ndebug) { + assert(index < 4U); + auto channelStart = reinterpret_cast(Base::start) + index; + return ChannelView(channelStart, Base::row_stride * 4, Base::pixel_stride * 4); + } + + constexpr ChannelView GetR() noexcept(ndebug) { return GetChannel(0); }; + constexpr ChannelView GetG() noexcept(ndebug) { return GetChannel(1); }; + constexpr ChannelView GetB() noexcept(ndebug) { return GetChannel(2); }; + constexpr ChannelView GetA() noexcept(ndebug) { return GetChannel(3); }; +}; + +using Color4x4 = ColorBlockView<4, 4>; + +} // namespace rgbcx \ No newline at end of file diff --git a/src/ColorBlock.h b/src/ColorBlock.h deleted file mode 100644 index dfb9a3b..0000000 --- a/src/ColorBlock.h +++ /dev/null @@ -1,57 +0,0 @@ -/* Python-rgbcx Texture Compression Library - Copyright (C) 2021 Andrew Cassidy - Partially derived from rgbcx.h written by Richard Geldreich - and licenced under the public domain - - This program is free software: you can redistribute it and/or modify - it under the terms of the GNU Lesser General Public License as published by - the Free Software Foundation, either version 3 of the License, or - (at your option) any later version. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU Lesser General Public License for more details. - - You should have received a copy of the GNU Lesser General Public License - along with this program. If not, see . - */ - -#pragma once - -#include -#include -#include -#include -#include - -#include "Color.h" - -template class ColorRow { - public: - constexpr Color &operator[](size_t n) noexcept { return _colors[n]; } - constexpr const Color &operator[](size_t n) const noexcept { return _colors[n]; } - - constexpr int size() noexcept { return N; } - - private: - std::array _colors; -}; - -template class ColorBlock { - public: - using Row = ColorRow; - constexpr Row &operator[](size_t n) noexcept { return *_rows[n]; } - constexpr const Row &operator[](size_t n) const noexcept { return *_rows[n]; } - - constexpr int width() noexcept { return N; } - constexpr int height() noexcept { return M; } - constexpr int size() noexcept { return N * M; } - - ColorBlock(const std::array &Rows) : _rows(Rows) {} - - private: - std::array _rows; -}; - -using Color4x4 = ColorBlock<4, 4>; diff --git a/src/interpolator.cpp b/src/Interpolator.cpp similarity index 99% rename from src/interpolator.cpp rename to src/Interpolator.cpp index 5fe13ac..9262502 100644 --- a/src/interpolator.cpp +++ b/src/Interpolator.cpp @@ -17,7 +17,7 @@ along with this program. If not, see . */ -#include "interpolator.h" +#include "Interpolator.h" #include #include diff --git a/src/interpolator.h b/src/Interpolator.h similarity index 100% rename from src/interpolator.h rename to src/Interpolator.h diff --git a/src/rgbcx.h b/src/rgbcx.h index da92b70..662f512 100644 --- a/src/rgbcx.h +++ b/src/rgbcx.h @@ -59,7 +59,7 @@ #include "BC3/BC3Block.h" #include "BC4/BC4Block.h" #include "BC5/BC5Block.h" -#include "interpolator.h" +#include "Interpolator.h" // By default, the table used to accelerate cluster fit on 4 color blocks uses a 969x128 entry table. // To reduce the executable size, set RGBCX_USE_SMALLER_TABLES to 1, which selects the smaller 969x32 entry table. diff --git a/src/test/test.cpp b/src/test/test.cpp index c43824f..5c98fcd 100644 --- a/src/test/test.cpp +++ b/src/test/test.cpp @@ -742,6 +742,8 @@ int main(int argc, char *argv[]) { printf("Wrote DDS file %s\n", dds_output_filename.c_str()); if ((!no_output_png) && (png_output_filename.size())) { + clock_t start_decode_t = clock(); + image_u8 unpacked_image(source_image.width(), source_image.height()); bool punchthrough_flag = false; @@ -801,6 +803,9 @@ int main(int argc, char *argv[]) { // unpacked_image.set_block(bx, by, 4, 4, unpacked_pixels); // } // bx // } // by + clock_t end_decode_t = clock(); + printf("\nDecode time: %f secs\n", (double)(end_decode_t - start_decode_t) / CLOCKS_PER_SEC); + if ((punchthrough_flag) && (dxgi_format == DXGI_FORMAT_BC3_UNORM)) fprintf(stderr, "Warning: BC3 mode selected, but rgbcx::unpack_bc3() returned one or more blocks using 3-color mode!\n");