├── .bazelrc ├── .gitignore ├── BUILD.bazel ├── CMakeLists.txt ├── CONTRIBUTING.md ├── GoogleTest-CMakeLists.txt.in ├── LICENSE ├── README.md ├── WORKSPACE ├── cmake-format.json ├── include └── astc-codec │ └── astc-codec.h ├── src ├── .clang-format ├── base │ ├── BUILD.bazel │ ├── CMakeLists.txt │ ├── bit_stream.h │ ├── bottom_n.h │ ├── math_utils.h │ ├── optional.h │ ├── string_utils.h │ ├── test │ │ ├── bit_stream_test.cpp │ │ ├── bottom_n_test.cpp │ │ ├── math_utils_test.cpp │ │ ├── optional_test.cpp │ │ ├── string_utils_test.cpp │ │ ├── type_traits_test.cpp │ │ └── uint128_test.cpp │ ├── type_traits.h │ ├── uint128.h │ └── utils.h └── decoder │ ├── BUILD.bazel │ ├── CMakeLists.txt │ ├── astc_file.cc │ ├── astc_file.h │ ├── codec.cc │ ├── codec.h │ ├── endpoint_codec.cc │ ├── endpoint_codec.h │ ├── footprint.cc │ ├── footprint.h │ ├── integer_sequence_codec.cc │ ├── integer_sequence_codec.h │ ├── intermediate_astc_block.cc │ ├── intermediate_astc_block.h │ ├── logical_astc_block.cc │ ├── logical_astc_block.h │ ├── partition.cc │ ├── partition.h │ ├── physical_astc_block.cc │ ├── physical_astc_block.h │ ├── quantization.cc │ ├── quantization.h │ ├── test │ ├── astc_fuzzer.cc │ ├── codec_test.cc │ ├── endpoint_codec_test.cc │ ├── footprint_test.cc │ ├── image_utils.h │ ├── integer_sequence_codec_test.cc │ ├── intermediate_astc_block_test.cc │ ├── logical_astc_block_test.cc │ ├── partition_test.cc │ ├── physical_astc_block_test.cc │ ├── quantization_test.cc │ └── weight_infill_test.cc │ ├── testdata │ ├── atlas_small_4x4.astc │ ├── atlas_small_4x4.bmp │ ├── atlas_small_5x5.astc │ ├── atlas_small_5x5.bmp │ ├── atlas_small_6x6.astc │ ├── atlas_small_6x6.bmp │ ├── atlas_small_8x8.astc │ ├── atlas_small_8x8.bmp │ ├── checkerboard.astc │ ├── checkered_10.astc │ ├── checkered_11.astc │ ├── checkered_12.astc │ ├── checkered_4.astc │ ├── checkered_5.astc │ ├── checkered_6.astc │ ├── checkered_7.astc │ ├── checkered_8.astc │ ├── checkered_9.astc │ ├── footprint_10x10.astc │ ├── footprint_10x10.bmp │ ├── footprint_10x5.astc │ ├── footprint_10x5.bmp │ ├── footprint_10x6.astc │ ├── footprint_10x6.bmp │ ├── footprint_10x8.astc │ ├── footprint_10x8.bmp │ ├── footprint_12x10.astc │ ├── footprint_12x10.bmp │ ├── footprint_12x12.astc │ ├── footprint_12x12.bmp │ ├── footprint_4x4.astc │ ├── footprint_4x4.bmp │ ├── footprint_5x4.astc │ ├── footprint_5x4.bmp │ ├── footprint_5x5.astc │ ├── footprint_5x5.bmp │ ├── footprint_6x5.astc │ ├── footprint_6x5.bmp │ ├── footprint_6x6.astc │ ├── footprint_6x6.bmp │ ├── footprint_8x5.astc │ ├── footprint_8x5.bmp │ ├── footprint_8x6.astc │ ├── footprint_8x6.bmp │ ├── footprint_8x8.astc │ ├── footprint_8x8.bmp │ ├── rgb_12x12.astc │ ├── rgb_12x12.bmp │ ├── rgb_4x4.astc │ ├── rgb_4x4.bmp │ ├── rgb_5x4.astc │ ├── rgb_5x4.bmp │ ├── rgb_6x6.astc │ ├── rgb_6x6.bmp │ ├── rgb_8x8.astc │ └── rgb_8x8.bmp │ ├── tools │ └── astc_inspector_cli.cc │ ├── types.h │ ├── weight_infill.cc │ └── weight_infill.h ├── third_party ├── BUILD └── honggfuzz.BUILD └── tools └── build-ci └── linux ├── build.sh ├── continuous.cfg └── presubmit.cfg /.bazelrc: -------------------------------------------------------------------------------- 1 | # For building with the clang-specific flavor of ASAN. 2 | build:clang-asan --client_env=CC=clang-5.0 3 | build:clang-asan --copt -g3 4 | build:clang-asan --copt -fsanitize=address 5 | build:clang-asan --linkopt -fsanitize=address 6 | build:clang-asan --copt -fno-omit-frame-pointer 7 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | bazel-* 2 | .bazelrc 3 | build 4 | .vs 5 | .vscode 6 | -------------------------------------------------------------------------------- /BUILD.bazel: -------------------------------------------------------------------------------- 1 | # Copyright 2018 Google LLC 2 | # 3 | # Licensed under the Apache License, Version 2.0 (the "License"); 4 | # you may not use this file except in compliance with the License. 5 | # You may obtain a copy of the License at 6 | # 7 | # https://www.apache.org/licenses/LICENSE-2.0 8 | # 9 | # Unless required by applicable law or agreed to in writing, software 10 | # distributed under the License is distributed on an "AS IS" BASIS, 11 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | # See the License for the specific language governing permissions and 13 | # limitations under the License. 14 | 15 | licenses(["notice"]) 16 | 17 | cc_library( 18 | name = "api", 19 | hdrs = ["include/astc-codec/astc-codec.h"], 20 | visibility = ["//src/decoder:__pkg__"], 21 | ) 22 | 23 | cc_library( 24 | name = "astc_codec", 25 | hdrs = ["include/astc-codec/astc-codec.h"], 26 | includes = ["include"], 27 | visibility = ["//visibility:public"], 28 | deps = ["//src/decoder:codec"], 29 | ) 30 | -------------------------------------------------------------------------------- /CMakeLists.txt: -------------------------------------------------------------------------------- 1 | # Copyright 2018 Google LLC 2 | # 3 | # Licensed under the Apache License, Version 2.0 (the "License"); you may not 4 | # use this file except in compliance with the License. You may obtain a copy of 5 | # the License at 6 | # 7 | # https://www.apache.org/licenses/LICENSE-2.0 8 | # 9 | # Unless required by applicable law or agreed to in writing, software 10 | # distributed under the License is distributed on an "AS IS" BASIS, WITHOUT 11 | # WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the 12 | # License for the specific language governing permissions and limitations under 13 | # the License. 14 | cmake_minimum_required(VERSION 3.1.0) 15 | project(astc-codec) 16 | 17 | option(OPTION_ASTC_TESTS "Build all the unit tests." ON) 18 | 19 | # TODO add support for the fuzzer, it has some additional dependencies we are not 20 | # yet bringing in. 21 | option(OPTION_BUILD_FUZZER "Build the fuzzer tests." OFF) 22 | 23 | set (CMAKE_CXX_STANDARD 11) 24 | if(OPTION_ASTC_TESTS) 25 | enable_testing() 26 | 27 | # No need to build gmock if an external project defines it. 28 | if(NOT TARGET gmock_main) 29 | # We use the approach suggested by https://crascit.com/2015/07/25/cmake-gtest/ to download gtest. 30 | include(ExternalProject) 31 | # Download and unpack googletest at configure time 32 | configure_file(GoogleTest-CMakeLists.txt.in googletest-download/CMakeLists.txt) 33 | execute_process(COMMAND "${CMAKE_COMMAND}" -G "${CMAKE_GENERATOR}" . 34 | WORKING_DIRECTORY "${CMAKE_BINARY_DIR}/googletest-download") 35 | execute_process(COMMAND "${CMAKE_COMMAND}" --build . WORKING_DIRECTORY "${CMAKE_BINARY_DIR}/googletest-download") 36 | 37 | # Prevent GoogleTest from overriding our compiler/linker options when building with Visual Studio 38 | set(gtest_force_shared_crt ON CACHE BOOL "" FORCE) 39 | 40 | # Add googletest directly to our build. This adds the following targets: gtest, gtest_main, gmock and gmock_main 41 | add_subdirectory("${CMAKE_BINARY_DIR}/googletest-src" "${CMAKE_BINARY_DIR}/googletest-build") 42 | endif() 43 | endif() 44 | 45 | add_subdirectory(src/base) 46 | add_subdirectory(src/decoder) 47 | -------------------------------------------------------------------------------- /CONTRIBUTING.md: -------------------------------------------------------------------------------- 1 | # How to Contribute 2 | 3 | We'd love to accept your patches and contributions to this project. There are 4 | just a few small guidelines you need to follow. 5 | 6 | ## Contributor License Agreement 7 | 8 | Contributions to this project must be accompanied by a Contributor License 9 | Agreement. You (or your employer) retain the copyright to your contribution; 10 | this simply gives us permission to use and redistribute your contributions as 11 | part of the project. Head over to to see 12 | your current agreements on file or to sign a new one. 13 | 14 | You generally only need to submit a CLA once, so if you've already submitted one 15 | (even if it was for a different project), you probably don't need to do it 16 | again. 17 | 18 | ## Code reviews 19 | 20 | All submissions, including submissions by project members, require review. We 21 | use GitHub pull requests for this purpose. Consult 22 | [GitHub Help](https://help.github.com/articles/about-pull-requests/) for more 23 | information on using pull requests. 24 | 25 | ## Community Guidelines 26 | 27 | This project follows [Google's Open Source Community 28 | Guidelines](https://opensource.google.com/conduct/). 29 | -------------------------------------------------------------------------------- /GoogleTest-CMakeLists.txt.in: -------------------------------------------------------------------------------- 1 | cmake_minimum_required(VERSION 2.8.2) 2 | 3 | project(googletest-download NONE) 4 | 5 | include(ExternalProject) 6 | ExternalProject_Add(googletest 7 | GIT_REPOSITORY https://github.com/google/googletest.git 8 | GIT_TAG "release-1.8.1" 9 | SOURCE_DIR "${CMAKE_CURRENT_BINARY_DIR}/googletest-src" 10 | BINARY_DIR "${CMAKE_CURRENT_BINARY_DIR}/googletest-build" 11 | CONFIGURE_COMMAND "" 12 | BUILD_COMMAND "" 13 | INSTALL_COMMAND "" 14 | TEST_COMMAND "" 15 | ) -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # astc-codec 2 | 3 | astc-codec is a software ASTC decoder implementation, which supports the ASTC 4 | LDR profile. 5 | 6 | Example usage: 7 | 8 | ``` 9 | #include 10 | 11 | // ... 12 | 13 | std::vector astc = LoadMyASTCData(); 14 | const size_t width = 640; 15 | const size_t height = 480; 16 | 17 | std::vector result; 18 | result.resize(width * height * 4); 19 | 20 | bool success = astc_codec::ASTCDecompressToRGBA( 21 | astc.data(), astc.size(), width, height, astc_codec::FootprintType::k4x4, 22 | result.data(), result.size(), /* stride */ width * 4); 23 | ``` 24 | 25 | ## Building 26 | 27 | ### With bazel 28 | 29 | Install [Bazel](https://bazel.build/), and then run: 30 | 31 | ``` 32 | bazel build :astc_codec -c opt 33 | ``` 34 | 35 | astc-codec has been tested on Mac and Linux. 36 | 37 | ### Run Tests 38 | 39 | ``` 40 | bazel test //... 41 | ``` 42 | 43 | ### With CMake 44 | 45 | Install [CMake](https://cmake.org/), and the run: 46 | 47 | ``` 48 | mkdir build && cd build && cmake .. && make 49 | ``` 50 | 51 | Or open the project in your favorite IDE and import CMakeLists.txt. 52 | 53 | ### Run Tests 54 | 55 | In the build directory, execute: 56 | 57 | ``` 58 | ctest 59 | ``` 60 | 61 | 62 | ## Contributing 63 | 64 | See [CONTRIBUTING.md](CONTRIBUTING.md) for important contributing requirements. 65 | 66 | ## License 67 | 68 | astc-codec project is licensed under the Apache License Version 2.0. You can 69 | find a copy of it in [LICENSE](LICENSE). 70 | 71 | This is not an officially supported Google product. 72 | -------------------------------------------------------------------------------- /WORKSPACE: -------------------------------------------------------------------------------- 1 | # Copyright 2018 Google LLC 2 | # 3 | # Licensed under the Apache License, Version 2.0 (the "License"); 4 | # you may not use this file except in compliance with the License. 5 | # You may obtain a copy of the License at 6 | # 7 | # https://www.apache.org/licenses/LICENSE-2.0 8 | # 9 | # Unless required by applicable law or agreed to in writing, software 10 | # distributed under the License is distributed on an "AS IS" BASIS, 11 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | # See the License for the specific language governing permissions and 13 | # limitations under the License. 14 | 15 | load("@bazel_tools//tools/build_defs/repo:git.bzl", "git_repository") 16 | load("@bazel_tools//tools/build_defs/repo:http.bzl", "http_archive") 17 | 18 | git_repository( 19 | name = "gtest", 20 | remote = "https://github.com/google/googletest.git", 21 | commit = "ba96d0b1161f540656efdaed035b3c062b60e006", 22 | ) 23 | 24 | http_archive( 25 | name = "honggfuzz", 26 | url = "https://github.com/google/honggfuzz/archive/1.7.zip", 27 | sha256 = "9d420326979fed4a065fa6176d5e09bd513cd2820fe216ae8b684aa6780d72b2", 28 | build_file = "//third_party:honggfuzz.BUILD", 29 | strip_prefix = "honggfuzz-1.7", 30 | ) 31 | 32 | http_archive( 33 | name = "benchmark", 34 | url = "https://github.com/google/benchmark/archive/v1.4.1.zip", 35 | sha256 = "61ae07eb5d4a0b02753419eb17a82b7d322786bb36ab62bd3df331a4d47c00a7", 36 | strip_prefix = "benchmark-1.4.1", 37 | ) 38 | -------------------------------------------------------------------------------- /cmake-format.json: -------------------------------------------------------------------------------- 1 | { 2 | "line_width": 120, 3 | "dangle_parens": false, 4 | "first_comment_is_literal": true, 5 | "algorithm_order": [ 6 | 0, 7 | 1, 8 | 2, 9 | 3 10 | ], 11 | "command_case": "lower", 12 | "additional_commands": { 13 | "foo": { 14 | "flags": [ 15 | "BAR", 16 | "BAZ" 17 | ], 18 | "kwargs": { 19 | "HEADERS": "*", 20 | "DEPENDS": "*", 21 | "SOURCES": "*" 22 | } 23 | } 24 | }, 25 | "separate_fn_name_with_space": false, 26 | "always_wrap": [], 27 | "separate_ctrl_name_with_space": false, 28 | "max_subargs_per_line": 5, 29 | "fence_pattern": "^\\s*([`~]{3}[`~]*)(.*)$", 30 | "enable_markup": true, 31 | "ruler_pattern": "^\\s*[^\\w\\s]{3}.*[^\\w\\s]{3}$", 32 | "tab_size": 2, 33 | "keyword_case": "unchanged", 34 | "enum_char": ".", 35 | "literal_comment_pattern": null, 36 | "bullet_char": "*", 37 | "line_ending": "unix" 38 | } 39 | -------------------------------------------------------------------------------- /include/astc-codec/astc-codec.h: -------------------------------------------------------------------------------- 1 | // Copyright 2018 Google LLC 2 | // 3 | // Licensed under the Apache License, Version 2.0 (the "License"); 4 | // you may not use this file except in compliance with the License. 5 | // You may obtain a copy of the License at 6 | // 7 | // https://www.apache.org/licenses/LICENSE-2.0 8 | // 9 | // Unless required by applicable law or agreed to in writing, software 10 | // distributed under the License is distributed on an "AS IS" BASIS, 11 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | // See the License for the specific language governing permissions and 13 | // limitations under the License. 14 | 15 | #ifndef ASTC_CODEC_ASTC_CODEC_H_ 16 | #define ASTC_CODEC_ASTC_CODEC_H_ 17 | 18 | #include 19 | #include 20 | 21 | namespace astc_codec { 22 | 23 | // These are the valid ASTC footprints according to the specification in 24 | // Section C.2.7. 25 | enum class FootprintType { 26 | k4x4, 27 | k5x4, 28 | k5x5, 29 | k6x5, 30 | k6x6, 31 | k8x5, 32 | k8x6, 33 | k10x5, 34 | k10x6, 35 | k8x8, 36 | k10x8, 37 | k10x10, 38 | k12x10, 39 | k12x12, 40 | 41 | kCount 42 | }; 43 | 44 | // Decompresses ASTC LDR image data to a RGBA32 buffer. 45 | // 46 | // Supports formats defined in the KHR_texture_compression_astc_ldr spec and 47 | // returns UNORM8 values. sRGB is not supported, and should be implemented 48 | // by the caller. 49 | // 50 | // |astc_data| - Compressed ASTC image buffer, must be at least |astc_data_size| 51 | // bytes long. 52 | // |astc_data_size| - The size of |astc_data|, in bytes. 53 | // |width| - Image width, in pixels. 54 | // |height| - Image height, in pixels. 55 | // |footprint| - The ASTC footprint (block size) of the compressed image buffer. 56 | // |out_buffer| - Pointer to a buffer where the decompressed image will be 57 | // stored, must be at least |out_buffer_size| bytes long. 58 | // |out_buffer_size| - The size of |out_buffer|, in bytes, at least 59 | // height*out_buffer_stride. If this is too small, this 60 | // function will return false and no data will be 61 | // decompressed. 62 | // |out_buffer_stride| - The stride that should be used to store rows of the 63 | // decoded image, must be at least 4*width bytes. 64 | // 65 | // Returns true if the decompression succeeded, or false if decompression 66 | // failed, or if the astc_data_size was too small for the given width, height, 67 | // and footprint, or if out_buffer_size is too small. 68 | bool ASTCDecompressToRGBA(const uint8_t* astc_data, size_t astc_data_size, 69 | size_t width, size_t height, FootprintType footprint, 70 | uint8_t* out_buffer, size_t out_buffer_size, 71 | size_t out_buffer_stride); 72 | 73 | } // namespace astc_codec 74 | 75 | #endif // ASTC_CODEC_ASTC_CODEC_H_ 76 | -------------------------------------------------------------------------------- /src/.clang-format: -------------------------------------------------------------------------------- 1 | BasedOnStyle: Google 2 | AllowShortCaseLabelsOnASingleLine: true 3 | AllowShortFunctionsOnASingleLine: Inline 4 | SpaceAfterTemplateKeyword: false 5 | -------------------------------------------------------------------------------- /src/base/BUILD.bazel: -------------------------------------------------------------------------------- 1 | # Copyright 2018 Google LLC 2 | # 3 | # Licensed under the Apache License, Version 2.0 (the "License"); 4 | # you may not use this file except in compliance with the License. 5 | # You may obtain a copy of the License at 6 | # 7 | # https://www.apache.org/licenses/LICENSE-2.0 8 | # 9 | # Unless required by applicable law or agreed to in writing, software 10 | # distributed under the License is distributed on an "AS IS" BASIS, 11 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | # See the License for the specific language governing permissions and 13 | # limitations under the License. 14 | 15 | licenses(["notice"]) 16 | 17 | cc_library( 18 | name = "base", 19 | hdrs = [ 20 | "bit_stream.h", 21 | "bottom_n.h", 22 | "math_utils.h", 23 | "optional.h", 24 | "string_utils.h", 25 | "type_traits.h", 26 | "uint128.h", 27 | "utils.h", 28 | ], 29 | features = ["-parse_headers"], 30 | visibility = ["//src/decoder:__pkg__"], 31 | ) 32 | 33 | cc_test( 34 | name = "base_test", 35 | srcs = [ 36 | "test/bit_stream_test.cpp", 37 | "test/bottom_n_test.cpp", 38 | "test/math_utils_test.cpp", 39 | "test/optional_test.cpp", 40 | "test/string_utils_test.cpp", 41 | "test/type_traits_test.cpp", 42 | "test/uint128_test.cpp", 43 | ], 44 | deps = [ 45 | "@gtest//:gtest_main", 46 | ":base", 47 | ], 48 | ) 49 | 50 | -------------------------------------------------------------------------------- /src/base/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | # Copyright 2018 Google LLC 2 | # 3 | # Licensed under the Apache License Version 2.0 (the License); you may not use 4 | # this file except in compliance with the License. You may obtain a copy of the 5 | # License at 6 | # 7 | # https://www.apache.org/licenses/LICENSE-2.0 8 | # 9 | # Unless required by applicable law or agreed to in writing software distributed 10 | # under the License is distributed on an AS IS BASIS WITHOUT WARRANTIES OR 11 | # CONDITIONS OF ANY KIND either express or implied. See the License for the 12 | # specific language governing permissions and limitations under the License. 13 | add_library(base INTERFACE) 14 | target_include_directories(base INTERFACE ../..) 15 | 16 | if(OPTION_ASTC_TESTS) 17 | add_executable(base_test 18 | test/bit_stream_test.cpp 19 | test/bottom_n_test.cpp 20 | test/math_utils_test.cpp 21 | test/optional_test.cpp 22 | test/string_utils_test.cpp 23 | test/type_traits_test.cpp 24 | test/uint128_test.cpp) 25 | target_link_libraries(base_test base gmock_main) 26 | add_test(NAME base_test COMMAND base_test WORKING_DIRECTORY ${PROJECT_SOURCE_DIR}) 27 | endif() 28 | -------------------------------------------------------------------------------- /src/base/bit_stream.h: -------------------------------------------------------------------------------- 1 | // Copyright 2018 Google LLC 2 | // 3 | // Licensed under the Apache License, Version 2.0 (the "License"); 4 | // you may not use this file except in compliance with the License. 5 | // You may obtain a copy of the License at 6 | // 7 | // https://www.apache.org/licenses/LICENSE-2.0 8 | // 9 | // Unless required by applicable law or agreed to in writing, software 10 | // distributed under the License is distributed on an "AS IS" BASIS, 11 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | // See the License for the specific language governing permissions and 13 | // limitations under the License. 14 | 15 | #ifndef ASTC_CODEC_BASE_BIT_STREAM_H_ 16 | #define ASTC_CODEC_BASE_BIT_STREAM_H_ 17 | 18 | #include 19 | #include 20 | 21 | namespace astc_codec { 22 | namespace base { 23 | 24 | // Represents a stream of bits that can be read or written in arbitrary-sized 25 | // chunks. 26 | template 27 | class BitStream { 28 | public: 29 | // Creates an empty BitStream. 30 | BitStream() = default; 31 | BitStream(IntType data, uint32_t data_size) 32 | : data_(data), data_size_(data_size) { 33 | assert(data_size_ <= sizeof(data_) * 8); 34 | } 35 | 36 | // Return the number of bits in the stream. 37 | uint32_t Bits() const { return data_size_; } 38 | 39 | // Put |size| bits into the stream. 40 | // Fails if there is not enough space in the buffer to store the bits. 41 | template 42 | void PutBits(ResultType x, uint32_t size) { 43 | assert(data_size_ + size <= sizeof(data_) * 8); 44 | 45 | data_ |= (IntType(x) & MaskFor(size)) << data_size_; 46 | data_size_ += size; 47 | } 48 | 49 | // Get |count| bits from the stream. 50 | // Returns true if |count| bits were successfully retrieved. 51 | template 52 | bool GetBits(uint32_t count, ResultType* result) { 53 | if (count <= data_size_) { 54 | *result = static_cast(data_ & MaskFor(count)); 55 | data_ = data_ >> count; 56 | data_size_ -= count; 57 | return true; 58 | } else { 59 | *result = ResultType(); 60 | return false; 61 | } 62 | } 63 | 64 | private: 65 | IntType MaskFor(uint32_t bits) const { 66 | return (bits == sizeof(IntType) * 8) ? ~IntType(0) 67 | : (IntType(1) << bits) - 1; 68 | } 69 | 70 | IntType data_ = IntType(); 71 | uint32_t data_size_ = 0; 72 | }; 73 | 74 | } // namespace base 75 | } // namespace astc_codec 76 | 77 | #endif // ASTC_CODEC_BASE_BIT_STREAM_H_ 78 | -------------------------------------------------------------------------------- /src/base/bottom_n.h: -------------------------------------------------------------------------------- 1 | // Copyright 2018 Google LLC 2 | // 3 | // Licensed under the Apache License, Version 2.0 (the "License"); 4 | // you may not use this file except in compliance with the License. 5 | // You may obtain a copy of the License at 6 | // 7 | // https://www.apache.org/licenses/LICENSE-2.0 8 | // 9 | // Unless required by applicable law or agreed to in writing, software 10 | // distributed under the License is distributed on an "AS IS" BASIS, 11 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | // See the License for the specific language governing permissions and 13 | // limitations under the License. 14 | 15 | #ifndef ASTC_CODEC_BASE_BOTTOM_N_H_ 16 | #define ASTC_CODEC_BASE_BOTTOM_N_H_ 17 | 18 | #include 19 | #include 20 | #include 21 | 22 | namespace astc_codec { 23 | namespace base { 24 | 25 | // Used to aggregate the lowest N values of data supplied. 26 | template> 27 | class BottomN { 28 | public: 29 | typedef std::vector ContainerType; 30 | 31 | // Creates an empty BottomN with limit |max_size|. 32 | BottomN(size_t max_size) : max_size_(max_size) { } 33 | 34 | bool Empty() const { return data_.empty(); } 35 | size_t Size() const { return data_.size(); } 36 | 37 | const T& Top() const { return data_.front(); } 38 | 39 | void Push(const T& value) { 40 | if (data_.size() < max_size_ || compare_(value, Top())) { 41 | data_.push_back(value); 42 | std::push_heap(data_.begin(), data_.end(), compare_); 43 | 44 | if (Size() > max_size_) { 45 | PopTop(); 46 | } 47 | } 48 | } 49 | 50 | std::vector Pop() { 51 | const size_t len = Size(); 52 | std::vector result(len); 53 | 54 | for (size_t i = 0; i < len; ++i) { 55 | result[len - i - 1] = PopTop(); 56 | } 57 | 58 | return result; 59 | } 60 | 61 | private: 62 | T PopTop() { 63 | std::pop_heap(data_.begin(), data_.end(), compare_); 64 | T result = data_.back(); 65 | data_.pop_back(); 66 | return result; 67 | } 68 | 69 | ContainerType data_; 70 | CompareFn compare_; 71 | 72 | const size_t max_size_; 73 | }; 74 | 75 | } // namespace base 76 | } // namespace astc_codec 77 | 78 | #endif // ASTC_CODEC_BASE_BOTTOM_N_H_ 79 | -------------------------------------------------------------------------------- /src/base/math_utils.h: -------------------------------------------------------------------------------- 1 | // Copyright 2018 Google LLC 2 | // 3 | // Licensed under the Apache License, Version 2.0 (the "License"); 4 | // you may not use this file except in compliance with the License. 5 | // You may obtain a copy of the License at 6 | // 7 | // https://www.apache.org/licenses/LICENSE-2.0 8 | // 9 | // Unless required by applicable law or agreed to in writing, software 10 | // distributed under the License is distributed on an "AS IS" BASIS, 11 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | // See the License for the specific language governing permissions and 13 | // limitations under the License. 14 | 15 | #ifndef ASTC_CODEC_BASE_MATH_UTILS_H_ 16 | #define ASTC_CODEC_BASE_MATH_UTILS_H_ 17 | 18 | #include "src/base/uint128.h" 19 | 20 | #include 21 | #include 22 | #include 23 | 24 | namespace astc_codec { 25 | namespace base { 26 | 27 | inline int Log2Floor(uint32_t n) { 28 | if (n == 0) { 29 | return -1; 30 | } 31 | 32 | int log = 0; 33 | uint32_t value = n; 34 | for (int i = 4; i >= 0; --i) { 35 | int shift = (1 << i); 36 | uint32_t x = value >> shift; 37 | if (x != 0) { 38 | value = x; 39 | log += shift; 40 | } 41 | } 42 | assert(value == 1); 43 | return log; 44 | } 45 | 46 | inline int CountOnes(uint32_t n) { 47 | n -= ((n >> 1) & 0x55555555); 48 | n = ((n >> 2) & 0x33333333) + (n & 0x33333333); 49 | return static_cast((((n + (n >> 4)) & 0xF0F0F0F) * 0x1010101) >> 24); 50 | } 51 | 52 | template 53 | inline T ReverseBits(T value) { 54 | uint32_t s = sizeof(value) * 8; 55 | T mask = ~T(0); 56 | while ((s >>= 1) > 0) { 57 | mask ^= (mask << s); 58 | value = ((value >> s) & mask) | ((value << s) & ~mask); 59 | } 60 | 61 | return value; 62 | } 63 | 64 | template 65 | inline T GetBits(T source, uint32_t offset, uint32_t count) { 66 | static_assert(std::is_same::value || std::is_unsigned::value, 67 | "T must be unsigned."); 68 | 69 | const uint32_t total_bits = sizeof(T) * 8; 70 | assert(count > 0); 71 | assert(offset + count <= total_bits); 72 | 73 | const T mask = count == total_bits ? ~T(0) : ~T(0) >> (total_bits - count); 74 | return (source >> offset) & mask; 75 | } 76 | 77 | } // namespace base 78 | } // namespace astc_codec 79 | 80 | #endif // ASTC_CODEC_BASE_MATH_UTILS_H_ 81 | -------------------------------------------------------------------------------- /src/base/string_utils.h: -------------------------------------------------------------------------------- 1 | // Copyright 2018 Google LLC 2 | // 3 | // Licensed under the Apache License, Version 2.0 (the "License"); 4 | // you may not use this file except in compliance with the License. 5 | // You may obtain a copy of the License at 6 | // 7 | // https://www.apache.org/licenses/LICENSE-2.0 8 | // 9 | // Unless required by applicable law or agreed to in writing, software 10 | // distributed under the License is distributed on an "AS IS" BASIS, 11 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | // See the License for the specific language governing permissions and 13 | // limitations under the License. 14 | 15 | #ifndef ASTC_CODEC_BASE_STRING_UTILS_H_ 16 | #define ASTC_CODEC_BASE_STRING_UTILS_H_ 17 | 18 | #include 19 | #include 20 | 21 | namespace astc_codec { 22 | namespace base { 23 | 24 | // Iterates over a string's parts using |splitBy| as a delimiter. 25 | // |splitBy| must be a nonempty string well, or it's a no-op. 26 | // Otherwise, |func| is called on each of the splits, excluding the 27 | // characters that are part of |splitBy|. If two |splitBy|'s occur in a row, 28 | // |func| will be called on a StringView("") in between. See 29 | // StringUtils_unittest.cpp for the full story. 30 | template 31 | void Split(const std::string& str, const std::string& splitBy, Func func) { 32 | if (splitBy.empty()) { 33 | return; 34 | } 35 | 36 | size_t splitSize = splitBy.size(); 37 | size_t begin = 0; 38 | size_t end = str.find(splitBy); 39 | 40 | while (true) { 41 | func(str.substr(begin, end - begin)); 42 | if (end == std::string::npos) { 43 | return; 44 | } 45 | 46 | begin = end + splitSize; 47 | end = str.find(splitBy, begin); 48 | } 49 | } 50 | 51 | static int32_t ParseInt32(const char* str, int32_t deflt) { 52 | using std::numeric_limits; 53 | 54 | char* error = nullptr; 55 | int64_t value = strtol(str, &error, 0); 56 | // Limit long values to int32 min/max. Needed for lp64; no-op on 32 bits. 57 | if (value > std::numeric_limits::max()) { 58 | value = std::numeric_limits::max(); 59 | } else if (value < std::numeric_limits::min()) { 60 | value = std::numeric_limits::min(); 61 | } 62 | return (error == str) ? deflt : static_cast(value); 63 | } 64 | 65 | } // namespace base 66 | } // namespace astc_codec 67 | 68 | #endif // ASTC_CODEC_BASE_STRING_UTILS_H_ 69 | -------------------------------------------------------------------------------- /src/base/test/bit_stream_test.cpp: -------------------------------------------------------------------------------- 1 | // Copyright 2018 Google LLC 2 | // 3 | // Licensed under the Apache License, Version 2.0 (the "License"); 4 | // you may not use this file except in compliance with the License. 5 | // You may obtain a copy of the License at 6 | // 7 | // https://www.apache.org/licenses/LICENSE-2.0 8 | // 9 | // Unless required by applicable law or agreed to in writing, software 10 | // distributed under the License is distributed on an "AS IS" BASIS, 11 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | // See the License for the specific language governing permissions and 13 | // limitations under the License. 14 | 15 | #include "src/base/bit_stream.h" 16 | 17 | #include 18 | 19 | namespace astc_codec { 20 | namespace base { 21 | 22 | namespace { 23 | static constexpr uint64_t kAllBits = 0xFFFFFFFFFFFFFFFF; 24 | static constexpr uint64_t k40Bits = 0x000000FFFFFFFFFF; 25 | } 26 | 27 | TEST(BitStream, Decode) { 28 | { 29 | BitStream stream(0, 1); 30 | 31 | uint64_t bits = kAllBits; 32 | EXPECT_TRUE(stream.GetBits(1, &bits)); 33 | EXPECT_EQ(bits, 0); 34 | EXPECT_FALSE(stream.GetBits(1, &bits)); 35 | } 36 | 37 | { 38 | BitStream stream(0b1010101010101010, 32); 39 | EXPECT_EQ(stream.Bits(), 32); 40 | 41 | uint64_t bits = 0; 42 | EXPECT_TRUE(stream.GetBits(1, &bits)); 43 | EXPECT_EQ(bits, 0); 44 | 45 | EXPECT_TRUE(stream.GetBits(3, &bits)); 46 | EXPECT_EQ(bits, 0b101); 47 | 48 | EXPECT_TRUE(stream.GetBits(8, &bits)); 49 | EXPECT_EQ(bits, 0b10101010); 50 | 51 | EXPECT_EQ(stream.Bits(), 20); 52 | 53 | EXPECT_TRUE(stream.GetBits(20, &bits)); 54 | EXPECT_EQ(bits, 0b1010); 55 | EXPECT_EQ(stream.Bits(), 0); 56 | } 57 | 58 | { 59 | BitStream stream(kAllBits, 64); 60 | EXPECT_EQ(stream.Bits(), 64); 61 | 62 | uint64_t bits = 0; 63 | EXPECT_TRUE(stream.GetBits(64, &bits)); 64 | EXPECT_EQ(bits, kAllBits); 65 | EXPECT_EQ(stream.Bits(), 0); 66 | } 67 | 68 | { 69 | BitStream stream(kAllBits, 64); 70 | EXPECT_EQ(stream.Bits(), 64); 71 | 72 | uint64_t bits = 0; 73 | EXPECT_TRUE(stream.GetBits(40, &bits)); 74 | EXPECT_EQ(bits, k40Bits); 75 | EXPECT_EQ(stream.Bits(), 24); 76 | } 77 | 78 | { 79 | BitStream stream(kAllBits, 32); 80 | 81 | uint64_t bits = 0; 82 | EXPECT_TRUE(stream.GetBits(0, &bits)); 83 | EXPECT_EQ(bits, 0); 84 | EXPECT_TRUE(stream.GetBits(32, &bits)); 85 | EXPECT_EQ(bits, k40Bits & 0xFFFFFFFF); 86 | EXPECT_TRUE(stream.GetBits(0, &bits)); 87 | EXPECT_EQ(bits, 0); 88 | EXPECT_EQ(stream.Bits(), 0); 89 | } 90 | } 91 | 92 | TEST(BitStream, Encode) { 93 | { 94 | BitStream stream; 95 | 96 | stream.PutBits(0, 1); 97 | stream.PutBits(0b11, 2); 98 | EXPECT_EQ(stream.Bits(), 3); 99 | 100 | uint64_t bits = 0; 101 | EXPECT_TRUE(stream.GetBits(3, &bits)); 102 | EXPECT_EQ(bits, 0b110); 103 | } 104 | 105 | { 106 | BitStream stream; 107 | 108 | uint64_t bits = 0; 109 | stream.PutBits(kAllBits, 64); 110 | EXPECT_EQ(stream.Bits(), 64); 111 | 112 | EXPECT_TRUE(stream.GetBits(64, &bits)); 113 | EXPECT_EQ(bits, kAllBits); 114 | EXPECT_EQ(stream.Bits(), 0); 115 | } 116 | 117 | { 118 | BitStream stream; 119 | stream.PutBits(kAllBits, 40); 120 | 121 | uint64_t bits = 0; 122 | EXPECT_TRUE(stream.GetBits(40, &bits)); 123 | EXPECT_EQ(bits, k40Bits); 124 | EXPECT_EQ(stream.Bits(), 0); 125 | } 126 | 127 | { 128 | BitStream stream; 129 | stream.PutBits(0, 0); 130 | stream.PutBits(kAllBits, 32); 131 | stream.PutBits(0, 0); 132 | 133 | uint64_t bits = 0; 134 | EXPECT_TRUE(stream.GetBits(32, &bits)); 135 | EXPECT_EQ(bits, k40Bits & 0xFFFFFFFF); 136 | EXPECT_EQ(stream.Bits(), 0); 137 | } 138 | } 139 | 140 | } // namespace base 141 | } // namespace astc_codec 142 | -------------------------------------------------------------------------------- /src/base/test/bottom_n_test.cpp: -------------------------------------------------------------------------------- 1 | // Copyright 2018 Google LLC 2 | // 3 | // Licensed under the Apache License, Version 2.0 (the "License"); 4 | // you may not use this file except in compliance with the License. 5 | // You may obtain a copy of the License at 6 | // 7 | // https://www.apache.org/licenses/LICENSE-2.0 8 | // 9 | // Unless required by applicable law or agreed to in writing, software 10 | // distributed under the License is distributed on an "AS IS" BASIS, 11 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | // See the License for the specific language governing permissions and 13 | // limitations under the License. 14 | 15 | #include "src/base/bottom_n.h" 16 | 17 | #include 18 | #include 19 | 20 | namespace astc_codec { 21 | namespace base { 22 | 23 | using ::testing::ElementsAre; 24 | 25 | template 26 | static void pushAll(BottomN& heap, const T (&arr)[N]) { 27 | for (auto i : arr) { 28 | heap.Push(i); 29 | } 30 | } 31 | 32 | TEST(BottomN, Sort) { 33 | { 34 | BottomN heap(10); 35 | EXPECT_TRUE(heap.Empty()); 36 | int list[] = { 1,2 }; 37 | pushAll(heap, list); 38 | 39 | EXPECT_EQ(heap.Size(), 2); 40 | EXPECT_FALSE(heap.Empty()); 41 | EXPECT_THAT(heap.Pop(), ElementsAre(1, 2)); 42 | } 43 | 44 | { 45 | BottomN heap(6); 46 | int list[] = {1, 4, 3, 2, 2, 1}; 47 | pushAll(heap, list); 48 | 49 | EXPECT_EQ(heap.Size(), 6); 50 | EXPECT_THAT(heap.Pop(), ElementsAre(1, 1, 2, 2, 3, 4)); 51 | } 52 | } 53 | 54 | TEST(BottomN, Bounds) { 55 | { 56 | BottomN heap(4); 57 | int list[] = { 1, 2, 3, 4 }; 58 | pushAll(heap, list); 59 | EXPECT_EQ(heap.Size(), 4); 60 | 61 | heap.Push(0); 62 | EXPECT_EQ(heap.Size(), 4); 63 | 64 | EXPECT_THAT(heap.Pop(), ElementsAre(0, 1, 2, 3)); 65 | } 66 | 67 | { 68 | BottomN heap(4); 69 | int list[] = { 4, 3, 2,1 }; 70 | pushAll(heap, list); 71 | EXPECT_EQ(heap.Size(), 4); 72 | 73 | int list2[] = { 4,4,4,4 }; 74 | pushAll(heap, list2); 75 | EXPECT_EQ(heap.Size(), 4); 76 | 77 | EXPECT_THAT(heap.Pop(), ElementsAre(1, 2, 3, 4)); 78 | } 79 | 80 | { 81 | BottomN heap(4); 82 | int list[] = { 4, 3, 2, 1 }; 83 | pushAll(heap, list); 84 | EXPECT_EQ(heap.Size(), 4); 85 | 86 | int list2[] = { 5, 5, 5, 5 }; 87 | pushAll(heap, list2); 88 | EXPECT_EQ(heap.Size(), 4); 89 | 90 | EXPECT_THAT(heap.Pop(), ElementsAre(1, 2, 3, 4)); 91 | } 92 | 93 | { 94 | BottomN heap(4); 95 | int list[] = { 4, 3, 2, 1 }; 96 | pushAll(heap, list); 97 | EXPECT_EQ(heap.Size(), 4); 98 | 99 | int list2[] = { 0, 0, 0, 0 }; 100 | pushAll(heap, list2); 101 | EXPECT_EQ(heap.Size(), 4); 102 | 103 | EXPECT_THAT(heap.Pop(), ElementsAre(0, 0, 0, 0)); 104 | } 105 | } 106 | 107 | } // namespace base 108 | } // namespace astc_codec 109 | -------------------------------------------------------------------------------- /src/base/test/math_utils_test.cpp: -------------------------------------------------------------------------------- 1 | // Copyright 2018 Google LLC 2 | // 3 | // Licensed under the Apache License, Version 2.0 (the "License"); 4 | // you may not use this file except in compliance with the License. 5 | // You may obtain a copy of the License at 6 | // 7 | // https://www.apache.org/licenses/LICENSE-2.0 8 | // 9 | // Unless required by applicable law or agreed to in writing, software 10 | // distributed under the License is distributed on an "AS IS" BASIS, 11 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | // See the License for the specific language governing permissions and 13 | // limitations under the License. 14 | 15 | #include "src/base/math_utils.h" 16 | 17 | #include 18 | 19 | namespace astc_codec { 20 | namespace base { 21 | 22 | TEST(MathUtils, Log2Floor) { 23 | EXPECT_EQ(-1, Log2Floor(0)); 24 | 25 | for (int i = 0; i < 32; i++) { 26 | uint32_t n = 1U << i; 27 | EXPECT_EQ(i, Log2Floor(n)); 28 | if (n > 2) { 29 | EXPECT_EQ(i - 1, Log2Floor(n - 1)); 30 | EXPECT_EQ(i, Log2Floor(n + 1)); 31 | } 32 | } 33 | } 34 | 35 | TEST(MathUtils, CountOnes) { 36 | EXPECT_EQ(0, CountOnes(0)); 37 | EXPECT_EQ(1, CountOnes(1)); 38 | EXPECT_EQ(32, CountOnes(static_cast(~0U))); 39 | EXPECT_EQ(1, CountOnes(0x8000000)); 40 | 41 | for (int i = 0; i < 32; i++) { 42 | EXPECT_EQ(1, CountOnes(1U << i)); 43 | EXPECT_EQ(31, CountOnes(static_cast(~0U) ^ (1U << i))); 44 | } 45 | } 46 | 47 | TEST(MathUtils, ReverseBits) { 48 | EXPECT_EQ(ReverseBits(0u), 0u); 49 | EXPECT_EQ(ReverseBits(1u), 1u << 31); 50 | EXPECT_EQ(ReverseBits(0xffffffff), 0xffffffff); 51 | EXPECT_EQ(ReverseBits(0x00000001), 0x80000000); 52 | EXPECT_EQ(ReverseBits(0x80000000), 0x00000001); 53 | EXPECT_EQ(ReverseBits(0xaaaaaaaa), 0x55555555); 54 | EXPECT_EQ(ReverseBits(0x55555555), 0xaaaaaaaa); 55 | EXPECT_EQ(ReverseBits(0x7d5d7f53), 0xcafebabe); 56 | EXPECT_EQ(ReverseBits(0xcafebabe), 0x7d5d7f53); 57 | } 58 | 59 | TEST(MathUtils, GetBits) { 60 | EXPECT_EQ(GetBits(0u, 0, 1), 0u); 61 | EXPECT_EQ(GetBits(0u, 0, 32), 0u); 62 | EXPECT_EQ(GetBits(0x00000001u, 0, 1), 0x00000001); 63 | EXPECT_EQ(GetBits(0x00000001u, 0, 32), 0x00000001); 64 | EXPECT_EQ(GetBits(0x00000001u, 1, 31), 0x00000000); 65 | EXPECT_EQ(GetBits(0x00000001u, 31, 1), 0x00000000); 66 | 67 | EXPECT_DEBUG_DEATH(GetBits(0x00000000u, 1, 32), ""); 68 | EXPECT_DEBUG_DEATH(GetBits(0x00000000u, 32, 0), ""); 69 | EXPECT_DEBUG_DEATH(GetBits(0x00000000u, 32, 1), ""); 70 | 71 | EXPECT_EQ(GetBits(0XFFFFFFFFu, 0, 4), 0x0000000F); 72 | EXPECT_EQ(GetBits(0XFFFFFFFFu, 16, 16), 0xFFFF); 73 | EXPECT_EQ(GetBits(0x80000000u, 31, 1), 1); 74 | EXPECT_EQ(GetBits(0xCAFEBABEu, 24, 8), 0xCA); 75 | } 76 | 77 | } // namespace base 78 | } // namespace astc_codec 79 | -------------------------------------------------------------------------------- /src/base/test/string_utils_test.cpp: -------------------------------------------------------------------------------- 1 | // Copyright 2018 Google LLC 2 | // 3 | // Licensed under the Apache License, Version 2.0 (the "License"); 4 | // you may not use this file except in compliance with the License. 5 | // You may obtain a copy of the License at 6 | // 7 | // https://www.apache.org/licenses/LICENSE-2.0 8 | // 9 | // Unless required by applicable law or agreed to in writing, software 10 | // distributed under the License is distributed on an "AS IS" BASIS, 11 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | // See the License for the specific language governing permissions and 13 | // limitations under the License. 14 | 15 | #include "src/base/string_utils.h" 16 | 17 | #include 18 | 19 | #include 20 | #include 21 | #include 22 | 23 | namespace astc_codec { 24 | namespace base { 25 | 26 | TEST(StringUtils, Split) { 27 | std::vector results; 28 | 29 | auto testFunc = [&results](std::string&& s) { 30 | results.push_back(std::move(s)); 31 | }; 32 | 33 | Split("", "abc", testFunc); 34 | EXPECT_EQ(results.size(), 1); 35 | 36 | Split("abc", "", testFunc); 37 | EXPECT_EQ(results.size(), 1); 38 | 39 | results.clear(); 40 | Split("abc", "a", testFunc); 41 | EXPECT_EQ(results.size(), 2); 42 | EXPECT_EQ(results[0], ""); 43 | EXPECT_EQ(results[1], "bc"); 44 | 45 | results.clear(); 46 | Split("aaa", "a", testFunc); 47 | EXPECT_EQ(4, results.size()); 48 | EXPECT_EQ("", results[0]); 49 | EXPECT_EQ("", results[1]); 50 | EXPECT_EQ("", results[2]); 51 | EXPECT_EQ("", results[3]); 52 | 53 | results.clear(); 54 | Split("1a2a3a4", "a", testFunc); 55 | EXPECT_EQ(4, results.size()); 56 | EXPECT_EQ("1", results[0]); 57 | EXPECT_EQ("2", results[1]); 58 | EXPECT_EQ("3", results[2]); 59 | EXPECT_EQ("4", results[3]); 60 | 61 | results.clear(); 62 | Split("1a2aa3a4", "a", testFunc); 63 | EXPECT_EQ(5, results.size()); 64 | EXPECT_EQ("1", results[0]); 65 | EXPECT_EQ("2", results[1]); 66 | EXPECT_EQ("", results[2]); 67 | EXPECT_EQ("3", results[3]); 68 | EXPECT_EQ("4", results[4]); 69 | 70 | results.clear(); 71 | Split("The quick brown fox jumped over the lazy dog", 72 | " ", testFunc); 73 | EXPECT_EQ(9, results.size()); 74 | EXPECT_EQ("The", results[0]); 75 | EXPECT_EQ("quick", results[1]); 76 | EXPECT_EQ("brown", results[2]); 77 | EXPECT_EQ("fox", results[3]); 78 | EXPECT_EQ("jumped", results[4]); 79 | EXPECT_EQ("over", results[5]); 80 | EXPECT_EQ("the", results[6]); 81 | EXPECT_EQ("lazy", results[7]); 82 | EXPECT_EQ("dog", results[8]); 83 | 84 | results.clear(); 85 | Split("a; b; c; d", "; ", testFunc); 86 | EXPECT_EQ(4, results.size()); 87 | EXPECT_EQ("a", results[0]); 88 | EXPECT_EQ("b", results[1]); 89 | EXPECT_EQ("c", results[2]); 90 | EXPECT_EQ("d", results[3]); 91 | } 92 | 93 | TEST(StringUtils, ParseInt32) { 94 | EXPECT_EQ(ParseInt32("0", -1), 0); 95 | EXPECT_EQ(ParseInt32("100", -1), 100); 96 | EXPECT_EQ(ParseInt32("-100", -1), -100); 97 | 98 | EXPECT_EQ(ParseInt32("", -1), -1); 99 | EXPECT_EQ(ParseInt32("a", -1), -1); 100 | EXPECT_EQ(ParseInt32("10x1", -1), 10); 101 | 102 | EXPECT_EQ(ParseInt32("2147483647", -1), 2147483647); 103 | EXPECT_EQ(ParseInt32("2147483648", -1), 2147483647); 104 | 105 | EXPECT_EQ(ParseInt32("-2147483648", -1), -2147483648); 106 | EXPECT_EQ(ParseInt32("-2147483649", -1), -2147483648); 107 | } 108 | 109 | } // namespace base 110 | } // namespace astc_codec 111 | -------------------------------------------------------------------------------- /src/base/test/type_traits_test.cpp: -------------------------------------------------------------------------------- 1 | // Copyright 2018 Google LLC 2 | // 3 | // Licensed under the Apache License, Version 2.0 (the "License"); 4 | // you may not use this file except in compliance with the License. 5 | // You may obtain a copy of the License at 6 | // 7 | // https://www.apache.org/licenses/LICENSE-2.0 8 | // 9 | // Unless required by applicable law or agreed to in writing, software 10 | // distributed under the License is distributed on an "AS IS" BASIS, 11 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | // See the License for the specific language governing permissions and 13 | // limitations under the License. 14 | 15 | #include "src/base/type_traits.h" 16 | 17 | #include 18 | 19 | #include 20 | #include 21 | #include 22 | #include 23 | 24 | namespace astc_codec { 25 | namespace base { 26 | 27 | TEST(TypeTraits, IsCallable) { 28 | class C; 29 | C* c = nullptr; 30 | 31 | auto lambda = [c](bool) -> C* { return nullptr; }; 32 | 33 | static_assert(is_callable_as::value, "simple function"); 34 | static_assert(is_callable_as::value, 35 | "function reference"); 36 | static_assert(is_callable_as::value, "function pointer"); 37 | static_assert(is_callable_as::value, 38 | "function with arguments and return type"); 39 | static_assert(is_callable_as::value, "lambda"); 40 | static_assert(is_callable_as, bool(int)>::value, 41 | "std::function"); 42 | 43 | static_assert(!is_callable_as::value, 44 | "int should not be callable"); 45 | static_assert(!is_callable_as::value, "incomplete type"); 46 | static_assert(!is_callable_as::value, 47 | "different arguments"); 48 | static_assert(!is_callable_as::value, 49 | "different return types"); 50 | static_assert(!is_callable_as::value, 51 | "slightly different return types"); 52 | static_assert(!is_callable_as::value, 53 | "more arguments"); 54 | static_assert(!is_callable_as::value, 55 | "less arguments"); 56 | 57 | static_assert(!is_callable_as::value, 58 | "bad required signature"); 59 | 60 | static_assert(is_callable_with_args::value, 61 | "simple function"); 62 | static_assert(is_callable_with_args::value, 63 | "function reference"); 64 | static_assert(is_callable_with_args::value, 65 | "function pointer"); 66 | static_assert(is_callable_with_args::value, 67 | "function with arguments and return type"); 68 | static_assert(is_callable_with_args::value, 69 | "lambda"); 70 | static_assert( 71 | is_callable_with_args, bool(int)>::value, 72 | "std::function"); 73 | 74 | static_assert(!is_callable_with_args::value, 75 | "int should not be callable"); 76 | static_assert(!is_callable_with_args::value, "incomplete type"); 77 | static_assert(!is_callable_with_args::value, 78 | "different arguments"); 79 | static_assert(is_callable_with_args::value, 80 | "different return types are ignored"); 81 | static_assert(is_callable_with_args::value, 82 | "slightly different return types are ignored"); 83 | static_assert(!is_callable_with_args::value, 84 | "more arguments"); 85 | static_assert(!is_callable_with_args::value, 86 | "less arguments"); 87 | 88 | static_assert(!is_callable_with_args::value, 89 | "bad required signature"); 90 | } 91 | 92 | TEST(TypeTraits, IsTemplateInstantiation) { 93 | static_assert(!is_template_instantiation_of::value, 94 | "int is not an instance of vector"); 95 | static_assert(!is_template_instantiation_of>, 96 | std::vector>::value, 97 | "list is not an instance of vector"); 98 | 99 | static_assert( 100 | is_template_instantiation_of, std::vector>::value, 101 | "std::vector is an instance of vector"); 102 | static_assert( 103 | is_template_instantiation_of>>, 104 | std::vector>::value, 105 | "nested std::vector<> is an instance of vector"); 106 | } 107 | 108 | #ifndef _MSC_VER 109 | TEST(TypeTraits, IsRange) { 110 | static_assert(is_range>::value, 111 | "vector<> should be detected as a range"); 112 | static_assert(is_range>>::value, 113 | "const list<> should be detected as a range"); 114 | static_assert(is_range, 10>>::value, 115 | "array<> should be detected as a range"); 116 | char arr[100]; 117 | static_assert(is_range::value, 118 | "C array should be detected as a range"); 119 | static_assert(is_range::value, 120 | "String literal should be detected as a range"); 121 | 122 | static_assert(!is_range::value, "int shouldn't be a range"); 123 | static_assert(!is_range::value, "int* shouldn't be a range"); 124 | static_assert(!is_range::value, 125 | "even const int* shouldn't be a range"); 126 | } 127 | #endif 128 | 129 | } // namespace base 130 | } // namespace astc_codec 131 | -------------------------------------------------------------------------------- /src/base/test/uint128_test.cpp: -------------------------------------------------------------------------------- 1 | // Copyright 2018 Google LLC 2 | // 3 | // Licensed under the Apache License, Version 2.0 (the "License"); 4 | // you may not use this file except in compliance with the License. 5 | // You may obtain a copy of the License at 6 | // 7 | // https://www.apache.org/licenses/LICENSE-2.0 8 | // 9 | // Unless required by applicable law or agreed to in writing, software 10 | // distributed under the License is distributed on an "AS IS" BASIS, 11 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | // See the License for the specific language governing permissions and 13 | // limitations under the License. 14 | 15 | #include "src/base/uint128.h" 16 | 17 | #include 18 | 19 | namespace astc_codec { 20 | namespace base { 21 | 22 | TEST(UInt128, Equality) { 23 | const UInt128 zero(0); 24 | const UInt128 max64(~0ULL); 25 | 26 | EXPECT_EQ(zero, zero); 27 | EXPECT_NE(zero, max64); 28 | EXPECT_EQ(zero, UInt128(0)); 29 | EXPECT_NE(zero, UInt128(1)); 30 | EXPECT_EQ(max64, max64); 31 | } 32 | 33 | TEST(UInt128, Shifting) { 34 | const UInt128 max64(~0ULL); 35 | const UInt128 upper64(~0ULL, 0); 36 | EXPECT_EQ(upper64.HighBits(), ~0ULL); 37 | EXPECT_EQ(upper64.LowBits(), 0); 38 | 39 | EXPECT_EQ(upper64 >> 64, max64); 40 | 41 | EXPECT_EQ(UInt128(1) << 1, UInt128(2)); 42 | EXPECT_EQ(UInt128(0) << 0, UInt128(0)); 43 | EXPECT_EQ(max64 << 0, max64); 44 | EXPECT_EQ(max64 >> 0, max64); 45 | EXPECT_EQ(upper64 << 0, upper64); 46 | EXPECT_EQ(upper64 >> 0, upper64); 47 | 48 | { 49 | const UInt128 bit63 = UInt128(1ULL << 62) << 1; 50 | EXPECT_EQ(bit63.LowBits(), 1ULL << 63); 51 | EXPECT_EQ(bit63.HighBits(), 0); 52 | } 53 | 54 | { 55 | const UInt128 bit64 = UInt128(1ULL << 63) << 1; 56 | EXPECT_EQ(bit64.LowBits(), 0); 57 | EXPECT_EQ(bit64.HighBits(), 1); 58 | EXPECT_EQ(bit64 >> 1, UInt128(1ULL << 63)); 59 | } 60 | 61 | { 62 | const UInt128 overshift = max64 << 128; 63 | EXPECT_EQ(overshift.HighBits(), 0); 64 | EXPECT_EQ(overshift.LowBits(), 0); 65 | } 66 | 67 | { 68 | const UInt128 overlap = upper64 >> 32; 69 | EXPECT_EQ(overlap.HighBits(), 0x00000000FFFFFFFF); 70 | EXPECT_EQ(overlap.LowBits(), 0xFFFFFFFF00000000); 71 | } 72 | 73 | { 74 | const UInt128 overlap = max64 << 32; 75 | EXPECT_EQ(overlap.HighBits(), 0x00000000FFFFFFFF); 76 | EXPECT_EQ(overlap.LowBits(), 0xFFFFFFFF00000000); 77 | } 78 | } 79 | 80 | TEST(UInt128, LargeShift) { 81 | const UInt128 base(0xFF); 82 | EXPECT_EQ(base << 64, UInt128(0xFFULL, 0)); 83 | EXPECT_EQ(base << 72, UInt128(0xFF00ULL, 0)); 84 | EXPECT_EQ(base << 80, UInt128(0xFF0000ULL, 0)); 85 | EXPECT_EQ(base << 88, UInt128(0xFF000000ULL, 0)); 86 | EXPECT_EQ(base << 96, UInt128(0xFF00000000ULL, 0)); 87 | EXPECT_EQ(base << 104, UInt128(0xFF0000000000ULL, 0)); 88 | EXPECT_EQ(base << 112, UInt128(0xFF000000000000ULL, 0)); 89 | EXPECT_EQ(base << 120, UInt128(0xFF00000000000000ULL, 0)); 90 | 91 | const UInt128 upper(0xFF00000000000000ULL, 0); 92 | EXPECT_EQ(upper >> 64, UInt128(0, 0xFF00000000000000ULL)); 93 | EXPECT_EQ(upper >> 72, UInt128(0, 0xFF000000000000ULL)); 94 | EXPECT_EQ(upper >> 80, UInt128(0, 0xFF0000000000ULL)); 95 | EXPECT_EQ(upper >> 88, UInt128(0, 0xFF00000000ULL)); 96 | EXPECT_EQ(upper >> 96, UInt128(0, 0xFF000000ULL)); 97 | EXPECT_EQ(upper >> 104, UInt128(0, 0xFF0000ULL)); 98 | EXPECT_EQ(upper >> 112, UInt128(0, 0xFF00ULL)); 99 | EXPECT_EQ(upper >> 120, UInt128(0, 0xFFULL)); 100 | } 101 | 102 | TEST(UInt128, BooleanOperators) { 103 | const UInt128 allOnes(~0ULL, ~0ULL); 104 | EXPECT_EQ(allOnes.HighBits(), ~0ULL); 105 | EXPECT_EQ(allOnes.LowBits(), ~0ULL); 106 | 107 | EXPECT_EQ(~allOnes, UInt128(0)); 108 | EXPECT_EQ(~UInt128(0), allOnes); 109 | 110 | EXPECT_EQ(UInt128(0xFFFF00) & UInt128(0x00FFFF), UInt128(0x00FF00)); 111 | EXPECT_EQ(UInt128(0xFFFF00) | UInt128(0x00FFFF), UInt128(0xFFFFFF)); 112 | EXPECT_EQ(UInt128(0xFFFF00) ^ UInt128(0x00FFFF), UInt128(0xFF00FF)); 113 | } 114 | 115 | TEST(UInt128, Addition) { 116 | const UInt128 bit63(1ULL << 63); 117 | 118 | EXPECT_EQ(UInt128(1) + 1, UInt128(2)); 119 | EXPECT_EQ(bit63 + bit63, UInt128(1) << 64); 120 | 121 | const UInt128 carryUp = UInt128(~0ULL) + 1; 122 | EXPECT_EQ(carryUp.HighBits(), 1); 123 | EXPECT_EQ(carryUp.LowBits(), 0); 124 | 125 | const UInt128 allOnes(~0ULL, ~0ULL); 126 | EXPECT_EQ(allOnes + 1, UInt128(0)); 127 | } 128 | 129 | TEST(UInt128, Subtraction) { 130 | const UInt128 bit64 = UInt128(1) << 64; 131 | EXPECT_EQ(bit64 - 1, UInt128(~0ULL)); 132 | 133 | EXPECT_EQ(UInt128(1) - 1, UInt128(0)); 134 | 135 | const UInt128 allOnes(~0ULL, ~0ULL); 136 | EXPECT_EQ(UInt128(0) - 1, allOnes); 137 | } 138 | 139 | } // namespace base 140 | } // namespace astc_codec 141 | -------------------------------------------------------------------------------- /src/base/type_traits.h: -------------------------------------------------------------------------------- 1 | // Copyright 2018 Google LLC 2 | // 3 | // Licensed under the Apache License, Version 2.0 (the "License"); 4 | // you may not use this file except in compliance with the License. 5 | // You may obtain a copy of the License at 6 | // 7 | // https://www.apache.org/licenses/LICENSE-2.0 8 | // 9 | // Unless required by applicable law or agreed to in writing, software 10 | // distributed under the License is distributed on an "AS IS" BASIS, 11 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | // See the License for the specific language governing permissions and 13 | // limitations under the License. 14 | 15 | #ifndef ASTC_CODEC_BASE_TYPE_TRAITS_H_ 16 | #define ASTC_CODEC_BASE_TYPE_TRAITS_H_ 17 | 18 | #include 19 | #include 20 | 21 | namespace astc_codec { 22 | namespace base { 23 | 24 | namespace details { 25 | 26 | // a simple helper class for SFINAE below. 27 | template 28 | struct dummy { 29 | using type = X; 30 | }; 31 | 32 | } // namespace details 33 | 34 | // add some convenience shortcuts for an overly complex std::enable_if syntax 35 | 36 | // Use 'enable_if' instead of 37 | // 'typename std::enable_if::type' 38 | template 39 | using enable_if = typename std::enable_if::type; 40 | 41 | // Use 'enable_if_c' instead of 42 | // 'typename std::enable_if::type' 43 | template 44 | using enable_if_c = typename std::enable_if::type; 45 | 46 | // Use 'enable_if_convertible' instead of 47 | // 'typename std::enable_if::value, Type>::type' 48 | template 49 | using enable_if_convertible = enable_if>; 50 | 51 | // ----------------------------------------------------------------------------- 52 | // A predicate for checking if some object is callable with a specific 53 | // signature. Examples: 54 | // 55 | // is_callable_as::value == false. 56 | // is_callable_as::value == false. 57 | // is_callable_as::value == true 58 | // 59 | template 60 | struct is_callable_as : std::false_type {}; 61 | 62 | // This specialization is SFINAE-d out if template arguments can't be combined 63 | // into a call expression F(), or if the result of that call is not |R| 64 | template 65 | struct is_callable_as()( 68 | std::declval()...))>::type, 69 | R>::value>::type> : std::true_type {}; 70 | 71 | // 72 | // A similar predicate to only check arguments of the function call and ignore 73 | // the specified return type 74 | // 75 | // is_callable_as::value == true 76 | // is_callable_as::value == false 77 | // is_callable_with_args::value == true 78 | // 79 | template 80 | struct is_callable_with_args : std::false_type {}; 81 | 82 | template 83 | struct is_callable_with_args< 84 | F, R(Args...), 85 | typename std::enable_if< 86 | !std::is_same()(std::declval()...))>::type, 88 | F>::value>::type> : std::true_type {}; 89 | 90 | // ----------------------------------------------------------------------------- 91 | // Check if a type |T| is any instantiation of a template |U|. Examples: 92 | // 93 | // is_template_instantiation_of::value == false 94 | // is_template_instantiation_of< 95 | // std::list>, std::vector>::value == false 96 | // is_template_instantiation_of, std::vector>::value == true 97 | // is_template_instantiation_of< 98 | // std::vector>, std::vector>::value == true 99 | // 100 | template class U> 101 | struct is_template_instantiation_of : std::false_type {}; 102 | 103 | template class U, class... Args> 104 | struct is_template_instantiation_of, U> : std::true_type {}; 105 | // ----------------------------------------------------------------------------- 106 | 107 | // 108 | // is_range - check if type |T| is a range-like type. 109 | // 110 | // It makes sure that expressions std::begin(t) and std::end(t) are well-formed 111 | // and those return the same type. 112 | // 113 | // Note: with expression SFINAE from C++14 is_range_helper<> could be renamed to 114 | // is_range<> with no extra code. C++11 needs an extra level of enable_if<> 115 | // to make it work when the type isn't a range. 116 | // 117 | 118 | namespace details { 119 | 120 | template 121 | using is_range_helper = std::is_same< 122 | decltype(std::begin( 123 | std::declval::type>())), 124 | decltype( 125 | std::end(std::declval::type>()))>; 126 | 127 | } // namespace details 128 | 129 | template 130 | struct is_range : std::false_type {}; 131 | 132 | template 133 | struct is_range< 134 | T, typename std::enable_if::value>::type> 135 | : std::true_type {}; 136 | 137 | //////////////////////////////////////////////////////////////////////////////// 138 | // 139 | // A class to incapsulate integer sequence 0, 1, ..., 140 | // Seq 141 | // Useful to pass function parameters in an array/tuple to call it later. 142 | // 143 | 144 | template 145 | struct Seq {}; 146 | 147 | // A 'maker' class to construct Seq given only 148 | // value. 149 | // MakeSeq works this way, e.g. 150 | // 151 | // MakeSeq<2> inherits MakeSeq<2 - 1, 2 - 1> == MakeSeq<1, 1> 152 | // MakeSeq<1, 1> : MakeSeq<1 - 1, 1 - 1, 1> == MakeSeq<0, 0, 1> 153 | // MakeSeq<0, 0, 1> == MakeSeq<0, S...> and defines |type| = Seq<0, 1> 154 | 155 | template 156 | struct MakeSeq : MakeSeq {}; 157 | 158 | template 159 | struct MakeSeq<0, S...> { 160 | using type = Seq; 161 | }; 162 | 163 | // 164 | // MakeSeqT alias to quickly create Seq<...>: 165 | // MakeSeqT<3> == Seq<0, 1, 2> 166 | template 167 | using MakeSeqT = typename MakeSeq::type; 168 | 169 | } // namespace base 170 | } // namespace astc_codec 171 | 172 | #endif // ASTC_CODEC_BASE_TYPE_TRAITS_H_ 173 | -------------------------------------------------------------------------------- /src/base/uint128.h: -------------------------------------------------------------------------------- 1 | // Copyright 2018 Google LLC 2 | // 3 | // Licensed under the Apache License, Version 2.0 (the "License"); 4 | // you may not use this file except in compliance with the License. 5 | // You may obtain a copy of the License at 6 | // 7 | // https://www.apache.org/licenses/LICENSE-2.0 8 | // 9 | // Unless required by applicable law or agreed to in writing, software 10 | // distributed under the License is distributed on an "AS IS" BASIS, 11 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | // See the License for the specific language governing permissions and 13 | // limitations under the License. 14 | 15 | #ifndef ASTC_CODEC_BASE_UINT128_H_ 16 | #define ASTC_CODEC_BASE_UINT128_H_ 17 | 18 | #include 19 | #include 20 | 21 | namespace astc_codec { 22 | namespace base { 23 | 24 | class UInt128 { 25 | public: 26 | UInt128() = default; 27 | UInt128(uint64_t low) : low_(low) { } 28 | UInt128(uint64_t high, uint64_t low) : low_(low), high_(high) { } 29 | UInt128(const UInt128& other) : low_(other.low_), high_(other.high_) { } 30 | 31 | uint64_t LowBits() const { return low_; } 32 | uint64_t HighBits() const { return high_; } 33 | 34 | // Allow explicit casts to uint64_t. 35 | explicit operator uint64_t() const { return low_; } 36 | 37 | // Copy operators. 38 | UInt128& operator=(const UInt128& other) { 39 | high_ = other.high_; 40 | low_ = other.low_; 41 | return *this; 42 | } 43 | 44 | // Equality operators. 45 | bool operator==(const UInt128& other) const { 46 | return high_ == other.high_ && low_ == other.low_; 47 | } 48 | 49 | bool operator!=(const UInt128& other) const { 50 | return high_ != other.high_ || low_ != other.low_; 51 | } 52 | 53 | // Shifting. 54 | UInt128& operator<<=(int shift) { 55 | high_ = shift >= 64 ? (shift >= 128 ? 0 : low_ << (shift - 64)) 56 | : high_ << shift; 57 | 58 | if (shift > 0 && shift < 64) { 59 | const uint64_t overlappingBits = low_ >> (64 - shift); 60 | high_ |= overlappingBits; 61 | } 62 | 63 | low_ = shift >= 64 ? 0 : low_ << shift; 64 | return *this; 65 | } 66 | 67 | UInt128 operator<<(int shift) const { 68 | UInt128 result = *this; 69 | result <<= shift; 70 | return result; 71 | } 72 | 73 | UInt128& operator>>=(int shift) { 74 | low_ = shift >= 64 ? (shift >= 128 ? 0 : high_ >> (shift - 64)) 75 | : low_ >> shift; 76 | 77 | if (shift > 0 && shift < 64) { 78 | const uint64_t overlappingBits = high_ << (64 - shift); 79 | low_ |= overlappingBits; 80 | } 81 | 82 | high_ = shift >= 64 ? 0 : high_ >> shift; 83 | 84 | return *this; 85 | } 86 | 87 | UInt128 operator>>(int shift) const { 88 | UInt128 result = *this; 89 | result >>= shift; 90 | return result; 91 | } 92 | 93 | // Binary operations. 94 | UInt128& operator|=(const UInt128& other) { 95 | high_ |= other.high_; 96 | low_ |= other.low_; 97 | return *this; 98 | } 99 | 100 | UInt128 operator|(const UInt128& other) const { 101 | UInt128 result = *this; 102 | result |= other; 103 | return result; 104 | } 105 | 106 | UInt128& operator&=(const UInt128& other) { 107 | high_ &= other.high_; 108 | low_ &= other.low_; 109 | return *this; 110 | } 111 | 112 | UInt128 operator&(const UInt128& other) const { 113 | UInt128 result = *this; 114 | result &= other; 115 | return result; 116 | } 117 | 118 | UInt128& operator^=(const UInt128& other) { 119 | high_ ^= other.high_; 120 | low_ ^= other.low_; 121 | return *this; 122 | } 123 | 124 | UInt128 operator^(const UInt128& other) const { 125 | UInt128 result = *this; 126 | result ^= other; 127 | return result; 128 | } 129 | 130 | UInt128 operator~() const { 131 | UInt128 result = *this; 132 | result.high_ = ~high_; 133 | result.low_ = ~low_; 134 | return result; 135 | } 136 | 137 | // Addition/subtraction. 138 | UInt128& operator+=(const UInt128& other) { 139 | const uint64_t carry = 140 | (((low_ & other.low_) & 1) + (low_ >> 1) + (other.low_ >> 1)) >> 63; 141 | high_ += other.high_ + carry; 142 | low_ += other.low_; 143 | return *this; 144 | } 145 | 146 | UInt128 operator+(const UInt128& other) const { 147 | UInt128 result = *this; 148 | result += other; 149 | return result; 150 | } 151 | 152 | UInt128& operator-=(const UInt128& other) { 153 | low_ -= other.low_; 154 | const uint64_t carry = 155 | (((low_ & other.low_) & 1) + (low_ >> 1) + (other.low_ >> 1)) >> 63; 156 | high_ -= other.high_ + carry; 157 | return *this; 158 | } 159 | 160 | UInt128 operator-(const UInt128& other) const { 161 | UInt128 result = *this; 162 | result -= other; 163 | return result; 164 | } 165 | 166 | private: 167 | // TODO(google): Different order for little endian. 168 | uint64_t low_ = 0; 169 | uint64_t high_ = 0; 170 | }; 171 | 172 | } // namespace base 173 | } // namespace astc_codec 174 | 175 | #endif // ASTC_CODEC_BASE_UINT128_H_ 176 | -------------------------------------------------------------------------------- /src/base/utils.h: -------------------------------------------------------------------------------- 1 | // Copyright 2018 Google LLC 2 | // 3 | // Licensed under the Apache License, Version 2.0 (the "License"); 4 | // you may not use this file except in compliance with the License. 5 | // You may obtain a copy of the License at 6 | // 7 | // https://www.apache.org/licenses/LICENSE-2.0 8 | // 9 | // Unless required by applicable law or agreed to in writing, software 10 | // distributed under the License is distributed on an "AS IS" BASIS, 11 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | // See the License for the specific language governing permissions and 13 | // limitations under the License. 14 | 15 | #ifndef ASTC_CODEC_BASE_UTILS_H_ 16 | #define ASTC_CODEC_BASE_UTILS_H_ 17 | 18 | #include 19 | #include 20 | #include 21 | 22 | #ifdef NDEBUG 23 | #define UTILS_RELEASE_ASSERT(x) \ 24 | do { \ 25 | const bool result = (x); \ 26 | if (!result) { \ 27 | fprintf(stderr, "Error: UTILS_RELEASE_ASSERT failed: %s\n", #x); \ 28 | abort(); \ 29 | } \ 30 | } while (false) 31 | #else 32 | #define UTILS_RELEASE_ASSERT(x) assert(x) 33 | #endif 34 | 35 | // In C++11, `assert` can't be used portably within constexpr functions. 36 | // ASTC_CONSTEXPR_ASSERT functions as a runtime assert but works in C++11 37 | // constexpr functions. Example: 38 | // 39 | // constexpr double Divide(double a, double b) { 40 | // return ASTC_CONSTEXPR_ASSERT(b != 0), a / b; 41 | // } 42 | // 43 | // This macro is based on ABSL_ASSERT. 44 | #ifdef NDEBUG 45 | #define ASTC_CONSTEXPR_ASSERT(expr) \ 46 | (false ? static_cast(expr) : static_cast(0)) 47 | #else 48 | #define ASTC_CONSTEXPR_ASSERT(expr) \ 49 | ((expr) ? static_cast(0) : [] { assert(false && #expr); }()) 50 | #endif 51 | 52 | #endif // ASTC_CODEC_BASE_UTILS_H_ 53 | -------------------------------------------------------------------------------- /src/decoder/BUILD.bazel: -------------------------------------------------------------------------------- 1 | # Copyright 2018 Google LLC 2 | # 3 | # Licensed under the Apache License, Version 2.0 (the "License"); 4 | # you may not use this file except in compliance with the License. 5 | # You may obtain a copy of the License at 6 | # 7 | # https://www.apache.org/licenses/LICENSE-2.0 8 | # 9 | # Unless required by applicable law or agreed to in writing, software 10 | # distributed under the License is distributed on an "AS IS" BASIS, 11 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | # See the License for the specific language governing permissions and 13 | # limitations under the License. 14 | 15 | licenses(["notice"]) 16 | 17 | cc_library( 18 | name = "footprint", 19 | srcs = ["footprint.cc"], 20 | hdrs = ["footprint.h"], 21 | deps = [ 22 | "//:api", 23 | "//src/base", 24 | ], 25 | ) 26 | 27 | cc_library( 28 | name = "astc_utils", 29 | srcs = [ 30 | "astc_file.cc", 31 | "endpoint_codec.cc", 32 | "integer_sequence_codec.cc", 33 | "intermediate_astc_block.cc", 34 | "logical_astc_block.cc", 35 | "partition.cc", 36 | "physical_astc_block.cc", 37 | "quantization.cc", 38 | "weight_infill.cc", 39 | ], 40 | hdrs = [ 41 | "astc_file.h", 42 | "endpoint_codec.h", 43 | "integer_sequence_codec.h", 44 | "intermediate_astc_block.h", 45 | "logical_astc_block.h", 46 | "partition.h", 47 | "physical_astc_block.h", 48 | "quantization.h", 49 | "types.h", 50 | "weight_infill.h", 51 | ], 52 | copts = [ 53 | "-Wno-unused-variable", 54 | "-O3", 55 | ], 56 | deps = [ 57 | ":footprint", 58 | "//src/base", 59 | ], 60 | ) 61 | 62 | cc_library( 63 | name = "codec", 64 | srcs = ["codec.cc"], 65 | hdrs = ["codec.h"], 66 | visibility = ["//:__pkg__"], 67 | deps = [ 68 | ":astc_utils", 69 | ":footprint", 70 | "//src/base", 71 | ], 72 | ) 73 | 74 | cc_binary( 75 | name = "astc_inspector_cli", 76 | srcs = ["tools/astc_inspector_cli.cc"], 77 | deps = [ 78 | ":astc_utils", 79 | "//src/base", 80 | ], 81 | ) 82 | 83 | ################################################################################ 84 | ## 85 | ## Testing 86 | ## 87 | ################################################################################ 88 | 89 | cc_library( 90 | name = "test", 91 | testonly = 1, 92 | hdrs = ["test/image_utils.h"], 93 | deps = ["@gtest//:gtest"], 94 | ) 95 | 96 | cc_test( 97 | name = "physical_astc_block_test", 98 | size = "small", 99 | srcs = ["test/physical_astc_block_test.cc"], 100 | deps = [ 101 | ":astc_utils", 102 | "@gtest//:gtest_main", 103 | "//src/base", 104 | ], 105 | ) 106 | 107 | cc_test( 108 | name = "partition_test", 109 | size = "medium", 110 | srcs = ["test/partition_test.cc"], 111 | deps = [ 112 | ":astc_utils", 113 | "@gtest//:gtest_main", 114 | ], 115 | ) 116 | 117 | cc_test( 118 | name = "integer_sequence_codec_test", 119 | size = "small", 120 | srcs = ["test/integer_sequence_codec_test.cc"], 121 | deps = [ 122 | ":astc_utils", 123 | "@gtest//:gtest_main", 124 | "//src/base", 125 | ], 126 | ) 127 | 128 | cc_test( 129 | name = "intermediate_astc_block_test", 130 | size = "small", 131 | srcs = ["test/intermediate_astc_block_test.cc"], 132 | data = glob([ 133 | "testdata/checkered_*.astc", 134 | ]), 135 | deps = [ 136 | ":astc_utils", 137 | ":test", 138 | "@gtest//:gtest_main", 139 | ], 140 | ) 141 | 142 | cc_test( 143 | name = "quantization_test", 144 | size = "medium", 145 | srcs = ["test/quantization_test.cc"], 146 | deps = [ 147 | ":astc_utils", 148 | "@gtest//:gtest_main", 149 | ], 150 | ) 151 | 152 | cc_test( 153 | name = "weight_infill_test", 154 | size = "small", 155 | srcs = ["test/weight_infill_test.cc"], 156 | deps = [ 157 | ":astc_utils", 158 | ":footprint", 159 | "@gtest//:gtest_main", 160 | ], 161 | ) 162 | 163 | cc_test( 164 | name = "endpoint_codec_test", 165 | size = "small", 166 | srcs = ["test/endpoint_codec_test.cc"], 167 | data = [ 168 | ":testdata/checkerboard.astc", 169 | ], 170 | deps = [ 171 | ":astc_utils", 172 | ":test", 173 | "@gtest//:gtest_main", 174 | ], 175 | ) 176 | 177 | cc_test( 178 | name = "logical_astc_block_test", 179 | size = "large", 180 | srcs = ["test/logical_astc_block_test.cc"], 181 | data = glob([ 182 | "testdata/atlas_small_*.astc", 183 | "testdata/atlas_small_*.bmp", 184 | "testdata/footprint_*.astc", 185 | "testdata/footprint_*.bmp", 186 | "testdata/rgb_*.astc", 187 | "testdata/rgb_*.bmp", 188 | ]), 189 | deps = [ 190 | ":astc_utils", 191 | ":test", 192 | "@gtest//:gtest_main", 193 | ], 194 | ) 195 | 196 | cc_test( 197 | name = "codec_test", 198 | size = "large", 199 | srcs = ["test/codec_test.cc"], 200 | data = glob([ 201 | "testdata/atlas_small_*.astc", 202 | "testdata/atlas_small_*.bmp", 203 | ]), 204 | deps = [ 205 | ":codec", 206 | ":test", 207 | "@gtest//:gtest_main", 208 | "//:api", 209 | ], 210 | ) 211 | 212 | cc_test( 213 | name = "footprint_test", 214 | size = "small", 215 | srcs = ["test/footprint_test.cc"], 216 | deps = [ 217 | ":footprint", 218 | "@gtest//:gtest_main", 219 | ], 220 | ) 221 | 222 | cc_test( 223 | name = "astc_fuzzer", 224 | srcs = ["test/astc_fuzzer.cc"], 225 | copts = select({ 226 | # Clang-only flags. TODO: Find a better way to detect GCC/clang. 227 | "@bazel_tools//src/conditions:darwin_x86_64": [ 228 | "-fsanitize-coverage=trace-pc-guard,indirect-calls,trace-cmp", 229 | "-fsanitize-coverage=bb", 230 | ], 231 | "@bazel_tools//src/conditions:darwin": [ 232 | "-fsanitize-coverage=trace-pc-guard,indirect-calls,trace-cmp", 233 | "-fsanitize-coverage=bb", 234 | ], 235 | # GCC-only flags. 236 | "//conditions:default": [ 237 | "-finstrument-functions" 238 | ], 239 | }), 240 | deps = [ 241 | ":codec", 242 | "@honggfuzz//:honggfuzz", 243 | "@benchmark//:benchmark", 244 | ], 245 | linkstatic = 1, 246 | ) 247 | -------------------------------------------------------------------------------- /src/decoder/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | # Copyright 2018 Google LLC 2 | # 3 | # Licensed under the Apache License, Version 2.0 (the "License"); you may not 4 | # use this file except in compliance with the License. You may obtain a copy of 5 | # the License at 6 | # 7 | # https://www.apache.org/licenses/LICENSE-2.0 8 | # 9 | # Unless required by applicable law or agreed to in writing, software 10 | # distributed under the License is distributed on an "AS IS" BASIS, WITHOUT 11 | # WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the 12 | # License for the specific language governing permissions and limitations under 13 | # the License. 14 | add_library(footprint footprint.cc) 15 | target_link_libraries(footprint base) 16 | 17 | add_library(astc_utils 18 | astc_file.cc 19 | endpoint_codec.cc 20 | integer_sequence_codec.cc 21 | intermediate_astc_block.cc 22 | logical_astc_block.cc 23 | partition.cc 24 | physical_astc_block.cc 25 | quantization.cc 26 | weight_infill.cc) 27 | target_link_libraries(astc_utils PRIVATE base footprint) 28 | target_include_directories(astc_utils PRIVATE ../..) 29 | 30 | add_library(astc-codec codec.cc) 31 | target_link_libraries(astc-codec PRIVATE astc_utils) 32 | target_include_directories(astc-codec PUBLIC ../../include) 33 | target_include_directories(astc-codec PRIVATE ../..) 34 | 35 | add_executable(astc_inspector_cli tools/astc_inspector_cli.cc) 36 | target_include_directories(astc_inspector_cli PRIVATE ../..) 37 | target_link_libraries(astc_inspector_cli PRIVATE astc_utils) 38 | 39 | # 40 | # Testing 41 | # 42 | if(OPTION_ASTC_TESTS) 43 | # Note that we will execute all the tests in the project directory. 44 | # We do this to ensure the unit tests can pick up the required test data 45 | 46 | # Create interface library exposing the root as an include directory 47 | add_library(codec_test_dependencies INTERFACE) 48 | target_include_directories(codec_test_dependencies INTERFACE ../..) 49 | 50 | add_executable(physical_astc_block_test test/physical_astc_block_test.cc) 51 | add_test(NAME physical_astc_block_test COMMAND physical_astc_block_test WORKING_DIRECTORY ${PROJECT_SOURCE_DIR}) 52 | target_link_libraries(physical_astc_block_test astc_utils codec_test_dependencies gmock_main) 53 | 54 | add_executable(partition_test test/partition_test.cc) 55 | add_test(NAME partition_test COMMAND partition_test WORKING_DIRECTORY ${PROJECT_SOURCE_DIR}) 56 | target_link_libraries(partition_test PRIVATE astc_utils codec_test_dependencies gmock_main) 57 | 58 | add_executable(integer_sequence_codec_test test/integer_sequence_codec_test.cc) 59 | target_link_libraries(integer_sequence_codec_test PRIVATE astc_utils codec_test_dependencies gmock_main) 60 | 61 | add_executable(intermediate_astc_block_test test/intermediate_astc_block_test.cc) 62 | add_test(NAME intermediate_astc_block_test COMMAND intermediate_astc_block_test WORKING_DIRECTORY ${PROJECT_SOURCE_DIR}) 63 | target_link_libraries(intermediate_astc_block_test PRIVATE astc_utils codec_test_dependencies gmock_main) 64 | 65 | add_executable(quantization_test test/quantization_test.cc) 66 | add_test(NAME quantization_test COMMAND quantization_test WORKING_DIRECTORY ${PROJECT_SOURCE_DIR}) 67 | target_link_libraries(quantization_test PRIVATE astc_utils codec_test_dependencies gmock_main) 68 | 69 | add_executable(weight_infill_test test/weight_infill_test.cc) 70 | add_test(NAME weight_infill_test COMMAND weight_infill_test WORKING_DIRECTORY ${PROJECT_SOURCE_DIR}) 71 | target_link_libraries(weight_infill_test PRIVATE astc_utils footprint codec_test_dependencies gmock_main) 72 | 73 | add_executable(endpoint_codec_test test/endpoint_codec_test.cc) 74 | add_test(NAME endpoint_codec_test COMMAND endpoint_codec_test WORKING_DIRECTORY ${PROJECT_SOURCE_DIR}) 75 | target_link_libraries(endpoint_codec_test PRIVATE astc_utils codec_test_dependencies gmock_main) 76 | 77 | add_executable(logical_astc_block_test test/logical_astc_block_test.cc) 78 | add_test(NAME logical_astc_block_test COMMAND logical_astc_block_test WORKING_DIRECTORY ${PROJECT_SOURCE_DIR}) 79 | target_link_libraries(logical_astc_block_test PRIVATE astc_utils codec_test_dependencies gmock_main) 80 | 81 | add_executable(codec_test test/codec_test.cc) 82 | add_test(NAME codec_test COMMAND codec_test WORKING_DIRECTORY ${PROJECT_SOURCE_DIR}) 83 | 84 | target_link_libraries(codec_test PRIVATE astc-codec codec_test_dependencies gmock_main) 85 | 86 | add_executable(footprint_test test/footprint_test.cc) 87 | add_test(NAME footprint_test COMMAND footprint_test WORKING_DIRECTORY ${PROJECT_SOURCE_DIR}) 88 | target_link_libraries(footprint_test PRIVATE footprint codec_test_dependencies gmock_main) 89 | 90 | if(OPTION_BUILD_FUZZER) 91 | message(FATAL_ERROR "Not yet supported due to missing dependencies") 92 | add_executable(astc_fuzzer test/astc_fuzzer.cc codec_test_dependencies gmock_main) 93 | target_link_libraries(astc_fuzzer PRIVATE astc-codec honggfuzz benchmark) 94 | endif() 95 | endif() 96 | -------------------------------------------------------------------------------- /src/decoder/astc_file.cc: -------------------------------------------------------------------------------- 1 | // Copyright 2018 Google LLC 2 | // 3 | // Licensed under the Apache License, Version 2.0 (the "License"); 4 | // you may not use this file except in compliance with the License. 5 | // You may obtain a copy of the License at 6 | // 7 | // https://www.apache.org/licenses/LICENSE-2.0 8 | // 9 | // Unless required by applicable law or agreed to in writing, software 10 | // distributed under the License is distributed on an "AS IS" BASIS, 11 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | // See the License for the specific language governing permissions and 13 | // limitations under the License. 14 | 15 | #include "src/decoder/astc_file.h" 16 | 17 | #include 18 | #include 19 | #include 20 | #include 21 | 22 | namespace astc_codec { 23 | 24 | namespace { 25 | static constexpr size_t kASTCHeaderSize = 16; 26 | 27 | // Reads a value of size T from the buffer at the current offset, then 28 | // increments the offset. 29 | template 30 | inline T ReadVal(const char* file_data, size_t& offset) { 31 | T x; 32 | memcpy(&x, &file_data[offset], sizeof(T)); 33 | offset += sizeof(T); 34 | return x; 35 | } 36 | } // namespace 37 | 38 | ASTCFile::ASTCFile(Header&& header, std::string&& blocks) 39 | : header_(std::move(header)), blocks_(std::move(blocks)) {} 40 | 41 | std::unique_ptr ASTCFile::LoadFromMemory(const char* data, 42 | size_t length, 43 | std::string* error) { 44 | if (length < kASTCHeaderSize) { 45 | *error = "Incomplete header."; 46 | return nullptr; 47 | } 48 | 49 | base::Optional
header_opt = ParseHeader(data); 50 | if (!header_opt) { 51 | *error = "Invalid ASTC header."; 52 | return nullptr; 53 | } 54 | 55 | Header header = header_opt.value(); 56 | 57 | if (header.block_width_ == 0 || header.block_height_ == 0) { 58 | *error = "Invalid block size."; 59 | return nullptr; 60 | } 61 | 62 | std::string blocks(data + kASTCHeaderSize, data + length); 63 | 64 | // Check that this file has the expected number of blocks. 65 | const size_t expected_block_count = 66 | ((header.width_ + header.block_width_ - 1) / header.block_width_) * 67 | ((header.height_ + header.block_height_ - 1) / header.block_height_); 68 | 69 | if (blocks.size() % PhysicalASTCBlock::kSizeInBytes != 0 || 70 | blocks.size() / PhysicalASTCBlock::kSizeInBytes != expected_block_count) { 71 | std::stringstream ss; 72 | ss << "Unexpected file length " << blocks.size() << " expected " 73 | << kASTCHeaderSize + 74 | expected_block_count * PhysicalASTCBlock::kSizeInBytes 75 | << " bytes."; 76 | *error = ss.str(); 77 | return nullptr; 78 | } 79 | 80 | return std::unique_ptr( 81 | new ASTCFile(std::move(header), std::move(blocks))); 82 | } 83 | 84 | std::unique_ptr ASTCFile::LoadFile(const std::string& path, 85 | std::string* error) { 86 | std::ifstream is(path, std::ios::binary); 87 | if (!is) { 88 | *error = "File not found: " + path; 89 | return nullptr; 90 | } 91 | 92 | char header_data[kASTCHeaderSize] = {}; 93 | if (!is.read(header_data, kASTCHeaderSize)) { 94 | *error = "Failed to load ASTC header."; 95 | return nullptr; 96 | } 97 | 98 | base::Optional
header_opt = ParseHeader(header_data); 99 | if (!header_opt) { 100 | *error = "Invalid ASTC header."; 101 | return nullptr; 102 | } 103 | 104 | Header header = header_opt.value(); 105 | 106 | std::string blocks; 107 | { 108 | std::ostringstream ss; 109 | ss << is.rdbuf(); 110 | blocks = ss.str(); 111 | } 112 | 113 | // Check that this file has the expected number of blocks. 114 | const size_t expected_block_count = 115 | ((header.width_ + header.block_width_ - 1) / header.block_width_) * 116 | ((header.height_ + header.block_height_ - 1) / header.block_height_); 117 | 118 | if (blocks.size() % PhysicalASTCBlock::kSizeInBytes != 0 || 119 | blocks.size() / PhysicalASTCBlock::kSizeInBytes != expected_block_count) { 120 | std::stringstream ss; 121 | ss << "Unexpected file length " << blocks.size() << " expected " 122 | << kASTCHeaderSize + 123 | expected_block_count * PhysicalASTCBlock::kSizeInBytes 124 | << " bytes."; 125 | *error = ss.str(); 126 | return nullptr; 127 | } 128 | 129 | return std::unique_ptr( 130 | new ASTCFile(std::move(header), std::move(blocks))); 131 | } 132 | 133 | base::Optional ASTCFile::GetFootprint() const { 134 | return Footprint::FromDimensions(header_.block_width_, header_.block_height_); 135 | } 136 | 137 | std::string ASTCFile::GetFootprintString() const { 138 | std::stringstream footprint; 139 | footprint << header_.block_width_ << "x" << header_.block_height_; 140 | return footprint.str(); 141 | } 142 | 143 | const std::string& ASTCFile::GetRawBlockData() const { 144 | return blocks_; 145 | } 146 | 147 | PhysicalASTCBlock ASTCFile::GetBlock(size_t block_idx) const { 148 | const size_t sz = PhysicalASTCBlock::kSizeInBytes; 149 | const size_t offset = PhysicalASTCBlock::kSizeInBytes * block_idx; 150 | assert(offset <= blocks_.size() - sz); 151 | return PhysicalASTCBlock(blocks_.substr(offset, sz)); 152 | } 153 | 154 | base::Optional ASTCFile::ParseHeader(const char* header) { 155 | size_t offset = 0; 156 | // TODO(google): Handle endianness. 157 | const uint32_t magic = ReadVal(header, offset); 158 | if (magic != 0x5CA1AB13) { 159 | return {}; 160 | } 161 | 162 | const uint32_t block_width = ReadVal(header, offset); 163 | const uint32_t block_height = ReadVal(header, offset); 164 | const uint32_t block_depth = ReadVal(header, offset); 165 | 166 | uint32_t width = 0; 167 | width |= ReadVal(header, offset); 168 | width |= ReadVal(header, offset) << 8; 169 | width |= ReadVal(header, offset) << 16; 170 | 171 | uint32_t height = 0; 172 | height |= ReadVal(header, offset); 173 | height |= ReadVal(header, offset) << 8; 174 | height |= ReadVal(header, offset) << 16; 175 | 176 | uint32_t depth = 0; 177 | depth |= ReadVal(header, offset); 178 | depth |= ReadVal(header, offset) << 8; 179 | depth |= ReadVal(header, offset) << 16; 180 | assert(offset == kASTCHeaderSize); 181 | 182 | return Header(width, height, depth, block_width, block_height, block_depth); 183 | } 184 | 185 | } // namespace astc_codec 186 | -------------------------------------------------------------------------------- /src/decoder/astc_file.h: -------------------------------------------------------------------------------- 1 | // Copyright 2018 Google LLC 2 | // 3 | // Licensed under the Apache License, Version 2.0 (the "License"); 4 | // you may not use this file except in compliance with the License. 5 | // You may obtain a copy of the License at 6 | // 7 | // https://www.apache.org/licenses/LICENSE-2.0 8 | // 9 | // Unless required by applicable law or agreed to in writing, software 10 | // distributed under the License is distributed on an "AS IS" BASIS, 11 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | // See the License for the specific language governing permissions and 13 | // limitations under the License. 14 | 15 | #ifndef ASTC_CODEC_DECODER_ASTC_FILE_H_ 16 | #define ASTC_CODEC_DECODER_ASTC_FILE_H_ 17 | 18 | #include "src/base/optional.h" 19 | #include "src/decoder/footprint.h" 20 | #include "src/decoder/physical_astc_block.h" 21 | 22 | #include 23 | #include 24 | 25 | namespace astc_codec { 26 | 27 | // A thin wrapper around a .astc file on disk. This class simply reads the ASTC 28 | // header, and stores the block data in memory. 29 | class ASTCFile { 30 | private: 31 | struct Header { 32 | Header(size_t width, size_t height, size_t depth, size_t block_width, 33 | size_t block_height, size_t block_depth) 34 | : width_(width), 35 | height_(height), 36 | depth_(depth), 37 | block_width_(block_width), 38 | block_height_(block_height), 39 | block_depth_(block_depth) {} 40 | 41 | size_t width_; 42 | size_t height_; 43 | size_t depth_; 44 | 45 | size_t block_width_; 46 | size_t block_height_; 47 | size_t block_depth_; 48 | }; 49 | 50 | ASTCFile(ASTCFile::Header&& header, std::string&& blocks); 51 | 52 | public: 53 | // Load an ASTC file from memory. 54 | // If loading failed, nullptr is returned and an error string is populated 55 | // in the error parameter. 56 | static std::unique_ptr LoadFromMemory(const char* data, 57 | size_t length, 58 | std::string* error); 59 | 60 | // Load an ASTC file from file. 61 | // If loading failed, nullptr is returned and an error string is populated 62 | // in the error parameter. 63 | static std::unique_ptr LoadFile(const std::string& path, 64 | std::string* error); 65 | 66 | // Returns the footprint for the file, if it is considered to be a valid 67 | // footprint. 68 | base::Optional GetFootprint() const; 69 | 70 | // Returns the string of the form "NxM" where N and M are the width and height 71 | // of the block footprint, respectively. 72 | std::string GetFootprintString() const; 73 | 74 | // Get the raw block data for the astc file. 75 | const std::string& GetRawBlockData() const; 76 | 77 | // Returns the physical block at the associated block index. 78 | PhysicalASTCBlock GetBlock(size_t block_idx) const; 79 | 80 | size_t GetWidth() const { return header_.width_; } 81 | size_t GetHeight() const { return header_.height_; } 82 | size_t GetDepth() const { return header_.depth_; } 83 | 84 | size_t NumBlocks() const { 85 | return blocks_.size() / PhysicalASTCBlock::kSizeInBytes; 86 | } 87 | 88 | private: 89 | static base::Optional ParseHeader(const char* header); 90 | 91 | const Header header_; 92 | const std::string blocks_; 93 | }; 94 | 95 | } // namespace astc_codec 96 | 97 | #endif // ASTC_CODEC_DECODER_ASTC_FILE_H_ 98 | -------------------------------------------------------------------------------- /src/decoder/codec.cc: -------------------------------------------------------------------------------- 1 | // Copyright 2018 Google LLC 2 | // 3 | // Licensed under the Apache License, Version 2.0 (the "License"); 4 | // you may not use this file except in compliance with the License. 5 | // You may obtain a copy of the License at 6 | // 7 | // https://www.apache.org/licenses/LICENSE-2.0 8 | // 9 | // Unless required by applicable law or agreed to in writing, software 10 | // distributed under the License is distributed on an "AS IS" BASIS, 11 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | // See the License for the specific language governing permissions and 13 | // limitations under the License. 14 | 15 | #include "src/decoder/codec.h" 16 | #include "src/base/uint128.h" 17 | #include "src/decoder/logical_astc_block.h" 18 | #include "src/decoder/physical_astc_block.h" 19 | 20 | #include 21 | 22 | namespace astc_codec { 23 | 24 | namespace { 25 | static constexpr size_t kBytesPerPixelUNORM8 = 4; 26 | } 27 | 28 | bool DecompressToImage(const uint8_t* astc_data, size_t astc_data_size, 29 | size_t width, size_t height, Footprint footprint, 30 | uint8_t* out_buffer, size_t out_buffer_size, 31 | size_t out_buffer_stride) { 32 | const size_t block_width = footprint.Width(); 33 | const size_t block_height = footprint.Height(); 34 | assert(block_width != 0); 35 | assert(block_height != 0); 36 | 37 | if (width == 0 || height == 0) { 38 | return false; 39 | } 40 | 41 | const size_t blocks_wide = (width + block_width - 1) / block_width; 42 | assert(blocks_wide != 0); 43 | 44 | // Check that this buffer has the expected number of blocks. 45 | const size_t expected_block_count = 46 | ((width + block_width - 1) / block_width) * 47 | ((height + block_height - 1) / block_height); 48 | 49 | if (astc_data_size % PhysicalASTCBlock::kSizeInBytes != 0 || 50 | astc_data_size / PhysicalASTCBlock::kSizeInBytes != 51 | expected_block_count) { 52 | // TODO(google): Expose error? 53 | return false; 54 | } 55 | 56 | if (kBytesPerPixelUNORM8 * width > out_buffer_stride || 57 | out_buffer_stride * height < out_buffer_size) { 58 | // Output buffer too small. 59 | return false; 60 | } 61 | 62 | base::UInt128 block; 63 | static_assert(sizeof(block) == PhysicalASTCBlock::kSizeInBytes, 64 | "Block size mismatch"); 65 | 66 | for (size_t i = 0; i < astc_data_size; i += PhysicalASTCBlock::kSizeInBytes) { 67 | const size_t block_index = i / PhysicalASTCBlock::kSizeInBytes; 68 | const size_t block_x = block_index % blocks_wide; 69 | const size_t block_y = block_index / blocks_wide; 70 | memcpy(&block, astc_data + i, sizeof(block)); 71 | 72 | PhysicalASTCBlock physical_block(block); 73 | auto lb = UnpackLogicalBlock(footprint, physical_block); 74 | if (!lb) { 75 | return false; 76 | } 77 | 78 | LogicalASTCBlock logical_block = lb.value(); 79 | 80 | for (size_t y = 0; y < block_height; ++y) { 81 | const size_t py = block_height * block_y + y; 82 | uint8_t* out_row = out_buffer + py * out_buffer_stride; 83 | 84 | for (size_t x = 0; x < block_width; ++x) { 85 | const size_t px = block_width * block_x + x; 86 | 87 | // Skip out of bounds. 88 | if (px >= width || py >= height) { 89 | continue; 90 | } 91 | 92 | uint8_t* pixel = out_row + px * kBytesPerPixelUNORM8; 93 | const RgbaColor decoded_color = logical_block.ColorAt(x, y); 94 | for (size_t i = 0; i < kBytesPerPixelUNORM8; ++i) { 95 | pixel[i] = static_cast(decoded_color[i]); 96 | } 97 | } 98 | } 99 | } 100 | 101 | return true; 102 | } 103 | 104 | bool DecompressToImage(const ASTCFile& file, uint8_t* out_buffer, 105 | size_t out_buffer_size, size_t out_buffer_stride) { 106 | base::Optional footprint = file.GetFootprint(); 107 | if (!footprint) { 108 | return false; 109 | } 110 | 111 | return DecompressToImage( 112 | reinterpret_cast(file.GetRawBlockData().c_str()), 113 | file.GetRawBlockData().size(), file.GetWidth(), file.GetHeight(), 114 | footprint.value(), out_buffer, out_buffer_size, out_buffer_stride); 115 | } 116 | 117 | bool ASTCDecompressToRGBA(const uint8_t* astc_data, size_t astc_data_size, 118 | size_t width, size_t height, FootprintType footprint, 119 | uint8_t* out_buffer, size_t out_buffer_size, 120 | size_t out_buffer_stride) { 121 | base::Optional footprint_opt = 122 | Footprint::FromFootprintType(footprint); 123 | if (!footprint_opt) { 124 | return false; 125 | } 126 | 127 | return DecompressToImage(astc_data, astc_data_size, width, height, 128 | footprint_opt.value(), out_buffer, out_buffer_size, 129 | out_buffer_stride); 130 | } 131 | 132 | } // namespace astc_codec 133 | -------------------------------------------------------------------------------- /src/decoder/codec.h: -------------------------------------------------------------------------------- 1 | // Copyright 2018 Google LLC 2 | // 3 | // Licensed under the Apache License, Version 2.0 (the "License"); 4 | // you may not use this file except in compliance with the License. 5 | // You may obtain a copy of the License at 6 | // 7 | // https://www.apache.org/licenses/LICENSE-2.0 8 | // 9 | // Unless required by applicable law or agreed to in writing, software 10 | // distributed under the License is distributed on an "AS IS" BASIS, 11 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | // See the License for the specific language governing permissions and 13 | // limitations under the License. 14 | 15 | #ifndef ASTC_CODEC_DECODER_CODEC_H_ 16 | #define ASTC_CODEC_DECODER_CODEC_H_ 17 | 18 | #include "src/decoder/astc_file.h" 19 | #include "src/decoder/footprint.h" 20 | 21 | #include 22 | 23 | namespace astc_codec { 24 | 25 | // Decompresses ASTC blocks to an image buffer. 26 | // Returns true if the decompression succeeded and the out buffer has been 27 | // filled. 28 | bool DecompressToImage(const uint8_t* astc_data, size_t astc_data_size, 29 | size_t width, size_t height, Footprint footprint, 30 | uint8_t* out_buffer, size_t out_buffer_size, 31 | size_t out_buffer_stride); 32 | 33 | // Decompresses an ASTC file to an image buffer. 34 | // Returns true if the decompression succeeded and the out buffer has been 35 | // filled. 36 | bool DecompressToImage(const ASTCFile& file, uint8_t* out_buffer, 37 | size_t out_buffer_size, size_t out_buffer_stride); 38 | 39 | } // namespace astc_codec 40 | 41 | #endif // ASTC_CODEC_DECODER_CODEC_H_ 42 | -------------------------------------------------------------------------------- /src/decoder/endpoint_codec.h: -------------------------------------------------------------------------------- 1 | // Copyright 2018 Google LLC 2 | // 3 | // Licensed under the Apache License, Version 2.0 (the "License"); 4 | // you may not use this file except in compliance with the License. 5 | // You may obtain a copy of the License at 6 | // 7 | // https://www.apache.org/licenses/LICENSE-2.0 8 | // 9 | // Unless required by applicable law or agreed to in writing, software 10 | // distributed under the License is distributed on an "AS IS" BASIS, 11 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | // See the License for the specific language governing permissions and 13 | // limitations under the License. 14 | 15 | #ifndef ASTC_CODEC_DECODER_ENDPOINT_CODEC_H_ 16 | #define ASTC_CODEC_DECODER_ENDPOINT_CODEC_H_ 17 | 18 | #include "src/decoder/physical_astc_block.h" 19 | #include "src/decoder/types.h" 20 | 21 | #include 22 | #include 23 | 24 | namespace astc_codec { 25 | 26 | // We use a special distinction for encode modes used to pass to the 27 | // EncodeColorsForMode function below. The reason is that some of the color 28 | // modes have sub-modes (like blue-contract) that change whether or not it is 29 | // useful to encode an endpoint pair using one mode versus another. To avoid 30 | // this problem, we approach the problem of encoding by specifying some 31 | // high-level encoding modes. These eventually choose one of the low level 32 | // ColorEndpointModes from Section C.2.14 when used in EncodeColorsForMode. 33 | enum class EndpointEncodingMode { 34 | kDirectLuma, 35 | kDirectLumaAlpha, 36 | kBaseScaleRGB, 37 | kBaseScaleRGBA, 38 | kDirectRGB, 39 | kDirectRGBA 40 | }; 41 | 42 | // Returns the number of values in the encoded endpoint pair after encoding 43 | // to a specific high-level encoding mode. 44 | constexpr int NumValuesForEncodingMode(EndpointEncodingMode mode) { 45 | return 46 | mode == EndpointEncodingMode::kDirectLuma ? 2 : 47 | mode == EndpointEncodingMode::kDirectLumaAlpha ? 4 : 48 | mode == EndpointEncodingMode::kBaseScaleRGB ? 4 : 49 | mode == EndpointEncodingMode::kBaseScaleRGBA ? 6 : 50 | mode == EndpointEncodingMode::kDirectRGB ? 6 : 8; 51 | } 52 | 53 | // Fills |vals| with the quantized endpoint colors values defined in the ASTC 54 | // specification. The values are quantized to the range [0, max_value]. These 55 | // quantization limits can be obtained by querying the associated functions in 56 | // integer_sequence_codec. The returned |astc_mode| will be the ASTC mode used 57 | // to encode the resulting sequence. 58 | // 59 | // The |encoding_mode| is used to determine the way that we encode the values. 60 | // Each encoding mode is used to determine which ASTC mode best corresponds 61 | // to the pair of endpoints. It is a necessary hint to the encoding function 62 | // in order to process the endpoints. Each encoding mode gurantees a certain 63 | // number of values generated per endpoints. 64 | // 65 | // The return value will be true if the endpoints have been switched in order to 66 | // reap the most benefit from the way the hardware decodes the given mode. In 67 | // this case, the associated weights that interpolate this color must also be 68 | // switched. In other words, for each w, it should change to 64 - w. 69 | bool EncodeColorsForMode( 70 | const RgbaColor& endpoint_low_rgba, const RgbaColor& endpoint_high_rgba, 71 | int max_value, EndpointEncodingMode encoding_mode, 72 | ColorEndpointMode* astc_mode, std::vector* vals); 73 | 74 | // Decodes the color values quantized to the range [0, max_value] into RGBA 75 | // endpoints for the given mode. This function is the inverse of 76 | // EncodeColorsForMode -- see that function for details. This function should 77 | // work on all LDR endpoint modes, but no HDR modes. 78 | void DecodeColorsForMode(const std::vector& vals, 79 | int max_value, ColorEndpointMode mode, 80 | RgbaColor* endpoint_low_rgba, 81 | RgbaColor* endpoint_high_rgba); 82 | 83 | // Returns true if the quantized |vals| in the range [0, max_value] use the 84 | // 'blue_contract' modification during decoding for the given |mode|. 85 | bool UsesBlueContract(int max_value, ColorEndpointMode mode, 86 | const std::vector& vals); 87 | 88 | } // namespace astc_codec 89 | 90 | #endif // ASTC_CODEC_DECODER_ENDPOINT_CODEC_H_ 91 | -------------------------------------------------------------------------------- /src/decoder/footprint.cc: -------------------------------------------------------------------------------- 1 | // Copyright 2018 Google LLC 2 | // 3 | // Licensed under the Apache License, Version 2.0 (the "License"); 4 | // you may not use this file except in compliance with the License. 5 | // You may obtain a copy of the License at 6 | // 7 | // https://www.apache.org/licenses/LICENSE-2.0 8 | // 9 | // Unless required by applicable law or agreed to in writing, software 10 | // distributed under the License is distributed on an "AS IS" BASIS, 11 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | // See the License for the specific language governing permissions and 13 | // limitations under the License. 14 | 15 | #include "src/decoder/footprint.h" 16 | #include "src/base/string_utils.h" 17 | 18 | #include 19 | #include 20 | #include 21 | #include 22 | 23 | namespace astc_codec { 24 | 25 | namespace { 26 | 27 | // Encodes the width and height into an integer so that we can use a switch 28 | // statement instead of a costly lookup map. 29 | constexpr int EncodeDims(int width, int height) { 30 | return (width << 16) | height; 31 | } 32 | 33 | } // namespace 34 | 35 | base::Optional 36 | Footprint::GetValidFootprintForDimensions(int width, int height) { 37 | switch (EncodeDims(width, height)) { 38 | case EncodeDims(4, 4): return FootprintType::k4x4; 39 | case EncodeDims(5, 4): return FootprintType::k5x4; 40 | case EncodeDims(5, 5): return FootprintType::k5x5; 41 | case EncodeDims(6, 5): return FootprintType::k6x5; 42 | case EncodeDims(6, 6): return FootprintType::k6x6; 43 | case EncodeDims(8, 5): return FootprintType::k8x5; 44 | case EncodeDims(8, 6): return FootprintType::k8x6; 45 | case EncodeDims(8, 8): return FootprintType::k8x8; 46 | case EncodeDims(10, 5): return FootprintType::k10x5; 47 | case EncodeDims(10, 6): return FootprintType::k10x6; 48 | case EncodeDims(10, 8): return FootprintType::k10x8; 49 | case EncodeDims(10, 10): return FootprintType::k10x10; 50 | case EncodeDims(12, 10): return FootprintType::k12x10; 51 | case EncodeDims(12, 12): return FootprintType::k12x12; 52 | default: return {}; 53 | } 54 | } 55 | 56 | int Footprint::GetWidthForFootprint(FootprintType footprint) { 57 | switch (footprint) { 58 | case FootprintType::k4x4: return 4; 59 | case FootprintType::k5x4: return 5; 60 | case FootprintType::k5x5: return 5; 61 | case FootprintType::k6x5: return 6; 62 | case FootprintType::k6x6: return 6; 63 | case FootprintType::k8x5: return 8; 64 | case FootprintType::k8x6: return 8; 65 | case FootprintType::k10x5: return 10; 66 | case FootprintType::k10x6: return 10; 67 | case FootprintType::k8x8: return 8; 68 | case FootprintType::k10x8: return 10; 69 | case FootprintType::k10x10: return 10; 70 | case FootprintType::k12x10: return 12; 71 | case FootprintType::k12x12: return 12; 72 | default: 73 | assert(false); 74 | return -1; 75 | } 76 | } 77 | 78 | int Footprint::GetHeightForFootprint(FootprintType footprint) { 79 | switch (footprint) { 80 | case FootprintType::k4x4: return 4; 81 | case FootprintType::k5x4: return 4; 82 | case FootprintType::k5x5: return 5; 83 | case FootprintType::k6x5: return 5; 84 | case FootprintType::k6x6: return 6; 85 | case FootprintType::k8x5: return 5; 86 | case FootprintType::k8x6: return 6; 87 | case FootprintType::k10x5: return 5; 88 | case FootprintType::k10x6: return 6; 89 | case FootprintType::k8x8: return 8; 90 | case FootprintType::k10x8: return 8; 91 | case FootprintType::k10x10: return 10; 92 | case FootprintType::k12x10: return 10; 93 | case FootprintType::k12x12: return 12; 94 | default: 95 | assert(false); 96 | return -1; 97 | } 98 | } 99 | 100 | Footprint::Footprint(FootprintType footprint) 101 | : footprint_(footprint), width_(GetWidthForFootprint(footprint)), 102 | height_(GetHeightForFootprint(footprint)) { } 103 | 104 | //////////////////////////////////////////////////////////////////////////////// 105 | 106 | base::Optional Footprint::Parse(const char* footprint_string) { 107 | assert(footprint_string && footprint_string[0] != '\0'); 108 | 109 | std::vector dimension_strings; 110 | base::Split(footprint_string, "x", [&dimension_strings](std::string&& s) { 111 | dimension_strings.push_back(std::move(s)); 112 | }); 113 | 114 | if (dimension_strings.size() != 2) { 115 | assert(false && "Invalid format for footprint"); 116 | return {}; 117 | } 118 | 119 | const int width = base::ParseInt32(dimension_strings[0].c_str(), 0); 120 | const int height = base::ParseInt32(dimension_strings[1].c_str(), 0); 121 | 122 | assert(width > 0 && height > 0 && "Invalid width or height."); 123 | 124 | return FromDimensions(width, height); 125 | } 126 | 127 | base::Optional Footprint::FromDimensions(int width, int height) { 128 | base::Optional valid_footprint = 129 | GetValidFootprintForDimensions(width, height); 130 | if (valid_footprint) { 131 | return Footprint(valid_footprint.value()); 132 | } else { 133 | return {}; 134 | } 135 | } 136 | 137 | // Returns a Footprint for the given FootprintType. 138 | base::Optional Footprint::FromFootprintType(FootprintType type) { 139 | if (type >= FootprintType::k4x4 && type < FootprintType::kCount) { 140 | return Footprint(type); 141 | } else { 142 | return {}; 143 | } 144 | } 145 | 146 | size_t Footprint::StorageRequirements(int width, int height) const { 147 | const int blocks_wide = (width + width_ - 1) / width_; 148 | const int blocks_high = (height + height_ - 1) / height_; 149 | 150 | constexpr size_t kASTCBlockSizeInBytes = 16; 151 | return blocks_wide * blocks_high * kASTCBlockSizeInBytes; 152 | } 153 | 154 | // Returns bits/pixel for a given footprint. 155 | float Footprint::Bitrate() const { 156 | const int kASTCBlockBitCount = 128; 157 | const int footprint_pixel_count = width_ * height_; 158 | return static_cast(kASTCBlockBitCount) / 159 | static_cast(footprint_pixel_count); 160 | } 161 | 162 | } // namespace astc_codec 163 | -------------------------------------------------------------------------------- /src/decoder/footprint.h: -------------------------------------------------------------------------------- 1 | // Copyright 2018 Google LLC 2 | // 3 | // Licensed under the Apache License, Version 2.0 (the "License"); 4 | // you may not use this file except in compliance with the License. 5 | // You may obtain a copy of the License at 6 | // 7 | // https://www.apache.org/licenses/LICENSE-2.0 8 | // 9 | // Unless required by applicable law or agreed to in writing, software 10 | // distributed under the License is distributed on an "AS IS" BASIS, 11 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | // See the License for the specific language governing permissions and 13 | // limitations under the License. 14 | 15 | #ifndef ASTC_CODEC_DECODER_FOOTPRINT_H_ 16 | #define ASTC_CODEC_DECODER_FOOTPRINT_H_ 17 | 18 | #include "include/astc-codec/astc-codec.h" 19 | #include "src/base/optional.h" 20 | 21 | #include 22 | 23 | namespace astc_codec { 24 | 25 | // An ASTC texture can be encoded with varying choices in block size. A set of 26 | // predefined block sizes are specified in the ASTC specification. These are 27 | // referred to in the literature as "footprints" available to an encoder when 28 | // constructing an ASTC bitstream. This class provides various utility functions 29 | // for interacting with these footprints. 30 | class Footprint { 31 | public: 32 | Footprint() = delete; 33 | Footprint(const Footprint& footprint) = default; 34 | 35 | // Return the footprint type. 36 | FootprintType Type() const { return footprint_; } 37 | 38 | // Return logical descriptions of the dimensions. 39 | int Width() const { return width_; } 40 | int Height() const { return height_; } 41 | 42 | // Returns the number of pixels for a block with this footprint. 43 | int NumPixels() const { return width_ * height_; } 44 | 45 | // Returns the number of bytes needed to store an ASTC encoded image with the 46 | // given width and height. 47 | size_t StorageRequirements(int width, int height) const; 48 | 49 | // Returns the number of bits used per pixel. 50 | float Bitrate() const; 51 | 52 | static constexpr int NumValidFootprints() { 53 | return static_cast(FootprintType::kCount); 54 | } 55 | 56 | bool operator==(const Footprint& other) const { 57 | return footprint_ == other.footprint_; 58 | } 59 | 60 | // These are the valid and available ASTC footprints. 61 | static Footprint Get4x4() { return Footprint(FootprintType::k4x4); } 62 | static Footprint Get5x4() { return Footprint(FootprintType::k5x4); } 63 | static Footprint Get5x5() { return Footprint(FootprintType::k5x5); } 64 | static Footprint Get6x5() { return Footprint(FootprintType::k6x5); } 65 | static Footprint Get6x6() { return Footprint(FootprintType::k6x6); } 66 | static Footprint Get8x5() { return Footprint(FootprintType::k8x5); } 67 | static Footprint Get8x6() { return Footprint(FootprintType::k8x6); } 68 | static Footprint Get8x8() { return Footprint(FootprintType::k8x8); } 69 | static Footprint Get10x5() { return Footprint(FootprintType::k10x5); } 70 | static Footprint Get10x6() { return Footprint(FootprintType::k10x6); } 71 | static Footprint Get10x8() { return Footprint(FootprintType::k10x8); } 72 | static Footprint Get10x10() { return Footprint(FootprintType::k10x10); } 73 | static Footprint Get12x10() { return Footprint(FootprintType::k12x10); } 74 | static Footprint Get12x12() { return Footprint(FootprintType::k12x12); } 75 | 76 | // Constructs a footprint from a string of the form "NxM", or no value if 77 | // width and height are not a valid footprint. 78 | static base::Optional Parse(const char* footprint_string); 79 | 80 | // Returns a footprint corresponding to a block of the given width and height, 81 | // or no value if it does not. 82 | static base::Optional FromDimensions(int width, int height); 83 | 84 | // Returns a Footprint for the given FootprintType. 85 | static base::Optional FromFootprintType(FootprintType type); 86 | 87 | private: 88 | // The only constructor. 89 | explicit Footprint(FootprintType footprint); 90 | 91 | // Returns the valid footprint for the width and height if possible. 92 | static base::Optional GetValidFootprintForDimensions( 93 | int width, int height); 94 | 95 | // Returns the associated dimension for the given valid footprint. 96 | static int GetWidthForFootprint(FootprintType footprint); 97 | static int GetHeightForFootprint(FootprintType footprint); 98 | 99 | FootprintType footprint_; 100 | int width_; 101 | int height_; 102 | }; 103 | 104 | } // namespace astc_codec 105 | 106 | #endif // ASTC_CODEC_DECODER_FOOTPRINT_H_ 107 | -------------------------------------------------------------------------------- /src/decoder/integer_sequence_codec.h: -------------------------------------------------------------------------------- 1 | // Copyright 2018 Google LLC 2 | // 3 | // Licensed under the Apache License, Version 2.0 (the "License"); 4 | // you may not use this file except in compliance with the License. 5 | // You may obtain a copy of the License at 6 | // 7 | // https://www.apache.org/licenses/LICENSE-2.0 8 | // 9 | // Unless required by applicable law or agreed to in writing, software 10 | // distributed under the License is distributed on an "AS IS" BASIS, 11 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | // See the License for the specific language governing permissions and 13 | // limitations under the License. 14 | 15 | #ifndef ASTC_CODEC_DECODER_INTEGER_SEQUENCE_CODEC_H_ 16 | #define ASTC_CODEC_DECODER_INTEGER_SEQUENCE_CODEC_H_ 17 | 18 | #include "src/base/bit_stream.h" 19 | #include "src/base/uint128.h" 20 | 21 | #include 22 | #include 23 | #include 24 | 25 | namespace astc_codec { 26 | 27 | // The maximum number of bits that we would need to encode an ISE value. The 28 | // ASTC specification does not give a maximum number, however unquantized color 29 | // values have a maximum range of 255, meaning that we can't feasibly have more 30 | // than eight bits per value. 31 | constexpr int kLog2MaxRangeForBits = 8; 32 | 33 | // Ranges can take any of the the forms 2^k, 3*2^k, or 5*2^k for k up to 34 | // kLog2MaxRangeForBits. Hence we have three types of ranges. Since the 35 | // maximum encoded value is 255, k won't go larger than 8. We don't have quints 36 | // that accompany [6, 8]-bits, as (5 * 2^6 = 320 > 255) and we don't have trits 37 | // that accompany [7, 8]-bits, as (3 * 2^7 = 384 > 255). But we do have trits 38 | // and quints that accompany no bits. Hence we have a total of 39 | // 3 * kLog2MaxRangeForBits - 3 - 2 + 2 total ranges. 40 | constexpr int kNumPossibleRanges = 3 * kLog2MaxRangeForBits - 3; 41 | 42 | // Returns an iterator through the available ASTC ranges. 43 | std::array::const_iterator ISERangeBegin(); 44 | std::array::const_iterator ISERangeEnd(); 45 | 46 | // Base class for ASTC integer sequence encoders and decoders. These codecs 47 | // operate on sequences of integers and produce bit patterns that pack the 48 | // integers based on the encoding scheme specified in the ASTC specification 49 | // Section C.2.12. The resulting bit pattern is a sequence of encoded blocks. 50 | // All blocks in a sequence are one of the following encodings: 51 | // 52 | // (1 -- bit encoding) one encoded value of the form 2^k 53 | // (2 -- trit encoding) five encoded values of the form 3*2^k 54 | // (3 -- quint encoding) three encoded values of the form 5*2^k 55 | // 56 | // The layouts of each block are designed such that the blocks can be truncated 57 | // during encoding in order to support variable length input sequences (i.e. a 58 | // sequence of values that are encoded using trit encoded blocks does not 59 | // need to have a multiple-of-five length). 60 | class IntegerSequenceCodec { 61 | public: 62 | // Returns the number of trits, quints, and bits needed to encode values in 63 | // [0, range]. This is used to determine the layout of ISE encoded bit 64 | // streams. The returned array holds the number of trits, quints, and bits 65 | // respectively. range is expected to be within the interval [1, 5242879] 66 | static void GetCountsForRange(int range, int* trits, int* quints, int* bits); 67 | 68 | // Returns the number of bits needed to encode the given number of values with 69 | // respect to the number of trits, quints, and bits specified in ise_counts 70 | // (in that order). It is expected that either trits or quints can be 71 | // nonzero, but not both, and neither can be larger than one. Anything else is 72 | // undefined. 73 | static int GetBitCount(int num_vals, int trits, int quints, int bits); 74 | 75 | // Convenience function that returns the number of bits needed to encoded 76 | // num_vals within the range [0, range] (inclusive). 77 | static inline int GetBitCountForRange(int num_vals, int range) { 78 | int trits, quints, bits; 79 | GetCountsForRange(range, &trits, &quints, &bits); 80 | return GetBitCount(num_vals, trits, quints, bits); 81 | } 82 | 83 | protected: 84 | explicit IntegerSequenceCodec(int range); 85 | IntegerSequenceCodec(int trits, int quints, int bits); 86 | 87 | // The encoding mode -- since having trits and quints are mutually exclusive, 88 | // we can store the encoding we decide on in this enum. 89 | enum EncodingMode { 90 | kTritEncoding = 0, 91 | kQuintEncoding, 92 | kBitEncoding, 93 | }; 94 | 95 | EncodingMode encoding_; 96 | int bits_; 97 | 98 | // Returns the number of values stored in a single ISE block. Since quints and 99 | // trits are packed three/five to a bit pattern (respectively), each sequence 100 | // is chunked into blocks in order to encode it. For only bit-encodings, the 101 | // block size is one. 102 | int NumValsPerBlock() const; 103 | 104 | // Returns the size of a single ISE block in bits (see NumValsPerBlock). 105 | int EncodedBlockSize() const; 106 | 107 | private: 108 | // Determines the encoding mode. 109 | void InitializeWithCounts(int trits, int quints, int bits); 110 | }; 111 | 112 | // The integer sequence decoder. The decoder only remembers the given encoding 113 | // but each invocation of Decode operates independently on the input bits. 114 | class IntegerSequenceDecoder : public IntegerSequenceCodec { 115 | public: 116 | // Creates a decoder that decodes values within [0, range] (inclusive). 117 | explicit IntegerSequenceDecoder(int range) 118 | : IntegerSequenceCodec(range) { } 119 | 120 | // Creates a decoder based on the number of trits, quints, and bits expected 121 | // in the bit stream passed to Decode. 122 | IntegerSequenceDecoder(int trits, int quints, int bits) 123 | : IntegerSequenceCodec(trits, quints, bits) { } 124 | 125 | // Decodes num_vals from the bit_src. The number of bits read is dependent 126 | // on the number of bits required to encode num_vals based on the calculation 127 | // provided in Section C.2.22 of the ASTC specification. The return value 128 | // always contains exactly num_vals. 129 | std::vector Decode(int num_vals, 130 | base::BitStream* bit_src) const; 131 | }; 132 | 133 | // The integer sequence encoder. The encoder accepts values one by one and 134 | // places them into a temporary array that it holds. When needed the user 135 | // may call Encode to produce an encoded bit stream of the associated values. 136 | class IntegerSequenceEncoder : public IntegerSequenceCodec { 137 | public: 138 | // Creates an encoder that encodes values within [0, range] (inclusive). 139 | explicit IntegerSequenceEncoder(int range) 140 | : IntegerSequenceCodec(range) { } 141 | 142 | // Creates an encoder based on the number of trits, quints, and bits for 143 | // the bit stream produced by Encode. 144 | IntegerSequenceEncoder(int trits, int quints, int bits) 145 | : IntegerSequenceCodec(trits, quints, bits) { } 146 | 147 | // Adds a value to the encoding sequence. 148 | void AddValue(int val) { 149 | // Make sure it's within bounds 150 | assert(encoding_ != EncodingMode::kTritEncoding || val < 3 * (1 << bits_)); 151 | assert(encoding_ != EncodingMode::kQuintEncoding || val < 5 * (1 << bits_)); 152 | assert(encoding_ != EncodingMode::kBitEncoding || val < (1 << bits_)); 153 | vals_.push_back(val); 154 | } 155 | 156 | // Writes the encoding for vals_ to the bit_sink. Multiple calls to Encode 157 | // will produce the same result. 158 | void Encode(base::BitStream* bit_sink) const; 159 | 160 | // Removes all of the previously added values to the encoder. 161 | void Reset() { vals_.clear(); } 162 | 163 | private: 164 | std::vector vals_; 165 | }; 166 | 167 | } // namespace astc_codec 168 | 169 | #endif // ASTC_CODEC_DECODER_INTEGER_SEQUENCE_CODEC_H_ 170 | -------------------------------------------------------------------------------- /src/decoder/intermediate_astc_block.h: -------------------------------------------------------------------------------- 1 | // Copyright 2018 Google LLC 2 | // 3 | // Licensed under the Apache License, Version 2.0 (the "License"); 4 | // you may not use this file except in compliance with the License. 5 | // You may obtain a copy of the License at 6 | // 7 | // https://www.apache.org/licenses/LICENSE-2.0 8 | // 9 | // Unless required by applicable law or agreed to in writing, software 10 | // distributed under the License is distributed on an "AS IS" BASIS, 11 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | // See the License for the specific language governing permissions and 13 | // limitations under the License. 14 | 15 | #ifndef ASTC_CODEC_DECODER_INTERMEDIATE_ASTC_BLOCK_H_ 16 | #define ASTC_CODEC_DECODER_INTERMEDIATE_ASTC_BLOCK_H_ 17 | 18 | #include "src/base/optional.h" 19 | #include "src/base/uint128.h" 20 | #include "src/decoder/physical_astc_block.h" 21 | 22 | #include 23 | #include 24 | 25 | namespace astc_codec { 26 | 27 | // From Table C.2.7 -- These are the only valid ranges that weight 28 | // values can take. 29 | constexpr std::array kValidWeightRanges = 30 | {{ 1, 2, 3, 4, 5, 7, 9, 11, 15, 19, 23, 31 }}; 31 | 32 | // Void extent data are all the ASTC blocks that are labeled for having a 33 | // constant color. In the ASTC spec, some of these blocks may optionally 34 | // have "void extent coordinates" that describe how far in texture space 35 | // the constant color should span. If these coordinates are not valid, 36 | // then the coordinates are all set to a fully saturated bit mask 37 | // ((1 << 13) - 1) and the block is treated as a singular constant color. 38 | // We call both types of these blocks "void extent" to remove confusion 39 | // in our code. 40 | struct VoidExtentData { 41 | uint16_t r; 42 | uint16_t g; 43 | uint16_t b; 44 | uint16_t a; 45 | std::array coords; 46 | }; 47 | 48 | // Intermediate endpoint data. Really this is just an endpoint mode 49 | // and a couple of values that represent the data used to decode the 50 | // RGB values from the color endpoint mode. 51 | struct IntermediateEndpointData { 52 | ColorEndpointMode mode; 53 | std::vector colors; 54 | }; 55 | 56 | // This is an unpacked physical ASTC block, but it does not have enough 57 | // information to be worked with logically. It is simply a container of 58 | // all of the unpacked ASTC information. It is used as a staging area 59 | // for the information that is later Pack()'d into a PhysicalASTCBlock. 60 | struct IntermediateBlockData { 61 | int weight_grid_dim_x; 62 | int weight_grid_dim_y; 63 | int weight_range; 64 | 65 | // Quantized, non-interpolated weights 66 | std::vector weights; 67 | 68 | // The 10-bit partition ID if we need one 69 | base::Optional partition_id; 70 | 71 | // The dual-plane channel in [0, 3] if it exists. 72 | base::Optional dual_plane_channel; 73 | 74 | // The quantized/encoded endpoint values for this block. The range of each 75 | // endpoint value is specified by |endpoint_range|, if it exists. If not, the 76 | // range can be queried by calling EndpointRangeForBlock 77 | std::vector endpoints; 78 | 79 | // The range [0, endpoint_range] that any one endpoint value can take. Users 80 | // should not write to this value themselves. If it is empty at the time 81 | // someone calls Pack(), it will be automatically inferred. Otherwise, it is 82 | // set by Unpack() based on what the underlying encoding specified. 83 | base::Optional endpoint_range; 84 | }; 85 | 86 | // Returns the maximum value that a given endpoint value can take according to 87 | // the other settings in the block. Ignores the |endpoint_range| member 88 | // variable. Returns negative values on error: 89 | // -1 : Too many bits required to store weight grid 90 | // -2 : There are too few bits allocated for color endpoint data according to 91 | // C.2.24 in the ASTC spec 92 | int EndpointRangeForBlock(const IntermediateBlockData& data); 93 | inline int EndpointRangeForBlock(const VoidExtentData& data); 94 | 95 | // Unpacks the physical ASTC block into the intermediate block. Returns false 96 | // if the physical block is an error encoded block, or if the physical block 97 | // is a void extent block. On error the contents of ib are undefined. 98 | base::Optional UnpackIntermediateBlock( 99 | const PhysicalASTCBlock& pb); 100 | 101 | // Unpacks the physical ASTC block into a void extent block. Returns false 102 | // if the physical block is an error encoded block, or if the physical block 103 | // is an intermediate block. On error the contents of ib are undefined. 104 | base::Optional UnpackVoidExtent(const PhysicalASTCBlock& pb); 105 | 106 | // Packs the given intermediate block into a physical block. Returns an error 107 | // string if the provided values in the intermediate block emit an illegal ASTC 108 | // encoding. In this case the results in the physical block are undefined. 109 | base::Optional Pack(const IntermediateBlockData& data, 110 | base::UInt128* pb); 111 | 112 | // Packs the given void extent block into a physical block. Returns an error 113 | // string if the provided values in the void extent block emit an illegal ASTC 114 | // encoding. In this case the results in the physical block are undefined. 115 | base::Optional Pack(const VoidExtentData& data, base::UInt128* pb); 116 | 117 | //////////////////////////////////////////////////////////////////////////////// 118 | // 119 | // Impl 120 | 121 | inline int EndpointRangeForBlock(const VoidExtentData& data) { 122 | // Void extent blocks use 16-bit ARGB definitions 123 | return (1 << 16) - 1; 124 | } 125 | 126 | } // namespace astc_codec 127 | 128 | #endif // ASTC_CODEC_DECODER_INTERMEDIATE_ASTC_BLOCK_H_ 129 | -------------------------------------------------------------------------------- /src/decoder/logical_astc_block.cc: -------------------------------------------------------------------------------- 1 | // Copyright 2018 Google LLC 2 | // 3 | // Licensed under the Apache License, Version 2.0 (the "License"); 4 | // you may not use this file except in compliance with the License. 5 | // You may obtain a copy of the License at 6 | // 7 | // https://www.apache.org/licenses/LICENSE-2.0 8 | // 9 | // Unless required by applicable law or agreed to in writing, software 10 | // distributed under the License is distributed on an "AS IS" BASIS, 11 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | // See the License for the specific language governing permissions and 13 | // limitations under the License. 14 | 15 | #include "src/decoder/logical_astc_block.h" 16 | #include "src/decoder/endpoint_codec.h" 17 | #include "src/decoder/footprint.h" 18 | #include "src/decoder/integer_sequence_codec.h" 19 | #include "src/decoder/quantization.h" 20 | #include "src/decoder/weight_infill.h" 21 | 22 | namespace astc_codec { 23 | 24 | namespace { 25 | 26 | Partition GenerateSinglePartition(Footprint footprint) { 27 | return Partition { footprint, /* num_parts = */ 1, /* partition_id = */ 0, 28 | std::vector(footprint.NumPixels(), 0) }; 29 | } 30 | 31 | static std::vector DecodeEndpoints(const IntermediateBlockData& block) { 32 | const int endpoint_range = block.endpoint_range 33 | ? block.endpoint_range.value() 34 | : EndpointRangeForBlock(block); 35 | assert(endpoint_range > 0); 36 | 37 | std::vector endpoints; 38 | for (const auto& eps : block.endpoints) { 39 | RgbaColor decmp_one_rgba, decmp_two_rgba; 40 | DecodeColorsForMode(eps.colors, endpoint_range, eps.mode, 41 | &decmp_one_rgba, &decmp_two_rgba); 42 | endpoints.emplace_back(decmp_one_rgba, decmp_two_rgba); 43 | } 44 | return endpoints; 45 | } 46 | 47 | static std::vector DecodeEndpoints(const VoidExtentData& block) { 48 | EndpointPair eps; 49 | eps.first[0] = eps.second[0] = (block.r * 255) / 65535; 50 | eps.first[1] = eps.second[1] = (block.g * 255) / 65535; 51 | eps.first[2] = eps.second[2] = (block.b * 255) / 65535; 52 | eps.first[3] = eps.second[3] = (block.a * 255) / 65535; 53 | 54 | std::vector endpoints; 55 | endpoints.emplace_back(eps); 56 | return endpoints; 57 | } 58 | 59 | Partition ComputePartition(const Footprint& footprint, 60 | const IntermediateBlockData& block) { 61 | if (block.partition_id) { 62 | const int part_id = block.partition_id.value(); 63 | const size_t num_parts = block.endpoints.size(); 64 | return GetASTCPartition(footprint, num_parts, part_id); 65 | } else { 66 | return GenerateSinglePartition(footprint); 67 | } 68 | } 69 | 70 | Partition ComputePartition(const Footprint& footprint, const VoidExtentData&) { 71 | return GenerateSinglePartition(footprint); 72 | } 73 | 74 | } // namespace 75 | 76 | //////////////////////////////////////////////////////////////////////////////// 77 | 78 | LogicalASTCBlock::LogicalASTCBlock(const Footprint& footprint) 79 | : endpoints_(1), 80 | weights_(footprint.NumPixels(), 0), 81 | partition_(GenerateSinglePartition(footprint)) { } 82 | 83 | LogicalASTCBlock::LogicalASTCBlock(const Footprint& footprint, 84 | const IntermediateBlockData& block) 85 | : endpoints_(DecodeEndpoints(block)), 86 | partition_(ComputePartition(footprint, block)) { 87 | CalculateWeights(footprint, block); 88 | } 89 | 90 | LogicalASTCBlock::LogicalASTCBlock(const Footprint& footprint, 91 | const VoidExtentData& block) 92 | : endpoints_(DecodeEndpoints(block)), 93 | partition_(ComputePartition(footprint, block)) { 94 | CalculateWeights(footprint, block); 95 | } 96 | 97 | void LogicalASTCBlock::CalculateWeights(const Footprint& footprint, 98 | const IntermediateBlockData& block) { 99 | const int grid_size_x = block.weight_grid_dim_x; 100 | const int grid_size_y = block.weight_grid_dim_y; 101 | const int weight_grid_size = grid_size_x * grid_size_y; 102 | 103 | // Either we have a dual plane and we have twice as many weights as 104 | // specified or we don't 105 | assert(block.dual_plane_channel 106 | ? block.weights.size() == weight_grid_size * 2 107 | : block.weights.size() == weight_grid_size); 108 | 109 | std::vector unquantized; 110 | unquantized.reserve(weight_grid_size); 111 | 112 | // According to C.2.16, if we have dual-plane weights, then we have two 113 | // weights per texel -- one adjacent to the other. Hence, we have to skip 114 | // some when we decode the separate weight values. 115 | const int weight_frequency = (block.dual_plane_channel) ? 2 : 1; 116 | const int weight_range = block.weight_range; 117 | 118 | for (int i = 0; i < weight_grid_size; ++i) { 119 | const int weight = block.weights[i * weight_frequency]; 120 | unquantized.push_back(UnquantizeWeightFromRange(weight, weight_range)); 121 | } 122 | weights_ = InfillWeights(unquantized, footprint, grid_size_x, grid_size_y); 123 | 124 | if (block.dual_plane_channel) { 125 | SetDualPlaneChannel(block.dual_plane_channel.value()); 126 | for (int i = 0; i < weight_grid_size; ++i) { 127 | const int weight = block.weights[i * weight_frequency + 1]; 128 | unquantized[i] = UnquantizeWeightFromRange(weight, weight_range); 129 | } 130 | dual_plane_->weights = 131 | InfillWeights(unquantized, footprint, grid_size_x, grid_size_y); 132 | } 133 | } 134 | 135 | void LogicalASTCBlock::CalculateWeights(const Footprint& footprint, 136 | const VoidExtentData&) { 137 | weights_ = std::vector(footprint.NumPixels(), 0); 138 | } 139 | 140 | void LogicalASTCBlock::SetWeightAt(int x, int y, int weight) { 141 | assert(weight >= 0); 142 | assert(weight <= 64); 143 | weights_.at(y * GetFootprint().Width() + x) = weight; 144 | } 145 | 146 | int LogicalASTCBlock::WeightAt(int x, int y) const { 147 | return weights_.at(y * GetFootprint().Width() + x); 148 | } 149 | 150 | void LogicalASTCBlock::SetDualPlaneWeightAt(int channel, int x, int y, 151 | int weight) { 152 | assert(weight >= 0); 153 | assert(weight <= 64); 154 | 155 | // If it's not a dual plane, then this has no logical meaning 156 | assert(IsDualPlane()); 157 | 158 | // If it is a dual plane and the passed channel matches the query, then we 159 | // return the specialized weights 160 | if (dual_plane_->channel == channel) { 161 | dual_plane_->weights.at(y * GetFootprint().Width() + x) = weight; 162 | } else { 163 | // If the channel is not the special channel, then return the general weight 164 | SetWeightAt(x, y, weight); 165 | } 166 | } 167 | 168 | int LogicalASTCBlock::DualPlaneWeightAt(int channel, int x, int y) const { 169 | // If it's not a dual plane, then we just return the weight for all channels 170 | if (!IsDualPlane()) { 171 | // TODO(google): Log warning, Requesting dual-plane channel for a non 172 | // dual-plane block! 173 | return WeightAt(x, y); 174 | } 175 | 176 | // If it is a dual plane and the passed channel matches the query, then we 177 | // return the specialized weights 178 | if (dual_plane_->channel == channel) { 179 | return dual_plane_->weights.at(y * GetFootprint().Width() + x); 180 | } 181 | 182 | // If the channel is not the special channel, then return the general weight 183 | return WeightAt(x, y); 184 | } 185 | 186 | void LogicalASTCBlock::SetDualPlaneChannel(int channel) { 187 | if (channel < 0) { 188 | dual_plane_.clear(); 189 | } else if (dual_plane_) { 190 | dual_plane_->channel = channel; 191 | } else { 192 | dual_plane_ = DualPlaneData {channel, weights_}; 193 | } 194 | } 195 | 196 | RgbaColor LogicalASTCBlock::ColorAt(int x, int y) const { 197 | const auto footprint = GetFootprint(); 198 | assert(x >= 0); assert(x < footprint.Width()); 199 | assert(y >= 0); assert(y < footprint.Height()); 200 | 201 | const int texel_idx = y * footprint.Width() + x; 202 | const int part = partition_.assignment[texel_idx]; 203 | const auto& endpoints = endpoints_[part]; 204 | 205 | RgbaColor result; 206 | for (int channel = 0; channel < 4; ++channel) { 207 | const int weight = (dual_plane_ && dual_plane_->channel == channel) 208 | ? dual_plane_->weights[texel_idx] 209 | : weights_[texel_idx]; 210 | const int p0 = endpoints.first[channel]; 211 | const int p1 = endpoints.second[channel]; 212 | 213 | assert(p0 >= 0); assert(p0 < 256); 214 | assert(p1 >= 0); assert(p1 < 256); 215 | 216 | // According to C.2.19 217 | const int c0 = (p0 << 8) | p0; 218 | const int c1 = (p1 << 8) | p1; 219 | const int c = (c0 * (64 - weight) + c1 * weight + 32) / 64; 220 | // TODO(google): Handle conversion to sRGB or FP16 per C.2.19. 221 | const int quantized = ((c * 255) + 32767) / 65536; 222 | assert(quantized < 256); 223 | result[channel] = quantized; 224 | } 225 | 226 | return result; 227 | } 228 | 229 | void LogicalASTCBlock::SetPartition(const Partition& p) { 230 | assert(p.footprint == partition_.footprint && 231 | "New partitions may not be for a different footprint"); 232 | partition_ = p; 233 | endpoints_.resize(p.num_parts); 234 | } 235 | 236 | void LogicalASTCBlock::SetEndpoints(const EndpointPair& eps, int subset) { 237 | assert(subset < partition_.num_parts); 238 | assert(subset < endpoints_.size()); 239 | 240 | endpoints_[subset] = eps; 241 | } 242 | 243 | base::Optional UnpackLogicalBlock( 244 | const Footprint& footprint, const PhysicalASTCBlock& pb) { 245 | if (pb.IsVoidExtent()) { 246 | base::Optional ve = UnpackVoidExtent(pb); 247 | if (!ve) { 248 | return {}; 249 | } 250 | 251 | return LogicalASTCBlock(footprint, ve.value()); 252 | } else { 253 | base::Optional ib = UnpackIntermediateBlock(pb); 254 | if (!ib) { 255 | return {}; 256 | } 257 | 258 | return LogicalASTCBlock(footprint, ib.value()); 259 | } 260 | } 261 | 262 | } // namespace astc_codec 263 | -------------------------------------------------------------------------------- /src/decoder/logical_astc_block.h: -------------------------------------------------------------------------------- 1 | // Copyright 2018 Google LLC 2 | // 3 | // Licensed under the Apache License, Version 2.0 (the "License"); 4 | // you may not use this file except in compliance with the License. 5 | // You may obtain a copy of the License at 6 | // 7 | // https://www.apache.org/licenses/LICENSE-2.0 8 | // 9 | // Unless required by applicable law or agreed to in writing, software 10 | // distributed under the License is distributed on an "AS IS" BASIS, 11 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | // See the License for the specific language governing permissions and 13 | // limitations under the License. 14 | 15 | #ifndef ASTC_CODEC_DECODER_LOGICAL_ASTC_BLOCK_H_ 16 | #define ASTC_CODEC_DECODER_LOGICAL_ASTC_BLOCK_H_ 17 | 18 | #include "src/base/optional.h" 19 | #include "src/decoder/footprint.h" 20 | #include "src/decoder/intermediate_astc_block.h" 21 | #include "src/decoder/partition.h" 22 | #include "src/decoder/physical_astc_block.h" 23 | 24 | #include 25 | #include 26 | #include 27 | 28 | namespace astc_codec { 29 | 30 | // A logical ASTC block holds the endpoints, indices, and partition information 31 | // of a compressed block. These values generally do not adhere to any 32 | // quality-for-bitrate-imposed limits and are solely logical entities for 33 | // determining the best representation of a given block. 34 | class LogicalASTCBlock { 35 | public: 36 | LogicalASTCBlock(const LogicalASTCBlock&) = default; 37 | LogicalASTCBlock(LogicalASTCBlock&&) = default; 38 | 39 | // Unpack an intermediate block into a logical one. 40 | LogicalASTCBlock(const Footprint& footprint, 41 | const IntermediateBlockData& block); 42 | 43 | // Unpack a void extent intermediate block into a logical one. 44 | LogicalASTCBlock(const Footprint& footprint, const VoidExtentData& block); 45 | 46 | // Create a new, empty ASTC block 47 | explicit LogicalASTCBlock(const Footprint& footprint); 48 | 49 | // Returns the footprint associated with this block. The footprint is defined 50 | // via the partition, because the partition definition is dependent on the 51 | // footprint. 52 | const Footprint& GetFootprint() const { return partition_.footprint; } 53 | 54 | // Returns the unquantized and infilled weight in the range [0, 64] for the 55 | // given texel location. Assumes that the block is a single-plane block, 56 | // meaning that weights are used equally across all channels. 57 | void SetWeightAt(int x, int y, int weight); 58 | int WeightAt(int x, int y) const; 59 | 60 | // Returns the unquantized and infilled weight in the range [0, 64] for the 61 | // given channel at the given texel location. If the block does not have a 62 | // dual-plane channel then the reference-returning version will fail, as it 63 | // cannot return a reference to a value that (potentially) doesn't exist. 64 | void SetDualPlaneWeightAt(int channel, int x, int y, int weight); 65 | int DualPlaneWeightAt(int channel, int x, int y) const; 66 | 67 | // Returns the color as it would be in the given pixel coordinates of the 68 | // block. Fails if the coordinates are outside of the range of the block 69 | // footprint 70 | RgbaColor ColorAt(int x, int y) const; 71 | 72 | // Sets the current partition for the block. |p|'s footprint must match the 73 | // return value of GetFootprint() or else this call will fail. 74 | void SetPartition(const Partition& p); 75 | 76 | // Sets the endpoints for the given subset. 77 | void SetEndpoints(const EndpointPair& eps, int subset); 78 | void SetEndpoints(const Endpoint& ep1, const Endpoint& ep2, int subset) { 79 | SetEndpoints(std::make_pair(ep1, ep2), subset); 80 | } 81 | 82 | // Sets the dual plane channel for the block. Value must be within the range 83 | // [0, 3]. If a negative value is passed, then the dual-plane data for the 84 | // block is removed, and the block is treated as a single-plane block. 85 | void SetDualPlaneChannel(int channel); 86 | bool IsDualPlane() const { return dual_plane_.hasValue(); } 87 | 88 | private: 89 | // A block may have up to four endpoint pairs. 90 | std::vector endpoints_; 91 | 92 | // Weights are stored as values in the interval [0, 64]. 93 | std::vector weights_; 94 | 95 | // The partition information for this block. This determines the 96 | // appropriate subsets that each pixel should belong to. 97 | Partition partition_; 98 | 99 | // Dual plane data holds both the channel and the weights that describe 100 | // the dual plane data for the given block. If a block has a dual plane, then 101 | // we need to know both the channel and the weights associated with it. 102 | struct DualPlaneData { 103 | int channel; 104 | std::vector weights; 105 | }; 106 | 107 | // The dual-plane data is optional from a logical representation of the block. 108 | base::Optional dual_plane_; 109 | 110 | // Calculates the unquantized and interpolated weights from the encoded weight 111 | // values and possibly dual-plane weights specified in the passed ASTC block. 112 | void CalculateWeights(const Footprint& footprint, 113 | const IntermediateBlockData& block); 114 | 115 | // Calculates the weights for a VoidExtentBlock. 116 | void CalculateWeights(const Footprint& footprint, 117 | const VoidExtentData& block); 118 | }; 119 | 120 | // Unpacks the physical ASTC block into a logical block. Returns false if the 121 | // physical block is an error encoded block. 122 | base::Optional UnpackLogicalBlock( 123 | const Footprint& footprint, const PhysicalASTCBlock& pb); 124 | 125 | } // namespace astc_codec 126 | 127 | #endif // ASTC_CODEC_DECODER_LOGICAL_ASTC_BLOCK_H_ 128 | -------------------------------------------------------------------------------- /src/decoder/partition.h: -------------------------------------------------------------------------------- 1 | // Copyright 2018 Google LLC 2 | // 3 | // Licensed under the Apache License, Version 2.0 (the "License"); 4 | // you may not use this file except in compliance with the License. 5 | // You may obtain a copy of the License at 6 | // 7 | // https://www.apache.org/licenses/LICENSE-2.0 8 | // 9 | // Unless required by applicable law or agreed to in writing, software 10 | // distributed under the License is distributed on an "AS IS" BASIS, 11 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | // See the License for the specific language governing permissions and 13 | // limitations under the License. 14 | 15 | #ifndef ASTC_CODEC_DECODER_PARTITION_H_ 16 | #define ASTC_CODEC_DECODER_PARTITION_H_ 17 | 18 | #include "src/base/optional.h" 19 | #include "src/decoder/footprint.h" 20 | 21 | #include 22 | 23 | namespace astc_codec { 24 | 25 | struct Partition; 26 | 27 | // Determines the "difference" between any two partitions of the same size. 28 | // This metric attempts to find the best one to one mapping from the labels in 29 | // partition a against the labels in partition b. Once that mapping is found, it 30 | // returns the number of pixels that are mismatched between the two. Each 31 | // partition is expected to start in the upper left corner of the block and 32 | // proceed in raster-scan order. Two partitions are equal if the mapping is 33 | // bijective. This metric is a metric in the mathematical sense. In other words 34 | // it has the following properties: 35 | // 36 | // 1) PartitionMetric(a, b) >= 0 37 | // 2) PartitionMetric(a, b) == PartitionMetric(b, a) 38 | // 3) PartitionMetric(a, b) == 0 iff a == b 39 | // 4) PartitionMetric(a, b) + PartitionMetric(b, c) >= PartitionMetric(a, c) 40 | // 41 | // Throws an error if one partition's footprint is not equal to the other. 42 | int PartitionMetric(const Partition& a, const Partition& b); 43 | 44 | // A partition is a way to divide up an ASTC block into disjoint subsets such 45 | // that each subset uses a different set of endpoints. This is used to increase 46 | // the compression quality of blocks. One way to store such a partition is to 47 | // assign an ID to use with a predetermined decoding method. Here we store the 48 | // logical representation of partitions by keeping a per-pixel label. All pixels 49 | // that share a label belong to the same subset. 50 | struct Partition { 51 | // The footprint width and height of this partition. This determines the size 52 | // of the assignment array. 53 | Footprint footprint; 54 | 55 | // The number of subsets in this partition. The values in the partition 56 | // assignment fall within the range [0, num_parts). The maximum number of 57 | // parts supported is four. 58 | int num_parts; 59 | 60 | // The 10-bit partition ID as stored in bits 13-22 of multi-part ASTC blocks. 61 | // (See Section C.2.9) If there is no guarantee that this partition is a valid 62 | // ASTC partition, this should be set to absl::nullopt. 63 | base::Optional partition_id; 64 | 65 | // A value in the range [0, num_parts) corresponding to the label for 66 | // the given texel (x, y) in [0, footprint_width) x [0, footprint_height) 67 | // using a raster-order layout. 68 | std::vector assignment; 69 | 70 | // Returns true only if their "distance" is zero, i.e. if they have compatible 71 | // subset assignments. 72 | bool operator==(const Partition& other) const { 73 | return PartitionMetric(*this, other) == 0; 74 | } 75 | }; 76 | 77 | // Generates the ASTC partition assignment for the given block attributes. 78 | Partition GetASTCPartition(const Footprint& footprint, int num_parts, 79 | int partition_id); 80 | 81 | // Returns the |k| valid ASTC partitions that are closest to the candidate based 82 | // on the PartitionMetric defined above. 83 | const std::vector FindKClosestASTCPartitions( 84 | const Partition& candidate, int k); 85 | 86 | // Returns the valid ASTC partition closest to the candidate with at most as 87 | // many subsets as the |candidate|. Note: this is not a deterministic function, 88 | // as the underlying valid partitions are sorted using a hash map and a distance 89 | // function whose range is the natural numbers. The chances that two or more 90 | // partitions are equally 'closest' is possible, in which case this function 91 | // makes no guarantees about which one it will return. For more control, use 92 | // FindKClosestASTCPartitions above. 93 | const Partition& FindClosestASTCPartition(const Partition& candidate); 94 | 95 | } // namespace astc_codec 96 | 97 | #endif // ASTC_CODEC_DECODER_PARTITION_H_ 98 | -------------------------------------------------------------------------------- /src/decoder/physical_astc_block.h: -------------------------------------------------------------------------------- 1 | // Copyright 2018 Google LLC 2 | // 3 | // Licensed under the Apache License, Version 2.0 (the "License"); 4 | // you may not use this file except in compliance with the License. 5 | // You may obtain a copy of the License at 6 | // 7 | // https://www.apache.org/licenses/LICENSE-2.0 8 | // 9 | // Unless required by applicable law or agreed to in writing, software 10 | // distributed under the License is distributed on an "AS IS" BASIS, 11 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | // See the License for the specific language governing permissions and 13 | // limitations under the License. 14 | 15 | #ifndef ASTC_CODEC_DECODER_PHYSICAL_ASTC_BLOCK_H_ 16 | #define ASTC_CODEC_DECODER_PHYSICAL_ASTC_BLOCK_H_ 17 | 18 | // The logic in this file is based on the ASTC specification, which can be 19 | // found here: 20 | // https://www.opengl.org/registry/specs/KHR/texture_compression_astc_hdr.txt 21 | 22 | #include "src/base/optional.h" 23 | #include "src/base/uint128.h" 24 | #include "src/decoder/types.h" 25 | 26 | #include 27 | 28 | namespace astc_codec { 29 | 30 | // A PhysicalASTCBlock contains all 128 bits and the logic for decoding the 31 | // various internals of an ASTC block. 32 | class PhysicalASTCBlock { 33 | public: 34 | // The physical size in bytes of an ASTC block 35 | static const size_t kSizeInBytes = 16; 36 | 37 | // Initializes an ASTC block based on the encoded string. 38 | explicit PhysicalASTCBlock(const std::string& encoded_block); 39 | explicit PhysicalASTCBlock(const base::UInt128 astc_block); 40 | 41 | // Returns the 128 bits of this ASTC block. 42 | base::UInt128 GetBlockBits() const { return astc_bits_; } 43 | 44 | // Weights are stored in a grid that may not have the same dimensions 45 | // as the block dimensions. This allows us to see what the physical 46 | // dimensions are of the grid. 47 | base::Optional> WeightGridDims() const; 48 | 49 | // The weight range is the maximum value a weight can take in the 50 | // weight grid. 51 | base::Optional WeightRange() const; 52 | 53 | // Returns true if the block encoding specifies a void-extent block. This 54 | // kind of block stores a single color to be used for every pixel in the 55 | // block. 56 | bool IsVoidExtent() const; 57 | 58 | // Returns the values (min_s, max_s, min_t, max_t) as defined in the void 59 | // extent block as the range of texture coordinates for which this block is 60 | // defined. (See Section C.2.23) 61 | base::Optional> VoidExtentCoords() const; 62 | 63 | // Returns true if the block contains two separate weight grids. One used 64 | // for the channel returned by DualPlaneChannel() and one used by the other 65 | // channels. 66 | bool IsDualPlane() const; 67 | 68 | // Returns the channel used as the "dual plane". The return value is only 69 | // meaningful if IsDualPlane() returns true... 70 | base::Optional DualPlaneChannel() const; 71 | 72 | // Returns a reason that the encoding doesn't adhere to the specification. 73 | // If the encoding is legal, then this returns a nullptr. This allows us to 74 | // still use code of the form: 75 | // 76 | // if (IsIllegalEncoding()) { 77 | // ... error ... 78 | // } 79 | // ... no error ... 80 | // 81 | // However, it also helps with debugging since we can find problems with 82 | // encodings a lot faster. 83 | base::Optional IsIllegalEncoding() const; 84 | 85 | // Returns the number of weight bits present in this block. 86 | base::Optional NumWeightBits() const; 87 | 88 | // Returns the starting position within the range [0, 127] of the 89 | // weight data within the block. 90 | base::Optional WeightStartBit() const; 91 | 92 | // Returns the number of endpoint pairs used in this block. 93 | base::Optional NumPartitions() const; 94 | 95 | // Returns the seed used to determine the partition for a given 96 | // (x, y) coordinate within the block. Determined using the 97 | // block size and the function as described in the specification. 98 | base::Optional PartitionID() const; 99 | 100 | // Returns the color endpoint mode for the given partition index. 101 | base::Optional GetEndpointMode(int partition) const; 102 | 103 | // Returns the starting position within the range [0, 127] of the 104 | // color data within the block. 105 | base::Optional ColorStartBit() const; 106 | 107 | // Returns the number of integers used to represent the color endpoints. 108 | base::Optional NumColorValues() const; 109 | 110 | // Returns the number of bits used to represent the color endpoints. 111 | base::Optional NumColorBits() const; 112 | 113 | // Returns the maximum value that each of the encoded integers used to 114 | // represent the color endpoints can take. 115 | base::Optional ColorValuesRange() const; 116 | 117 | private: 118 | const base::UInt128 astc_bits_; 119 | 120 | // The logic to return the number of color bits and the color values range 121 | // is very similar, so it's probably best to abstract it away into its own 122 | // function. 123 | void GetColorValuesInfo(int* color_bits, int* color_range) const; 124 | }; 125 | 126 | } // namespace astc_codec 127 | 128 | #endif // ASTC_CODEC_DECODER_PHYSICAL_ASTC_BLOCK_H_ 129 | -------------------------------------------------------------------------------- /src/decoder/quantization.h: -------------------------------------------------------------------------------- 1 | // Copyright 2018 Google LLC 2 | // 3 | // Licensed under the Apache License, Version 2.0 (the "License"); 4 | // you may not use this file except in compliance with the License. 5 | // You may obtain a copy of the License at 6 | // 7 | // https://www.apache.org/licenses/LICENSE-2.0 8 | // 9 | // Unless required by applicable law or agreed to in writing, software 10 | // distributed under the License is distributed on an "AS IS" BASIS, 11 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | // See the License for the specific language governing permissions and 13 | // limitations under the License. 14 | 15 | #ifndef ASTC_CODEC_DECODER_QUANTIZATION_H_ 16 | #define ASTC_CODEC_DECODER_QUANTIZATION_H_ 17 | 18 | //////////////////////////////////////////////////////////////////////////////// 19 | // 20 | // ASTC Quantization procedures. 21 | // 22 | // The values stored in ASTC blocks tend to be stored in a range much more 23 | // restricted than the logical range used. For example, sometimes weights are 24 | // stored in the range from [0, 3] but are used in the range [0, 64]. The 25 | // process of translating a value to or from this range is known as quantization 26 | // and dequantization. The ranges to which these values can be (de)quantized 27 | // are defined by ISERange[Begin|End]() in integer_sequence_codec.h 28 | 29 | namespace astc_codec { 30 | 31 | // The minimum possible range for a pair of endpoints. If endpoints are 32 | // quantized to something smaller than this, then it would constitute an 33 | // illegal ASTC encoding. 34 | constexpr int kEndpointRangeMinValue = 5; 35 | 36 | // The maximum possible range for a weight value. If weights are quantized to 37 | // something larger than this, then it would constitute an illegal ASTC 38 | // encoding. 39 | constexpr int kWeightRangeMaxValue = 31; 40 | 41 | // Quantizes a value in the range [0, 255] to [0, |range|]. The quantized values 42 | // have no correlation to the input values, and there should be no implicit 43 | // assumptions made about their ordering. Valid values of |range_max_value| are 44 | // in the interval [5, 255] 45 | int QuantizeCEValueToRange(int value, int range_max_value); 46 | 47 | // Unquantizes a value in the range [0, |range|] to [0, 255]. Performs the 48 | // inverse procedure of QuantizeValueToRange. Valid values of |range_max_value| 49 | // are in the interval [5, 255] 50 | int UnquantizeCEValueFromRange(int value, int range_max_value); 51 | 52 | // Quantizes a weight in the range [0, 64] to [0, |range_max_value|]. The 53 | // quantized values have no correlation to the input values, and there should 54 | // be no implicit assumptions made about their ordering. Valid values of 55 | // |range_max_value| are in the interval [1, 31] 56 | int QuantizeWeightToRange(int weight, int range_max_value); 57 | 58 | // Unquantizes a weight in the range [0, |range_max_value|] to [0, 64]. Performs 59 | // the inverse procedure of QuantizeWeightToRange. Valid values of 60 | // |range_max_value| are in the interval [1, 31] 61 | int UnquantizeWeightFromRange(int weight, int range_max_value); 62 | 63 | } // namespace astc_codec 64 | 65 | #endif // ASTC_CODEC_DECODER_QUANTIZATION_H_ 66 | -------------------------------------------------------------------------------- /src/decoder/test/astc_fuzzer.cc: -------------------------------------------------------------------------------- 1 | // Copyright 2018 Google LLC 2 | // 3 | // Licensed under the Apache License, Version 2.0 (the "License"); 4 | // you may not use this file except in compliance with the License. 5 | // You may obtain a copy of the License at 6 | // 7 | // https://www.apache.org/licenses/LICENSE-2.0 8 | // 9 | // Unless required by applicable law or agreed to in writing, software 10 | // distributed under the License is distributed on an "AS IS" BASIS, 11 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | // See the License for the specific language governing permissions and 13 | // limitations under the License. 14 | 15 | // ASTC fuzzing wrapper to help with fuzz testing. 16 | 17 | #include "src/decoder/codec.h" 18 | 19 | #include 20 | 21 | #include 22 | 23 | extern "C" int LLVMFuzzerTestOneInput(const uint8_t* data, size_t size) { 24 | std::string error; 25 | std::unique_ptr file = 26 | astc_codec::ASTCFile::LoadFromMemory(reinterpret_cast(data), 27 | size, &error); 28 | if (file) { 29 | std::vector out_buffer(file->GetWidth() * file->GetHeight() * 4); 30 | bool result = astc_codec::DecompressToImage( 31 | *file, out_buffer.data(), out_buffer.size(), file->GetWidth() * 4); 32 | benchmark::DoNotOptimize(result); 33 | } 34 | 35 | return 0; 36 | } 37 | -------------------------------------------------------------------------------- /src/decoder/test/codec_test.cc: -------------------------------------------------------------------------------- 1 | // Copyright 2018 Google LLC 2 | // 3 | // Licensed under the Apache License, Version 2.0 (the "License"); 4 | // you may not use this file except in compliance with the License. 5 | // You may obtain a copy of the License at 6 | // 7 | // https://www.apache.org/licenses/LICENSE-2.0 8 | // 9 | // Unless required by applicable law or agreed to in writing, software 10 | // distributed under the License is distributed on an "AS IS" BASIS, 11 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | // See the License for the specific language governing permissions and 13 | // limitations under the License. 14 | 15 | #include "src/decoder/codec.h" 16 | #include "include/astc-codec/astc-codec.h" 17 | #include "src/decoder/test/image_utils.h" 18 | 19 | #include 20 | 21 | #include 22 | 23 | namespace astc_codec { 24 | 25 | static void PrintTo(FootprintType footprint, std::ostream* os) { 26 | switch (footprint) { 27 | case FootprintType::k4x4: *os << "FootprintType::k4x4"; break; 28 | case FootprintType::k5x4: *os << "FootprintType::k5x4"; break; 29 | case FootprintType::k5x5: *os << "FootprintType::k5x5"; break; 30 | case FootprintType::k6x5: *os << "FootprintType::k6x5"; break; 31 | case FootprintType::k6x6: *os << "FootprintType::k6x6"; break; 32 | case FootprintType::k8x5: *os << "FootprintType::k8x5"; break; 33 | case FootprintType::k8x6: *os << "FootprintType::k8x6"; break; 34 | case FootprintType::k10x5: *os << "FootprintType::k10x5"; break; 35 | case FootprintType::k10x6: *os << "FootprintType::k10x6"; break; 36 | case FootprintType::k8x8: *os << "FootprintType::k8x8"; break; 37 | case FootprintType::k10x8: *os << "FootprintType::k10x8"; break; 38 | case FootprintType::k10x10: *os << "FootprintType::k10x10"; break; 39 | case FootprintType::k12x10: *os << "FootprintType::k12x10"; break; 40 | case FootprintType::k12x12: *os << "FootprintType::k12x12"; break; 41 | default: 42 | *os << "(footprint) << ">"; 44 | } 45 | } 46 | 47 | namespace { 48 | 49 | using ::testing::TestWithParam; 50 | using ::testing::ValuesIn; 51 | 52 | ImageBuffer LoadGoldenImageWithAlpha(std::string basename) { 53 | const std::string filename = 54 | std::string("src/decoder/testdata/") + basename + ".bmp"; 55 | ImageBuffer result; 56 | LoadGoldenBmp(filename, &result); 57 | EXPECT_EQ(result.BytesPerPixel(), 4); 58 | return result; 59 | } 60 | 61 | struct ImageTestParams { 62 | std::string image_name; 63 | FootprintType footprint; 64 | size_t width; 65 | size_t height; 66 | }; 67 | 68 | static void PrintTo(const ImageTestParams& params, std::ostream* os) { 69 | *os << "ImageTestParams(" << params.image_name << ", " << params.width << "x" 70 | << params.height << ", "; 71 | PrintTo(params.footprint, os); 72 | *os << ")"; 73 | } 74 | 75 | TEST(CodecTest, InvalidInput) { 76 | const size_t valid_width = 16; 77 | const size_t valid_height = 16; 78 | const size_t valid_stride = valid_width * 4; 79 | 80 | const std::vector data(256); 81 | std::vector output(valid_width * valid_height * 4); 82 | 83 | // Invalid footprint. 84 | EXPECT_FALSE(ASTCDecompressToRGBA( 85 | data.data(), data.size(), valid_width, valid_height, 86 | FootprintType::kCount, output.data(), output.size(), valid_stride)); 87 | 88 | // Fail for 0 width or height. 89 | EXPECT_FALSE(ASTCDecompressToRGBA(data.data(), data.size(), 0, valid_height, 90 | FootprintType::k4x4, output.data(), 91 | output.size(), valid_stride)); 92 | EXPECT_FALSE(ASTCDecompressToRGBA(data.data(), data.size(), valid_width, 0, 93 | FootprintType::k4x4, output.data(), 94 | output.size(), valid_stride)); 95 | 96 | // Fail for data size that's not a multiple of block size. 97 | EXPECT_FALSE(ASTCDecompressToRGBA( 98 | data.data(), data.size() - 1, valid_width, valid_height, 99 | FootprintType::k4x4, output.data(), output.size(), valid_stride)); 100 | // Fail for data size that doesn't match the block count. 101 | EXPECT_FALSE(ASTCDecompressToRGBA( 102 | data.data(), data.size() - 16, valid_width, valid_height, 103 | FootprintType::k4x4, output.data(), output.size(), valid_stride)); 104 | 105 | // Fail for invalid stride. 106 | EXPECT_FALSE(ASTCDecompressToRGBA( 107 | data.data(), data.size(), valid_width, valid_height, FootprintType::k4x4, 108 | output.data(), output.size(), valid_stride - 1)); 109 | 110 | // Fail for invalid output size. 111 | EXPECT_FALSE(ASTCDecompressToRGBA( 112 | data.data(), data.size(), valid_width, valid_height, FootprintType::k4x4, 113 | output.data(), output.size() - 1, valid_stride)); 114 | } 115 | 116 | class CodecTest : public TestWithParam {}; 117 | 118 | TEST_P(CodecTest, PublicAPI) { 119 | const auto& params = GetParam(); 120 | const std::string astc = LoadASTCFile(params.image_name); 121 | 122 | ImageBuffer our_decoded_image; 123 | our_decoded_image.Allocate(params.width, params.height, 4); 124 | ASSERT_TRUE(ASTCDecompressToRGBA( 125 | reinterpret_cast(astc.data()), astc.size(), params.width, 126 | params.height, params.footprint, our_decoded_image.Data().data(), 127 | our_decoded_image.DataSize(), our_decoded_image.Stride())); 128 | 129 | // Check that the decoded image is *very* similar to the library decoding 130 | // of an ASTC texture. They may not be exact due to differences in how we 131 | // convert a 16-bit float to an 8-bit integer. 132 | ImageBuffer decoded_image = LoadGoldenImageWithAlpha(params.image_name); 133 | CompareSumOfSquaredDifferences(decoded_image, our_decoded_image, 1.0); 134 | } 135 | 136 | TEST_P(CodecTest, DecompressToImage) { 137 | const auto& params = GetParam(); 138 | 139 | std::string error; 140 | std::unique_ptr image_file = ASTCFile::LoadFile( 141 | std::string("src/decoder/testdata/") + params.image_name + ".astc", 142 | &error); 143 | ASSERT_TRUE(image_file) << "Failed to load " << params.image_name << ": " 144 | << error; 145 | 146 | ASSERT_TRUE(image_file->GetFootprint()); 147 | EXPECT_EQ(params.footprint, image_file->GetFootprint().value().Type()); 148 | 149 | ImageBuffer our_decoded_image; 150 | our_decoded_image.Allocate(image_file->GetWidth(), image_file->GetHeight(), 151 | 4); 152 | 153 | ASSERT_TRUE(DecompressToImage(*image_file, our_decoded_image.Data().data(), 154 | our_decoded_image.DataSize(), 155 | our_decoded_image.Stride())); 156 | 157 | // Check that the decoded image is *very* similar to the library decoding 158 | // of an ASTC texture. They may not be exact due to differences in how we 159 | // convert a 16-bit float to an 8-bit integer. 160 | ImageBuffer decoded_image = LoadGoldenImageWithAlpha(params.image_name); 161 | CompareSumOfSquaredDifferences(decoded_image, our_decoded_image, 1.0); 162 | } 163 | 164 | // Test to make sure that reading out color values from blocks in a real-world 165 | // image isn't terribly wrong, either. 166 | std::vector GetTransparentImageTestParams() { 167 | return { 168 | // image_name astc footprint width height 169 | { "atlas_small_4x4", FootprintType::k4x4, 256, 256 }, 170 | { "atlas_small_5x5", FootprintType::k5x5, 256, 256 }, 171 | { "atlas_small_6x6", FootprintType::k6x6, 256, 256 }, 172 | { "atlas_small_8x8", FootprintType::k8x8, 256, 256 }, 173 | }; 174 | } 175 | 176 | INSTANTIATE_TEST_CASE_P(Transparent, CodecTest, 177 | ValuesIn(GetTransparentImageTestParams())); 178 | 179 | } // namespace 180 | 181 | } // namespace astc_codec 182 | -------------------------------------------------------------------------------- /src/decoder/test/footprint_test.cc: -------------------------------------------------------------------------------- 1 | // Copyright 2018 Google LLC 2 | // 3 | // Licensed under the Apache License, Version 2.0 (the "License"); 4 | // you may not use this file except in compliance with the License. 5 | // You may obtain a copy of the License at 6 | // 7 | // https://www.apache.org/licenses/LICENSE-2.0 8 | // 9 | // Unless required by applicable law or agreed to in writing, software 10 | // distributed under the License is distributed on an "AS IS" BASIS, 11 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | // See the License for the specific language governing permissions and 13 | // limitations under the License. 14 | 15 | #include "src/decoder/footprint.h" 16 | 17 | #include 18 | #include 19 | #include 20 | 21 | #include 22 | 23 | namespace astc_codec { 24 | 25 | namespace { 26 | 27 | TEST(FootprintTest, ParseAstcFootprintString) { 28 | using ASTCTestPair = std::pair; 29 | const std::array 30 | valid_footprints {{ 31 | std::make_pair("4x4", Footprint::Get4x4()), 32 | std::make_pair("5x4", Footprint::Get5x4()), 33 | std::make_pair("5x5", Footprint::Get5x5()), 34 | std::make_pair("6x5", Footprint::Get6x5()), 35 | std::make_pair("6x6", Footprint::Get6x6()), 36 | std::make_pair("8x5", Footprint::Get8x5()), 37 | std::make_pair("8x6", Footprint::Get8x6()), 38 | std::make_pair("8x8", Footprint::Get8x8()), 39 | std::make_pair("10x5", Footprint::Get10x5()), 40 | std::make_pair("10x6", Footprint::Get10x6()), 41 | std::make_pair("10x8", Footprint::Get10x8()), 42 | std::make_pair("10x10", Footprint::Get10x10()), 43 | std::make_pair("12x10", Footprint::Get12x10()), 44 | std::make_pair("12x12", Footprint::Get12x12()) 45 | }}; 46 | 47 | for (const auto& test : valid_footprints) { 48 | base::Optional footprint = Footprint::Parse(test.first.c_str()); 49 | EXPECT_TRUE(footprint); 50 | EXPECT_EQ(test.second, footprint.value()); 51 | } 52 | 53 | EXPECT_DEBUG_DEATH(EXPECT_FALSE(Footprint::Parse("")), ""); 54 | EXPECT_DEBUG_DEATH(EXPECT_FALSE(Footprint::Parse("3")), ""); 55 | EXPECT_DEBUG_DEATH(EXPECT_FALSE(Footprint::Parse("x")), ""); 56 | // Validly formed but out-of-bounds dimensions do not assert, otherwise 57 | // malformed ASTC files could crash the decoder in debug builds. 58 | EXPECT_FALSE(Footprint::Parse("9999999999x10")); 59 | EXPECT_DEBUG_DEATH(EXPECT_FALSE(Footprint::Parse("ax8")), ""); 60 | EXPECT_DEBUG_DEATH(EXPECT_FALSE(Footprint::Parse("2x3x4")), ""); 61 | EXPECT_DEBUG_DEATH(EXPECT_FALSE(Footprint::Parse("-3x4")), ""); 62 | EXPECT_FALSE(Footprint::Parse("10x4")); 63 | } 64 | 65 | TEST(FootprintTest, Bitrates) { 66 | EXPECT_NEAR(Footprint::Get4x4().Bitrate(), 8.f, 0.01f); 67 | EXPECT_NEAR(Footprint::Get5x4().Bitrate(), 6.4f, 0.01f); 68 | EXPECT_NEAR(Footprint::Get5x5().Bitrate(), 5.12f, 0.01f); 69 | EXPECT_NEAR(Footprint::Get6x5().Bitrate(), 4.27f, 0.01f); 70 | EXPECT_NEAR(Footprint::Get6x6().Bitrate(), 3.56f, 0.01f); 71 | EXPECT_NEAR(Footprint::Get8x5().Bitrate(), 3.20f, 0.01f); 72 | EXPECT_NEAR(Footprint::Get8x6().Bitrate(), 2.67f, 0.01f); 73 | EXPECT_NEAR(Footprint::Get8x8().Bitrate(), 2.00f, 0.01f); 74 | EXPECT_NEAR(Footprint::Get10x5().Bitrate(), 2.56f, 0.01f); 75 | EXPECT_NEAR(Footprint::Get10x6().Bitrate(), 2.13f, 0.01f); 76 | EXPECT_NEAR(Footprint::Get10x8().Bitrate(), 1.60f, 0.01f); 77 | EXPECT_NEAR(Footprint::Get10x10().Bitrate(), 1.28f, 0.01f); 78 | EXPECT_NEAR(Footprint::Get12x10().Bitrate(), 1.07f, 0.01f); 79 | EXPECT_NEAR(Footprint::Get12x12().Bitrate(), 0.89f, 0.01f); 80 | } 81 | 82 | TEST(FootprintTest, StorageRequirements) { 83 | auto footprint = Footprint::Get10x8(); 84 | EXPECT_EQ(footprint.Width(), 10); 85 | EXPECT_EQ(footprint.Height(), 8); 86 | 87 | // If we have 8x8 blocks, then we have 64*16 = 1024 bytes. 88 | EXPECT_EQ(footprint.StorageRequirements(80, 64), 1024); 89 | 90 | // If our block is a little smaller this still counts because we need to 91 | // cover a partial block with a fully encoded one. 92 | EXPECT_EQ(footprint.StorageRequirements(79, 63), 1024); 93 | } 94 | 95 | } // namespace 96 | 97 | } // namespace astc_codec 98 | -------------------------------------------------------------------------------- /src/decoder/test/image_utils.h: -------------------------------------------------------------------------------- 1 | // Copyright 2018 Google LLC 2 | // 3 | // Licensed under the Apache License, Version 2.0 (the "License"); 4 | // you may not use this file except in compliance with the License. 5 | // You may obtain a copy of the License at 6 | // 7 | // https://www.apache.org/licenses/LICENSE-2.0 8 | // 9 | // Unless required by applicable law or agreed to in writing, software 10 | // distributed under the License is distributed on an "AS IS" BASIS, 11 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | // See the License for the specific language governing permissions and 13 | // limitations under the License. 14 | 15 | #include 16 | 17 | #include 18 | #include 19 | 20 | static constexpr size_t kMaxVectorOutput = 128; 21 | 22 | class ImageBuffer { 23 | public: 24 | static constexpr size_t Align = 4; 25 | 26 | void Allocate(size_t width, size_t height, size_t bytes_per_pixel) { 27 | width_ = width; 28 | height_ = height; 29 | bytes_per_pixel_ = bytes_per_pixel; 30 | stride_ = AlignBytes(width * bytes_per_pixel); 31 | data_.resize(stride_ * height); 32 | } 33 | 34 | uint8_t* operator()(size_t x, size_t y) { 35 | assert(x < width_ && y < height_); 36 | return &data_[y * Stride() + x * bytes_per_pixel_]; 37 | } 38 | 39 | size_t Stride() const { return stride_; } 40 | size_t BytesPerPixel() const { return bytes_per_pixel_; } 41 | 42 | std::vector& Data() { return data_; } 43 | const std::vector& Data() const { return data_; } 44 | size_t DataSize() const { return data_.size(); } 45 | 46 | private: 47 | size_t AlignBytes(size_t bytes) const { 48 | return (bytes + (Align - 1)) / Align * Align; 49 | } 50 | 51 | size_t width_ = 0; 52 | size_t height_ = 0; 53 | size_t stride_ = 0; 54 | size_t bytes_per_pixel_ = 0; 55 | std::vector data_; 56 | }; 57 | 58 | namespace std { 59 | static void PrintTo(const vector& vec, ostream* os) { 60 | ios::fmtflags origFlags(os->flags()); 61 | 62 | *os << '{'; 63 | size_t count = 0; 64 | for (vector::const_iterator it = vec.begin(); it != vec.end(); 65 | ++it, ++count) { 66 | if (count > 0) { 67 | *os << ", "; 68 | } 69 | 70 | if (count == kMaxVectorOutput) { 71 | *os << "... "; 72 | break; 73 | } 74 | 75 | if ((count % 16) == 0) { 76 | *os << "\n"; 77 | } 78 | 79 | if (*it == 0) { 80 | *os << " "; 81 | } else { 82 | *os << "0x" << std::hex << std::uppercase << std::setw(2) 83 | << std::setfill('0') << int(*it) << std::dec; 84 | } 85 | } 86 | 87 | *os << '}'; 88 | 89 | os->flags(origFlags); 90 | } 91 | } // namespace std 92 | 93 | static inline std::string LoadFile(const std::string& path) { 94 | std::ifstream is(path, std::ios::binary); 95 | EXPECT_TRUE(is) << "Failed to load file " << path; 96 | if (!is) { 97 | return ""; 98 | } 99 | 100 | std::ostringstream ss; 101 | ss << is.rdbuf(); 102 | return ss.str(); 103 | } 104 | 105 | static inline std::string LoadASTCFile(const std::string& basename) { 106 | const std::string filename = 107 | std::string("src/decoder/testdata/") + basename + ".astc"; 108 | 109 | std::string result = LoadFile(filename); 110 | // Don't parse the header here, we already know what kind of astc encoding it 111 | // is. 112 | if (result.size() < 16) { 113 | return ""; 114 | } else { 115 | return result.substr(16); 116 | } 117 | } 118 | 119 | static inline void LoadGoldenBmp(const std::string& path, ImageBuffer* result) { 120 | constexpr size_t kBmpHeaderSize = 54; 121 | 122 | SCOPED_TRACE(testing::Message() << "LoadGoldenBmp " << path); 123 | 124 | const std::string data = LoadFile(path); 125 | ASSERT_FALSE(data.empty()) << "Failed to open golden image: " << path; 126 | 127 | ASSERT_GE(data.size(), kBmpHeaderSize); 128 | ASSERT_EQ('B', data[0]); 129 | ASSERT_EQ('M', data[1]); 130 | 131 | uint32_t dataPos = *reinterpret_cast(&data[0x0A]); 132 | uint32_t imageSize = *reinterpret_cast(&data[0x22]); 133 | const uint16_t bitsPerPixel = *reinterpret_cast(&data[0x1C]); 134 | int width = *reinterpret_cast(&data[0x12]); 135 | int height = *reinterpret_cast(&data[0x16]); 136 | 137 | SCOPED_TRACE(testing::Message() 138 | << "dataPos=" << dataPos << ", imageSize=" << imageSize 139 | << ", bitsPerPixel=" << bitsPerPixel << ", width=" << width 140 | << ", height=" << height); 141 | 142 | if (height < 0) { 143 | height = -height; 144 | } 145 | 146 | if (imageSize == 0) { 147 | imageSize = width * height * 3; 148 | } 149 | 150 | if (dataPos < kBmpHeaderSize) { 151 | dataPos = kBmpHeaderSize; 152 | } 153 | 154 | ASSERT_TRUE(bitsPerPixel == 24 || bitsPerPixel == 32) 155 | << "BMP bits per pixel mismatch, expected 24 or 32"; 156 | 157 | result->Allocate(width, height, bitsPerPixel == 24 ? 3 : 4); 158 | ASSERT_LE(imageSize, result->DataSize()); 159 | 160 | std::vector& resultData = result->Data(); 161 | const size_t stride = result->Stride(); 162 | 163 | // Copy the data row-by-row to make sure that stride is right. 164 | for (size_t row = 0; row < static_cast(height); ++row) { 165 | memcpy(&resultData[row * stride], &data[dataPos + row * stride], 166 | width * bitsPerPixel / 8); 167 | } 168 | 169 | if (bitsPerPixel == 32) { 170 | // Swizzle the data from ABGR to ARGB. 171 | for (size_t row = 0; row < static_cast(height); ++row) { 172 | uint8_t* rowData = resultData.data() + row * stride; 173 | 174 | for (size_t i = 3; i < stride; i += 4) { 175 | const uint8_t b = rowData[i - 3]; 176 | rowData[i - 3] = rowData[i - 1]; 177 | rowData[i - 1] = b; 178 | } 179 | } 180 | } else { 181 | // Swizzle the data from BGR to RGB. 182 | for (size_t row = 0; row < static_cast(height); ++row) { 183 | uint8_t* rowData = resultData.data() + row * stride; 184 | 185 | for (size_t i = 2; i < stride; i += 3) { 186 | const uint8_t tmp = rowData[i - 2]; 187 | rowData[i - 2] = rowData[i]; 188 | rowData[i] = tmp; 189 | } 190 | } 191 | } 192 | } 193 | 194 | static inline void CompareSumOfSquaredDifferences(const ImageBuffer& golden, 195 | const ImageBuffer& image, 196 | double threshold) { 197 | ASSERT_EQ(golden.DataSize(), image.DataSize()); 198 | ASSERT_EQ(golden.Stride(), image.Stride()); 199 | ASSERT_EQ(golden.BytesPerPixel(), image.BytesPerPixel()); 200 | 201 | const std::vector& image_data = image.Data(); 202 | const std::vector& golden_data = golden.Data(); 203 | 204 | double sum = 0.0; 205 | for (size_t i = 0; i < image_data.size(); ++i) { 206 | const double diff = static_cast(image_data[i]) - golden_data[i]; 207 | sum += diff * diff; 208 | } 209 | 210 | EXPECT_LE(sum, threshold * image_data.size()) 211 | << "Per pixel " << (sum / image_data.size()) 212 | << ", expected <= " << threshold; 213 | if (sum > threshold * image_data.size()) { 214 | // Fall back to comparison which will dump first chunk of vector. 215 | EXPECT_EQ(golden_data, image_data); 216 | } 217 | } 218 | -------------------------------------------------------------------------------- /src/decoder/test/logical_astc_block_test.cc: -------------------------------------------------------------------------------- 1 | // Copyright 2018 Google LLC 2 | // 3 | // Licensed under the Apache License, Version 2.0 (the "License"); 4 | // you may not use this file except in compliance with the License. 5 | // You may obtain a copy of the License at 6 | // 7 | // https://www.apache.org/licenses/LICENSE-2.0 8 | // 9 | // Unless required by applicable law or agreed to in writing, software 10 | // distributed under the License is distributed on an "AS IS" BASIS, 11 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | // See the License for the specific language governing permissions and 13 | // limitations under the License. 14 | 15 | #include "src/decoder/logical_astc_block.h" 16 | #include "src/decoder/test/image_utils.h" 17 | 18 | #include 19 | #include 20 | 21 | #include 22 | #include 23 | 24 | namespace astc_codec { 25 | 26 | namespace { 27 | 28 | using ::testing::Eq; 29 | using ::testing::ElementsAre; 30 | using ::testing::TestWithParam; 31 | using ::testing::ValuesIn; 32 | 33 | ImageBuffer LoadGoldenImageWithAlpha(std::string basename) { 34 | const std::string filename = std::string("src/decoder/testdata/") + basename + ".bmp"; 35 | ImageBuffer result; 36 | LoadGoldenBmp(filename, &result); 37 | EXPECT_EQ(result.BytesPerPixel(), 4); 38 | return result; 39 | } 40 | 41 | ImageBuffer LoadGoldenImage(std::string basename) { 42 | const std::string filename = std::string("src/decoder/testdata/") + basename + ".bmp"; 43 | ImageBuffer result; 44 | LoadGoldenBmp(filename, &result); 45 | EXPECT_EQ(result.BytesPerPixel(), 3); 46 | return result; 47 | } 48 | 49 | struct ImageTestParams { 50 | std::string image_name; 51 | bool has_alpha; 52 | Footprint footprint; 53 | int width; 54 | int height; 55 | }; 56 | 57 | static void PrintTo(const ImageTestParams& params, std::ostream* os) { 58 | *os << "ImageTestParams(" << params.image_name << ", " 59 | << params.width << "x" << params.height << ", " 60 | << (params.has_alpha ? "RGBA" : "RGB") << ", " 61 | << "footprint " << params.footprint.Width() << "x" 62 | << params.footprint.Height() << ")"; 63 | } 64 | 65 | class LogicalASTCBlockTest : public TestWithParam { }; 66 | 67 | // Test to make sure that reading out color values from blocks is not 68 | // terribly wrong. To do so, we compress an image and then decompress it 69 | // using our logical blocks and the library. The difference between the 70 | // decoded images should be minimal. 71 | TEST_P(LogicalASTCBlockTest, ImageWithFootprint) { 72 | const auto& params = GetParam(); 73 | const std::string astc = LoadASTCFile(params.image_name); 74 | 75 | ImageBuffer our_decoded_image; 76 | our_decoded_image.Allocate(params.width, params.height, params.has_alpha ? 4 : 3); 77 | 78 | const int block_width = params.footprint.Width(); 79 | const int block_height = params.footprint.Height(); 80 | 81 | base::UInt128 block; 82 | for (int i = 0; i < astc.size(); i += 16) { 83 | const int block_index = i / 16; 84 | const int blocks_wide = 85 | (params.width + block_width - 1) / block_width; 86 | const int block_x = block_index % blocks_wide; 87 | const int block_y = block_index / blocks_wide; 88 | memcpy(&block, astc.data() + i, sizeof(block)); 89 | 90 | PhysicalASTCBlock physical_block(block); 91 | if (physical_block.IsVoidExtent()) { 92 | auto ve = UnpackVoidExtent(physical_block); 93 | ASSERT_TRUE(ve) << "ASTC encoder produced invalid block!"; 94 | } else { 95 | auto ib = UnpackIntermediateBlock(physical_block); 96 | ASSERT_TRUE(ib) << "ASTC encoder produced invalid block!"; 97 | } 98 | 99 | // Make sure that the library doesn't produce incorrect ASTC blocks. 100 | // This is covered in more depth in other tests in 101 | // intermediate_astc_block_test and physical_astc_block_test 102 | auto lb = UnpackLogicalBlock(params.footprint, physical_block); 103 | ASSERT_TRUE(lb) << "ASTC encoder produced invalid block!"; 104 | 105 | LogicalASTCBlock logical_block = lb.value(); 106 | const size_t color_size = params.has_alpha ? 4 : 3; 107 | 108 | for (int y = 0; y < block_height; ++y) { 109 | for (int x = 0; x < block_width; ++x) { 110 | const int px = block_width * block_x + x; 111 | const int py = block_height * block_y + y; 112 | 113 | // Skip out of bounds. 114 | if (px >= params.width || py >= params.height) { 115 | continue; 116 | } 117 | 118 | uint8_t* pixel = our_decoded_image(px, py); 119 | const RgbaColor decoded_color = logical_block.ColorAt(x, y); 120 | ASSERT_LE(color_size, decoded_color.size()); 121 | 122 | for (int c = 0; c < color_size; ++c) { 123 | // All of the pixels should also be 8-bit values. 124 | ASSERT_GE(decoded_color[c], 0); 125 | ASSERT_LT(decoded_color[c], 256); 126 | pixel[c] = decoded_color[c]; 127 | } 128 | } 129 | } 130 | } 131 | 132 | // Check that the decoded image is *very* similar to the library decoding 133 | // of an ASTC texture. They may not be exact due to differences in how we 134 | // convert a 16-bit float to an 8-bit integer. 135 | ImageBuffer decoded_image = params.has_alpha ? LoadGoldenImageWithAlpha(params.image_name) : LoadGoldenImage(params.image_name); 136 | CompareSumOfSquaredDifferences(decoded_image, our_decoded_image, 1.0); 137 | } 138 | 139 | // Test to make sure that a simple gradient image can be compressed and decoded 140 | // by our logical block representation. This should work with every footprint. 141 | std::vector GetSyntheticImageTestParams() { 142 | return { 143 | // image_name alpha astc footprint width height 144 | { "footprint_4x4", false, Footprint::Get4x4(), 32, 32 }, 145 | { "footprint_5x4", false, Footprint::Get5x4(), 32, 32 }, 146 | { "footprint_5x5", false, Footprint::Get5x5(), 32, 32 }, 147 | { "footprint_6x5", false, Footprint::Get6x5(), 32, 32 }, 148 | { "footprint_6x6", false, Footprint::Get6x6(), 32, 32 }, 149 | { "footprint_8x5", false, Footprint::Get8x5(), 32, 32 }, 150 | { "footprint_8x6", false, Footprint::Get8x6(), 32, 32 }, 151 | { "footprint_10x5", false, Footprint::Get10x5(), 32, 32 }, 152 | { "footprint_10x6", false, Footprint::Get10x6(), 32, 32 }, 153 | { "footprint_8x8", false, Footprint::Get8x8(), 32, 32 }, 154 | { "footprint_10x8", false, Footprint::Get10x8(), 32, 32 }, 155 | { "footprint_10x10", false, Footprint::Get10x10(), 32, 32 }, 156 | { "footprint_12x10", false, Footprint::Get12x10(), 32, 32 }, 157 | { "footprint_12x12", false, Footprint::Get12x12(), 32, 32 }, 158 | }; 159 | } 160 | 161 | INSTANTIATE_TEST_CASE_P(Synthetic, LogicalASTCBlockTest, 162 | ValuesIn(GetSyntheticImageTestParams())); 163 | 164 | // Test to make sure that reading out color values from blocks in a real-world 165 | // image isn't terribly wrong, either. 166 | std::vector GetRealWorldImageTestParams() { 167 | return { 168 | // image_name alpha astc footprint width height 169 | { "rgb_4x4", false, Footprint::Get4x4(), 224, 288 }, 170 | { "rgb_6x6", false, Footprint::Get6x6(), 224, 288 }, 171 | { "rgb_8x8", false, Footprint::Get8x8(), 224, 288 }, 172 | { "rgb_12x12", false, Footprint::Get12x12(), 224, 288 }, 173 | { "rgb_5x4", false, Footprint::Get5x4(), 224, 288 } 174 | }; 175 | } 176 | 177 | INSTANTIATE_TEST_CASE_P(RealWorld, LogicalASTCBlockTest, 178 | ValuesIn(GetRealWorldImageTestParams())); 179 | 180 | // Test to make sure that reading out color values from blocks in a real-world 181 | // image isn't terribly wrong, either. 182 | std::vector GetTransparentImageTestParams() { 183 | return { 184 | // image_name alpha astc footprint width height 185 | { "atlas_small_4x4", true, Footprint::Get4x4(), 256, 256 }, 186 | { "atlas_small_5x5", true, Footprint::Get5x5(), 256, 256 }, 187 | { "atlas_small_6x6", true, Footprint::Get6x6(), 256, 256 }, 188 | { "atlas_small_8x8", true, Footprint::Get8x8(), 256, 256 }, 189 | }; 190 | } 191 | 192 | INSTANTIATE_TEST_CASE_P(Transparent, LogicalASTCBlockTest, 193 | ValuesIn(GetTransparentImageTestParams())); 194 | 195 | // Test to make sure that if we set our endpoints then it's reflected in our 196 | // color selection 197 | TEST(LogicalASTCBlockTest, SetEndpoints) { 198 | LogicalASTCBlock logical_block(Footprint::Get8x8()); 199 | 200 | // Setup a weight checkerboard 201 | for (int j = 0; j < 8; ++j) { 202 | for (int i = 0; i < 8; ++i) { 203 | if (((i ^ j) & 1) == 1) { 204 | logical_block.SetWeightAt(i, j, 0); 205 | } else { 206 | logical_block.SetWeightAt(i, j, 64); 207 | } 208 | } 209 | } 210 | 211 | // Now set the colors to something ridiculous 212 | logical_block.SetEndpoints({{ 123, 45, 67, 89 }}, {{ 101, 121, 31, 41 }}, 0); 213 | 214 | // For each pixel, we expect it to mirror the endpoints in a checkerboard 215 | // pattern 216 | for (int j = 0; j < 8; ++j) { 217 | for (int i = 0; i < 8; ++i) { 218 | if (((i ^ j) & 1) == 1) { 219 | EXPECT_THAT(logical_block.ColorAt(i, j), ElementsAre(123, 45, 67, 89)); 220 | } else { 221 | EXPECT_THAT(logical_block.ColorAt(i, j), ElementsAre(101, 121, 31, 41)); 222 | } 223 | } 224 | } 225 | } 226 | 227 | // Test whether or not setting weight values under different circumstances is 228 | // supported and reflected in the query functions. 229 | TEST(LogicalASTCBlockTest, SetWeightVals) { 230 | LogicalASTCBlock logical_block(Footprint::Get4x4()); 231 | 232 | EXPECT_THAT(logical_block.GetFootprint(), Eq(Footprint::Get4x4())); 233 | 234 | // Not a dual plane by default 235 | EXPECT_FALSE(logical_block.IsDualPlane()); 236 | logical_block.SetWeightAt(2, 3, 2); 237 | 238 | // Set the dual plane 239 | logical_block.SetDualPlaneChannel(0); 240 | EXPECT_TRUE(logical_block.IsDualPlane()); 241 | 242 | // This shouldn't have reset our weight 243 | const LogicalASTCBlock other_block = logical_block; 244 | EXPECT_THAT(other_block.WeightAt(2, 3), Eq(2)); 245 | EXPECT_THAT(other_block.DualPlaneWeightAt(0, 2, 3), Eq(2)); 246 | 247 | // If we set the dual plane weight, it shouldn't change the original weight 248 | // value or the other channels 249 | logical_block.SetDualPlaneWeightAt(0, 2, 3, 1); 250 | EXPECT_THAT(logical_block.WeightAt(2, 3), Eq(2)); 251 | EXPECT_THAT(logical_block.DualPlaneWeightAt(0, 2, 3), Eq(1)); 252 | for (int i = 1; i < 4; ++i) { 253 | EXPECT_THAT(logical_block.DualPlaneWeightAt(i, 2, 3), Eq(2)); 254 | } 255 | 256 | // Remove the dual plane 257 | logical_block.SetDualPlaneChannel(-1); 258 | EXPECT_FALSE(logical_block.IsDualPlane()); 259 | 260 | // Now the original dual plane weight should be reset back to the others. Note 261 | // that we have to call DualPlaneWeightAt from a const logical block since 262 | // returning a reference to a weight that doesn't exist is illegal. 263 | const LogicalASTCBlock other_block2 = logical_block; 264 | EXPECT_THAT(logical_block.WeightAt(2, 3), Eq(2)); 265 | for (int i = 0; i < 4; ++i) { 266 | EXPECT_EQ(logical_block.WeightAt(2, 3), 267 | other_block2.DualPlaneWeightAt(i, 2, 3)); 268 | } 269 | } 270 | 271 | } // namespace 272 | 273 | } // namespace astc_codec 274 | -------------------------------------------------------------------------------- /src/decoder/test/partition_test.cc: -------------------------------------------------------------------------------- 1 | // Copyright 2018 Google LLC 2 | // 3 | // Licensed under the Apache License, Version 2.0 (the "License"); 4 | // you may not use this file except in compliance with the License. 5 | // You may obtain a copy of the License at 6 | // 7 | // https://www.apache.org/licenses/LICENSE-2.0 8 | // 9 | // Unless required by applicable law or agreed to in writing, software 10 | // distributed under the License is distributed on an "AS IS" BASIS, 11 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | // See the License for the specific language governing permissions and 13 | // limitations under the License. 14 | 15 | #include "src/decoder/partition.h" 16 | 17 | #include 18 | #include 19 | 20 | #include 21 | #include 22 | #include 23 | #include 24 | 25 | namespace { 26 | 27 | using ::testing::ElementsAreArray; 28 | using ::testing::Eq; 29 | using ::testing::Le; 30 | using ::testing::Not; 31 | 32 | using astc_codec::Footprint; 33 | using astc_codec::Partition; 34 | using astc_codec::PartitionMetric; 35 | using astc_codec::GetASTCPartition; 36 | using astc_codec::FindClosestASTCPartition; 37 | 38 | // Test to make sure that a simple difference between two partitions where 39 | // most of the values are the same returns what we expect. 40 | TEST(PartitionTest, TestSimplePartitionMetric) { 41 | Partition a = {Footprint::Get6x6(), /* num_parts = */ 2, 42 | /* partition_id = */ {}, /* assignment = */ {}}; 43 | Partition b = a; 44 | 45 | a.assignment = { 46 | 0, 0, 0, 0, 0, 0, 47 | 0, 0, 0, 0, 0, 0, 48 | 0, 0, 0, 0, 0, 0, 49 | 0, 0, 0, 0, 0, 0, 50 | 0, 0, 0, 0, 0, 0, 51 | 0, 0, 0, 0, 0, 1, 52 | }; 53 | 54 | b.assignment = { 55 | 1, 0, 0, 0, 0, 0, 56 | 0, 0, 0, 0, 0, 0, 57 | 0, 0, 0, 0, 0, 0, 58 | 0, 0, 0, 0, 0, 0, 59 | 0, 0, 0, 0, 0, 0, 60 | 0, 0, 0, 0, 0, 0, 61 | }; 62 | 63 | const int dist = PartitionMetric(a, b); 64 | EXPECT_EQ(dist, 2); 65 | } 66 | 67 | // Test to make sure that if one partition is a subset of another that we still 68 | // return the proper difference against the subset of the larger one. 69 | TEST(PartitionDeathTest, TestPartitionMetric) { 70 | Partition a = {Footprint::Get4x4(), /* num_parts = */ 2, 71 | /* partition_id = */ {}, /* assignment = */ {}}; 72 | Partition b = {Footprint::Get6x6(), /* num_parts = */ 2, 73 | /* partition_id = */ {}, /* assignment = */ {}}; 74 | 75 | a.assignment = {{ 76 | 1, 1, 1, 1, 77 | 0, 0, 0, 0, 78 | 0, 0, 0, 0, 79 | 0, 0, 0, 1, 80 | }}; 81 | 82 | b.assignment = {{ 83 | 1, 0, 0, 0, 0, 0, 84 | 0, 0, 0, 0, 0, 0, 85 | 0, 0, 0, 0, 0, 1, 86 | 0, 0, 0, 0, 0, 0, 87 | 0, 1, 0, 0, 1, 0, 88 | 0, 0, 1, 1, 0, 0, 89 | }}; 90 | 91 | EXPECT_DEATH(PartitionMetric(a, b), ""); 92 | } 93 | 94 | // Test to make sure that even if we have different numbers of subsets for each 95 | // partition, that the returned value is what we'd expect. 96 | TEST(PartitionTest, TestDiffPartsPartitionMetric) { 97 | Partition a = {Footprint::Get4x4(), /* num_parts = */ 2, 98 | /* partition_id = */ {}, /* assignment = */ {}}; 99 | Partition b = {Footprint::Get4x4(), /* num_parts = */ 3, 100 | /* partition_id = */ {}, /* assignment = */ {}}; 101 | 102 | a.assignment = {{ 103 | 2, 2, 2, 0, 104 | 0, 0, 0, 0, 105 | 0, 0, 0, 0, 106 | 0, 0, 0, 1, 107 | }}; 108 | 109 | b.assignment = {{ 110 | 1, 0, 0, 0, 111 | 0, 0, 0, 0, 112 | 0, 0, 0, 0, 113 | 0, 0, 0, 0 114 | }}; 115 | 116 | const int dist = PartitionMetric(a, b); 117 | EXPECT_EQ(dist, 3); 118 | } 119 | 120 | // An additional sanity check test that makes sure that we're not always mapping 121 | // zero to zero in our tests. 122 | TEST(PartitionTest, TestDiffMappingPartitionMetric) { 123 | Partition a = {Footprint::Get4x4(), /* num_parts = */ 2, 124 | /* partition_id = */ {}, /* assignment = */ {}}; 125 | Partition b = {Footprint::Get4x4(), /* num_parts = */ 3, 126 | /* partition_id = */ {}, /* assignment = */ {}}; 127 | 128 | a.assignment = {{ 129 | 0, 1, 2, 2, 130 | 2, 2, 2, 2, 131 | 2, 2, 2, 2, 132 | 2, 2, 2, 2, 133 | }}; 134 | 135 | b.assignment = {{ 136 | 1, 0, 0, 0, 137 | 0, 0, 0, 0, 138 | 0, 0, 0, 0, 139 | 0, 0, 0, 0, 140 | }}; 141 | 142 | const int dist = PartitionMetric(a, b); 143 | EXPECT_EQ(dist, 1); 144 | } 145 | 146 | // Finally, if we grab an ASTC partition and modify it a tad, the closest 147 | // partition should still be the same ASTC partition. 148 | TEST(PartitionTest, TestFindingASTCPartition) { 149 | const Partition astc = GetASTCPartition(Footprint::Get12x12(), 3, 0x3CB); 150 | Partition almost_astc = astc; 151 | almost_astc.assignment[0]++; 152 | 153 | const Partition& closest_astc = FindClosestASTCPartition(almost_astc); 154 | EXPECT_EQ(astc, closest_astc); 155 | } 156 | 157 | // Test a partition that was obtained from the reference ASTC encoder. We should 158 | // be able to match it exactly 159 | TEST(PartitionTest, TestSpecificPartition) { 160 | const Partition astc = GetASTCPartition(Footprint::Get10x6(), 3, 557); 161 | EXPECT_THAT(astc.assignment, ElementsAreArray(std::array {{ 162 | 0, 0, 0, 0, 1, 1, 1, 2, 2, 2, 163 | 0, 0, 0, 0, 1, 1, 1, 2, 2, 2, 164 | 0, 0, 0, 0, 1, 1, 1, 2, 2, 2, 165 | 0, 0, 0, 0, 1, 1, 1, 2, 2, 2, 166 | 0, 0, 0, 0, 1, 1, 1, 2, 2, 2, 167 | 0, 0, 0, 0, 1, 1, 1, 2, 2, 2 }})); 168 | } 169 | 170 | // Make sure that when we match against this specific partition, it'll return a 171 | // partition with the same number of subsets 172 | TEST(PartitionTest, EstimatedPartitionSubsets) { 173 | Partition partition = { 174 | /* footprint = */ Footprint::Get6x6(), 175 | /* num_parts = */ 2, 176 | /* partition_id = */ {}, 177 | /* assignment = */ { 178 | 0, 0, 1, 1, 1, 0, 179 | 0, 0, 0, 0, 0, 0, 180 | 0, 0, 0, 0, 0, 0, 181 | 0, 1, 1, 1, 1, 1, 182 | 0, 0, 0, 0, 0, 0, 183 | 1, 1, 1, 1, 1, 1 184 | }}; 185 | 186 | const Partition astc = FindClosestASTCPartition(partition); 187 | EXPECT_THAT(astc.num_parts, Eq(partition.num_parts)); 188 | } 189 | 190 | // Make sure that regardless of what partition we match against, it'll return a 191 | // partition with at most a fewer number of subsets 192 | TEST(PartitionTest, EstimatedPartitionFewerSubsets) { 193 | std::mt19937 random(0xdeadbeef); 194 | auto randUniform = [&random](int max) { 195 | std::uniform_int_distribution<> dist(0, max - 1); 196 | return dist(random); 197 | }; 198 | 199 | constexpr int kNumFootprints = Footprint::NumValidFootprints(); 200 | const auto kFootprints = std::array {{ 201 | Footprint::Get4x4(), 202 | Footprint::Get5x4(), 203 | Footprint::Get5x5(), 204 | Footprint::Get6x5(), 205 | Footprint::Get6x6(), 206 | Footprint::Get8x5(), 207 | Footprint::Get8x6(), 208 | Footprint::Get8x8(), 209 | Footprint::Get10x5(), 210 | Footprint::Get10x6(), 211 | Footprint::Get10x8(), 212 | Footprint::Get10x10(), 213 | Footprint::Get12x10(), 214 | Footprint::Get12x12() 215 | }}; 216 | 217 | constexpr int kNumTests = 200; 218 | for (int i = 0; i < kNumTests; ++i) { 219 | const auto& footprint = kFootprints[randUniform(kNumFootprints)]; 220 | const int num_parts = 2 + randUniform(3); 221 | Partition partition = { 222 | footprint, 223 | num_parts, 224 | /* partition_id = */ {}, 225 | /* assignment = */ std::vector(footprint.NumPixels(), 0)}; 226 | 227 | for (auto& p : partition.assignment) { 228 | p = randUniform(num_parts); 229 | } 230 | 231 | const Partition astc = FindClosestASTCPartition(partition); 232 | EXPECT_THAT(astc.num_parts, Le(partition.num_parts)) 233 | << "Test #" << i << ": " 234 | << "Selected partition with ID " << astc.partition_id.value(); 235 | } 236 | } 237 | 238 | // Make sure that we generate unique partitions that are close to the 239 | // candidates. 240 | TEST(PartitionTest, UniquePartitionResults) { 241 | Partition partition = { 242 | /* footprint = */ Footprint::Get6x6(), 243 | /* num_parts = */ 2, 244 | /* partition_id = */ {}, 245 | /* assignment = */ { 246 | 0, 1, 1, 1, 1, 1, 247 | 0, 1, 1, 1, 1, 1, 248 | 0, 1, 1, 1, 1, 1, 249 | 0, 1, 1, 1, 1, 1, 250 | 0, 1, 1, 1, 1, 1, 251 | 0, 1, 1, 1, 1, 1 252 | }}; 253 | 254 | const auto parts = FindKClosestASTCPartitions(partition, 2); 255 | EXPECT_THAT(*parts[0], Not(Eq(*parts[1]))); 256 | } 257 | 258 | // TODO(google): Verify somehow that the assignment generated from 259 | // GetASTCPartition actually matches what's in the spec. The selection 260 | // function was more or less copy/pasted though so it's unclear how to 261 | // measure that against e.g. the ASTC encoder. 262 | 263 | } // namespace 264 | -------------------------------------------------------------------------------- /src/decoder/test/weight_infill_test.cc: -------------------------------------------------------------------------------- 1 | // Copyright 2018 Google LLC 2 | // 3 | // Licensed under the Apache License, Version 2.0 (the "License"); 4 | // you may not use this file except in compliance with the License. 5 | // You may obtain a copy of the License at 6 | // 7 | // https://www.apache.org/licenses/LICENSE-2.0 8 | // 9 | // Unless required by applicable law or agreed to in writing, software 10 | // distributed under the License is distributed on an "AS IS" BASIS, 11 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | // See the License for the specific language governing permissions and 13 | // limitations under the License. 14 | 15 | #include "src/decoder/weight_infill.h" 16 | #include "src/decoder/footprint.h" 17 | 18 | #include 19 | 20 | #include 21 | 22 | namespace astc_codec { 23 | 24 | namespace { 25 | 26 | // Make sure that the physical size of the bit representations for certain 27 | // dimensions of weight grids matches our expectations 28 | TEST(ASTCWeightInfillTest, TestGetBitCount) { 29 | // Bit encodings 30 | EXPECT_EQ(32, CountBitsForWeights(4, 4, 3)); 31 | EXPECT_EQ(48, CountBitsForWeights(4, 4, 7)); 32 | EXPECT_EQ(24, CountBitsForWeights(2, 4, 7)); 33 | EXPECT_EQ(8, CountBitsForWeights(2, 4, 1)); 34 | 35 | // Trit encodings 36 | EXPECT_EQ(32, CountBitsForWeights(4, 5, 2)); 37 | EXPECT_EQ(26, CountBitsForWeights(4, 4, 2)); 38 | EXPECT_EQ(52, CountBitsForWeights(4, 5, 5)); 39 | EXPECT_EQ(42, CountBitsForWeights(4, 4, 5)); 40 | 41 | // Quint encodings 42 | EXPECT_EQ(21, CountBitsForWeights(3, 3, 4)); 43 | EXPECT_EQ(38, CountBitsForWeights(4, 4, 4)); 44 | EXPECT_EQ(49, CountBitsForWeights(3, 7, 4)); 45 | EXPECT_EQ(52, CountBitsForWeights(4, 3, 19)); 46 | EXPECT_EQ(70, CountBitsForWeights(4, 4, 19)); 47 | } 48 | 49 | // Make sure that we bilerp our weights properly 50 | TEST(ASTCWeightInfillTest, TestInfillBilerp) { 51 | std::vector weights = InfillWeights( 52 | {{ 1, 3, 5, 3, 5, 7, 5, 7, 9 }}, Footprint::Get5x5(), 3, 3); 53 | 54 | std::vector expected_weights = { 55 | 1, 2, 3, 4, 5, 56 | 2, 3, 4, 5, 6, 57 | 3, 4, 5, 6, 7, 58 | 4, 5, 6, 7, 8, 59 | 5, 6, 7, 8, 9 }; 60 | 61 | ASSERT_EQ(weights.size(), expected_weights.size()); 62 | for (int i = 0; i < weights.size(); ++i) { 63 | EXPECT_EQ(weights[i], expected_weights[i]); 64 | } 65 | } 66 | 67 | } // namespace 68 | 69 | } // namespace astc_codec 70 | -------------------------------------------------------------------------------- /src/decoder/testdata/atlas_small_4x4.astc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/google/astc-codec/9757befb64db6662aad45de09ca87cd6f599ac02/src/decoder/testdata/atlas_small_4x4.astc -------------------------------------------------------------------------------- /src/decoder/testdata/atlas_small_4x4.bmp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/google/astc-codec/9757befb64db6662aad45de09ca87cd6f599ac02/src/decoder/testdata/atlas_small_4x4.bmp -------------------------------------------------------------------------------- /src/decoder/testdata/atlas_small_5x5.astc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/google/astc-codec/9757befb64db6662aad45de09ca87cd6f599ac02/src/decoder/testdata/atlas_small_5x5.astc -------------------------------------------------------------------------------- /src/decoder/testdata/atlas_small_5x5.bmp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/google/astc-codec/9757befb64db6662aad45de09ca87cd6f599ac02/src/decoder/testdata/atlas_small_5x5.bmp -------------------------------------------------------------------------------- /src/decoder/testdata/atlas_small_6x6.astc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/google/astc-codec/9757befb64db6662aad45de09ca87cd6f599ac02/src/decoder/testdata/atlas_small_6x6.astc -------------------------------------------------------------------------------- /src/decoder/testdata/atlas_small_6x6.bmp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/google/astc-codec/9757befb64db6662aad45de09ca87cd6f599ac02/src/decoder/testdata/atlas_small_6x6.bmp -------------------------------------------------------------------------------- /src/decoder/testdata/atlas_small_8x8.astc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/google/astc-codec/9757befb64db6662aad45de09ca87cd6f599ac02/src/decoder/testdata/atlas_small_8x8.astc -------------------------------------------------------------------------------- /src/decoder/testdata/atlas_small_8x8.bmp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/google/astc-codec/9757befb64db6662aad45de09ca87cd6f599ac02/src/decoder/testdata/atlas_small_8x8.bmp -------------------------------------------------------------------------------- /src/decoder/testdata/checkerboard.astc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/google/astc-codec/9757befb64db6662aad45de09ca87cd6f599ac02/src/decoder/testdata/checkerboard.astc -------------------------------------------------------------------------------- /src/decoder/testdata/checkered_10.astc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/google/astc-codec/9757befb64db6662aad45de09ca87cd6f599ac02/src/decoder/testdata/checkered_10.astc -------------------------------------------------------------------------------- /src/decoder/testdata/checkered_11.astc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/google/astc-codec/9757befb64db6662aad45de09ca87cd6f599ac02/src/decoder/testdata/checkered_11.astc -------------------------------------------------------------------------------- /src/decoder/testdata/checkered_12.astc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/google/astc-codec/9757befb64db6662aad45de09ca87cd6f599ac02/src/decoder/testdata/checkered_12.astc -------------------------------------------------------------------------------- /src/decoder/testdata/checkered_4.astc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/google/astc-codec/9757befb64db6662aad45de09ca87cd6f599ac02/src/decoder/testdata/checkered_4.astc -------------------------------------------------------------------------------- /src/decoder/testdata/checkered_5.astc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/google/astc-codec/9757befb64db6662aad45de09ca87cd6f599ac02/src/decoder/testdata/checkered_5.astc -------------------------------------------------------------------------------- /src/decoder/testdata/checkered_6.astc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/google/astc-codec/9757befb64db6662aad45de09ca87cd6f599ac02/src/decoder/testdata/checkered_6.astc -------------------------------------------------------------------------------- /src/decoder/testdata/checkered_7.astc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/google/astc-codec/9757befb64db6662aad45de09ca87cd6f599ac02/src/decoder/testdata/checkered_7.astc -------------------------------------------------------------------------------- /src/decoder/testdata/checkered_8.astc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/google/astc-codec/9757befb64db6662aad45de09ca87cd6f599ac02/src/decoder/testdata/checkered_8.astc -------------------------------------------------------------------------------- /src/decoder/testdata/checkered_9.astc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/google/astc-codec/9757befb64db6662aad45de09ca87cd6f599ac02/src/decoder/testdata/checkered_9.astc -------------------------------------------------------------------------------- /src/decoder/testdata/footprint_10x10.astc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/google/astc-codec/9757befb64db6662aad45de09ca87cd6f599ac02/src/decoder/testdata/footprint_10x10.astc -------------------------------------------------------------------------------- /src/decoder/testdata/footprint_10x10.bmp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/google/astc-codec/9757befb64db6662aad45de09ca87cd6f599ac02/src/decoder/testdata/footprint_10x10.bmp -------------------------------------------------------------------------------- /src/decoder/testdata/footprint_10x5.astc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/google/astc-codec/9757befb64db6662aad45de09ca87cd6f599ac02/src/decoder/testdata/footprint_10x5.astc -------------------------------------------------------------------------------- /src/decoder/testdata/footprint_10x5.bmp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/google/astc-codec/9757befb64db6662aad45de09ca87cd6f599ac02/src/decoder/testdata/footprint_10x5.bmp -------------------------------------------------------------------------------- /src/decoder/testdata/footprint_10x6.astc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/google/astc-codec/9757befb64db6662aad45de09ca87cd6f599ac02/src/decoder/testdata/footprint_10x6.astc -------------------------------------------------------------------------------- /src/decoder/testdata/footprint_10x6.bmp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/google/astc-codec/9757befb64db6662aad45de09ca87cd6f599ac02/src/decoder/testdata/footprint_10x6.bmp -------------------------------------------------------------------------------- /src/decoder/testdata/footprint_10x8.astc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/google/astc-codec/9757befb64db6662aad45de09ca87cd6f599ac02/src/decoder/testdata/footprint_10x8.astc -------------------------------------------------------------------------------- /src/decoder/testdata/footprint_10x8.bmp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/google/astc-codec/9757befb64db6662aad45de09ca87cd6f599ac02/src/decoder/testdata/footprint_10x8.bmp -------------------------------------------------------------------------------- /src/decoder/testdata/footprint_12x10.astc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/google/astc-codec/9757befb64db6662aad45de09ca87cd6f599ac02/src/decoder/testdata/footprint_12x10.astc -------------------------------------------------------------------------------- /src/decoder/testdata/footprint_12x10.bmp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/google/astc-codec/9757befb64db6662aad45de09ca87cd6f599ac02/src/decoder/testdata/footprint_12x10.bmp -------------------------------------------------------------------------------- /src/decoder/testdata/footprint_12x12.astc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/google/astc-codec/9757befb64db6662aad45de09ca87cd6f599ac02/src/decoder/testdata/footprint_12x12.astc -------------------------------------------------------------------------------- /src/decoder/testdata/footprint_12x12.bmp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/google/astc-codec/9757befb64db6662aad45de09ca87cd6f599ac02/src/decoder/testdata/footprint_12x12.bmp -------------------------------------------------------------------------------- /src/decoder/testdata/footprint_4x4.astc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/google/astc-codec/9757befb64db6662aad45de09ca87cd6f599ac02/src/decoder/testdata/footprint_4x4.astc -------------------------------------------------------------------------------- /src/decoder/testdata/footprint_4x4.bmp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/google/astc-codec/9757befb64db6662aad45de09ca87cd6f599ac02/src/decoder/testdata/footprint_4x4.bmp -------------------------------------------------------------------------------- /src/decoder/testdata/footprint_5x4.astc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/google/astc-codec/9757befb64db6662aad45de09ca87cd6f599ac02/src/decoder/testdata/footprint_5x4.astc -------------------------------------------------------------------------------- /src/decoder/testdata/footprint_5x4.bmp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/google/astc-codec/9757befb64db6662aad45de09ca87cd6f599ac02/src/decoder/testdata/footprint_5x4.bmp -------------------------------------------------------------------------------- /src/decoder/testdata/footprint_5x5.astc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/google/astc-codec/9757befb64db6662aad45de09ca87cd6f599ac02/src/decoder/testdata/footprint_5x5.astc -------------------------------------------------------------------------------- /src/decoder/testdata/footprint_5x5.bmp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/google/astc-codec/9757befb64db6662aad45de09ca87cd6f599ac02/src/decoder/testdata/footprint_5x5.bmp -------------------------------------------------------------------------------- /src/decoder/testdata/footprint_6x5.astc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/google/astc-codec/9757befb64db6662aad45de09ca87cd6f599ac02/src/decoder/testdata/footprint_6x5.astc -------------------------------------------------------------------------------- /src/decoder/testdata/footprint_6x5.bmp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/google/astc-codec/9757befb64db6662aad45de09ca87cd6f599ac02/src/decoder/testdata/footprint_6x5.bmp -------------------------------------------------------------------------------- /src/decoder/testdata/footprint_6x6.astc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/google/astc-codec/9757befb64db6662aad45de09ca87cd6f599ac02/src/decoder/testdata/footprint_6x6.astc -------------------------------------------------------------------------------- /src/decoder/testdata/footprint_6x6.bmp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/google/astc-codec/9757befb64db6662aad45de09ca87cd6f599ac02/src/decoder/testdata/footprint_6x6.bmp -------------------------------------------------------------------------------- /src/decoder/testdata/footprint_8x5.astc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/google/astc-codec/9757befb64db6662aad45de09ca87cd6f599ac02/src/decoder/testdata/footprint_8x5.astc -------------------------------------------------------------------------------- /src/decoder/testdata/footprint_8x5.bmp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/google/astc-codec/9757befb64db6662aad45de09ca87cd6f599ac02/src/decoder/testdata/footprint_8x5.bmp -------------------------------------------------------------------------------- /src/decoder/testdata/footprint_8x6.astc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/google/astc-codec/9757befb64db6662aad45de09ca87cd6f599ac02/src/decoder/testdata/footprint_8x6.astc -------------------------------------------------------------------------------- /src/decoder/testdata/footprint_8x6.bmp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/google/astc-codec/9757befb64db6662aad45de09ca87cd6f599ac02/src/decoder/testdata/footprint_8x6.bmp -------------------------------------------------------------------------------- /src/decoder/testdata/footprint_8x8.astc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/google/astc-codec/9757befb64db6662aad45de09ca87cd6f599ac02/src/decoder/testdata/footprint_8x8.astc -------------------------------------------------------------------------------- /src/decoder/testdata/footprint_8x8.bmp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/google/astc-codec/9757befb64db6662aad45de09ca87cd6f599ac02/src/decoder/testdata/footprint_8x8.bmp -------------------------------------------------------------------------------- /src/decoder/testdata/rgb_12x12.astc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/google/astc-codec/9757befb64db6662aad45de09ca87cd6f599ac02/src/decoder/testdata/rgb_12x12.astc -------------------------------------------------------------------------------- /src/decoder/testdata/rgb_12x12.bmp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/google/astc-codec/9757befb64db6662aad45de09ca87cd6f599ac02/src/decoder/testdata/rgb_12x12.bmp -------------------------------------------------------------------------------- /src/decoder/testdata/rgb_4x4.astc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/google/astc-codec/9757befb64db6662aad45de09ca87cd6f599ac02/src/decoder/testdata/rgb_4x4.astc -------------------------------------------------------------------------------- /src/decoder/testdata/rgb_4x4.bmp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/google/astc-codec/9757befb64db6662aad45de09ca87cd6f599ac02/src/decoder/testdata/rgb_4x4.bmp -------------------------------------------------------------------------------- /src/decoder/testdata/rgb_5x4.astc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/google/astc-codec/9757befb64db6662aad45de09ca87cd6f599ac02/src/decoder/testdata/rgb_5x4.astc -------------------------------------------------------------------------------- /src/decoder/testdata/rgb_5x4.bmp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/google/astc-codec/9757befb64db6662aad45de09ca87cd6f599ac02/src/decoder/testdata/rgb_5x4.bmp -------------------------------------------------------------------------------- /src/decoder/testdata/rgb_6x6.astc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/google/astc-codec/9757befb64db6662aad45de09ca87cd6f599ac02/src/decoder/testdata/rgb_6x6.astc -------------------------------------------------------------------------------- /src/decoder/testdata/rgb_6x6.bmp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/google/astc-codec/9757befb64db6662aad45de09ca87cd6f599ac02/src/decoder/testdata/rgb_6x6.bmp -------------------------------------------------------------------------------- /src/decoder/testdata/rgb_8x8.astc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/google/astc-codec/9757befb64db6662aad45de09ca87cd6f599ac02/src/decoder/testdata/rgb_8x8.astc -------------------------------------------------------------------------------- /src/decoder/testdata/rgb_8x8.bmp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/google/astc-codec/9757befb64db6662aad45de09ca87cd6f599ac02/src/decoder/testdata/rgb_8x8.bmp -------------------------------------------------------------------------------- /src/decoder/types.h: -------------------------------------------------------------------------------- 1 | // Copyright 2018 Google LLC 2 | // 3 | // Licensed under the Apache License, Version 2.0 (the "License"); 4 | // you may not use this file except in compliance with the License. 5 | // You may obtain a copy of the License at 6 | // 7 | // https://www.apache.org/licenses/LICENSE-2.0 8 | // 9 | // Unless required by applicable law or agreed to in writing, software 10 | // distributed under the License is distributed on an "AS IS" BASIS, 11 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | // See the License for the specific language governing permissions and 13 | // limitations under the License. 14 | 15 | #ifndef ASTC_CODEC_DECODER_ASTC_TYPES_H_ 16 | #define ASTC_CODEC_DECODER_ASTC_TYPES_H_ 17 | 18 | #include 19 | #include 20 | #include 21 | 22 | namespace astc_codec { 23 | 24 | // The color endpoint mode determines how the values encoded in the ASTC block 25 | // are interpreted in order to create the RGBA values for the given endpoint 26 | // pair. The order of this enum is required to match the ASTC specification in 27 | // Section C.2.14. 28 | enum class ColorEndpointMode { 29 | kLDRLumaDirect = 0, 30 | kLDRLumaBaseOffset, 31 | kHDRLumaLargeRange, 32 | kHDRLumaSmallRange, 33 | kLDRLumaAlphaDirect, 34 | kLDRLumaAlphaBaseOffset, 35 | kLDRRGBBaseScale, 36 | kHDRRGBBaseScale, 37 | kLDRRGBDirect, 38 | kLDRRGBBaseOffset, 39 | kLDRRGBBaseScaleTwoA, 40 | kHDRRGBDirect, 41 | kLDRRGBADirect, 42 | kLDRRGBABaseOffset, 43 | kHDRRGBDirectLDRAlpha, 44 | kHDRRGBDirectHDRAlpha, 45 | 46 | // The total number of color endpoints defined by the ASTC specification. 47 | // This isn't a specific endpoint mode and its sole purpose is to be used 48 | // as a constant number. 49 | kNumColorEndpointModes 50 | }; 51 | 52 | // Returns the class for the given mode as defined in Section C.2.11. 53 | constexpr int EndpointModeClass(ColorEndpointMode mode) { 54 | return static_cast(mode) / 4; 55 | } 56 | 57 | // Returns the number of encoded color values for the given endpoint mode. The 58 | // number of encoded color values and their range determines the size of the 59 | // color data in a physical ASTC block. This information is taken from 60 | // Section C.2.17 of the ASTC specification. 61 | constexpr int NumColorValuesForEndpointMode(ColorEndpointMode mode) { 62 | return (EndpointModeClass(mode) + 1) * 2; 63 | } 64 | 65 | // We define a number of convenience types here that give more logical meaning 66 | // throughout the ASTC utilities. 67 | using RgbColor = std::array; 68 | using RgbaColor = std::array; 69 | using Endpoint = RgbaColor; 70 | using EndpointPair = std::pair; 71 | 72 | } // namespace astc_codec 73 | 74 | #endif // ASTC_CODEC_DECODER_ASTC_TYPES_H_ 75 | -------------------------------------------------------------------------------- /src/decoder/weight_infill.cc: -------------------------------------------------------------------------------- 1 | // Copyright 2018 Google LLC 2 | // 3 | // Licensed under the Apache License, Version 2.0 (the "License"); 4 | // you may not use this file except in compliance with the License. 5 | // You may obtain a copy of the License at 6 | // 7 | // https://www.apache.org/licenses/LICENSE-2.0 8 | // 9 | // Unless required by applicable law or agreed to in writing, software 10 | // distributed under the License is distributed on an "AS IS" BASIS, 11 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | // See the License for the specific language governing permissions and 13 | // limitations under the License. 14 | 15 | #include "src/decoder/weight_infill.h" 16 | #include "src/decoder/integer_sequence_codec.h" 17 | 18 | #include 19 | #include 20 | #include 21 | 22 | namespace astc_codec { 23 | 24 | namespace { 25 | 26 | // The following functions are based on Section C.2.18 of the ASTC specification 27 | int GetScaleFactorD(int block_dim) { 28 | return static_cast((1024.f + static_cast(block_dim >> 1)) / 29 | static_cast(block_dim - 1)); 30 | } 31 | 32 | std::pair GetGridSpaceCoordinates( 33 | Footprint footprint, int s, int t, int weight_dim_x, int weight_dim_y) { 34 | const int ds = GetScaleFactorD(footprint.Width()); 35 | const int dt = GetScaleFactorD(footprint.Height()); 36 | 37 | const int cs = ds * s; 38 | const int ct = dt * t; 39 | 40 | const int gs = (cs * (weight_dim_x - 1) + 32) >> 6; 41 | const int gt = (ct * (weight_dim_y - 1) + 32) >> 6; 42 | 43 | assert(gt < 1 << 8); 44 | assert(gs < 1 << 8); 45 | 46 | return std::make_pair(gs, gt); 47 | } 48 | 49 | // Returns the weight-grid values that are to be used for bilinearly 50 | // interpolating the weight to its final value. If the returned value 51 | // is equal to weight_dim_x * weight_dim_y, it may be ignored. 52 | std::array BilerpGridPointsForWeight( 53 | const std::pair& grid_space_coords, int weight_dim_x) { 54 | const int js = grid_space_coords.first >> 4; 55 | const int jt = grid_space_coords.second >> 4; 56 | 57 | std::array result; 58 | result[0] = js + weight_dim_x * jt; 59 | result[1] = js + weight_dim_x * jt + 1; 60 | result[2] = js + weight_dim_x * (jt + 1); 61 | result[3] = js + weight_dim_x * (jt + 1) + 1; 62 | 63 | return result; 64 | } 65 | 66 | std::array BilerpGridPointFactorsForWeight( 67 | const std::pair& grid_space_coords) { 68 | const int fs = grid_space_coords.first & 0xF; 69 | const int ft = grid_space_coords.second & 0xF; 70 | 71 | std::array result; 72 | result[3] = (fs * ft + 8) >> 4; 73 | result[2] = ft - result[3]; 74 | result[1] = fs - result[3]; 75 | result[0] = 16 - fs - ft + result[3]; 76 | 77 | assert(result[0] <= 16); 78 | assert(result[1] <= 16); 79 | assert(result[2] <= 16); 80 | assert(result[3] <= 16); 81 | 82 | return result; 83 | } 84 | 85 | } // namespace 86 | 87 | //////////////////////////////////////////////////////////////////////////////// 88 | 89 | int CountBitsForWeights(int weight_dim_x, int weight_dim_y, 90 | int target_weight_range) { 91 | int num_weights = weight_dim_x * weight_dim_y; 92 | return IntegerSequenceCodec:: 93 | GetBitCountForRange(num_weights, target_weight_range); 94 | } 95 | 96 | std::vector InfillWeights(const std::vector& weights, 97 | Footprint footprint, int dim_x, int dim_y) { 98 | std::vector result; 99 | result.reserve(footprint.NumPixels()); 100 | for (int t = 0; t < footprint.Height(); ++t) { 101 | for (int s = 0; s < footprint.Width(); ++s) { 102 | const auto grid_space_coords = 103 | GetGridSpaceCoordinates(footprint, s, t, dim_x, dim_y); 104 | const auto grid_pts = 105 | BilerpGridPointsForWeight(grid_space_coords, dim_x); 106 | const auto grid_factors = 107 | BilerpGridPointFactorsForWeight(grid_space_coords); 108 | 109 | int weight = 0; 110 | for (int i = 0; i < 4; ++i) { 111 | if (grid_pts[i] < dim_x * dim_y) { 112 | weight += weights.at(grid_pts[i]) * grid_factors[i]; 113 | } 114 | } 115 | result.push_back((weight + 8) >> 4); 116 | } 117 | } 118 | 119 | return result; 120 | } 121 | 122 | } // namespace astc_codec 123 | -------------------------------------------------------------------------------- /src/decoder/weight_infill.h: -------------------------------------------------------------------------------- 1 | // Copyright 2018 Google LLC 2 | // 3 | // Licensed under the Apache License, Version 2.0 (the "License"); 4 | // you may not use this file except in compliance with the License. 5 | // You may obtain a copy of the License at 6 | // 7 | // https://www.apache.org/licenses/LICENSE-2.0 8 | // 9 | // Unless required by applicable law or agreed to in writing, software 10 | // distributed under the License is distributed on an "AS IS" BASIS, 11 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | // See the License for the specific language governing permissions and 13 | // limitations under the License. 14 | 15 | #ifndef ASTC_CODEC_DECODER_WEIGHT_INFILL_H_ 16 | #define ASTC_CODEC_DECODER_WEIGHT_INFILL_H_ 17 | 18 | #include "src/decoder/footprint.h" 19 | 20 | #include 21 | 22 | namespace astc_codec { 23 | 24 | // Returns the number of bits used to represent the weight grid at the target 25 | // dimensions and weight range. 26 | int CountBitsForWeights(int weight_dim_x, int weight_dim_y, 27 | int target_weight_range); 28 | 29 | // Performs weight infill of a grid of weights of size |dim_x * dim_y|. The 30 | // weights are fit using the algorithm laid out in Section C.2.18 of the ASTC 31 | // specification. Weights are expected to be passed unquantized and the returned 32 | // grid will be unquantized as well (i.e. each weight within the range [0, 64]). 33 | std::vector InfillWeights(const std::vector& weights, 34 | Footprint footprint, int dim_x, int dim_y); 35 | 36 | } // namespace astc_codec 37 | 38 | #endif // ASTC_CODEC_DECODER_WEIGHT_INFILL_H_ 39 | -------------------------------------------------------------------------------- /third_party/BUILD: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/google/astc-codec/9757befb64db6662aad45de09ca87cd6f599ac02/third_party/BUILD -------------------------------------------------------------------------------- /third_party/honggfuzz.BUILD: -------------------------------------------------------------------------------- 1 | config_setting( 2 | name = "opt", 3 | values = {"compilation_mode": "opt"} 4 | ) 5 | 6 | cc_library( 7 | name = "honggfuzz", 8 | srcs = glob([ 9 | "libhfuzz/*.c", 10 | "libhfcommon/*.c", 11 | ], 12 | exclude = ["libhfuzz/linux.c"], 13 | ) + select({ 14 | "@bazel_tools//src/conditions:darwin_x86_64": [], 15 | "@bazel_tools//src/conditions:darwin": [], 16 | "//conditions:default": ["libhfuzz/linux.c"], 17 | }), 18 | hdrs = glob([ 19 | "libhfuzz/*.h", 20 | "libhfcommon/*.h", 21 | "honggfuzz.h", 22 | ]), 23 | copts = [ 24 | "-std=c11", 25 | ], 26 | defines = select({ 27 | "@bazel_tools//src/conditions:darwin_x86_64": ["_HF_ARCH_DARWIN"], 28 | "@bazel_tools//src/conditions:darwin": ["_HF_ARCH_DARWIN"], 29 | "//conditions:default": ["_HF_ARCH_LINUX"], 30 | }) + select({ 31 | ":opt": [], 32 | "//conditions:default": ["DEBUG=DEBUG"], 33 | }) + [ 34 | "_GNU_SOURCE", 35 | ], 36 | includes = ["."], 37 | visibility = ["//visibility:public"], 38 | linkstatic = 1 39 | ) 40 | -------------------------------------------------------------------------------- /tools/build-ci/linux/build.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | # Configures builds for our CI environment. 3 | 4 | # Print commands and exit on error. 5 | set -ex 6 | 7 | if [ "$KOKORO_BUILD_ID" ]; then 8 | echo "Running job $KOKORO_JOB_NAME" 9 | TARGET=`echo "$KOKORO_JOB_NAME" | awk -F "/" '{print $NF}'` 10 | fi 11 | 12 | if [ ! "$TARGET" ]; then 13 | if [ "$1" ]; then 14 | TARGET=$1 15 | else 16 | TARGET=release 17 | fi 18 | fi 19 | 20 | echo "Building $TARGET target" 21 | 22 | pushd `dirname $0`/../../.. > /dev/null 23 | 24 | BUILD_RELEASE= 25 | BUILD_DEBUG= 26 | BUILD_CMAKE= 27 | RUN_TESTS= 28 | 29 | if [ "$TARGET" == "presubmit" ]; then 30 | BUILD_DEBUG=1 31 | BUILD_RELEASE=1 32 | BUILD_CMAKE=1 33 | RUN_TESTS=1 34 | fi 35 | 36 | if [ "$TARGET" == "debug" ]; then 37 | BUILD_DEBUG=1 38 | fi 39 | 40 | if [ "$TARGET" == "release" ]; then 41 | BUILD_RELEASE=1 42 | fi 43 | 44 | if [ "$TARGET" == "continuous" ]; then 45 | BUILD_DEBUG=1 46 | BUILD_RELEASE=1 47 | BUILD_CMAKE=1 48 | RUN_TESTS=1 49 | fi 50 | 51 | if [ "$BUILD_DEBUG" == "1" ]; then 52 | echo "Starting debug build" 53 | bazel build -c dbg //... 54 | 55 | if [ "$RUN_TESTS" == "1" ]; then 56 | bazel test -c dbg //... 57 | fi 58 | fi 59 | 60 | if [ "$BUILD_RELEASE" == "1" ]; then 61 | echo "Starting release build" 62 | bazel build -c opt //... 63 | 64 | if [ "$RUN_TESTS" == "1" ]; then 65 | bazel test -c opt //... 66 | fi 67 | fi 68 | 69 | if [ "$BUILD_CMAKE" == "1" ]; then 70 | echo "Starting cmake build" 71 | mkdir build 72 | pushd build 73 | cmake .. 74 | make -j$((`nproc`+1)) 75 | popd 76 | fi 77 | -------------------------------------------------------------------------------- /tools/build-ci/linux/continuous.cfg: -------------------------------------------------------------------------------- 1 | # Format: //devtools/kokoro/config/proto/build.proto 2 | 3 | build_file: "astc-codec/tools/build-ci/linux/build.sh" 4 | -------------------------------------------------------------------------------- /tools/build-ci/linux/presubmit.cfg: -------------------------------------------------------------------------------- 1 | # Format: //devtools/kokoro/config/proto/build.proto 2 | 3 | build_file: "astc-codec/tools/build-ci/linux/build.sh" 4 | --------------------------------------------------------------------------------