diff options
author | Greg Schlomoff <gregschlom@google.com> | 2022-07-19 17:01:07 -0700 |
---|---|---|
committer | Greg Schlomoff <gregschlom@google.com> | 2022-10-04 16:32:21 -0700 |
commit | 4f12c1042403cac665686e57f4dafec82656fa25 (patch) | |
tree | 173d083b79709f30729261ff58e070424587d554 | |
parent | 8456d5a83ab432c1d35aeb4d1606afb6b70d7dce (diff) | |
download | vulkan-cereal-4f12c1042403cac665686e57f4dafec82656fa25.tar.gz |
Remove our old ASTC decoder and replace it with Arm's one.
Change-Id: Icb49eb5ccfb31d4bf5a352e36dcad77dcde101d8
133 files changed, 58 insertions, 13302 deletions
diff --git a/stream-servers/Android.bp b/stream-servers/Android.bp index 13d418cd..2484f6a7 100644 --- a/stream-servers/Android.bp +++ b/stream-servers/Android.bp @@ -43,7 +43,6 @@ cc_library_shared { "gfxstream_vulkan_server", "gfxstream_renderControl_dec", "gfxstream_dispatch", - "gfxstream_astc_codec", "gfxstream_lz4", "gfxstream_glm", "gfxstream_compressedTextures", diff --git a/stream-servers/gl/glestranslator/EGL/Android.bp b/stream-servers/gl/glestranslator/EGL/Android.bp index 6275c628..037c37c8 100644 --- a/stream-servers/gl/glestranslator/EGL/Android.bp +++ b/stream-servers/gl/glestranslator/EGL/Android.bp @@ -12,7 +12,6 @@ cc_library_static { defaults: [ "gfxstream_defaults" ], static_libs: [ "gfxstream_base", - "gfxstream_astc_codec", "gfxstream_apigen_codec_common", "gfxstream_translator_glcommon", "gfxstream_translator_glescm", diff --git a/stream-servers/gl/glestranslator/EGL/CMakeLists.txt b/stream-servers/gl/glestranslator/EGL/CMakeLists.txt index 654f55d0..5033a63d 100644 --- a/stream-servers/gl/glestranslator/EGL/CMakeLists.txt +++ b/stream-servers/gl/glestranslator/EGL/CMakeLists.txt @@ -38,7 +38,7 @@ else() endif() target_link_libraries(EGL_translator_static PUBLIC GLcommon apigen-codec-common) -target_link_libraries(EGL_translator_static PRIVATE gfxstream-base.headers astc-codec logging-base) +target_link_libraries(EGL_translator_static PRIVATE gfxstream-base.headers logging-base) target_link_libraries(EGL_translator_static PUBLIC GLES_CM_translator_static GLES_V2_translator_static) if (NOT MSVC) target_compile_options(EGL_translator_static PRIVATE -fvisibility=hidden) diff --git a/stream-servers/gl/glestranslator/GLcommon/Android.bp b/stream-servers/gl/glestranslator/GLcommon/Android.bp index 91be25d5..d07f8d38 100644 --- a/stream-servers/gl/glestranslator/GLcommon/Android.bp +++ b/stream-servers/gl/glestranslator/GLcommon/Android.bp @@ -16,12 +16,8 @@ cc_library_static { "-Wno-unused-parameter", "-Wno-unused-function", ], - header_libs: [ - "gfxstream_astc_codec_headers", - ], static_libs: [ "gfxstream_base", - "gfxstream_astc_codec", ], srcs: [ "etc.cpp", diff --git a/stream-servers/gl/glestranslator/GLcommon/CMakeLists.txt b/stream-servers/gl/glestranslator/GLcommon/CMakeLists.txt index 8ccaf0a7..e7701179 100644 --- a/stream-servers/gl/glestranslator/GLcommon/CMakeLists.txt +++ b/stream-servers/gl/glestranslator/GLcommon/CMakeLists.txt @@ -32,7 +32,7 @@ target_link_libraries( gfxstream-base.headers gfxstream-host-common.headers gfxstream-snapshot.headers - astc-codec) + gfxstream-compressedTextures) if (NOT MSVC) target_compile_options(GLcommon PRIVATE -fvisibility=hidden) endif() diff --git a/stream-servers/gl/glestranslator/GLcommon/TextureUtils.cpp b/stream-servers/gl/glestranslator/GLcommon/TextureUtils.cpp index a66338bd..aa4c4129 100644 --- a/stream-servers/gl/glestranslator/GLcommon/TextureUtils.cpp +++ b/stream-servers/gl/glestranslator/GLcommon/TextureUtils.cpp @@ -22,10 +22,10 @@ #include <memory> #include "base/AlignedBuf.h" - -#include <astc-codec/astc-codec.h> +#include "compressedTextureFormats/AstcCpuDecompressor.h" using android::AlignedBuf; +using goldfish_vk::AstcCpuDecompressor; #define GL_R16 0x822A #define GL_RG16 0x822C @@ -35,34 +35,34 @@ using android::AlignedBuf; static constexpr size_t kASTCFormatsCount = 28; #define ASTC_FORMATS_LIST(EXPAND_MACRO) \ - EXPAND_MACRO(GL_COMPRESSED_RGBA_ASTC_4x4_KHR, astc_codec::FootprintType::k4x4, false) \ - EXPAND_MACRO(GL_COMPRESSED_RGBA_ASTC_5x4_KHR, astc_codec::FootprintType::k5x4, false) \ - EXPAND_MACRO(GL_COMPRESSED_RGBA_ASTC_5x5_KHR, astc_codec::FootprintType::k5x5, false) \ - EXPAND_MACRO(GL_COMPRESSED_RGBA_ASTC_6x5_KHR, astc_codec::FootprintType::k6x5, false) \ - EXPAND_MACRO(GL_COMPRESSED_RGBA_ASTC_6x6_KHR, astc_codec::FootprintType::k6x6, false) \ - EXPAND_MACRO(GL_COMPRESSED_RGBA_ASTC_8x5_KHR, astc_codec::FootprintType::k8x5, false) \ - EXPAND_MACRO(GL_COMPRESSED_RGBA_ASTC_8x6_KHR, astc_codec::FootprintType::k8x6, false) \ - EXPAND_MACRO(GL_COMPRESSED_RGBA_ASTC_8x8_KHR, astc_codec::FootprintType::k8x8, false) \ - EXPAND_MACRO(GL_COMPRESSED_RGBA_ASTC_10x5_KHR, astc_codec::FootprintType::k10x5, false) \ - EXPAND_MACRO(GL_COMPRESSED_RGBA_ASTC_10x6_KHR, astc_codec::FootprintType::k10x6, false) \ - EXPAND_MACRO(GL_COMPRESSED_RGBA_ASTC_10x8_KHR, astc_codec::FootprintType::k10x8, false) \ - EXPAND_MACRO(GL_COMPRESSED_RGBA_ASTC_10x10_KHR, astc_codec::FootprintType::k10x10, false) \ - EXPAND_MACRO(GL_COMPRESSED_RGBA_ASTC_12x10_KHR, astc_codec::FootprintType::k12x10, false) \ - EXPAND_MACRO(GL_COMPRESSED_RGBA_ASTC_12x12_KHR, astc_codec::FootprintType::k12x12, false) \ - EXPAND_MACRO(GL_COMPRESSED_SRGB8_ALPHA8_ASTC_4x4_KHR, astc_codec::FootprintType::k4x4, true) \ - EXPAND_MACRO(GL_COMPRESSED_SRGB8_ALPHA8_ASTC_5x4_KHR, astc_codec::FootprintType::k5x4, true) \ - EXPAND_MACRO(GL_COMPRESSED_SRGB8_ALPHA8_ASTC_5x5_KHR, astc_codec::FootprintType::k5x5, true) \ - EXPAND_MACRO(GL_COMPRESSED_SRGB8_ALPHA8_ASTC_6x5_KHR, astc_codec::FootprintType::k6x5, true) \ - EXPAND_MACRO(GL_COMPRESSED_SRGB8_ALPHA8_ASTC_6x6_KHR, astc_codec::FootprintType::k6x6, true) \ - EXPAND_MACRO(GL_COMPRESSED_SRGB8_ALPHA8_ASTC_8x5_KHR, astc_codec::FootprintType::k8x5, true) \ - EXPAND_MACRO(GL_COMPRESSED_SRGB8_ALPHA8_ASTC_8x6_KHR, astc_codec::FootprintType::k8x6, true) \ - EXPAND_MACRO(GL_COMPRESSED_SRGB8_ALPHA8_ASTC_8x8_KHR, astc_codec::FootprintType::k8x8, true) \ - EXPAND_MACRO(GL_COMPRESSED_SRGB8_ALPHA8_ASTC_10x5_KHR, astc_codec::FootprintType::k10x5, true) \ - EXPAND_MACRO(GL_COMPRESSED_SRGB8_ALPHA8_ASTC_10x6_KHR, astc_codec::FootprintType::k10x6, true) \ - EXPAND_MACRO(GL_COMPRESSED_SRGB8_ALPHA8_ASTC_10x8_KHR, astc_codec::FootprintType::k10x8, true) \ - EXPAND_MACRO(GL_COMPRESSED_SRGB8_ALPHA8_ASTC_10x10_KHR, astc_codec::FootprintType::k10x10, true) \ - EXPAND_MACRO(GL_COMPRESSED_SRGB8_ALPHA8_ASTC_12x10_KHR, astc_codec::FootprintType::k12x10, true) \ - EXPAND_MACRO(GL_COMPRESSED_SRGB8_ALPHA8_ASTC_12x12_KHR, astc_codec::FootprintType::k12x12, true) \ + EXPAND_MACRO(GL_COMPRESSED_RGBA_ASTC_4x4_KHR, 4, 4, false) \ + EXPAND_MACRO(GL_COMPRESSED_RGBA_ASTC_5x4_KHR, 5, 4, false) \ + EXPAND_MACRO(GL_COMPRESSED_RGBA_ASTC_5x5_KHR, 5, 5, false) \ + EXPAND_MACRO(GL_COMPRESSED_RGBA_ASTC_6x5_KHR, 6, 5, false) \ + EXPAND_MACRO(GL_COMPRESSED_RGBA_ASTC_6x6_KHR, 6, 6, false) \ + EXPAND_MACRO(GL_COMPRESSED_RGBA_ASTC_8x5_KHR, 8, 5, false) \ + EXPAND_MACRO(GL_COMPRESSED_RGBA_ASTC_8x6_KHR, 8, 6, false) \ + EXPAND_MACRO(GL_COMPRESSED_RGBA_ASTC_8x8_KHR, 8, 8, false) \ + EXPAND_MACRO(GL_COMPRESSED_RGBA_ASTC_10x5_KHR, 10, 5, false) \ + EXPAND_MACRO(GL_COMPRESSED_RGBA_ASTC_10x6_KHR, 10, 6, false) \ + EXPAND_MACRO(GL_COMPRESSED_RGBA_ASTC_10x8_KHR, 10, 8, false) \ + EXPAND_MACRO(GL_COMPRESSED_RGBA_ASTC_10x10_KHR, 10, 10, false) \ + EXPAND_MACRO(GL_COMPRESSED_RGBA_ASTC_12x10_KHR, 12, 10, false) \ + EXPAND_MACRO(GL_COMPRESSED_RGBA_ASTC_12x12_KHR, 12, 12, false) \ + EXPAND_MACRO(GL_COMPRESSED_SRGB8_ALPHA8_ASTC_4x4_KHR, 4, 4, true) \ + EXPAND_MACRO(GL_COMPRESSED_SRGB8_ALPHA8_ASTC_5x4_KHR, 5, 4, true) \ + EXPAND_MACRO(GL_COMPRESSED_SRGB8_ALPHA8_ASTC_5x5_KHR, 5, 5, true) \ + EXPAND_MACRO(GL_COMPRESSED_SRGB8_ALPHA8_ASTC_6x5_KHR, 6, 5, true) \ + EXPAND_MACRO(GL_COMPRESSED_SRGB8_ALPHA8_ASTC_6x6_KHR, 6, 6, true) \ + EXPAND_MACRO(GL_COMPRESSED_SRGB8_ALPHA8_ASTC_8x5_KHR, 8, 5, true) \ + EXPAND_MACRO(GL_COMPRESSED_SRGB8_ALPHA8_ASTC_8x6_KHR, 8, 6, true) \ + EXPAND_MACRO(GL_COMPRESSED_SRGB8_ALPHA8_ASTC_8x8_KHR, 8, 8, true) \ + EXPAND_MACRO(GL_COMPRESSED_SRGB8_ALPHA8_ASTC_10x5_KHR, 10, 5, true) \ + EXPAND_MACRO(GL_COMPRESSED_SRGB8_ALPHA8_ASTC_10x6_KHR, 10, 6, true) \ + EXPAND_MACRO(GL_COMPRESSED_SRGB8_ALPHA8_ASTC_10x8_KHR, 10, 8, true) \ + EXPAND_MACRO(GL_COMPRESSED_SRGB8_ALPHA8_ASTC_10x10_KHR, 10, 10, true) \ + EXPAND_MACRO(GL_COMPRESSED_SRGB8_ALPHA8_ASTC_12x10_KHR, 12, 10, true) \ + EXPAND_MACRO(GL_COMPRESSED_SRGB8_ALPHA8_ASTC_12x12_KHR, 12, 12, true) \ int getCompressedFormats(int majorVersion, int* formats) { static constexpr size_t kCount = MAX_SUPPORTED_PALETTE + MAX_ETC_SUPPORTED + kASTCFormatsCount; @@ -104,7 +104,7 @@ int getCompressedFormats(int majorVersion, int* formats) { formats[i++] = GL_COMPRESSED_R11_EAC; // ASTC -#define ASTC_FORMAT(typeName, footprintType, srgbValue) \ +#define ASTC_FORMAT(typeName, blockWidth, blockHeight, srgbValue) \ formats[i++] = typeName; ASTC_FORMATS_LIST(ASTC_FORMAT) @@ -151,13 +151,11 @@ ETC2ImageFormat getEtcFormat(GLenum internalformat) { return etcFormat; } -void getAstcFormatInfo(GLenum internalformat, - astc_codec::FootprintType* footprint, - bool* srgb) { +void getAstcFormatInfo(GLenum internalformat, uint32_t* width, uint32_t* height, bool* srgb) { switch (internalformat) { -#define ASTC_FORMAT(typeName, footprintType, srgbValue) \ +#define ASTC_FORMAT(typeName, blockWidth, blockHeight, srgbValue) \ case typeName: \ - *footprint = footprintType; *srgb = srgbValue; break; \ + *width = blockWidth; *height = blockHeight; *srgb = srgbValue; break; \ ASTC_FORMATS_LIST(ASTC_FORMAT) #undef ASTC_FORMAT @@ -167,22 +165,26 @@ void getAstcFormatInfo(GLenum internalformat, } } -void getAstcFormats(const GLint** formats, size_t* formatsCount) { - static constexpr GLint kATSCFormats[] = { -#define ASTC_FORMAT(typeName, footprintType, srgbValue) \ - typeName, - - ASTC_FORMATS_LIST(ASTC_FORMAT) -#undef ASTC_FORMAT - }; - - *formats = kATSCFormats; - *formatsCount = sizeof(kATSCFormats) / sizeof(kATSCFormats[0]); +// Helper function to decompress an ASTC image. +bool astcDecompress(const uint8_t* astcData, size_t astcDataSize, uint32_t width, uint32_t height, + uint32_t blockWidth, uint32_t blockHeight, uint8_t* outBuffer, + size_t outBufferSize) { + if (outBufferSize < width * height * 4) { + WARN("ASTC output buffer too small: %d bytes for %d x %d", outBufferSize, width, height); + return false; + } + int32_t status = AstcCpuDecompressor::get().decompress(width, height, blockWidth, blockHeight, + astcData, astcDataSize, outBuffer); + if (status != 0) { + WARN("astc decompression failed: %s", AstcCpuDecompressor::get().getStatusString(status)); + return false; + } + return true; } bool isAstcFormat(GLenum internalformat) { switch (internalformat) { -#define ASTC_FORMAT(typeName, footprintType, srgbValue) \ +#define ASTC_FORMAT(typeName, blockWidth, blockHeight, srgbValue) \ case typeName: ASTC_FORMATS_LIST(ASTC_FORMAT) @@ -505,9 +507,10 @@ void doCompressedTexImage2D(GLEScontext* ctx, GLenum target, GLint level, data = new char[imageSize]; } } - astc_codec::FootprintType footprint; + uint32_t blockWidth = 0; + uint32_t blockHeight = 0; bool srgb; - getAstcFormatInfo(internalformat, &footprint, &srgb); + getAstcFormatInfo(internalformat, &blockWidth, &blockHeight, &srgb); const int32_t align = unpackAlignment - 1; const int32_t stride = ((width * 4) + align) & ~align; @@ -515,10 +518,9 @@ void doCompressedTexImage2D(GLEScontext* ctx, GLenum target, GLint level, AlignedBuf<uint8_t, 64> alignedUncompressedData(size); - const bool result = astc_codec::ASTCDecompressToRGBA( + const bool result = astcDecompress( reinterpret_cast<const uint8_t*>(data), imageSize, width, - height, footprint, alignedUncompressedData.data(), size, - stride); + height, blockWidth, blockHeight, alignedUncompressedData.data(), size); SET_ERROR_IF(!result, GL_INVALID_VALUE); glTexImage2DPtr(target, level, srgb ? GL_SRGB8_ALPHA8 : GL_RGBA8, width, @@ -846,7 +848,7 @@ void forEachEtc2Format(std::function<void(GLint format)> f) { void forEachAstcFormat(std::function<void(GLint format)> f) { -#define CALL_ON_ASTC_FORMAT(typeName, footprintType, srgbValue) \ +#define CALL_ON_ASTC_FORMAT(typeName, blockWidth, blockHeight, srgbValue) \ f(typeName); ASTC_FORMATS_LIST(CALL_ON_ASTC_FORMAT) diff --git a/third-party/CMakeLists.txt b/third-party/CMakeLists.txt index 354d7a37..ceffa629 100644 --- a/third-party/CMakeLists.txt +++ b/third-party/CMakeLists.txt @@ -1,8 +1,5 @@ add_subdirectory(angle) -# TODO(gregschlom) Remove this in favor of astc-encoder -add_subdirectory(astc-codec) - # Configure and add `astc-encoder`, if needed if (ASTC_CPU_DECODING) set(DECOMPRESSOR ON) # Disable compression code diff --git a/third-party/astc-codec/.gitignore b/third-party/astc-codec/.gitignore deleted file mode 100644 index 9e281007..00000000 --- a/third-party/astc-codec/.gitignore +++ /dev/null @@ -1,5 +0,0 @@ -bazel-* -.bazelrc -build -.vs -.vscode diff --git a/third-party/astc-codec/Android.bp b/third-party/astc-codec/Android.bp deleted file mode 100644 index 02a9456d..00000000 --- a/third-party/astc-codec/Android.bp +++ /dev/null @@ -1,25 +0,0 @@ -package { - default_applicable_licenses: [ - "device_generic_vulkan-cereal_third-party_astc-codec_license", - ], -} - -// Added automatically by a large-scale-change -// See: http://go/android-license-faq -license { - name: "device_generic_vulkan-cereal_third-party_astc-codec_license", - visibility: [":__subpackages__"], - license_kinds: [ - "SPDX-license-identifier-Apache-2.0", - ], - license_text: [ - "LICENSE", - ], -} - -cc_library_headers { - name: "gfxstream_astc_codec_headers", - defaults: ["gfxstream_defaults"], - host_supported: true, - export_include_dirs: [ ".", "include" ], -} diff --git a/third-party/astc-codec/BUILD.bazel b/third-party/astc-codec/BUILD.bazel deleted file mode 100644 index 8fc9eca4..00000000 --- a/third-party/astc-codec/BUILD.bazel +++ /dev/null @@ -1,28 +0,0 @@ -# Copyright 2018 Google LLC -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# https://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. - -licenses(["notice"]) - -cc_library( - name = "api", - hdrs = ["include/astc-codec/astc-codec.h"], - visibility = ["//src/decoder:__pkg__"], -) - -cc_library( - name = "astc_codec", - deps = ["//src/decoder:codec"], - includes = ["include"], - visibility = ["//visibility:public"], -) diff --git a/third-party/astc-codec/CMakeLists.txt b/third-party/astc-codec/CMakeLists.txt deleted file mode 100644 index 4670d9a8..00000000 --- a/third-party/astc-codec/CMakeLists.txt +++ /dev/null @@ -1,46 +0,0 @@ -# Copyright 2018 Google LLC -# -# Licensed under the Apache License, Version 2.0 (the "License"); you may not -# use this file except in compliance with the License. You may obtain a copy of -# the License at -# -# https://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT -# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the -# License for the specific language governing permissions and limitations under -# the License. -cmake_minimum_required(VERSION 3.1.0) -project(astc-codec) - -option(OPTION_ASTC_TESTS "Build all the unit tests." OFF) - -# TODO add support for the fuzzer, it has some additional dependencies we are not -# yet bringing in. -option(OPTION_BUILD_FUZZER "Build the fuzzer tests." OFF) - -set (CMAKE_CXX_STANDARD 11) -if(OPTION_ASTC_TESTS) - enable_testing() - - # No need to build gmock if an external project defines it. - if(NOT TARGET gmock_main) - # We use the approach suggested by https://crascit.com/2015/07/25/cmake-gtest/ to download gtest. - include(ExternalProject) - # Download and unpack googletest at configure time - configure_file(GoogleTest-CMakeLists.txt.in googletest-download/CMakeLists.txt) - execute_process(COMMAND "${CMAKE_COMMAND}" -G "${CMAKE_GENERATOR}" . - WORKING_DIRECTORY "${CMAKE_BINARY_DIR}/googletest-download") - execute_process(COMMAND "${CMAKE_COMMAND}" --build . WORKING_DIRECTORY "${CMAKE_BINARY_DIR}/googletest-download") - - # Prevent GoogleTest from overriding our compiler/linker options when building with Visual Studio - set(gtest_force_shared_crt ON CACHE BOOL "" FORCE) - - # Add googletest directly to our build. This adds the following targets: gtest, gtest_main, gmock and gmock_main - add_subdirectory("${CMAKE_BINARY_DIR}/googletest-src" "${CMAKE_BINARY_DIR}/googletest-build") - endif() -endif() - -add_subdirectory(src/base) -add_subdirectory(src/decoder) diff --git a/third-party/astc-codec/CONTRIBUTING.md b/third-party/astc-codec/CONTRIBUTING.md deleted file mode 100644 index 939e5341..00000000 --- a/third-party/astc-codec/CONTRIBUTING.md +++ /dev/null @@ -1,28 +0,0 @@ -# How to Contribute - -We'd love to accept your patches and contributions to this project. There are -just a few small guidelines you need to follow. - -## Contributor License Agreement - -Contributions to this project must be accompanied by a Contributor License -Agreement. You (or your employer) retain the copyright to your contribution; -this simply gives us permission to use and redistribute your contributions as -part of the project. Head over to <https://cla.developers.google.com/> to see -your current agreements on file or to sign a new one. - -You generally only need to submit a CLA once, so if you've already submitted one -(even if it was for a different project), you probably don't need to do it -again. - -## Code reviews - -All submissions, including submissions by project members, require review. We -use GitHub pull requests for this purpose. Consult -[GitHub Help](https://help.github.com/articles/about-pull-requests/) for more -information on using pull requests. - -## Community Guidelines - -This project follows [Google's Open Source Community -Guidelines](https://opensource.google.com/conduct/). diff --git a/third-party/astc-codec/GoogleTest-CMakeLists.txt.in b/third-party/astc-codec/GoogleTest-CMakeLists.txt.in deleted file mode 100644 index 569f4dfb..00000000 --- a/third-party/astc-codec/GoogleTest-CMakeLists.txt.in +++ /dev/null @@ -1,15 +0,0 @@ -cmake_minimum_required(VERSION 2.8.2)
-
-project(googletest-download NONE)
-
-include(ExternalProject)
-ExternalProject_Add(googletest
- GIT_REPOSITORY https://github.com/google/googletest.git
- GIT_TAG "release-1.8.1"
- SOURCE_DIR "${CMAKE_CURRENT_BINARY_DIR}/googletest-src"
- BINARY_DIR "${CMAKE_CURRENT_BINARY_DIR}/googletest-build"
- CONFIGURE_COMMAND ""
- BUILD_COMMAND ""
- INSTALL_COMMAND ""
- TEST_COMMAND ""
-)
\ No newline at end of file diff --git a/third-party/astc-codec/LICENSE b/third-party/astc-codec/LICENSE deleted file mode 100644 index d6456956..00000000 --- a/third-party/astc-codec/LICENSE +++ /dev/null @@ -1,202 +0,0 @@ - - Apache License - Version 2.0, January 2004 - http://www.apache.org/licenses/ - - TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION - - 1. Definitions. - - "License" shall mean the terms and conditions for use, reproduction, - and distribution as defined by Sections 1 through 9 of this document. - - "Licensor" shall mean the copyright owner or entity authorized by - the copyright owner that is granting the License. - - "Legal Entity" shall mean the union of the acting entity and all - other entities that control, are controlled by, or are under common - control with that entity. For the purposes of this definition, - "control" means (i) the power, direct or indirect, to cause the - direction or management of such entity, whether by contract or - otherwise, or (ii) ownership of fifty percent (50%) or more of the - outstanding shares, or (iii) beneficial ownership of such entity. - - "You" (or "Your") shall mean an individual or Legal Entity - exercising permissions granted by this License. - - "Source" form shall mean the preferred form for making modifications, - including but not limited to software source code, documentation - source, and configuration files. - - "Object" form shall mean any form resulting from mechanical - transformation or translation of a Source form, including but - not limited to compiled object code, generated documentation, - and conversions to other media types. - - "Work" shall mean the work of authorship, whether in Source or - Object form, made available under the License, as indicated by a - copyright notice that is included in or attached to the work - (an example is provided in the Appendix below). - - "Derivative Works" shall mean any work, whether in Source or Object - form, that is based on (or derived from) the Work and for which the - editorial revisions, annotations, elaborations, or other modifications - represent, as a whole, an original work of authorship. For the purposes - of this License, Derivative Works shall not include works that remain - separable from, or merely link (or bind by name) to the interfaces of, - the Work and Derivative Works thereof. - - "Contribution" shall mean any work of authorship, including - the original version of the Work and any modifications or additions - to that Work or Derivative Works thereof, that is intentionally - submitted to Licensor for inclusion in the Work by the copyright owner - or by an individual or Legal Entity authorized to submit on behalf of - the copyright owner. For the purposes of this definition, "submitted" - means any form of electronic, verbal, or written communication sent - to the Licensor or its representatives, including but not limited to - communication on electronic mailing lists, source code control systems, - and issue tracking systems that are managed by, or on behalf of, the - Licensor for the purpose of discussing and improving the Work, but - excluding communication that is conspicuously marked or otherwise - designated in writing by the copyright owner as "Not a Contribution." - - "Contributor" shall mean Licensor and any individual or Legal Entity - on behalf of whom a Contribution has been received by Licensor and - subsequently incorporated within the Work. - - 2. Grant of Copyright License. Subject to the terms and conditions of - this License, each Contributor hereby grants to You a perpetual, - worldwide, non-exclusive, no-charge, royalty-free, irrevocable - copyright license to reproduce, prepare Derivative Works of, - publicly display, publicly perform, sublicense, and distribute the - Work and such Derivative Works in Source or Object form. - - 3. Grant of Patent License. Subject to the terms and conditions of - this License, each Contributor hereby grants to You a perpetual, - worldwide, non-exclusive, no-charge, royalty-free, irrevocable - (except as stated in this section) patent license to make, have made, - use, offer to sell, sell, import, and otherwise transfer the Work, - where such license applies only to those patent claims licensable - by such Contributor that are necessarily infringed by their - Contribution(s) alone or by combination of their Contribution(s) - with the Work to which such Contribution(s) was submitted. If You - institute patent litigation against any entity (including a - cross-claim or counterclaim in a lawsuit) alleging that the Work - or a Contribution incorporated within the Work constitutes direct - or contributory patent infringement, then any patent licenses - granted to You under this License for that Work shall terminate - as of the date such litigation is filed. - - 4. Redistribution. You may reproduce and distribute copies of the - Work or Derivative Works thereof in any medium, with or without - modifications, and in Source or Object form, provided that You - meet the following conditions: - - (a) You must give any other recipients of the Work or - Derivative Works a copy of this License; and - - (b) You must cause any modified files to carry prominent notices - stating that You changed the files; and - - (c) You must retain, in the Source form of any Derivative Works - that You distribute, all copyright, patent, trademark, and - attribution notices from the Source form of the Work, - excluding those notices that do not pertain to any part of - the Derivative Works; and - - (d) If the Work includes a "NOTICE" text file as part of its - distribution, then any Derivative Works that You distribute must - include a readable copy of the attribution notices contained - within such NOTICE file, excluding those notices that do not - pertain to any part of the Derivative Works, in at least one - of the following places: within a NOTICE text file distributed - as part of the Derivative Works; within the Source form or - documentation, if provided along with the Derivative Works; or, - within a display generated by the Derivative Works, if and - wherever such third-party notices normally appear. The contents - of the NOTICE file are for informational purposes only and - do not modify the License. You may add Your own attribution - notices within Derivative Works that You distribute, alongside - or as an addendum to the NOTICE text from the Work, provided - that such additional attribution notices cannot be construed - as modifying the License. - - You may add Your own copyright statement to Your modifications and - may provide additional or different license terms and conditions - for use, reproduction, or distribution of Your modifications, or - for any such Derivative Works as a whole, provided Your use, - reproduction, and distribution of the Work otherwise complies with - the conditions stated in this License. - - 5. Submission of Contributions. Unless You explicitly state otherwise, - any Contribution intentionally submitted for inclusion in the Work - by You to the Licensor shall be under the terms and conditions of - this License, without any additional terms or conditions. - Notwithstanding the above, nothing herein shall supersede or modify - the terms of any separate license agreement you may have executed - with Licensor regarding such Contributions. - - 6. Trademarks. This License does not grant permission to use the trade - names, trademarks, service marks, or product names of the Licensor, - except as required for reasonable and customary use in describing the - origin of the Work and reproducing the content of the NOTICE file. - - 7. Disclaimer of Warranty. Unless required by applicable law or - agreed to in writing, Licensor provides the Work (and each - Contributor provides its Contributions) on an "AS IS" BASIS, - WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or - implied, including, without limitation, any warranties or conditions - of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A - PARTICULAR PURPOSE. You are solely responsible for determining the - appropriateness of using or redistributing the Work and assume any - risks associated with Your exercise of permissions under this License. - - 8. Limitation of Liability. In no event and under no legal theory, - whether in tort (including negligence), contract, or otherwise, - unless required by applicable law (such as deliberate and grossly - negligent acts) or agreed to in writing, shall any Contributor be - liable to You for damages, including any direct, indirect, special, - incidental, or consequential damages of any character arising as a - result of this License or out of the use or inability to use the - Work (including but not limited to damages for loss of goodwill, - work stoppage, computer failure or malfunction, or any and all - other commercial damages or losses), even if such Contributor - has been advised of the possibility of such damages. - - 9. Accepting Warranty or Additional Liability. While redistributing - the Work or Derivative Works thereof, You may choose to offer, - and charge a fee for, acceptance of support, warranty, indemnity, - or other liability obligations and/or rights consistent with this - License. However, in accepting such obligations, You may act only - on Your own behalf and on Your sole responsibility, not on behalf - of any other Contributor, and only if You agree to indemnify, - defend, and hold each Contributor harmless for any liability - incurred by, or claims asserted against, such Contributor by reason - of your accepting any such warranty or additional liability. - - END OF TERMS AND CONDITIONS - - APPENDIX: How to apply the Apache License to your work. - - To apply the Apache License to your work, attach the following - boilerplate notice, with the fields enclosed by brackets "[]" - replaced with your own identifying information. (Don't include - the brackets!) The text should be enclosed in the appropriate - comment syntax for the file format. We also recommend that a - file or class name and description of purpose be included on the - same "printed page" as the copyright notice for easier - identification within third-party archives. - - Copyright [yyyy] [name of copyright owner] - - Licensed under the Apache License, Version 2.0 (the "License"); - you may not use this file except in compliance with the License. - You may obtain a copy of the License at - - http://www.apache.org/licenses/LICENSE-2.0 - - Unless required by applicable law or agreed to in writing, software - distributed under the License is distributed on an "AS IS" BASIS, - WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - See the License for the specific language governing permissions and - limitations under the License. diff --git a/third-party/astc-codec/README.md b/third-party/astc-codec/README.md deleted file mode 100644 index 8bb2c269..00000000 --- a/third-party/astc-codec/README.md +++ /dev/null @@ -1,71 +0,0 @@ -# astc-codec - -astc-codec is a software ASTC decoder implementation, which supports the ASTC -LDR profile. - -Example usage: - -``` -#include <astc-codec/astc-codec.h> - -// ... - -std::vector<uint8_t> astc = LoadMyASTCData(); -const size_t width = 640; -const size_t height = 480; - -std::vector<uint8_t> result; -result.resize(width * height * 4); - -bool result = astc_codec::ASTCDecompressToRGBA( - astc.data(), astc.size(), width, height, astc_codec::FootprintType::k4x4, - result.data(), result.size(), /* stride */ width * 4); -``` - -## Building - -### With bazel - -Install [Bazel](https://bazel.build/), and then run: - -``` -bazel build :astc_codec -c opt -``` - -astc-codec has been tested on Mac and Linux. - -### Run Tests - -``` -bazel test //... -``` - -### With CMake - -Install [CMake](https://https://cmake.org/), and the run: - -``` -mkdir build && cd build && cmake .. && make -``` - -Or open the project in your favorite IDE and import CMakeLists.txt. - -### Run Tests - -In the build directory, execute: - -``` -ctest -``` - - -## Contributing - -See [CONTRIBUTING.md](CONTRIBUTING.md) for important contributing requirements. - -## License - -astc-codec project is licensed under the Apache License Version 2.0. You can -find a copy of it in [LICENSE](LICENSE). - -This is not an officially supported Google product. diff --git a/third-party/astc-codec/WORKSPACE b/third-party/astc-codec/WORKSPACE deleted file mode 100644 index 77d6a692..00000000 --- a/third-party/astc-codec/WORKSPACE +++ /dev/null @@ -1,34 +0,0 @@ -# Copyright 2018 Google LLC -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# https://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. - -git_repository( - name = "gtest", - remote = "https://github.com/google/googletest.git", - commit = "ba96d0b1161f540656efdaed035b3c062b60e006", -) - -new_http_archive( - name = "honggfuzz", - url = "https://github.com/google/honggfuzz/archive/1.6.zip", - sha256 = "c331ac5beebe526bced3043ed3012109e439315b7d74d72760b0aa6d08cc05d2", - build_file = "third_party/honggfuzz.BUILD", - strip_prefix = "honggfuzz-1.6", -) - -http_archive( - name = "benchmark", - url = "https://github.com/google/benchmark/archive/v1.4.1.zip", - sha256 = "61ae07eb5d4a0b02753419eb17a82b7d322786bb36ab62bd3df331a4d47c00a7", - strip_prefix = "benchmark-1.4.1", -) diff --git a/third-party/astc-codec/cmake-format.json b/third-party/astc-codec/cmake-format.json deleted file mode 100644 index de38ed28..00000000 --- a/third-party/astc-codec/cmake-format.json +++ /dev/null @@ -1,38 +0,0 @@ -{ - "line_width": 120, - "dangle_parens": false, - "first_comment_is_literal": true, - "algorithm_order": [ - 0, - 1, - 2, - 3 - ], - "command_case": "lower", - "additional_commands": { - "foo": { - "flags": [ - "BAR", - "BAZ" - ], - "kwargs": { - "HEADERS": "*", - "DEPENDS": "*", - "SOURCES": "*" - } - } - }, - "separate_fn_name_with_space": false, - "always_wrap": [], - "separate_ctrl_name_with_space": false, - "max_subargs_per_line": 5, - "fence_pattern": "^\\s*([`~]{3}[`~]*)(.*)$", - "enable_markup": true, - "ruler_pattern": "^\\s*[^\\w\\s]{3}.*[^\\w\\s]{3}$", - "tab_size": 2, - "keyword_case": "unchanged", - "enum_char": ".", - "literal_comment_pattern": null, - "bullet_char": "*", - "line_ending": "unix" -} diff --git a/third-party/astc-codec/include/astc-codec/astc-codec.h b/third-party/astc-codec/include/astc-codec/astc-codec.h deleted file mode 100644 index 1d412181..00000000 --- a/third-party/astc-codec/include/astc-codec/astc-codec.h +++ /dev/null @@ -1,75 +0,0 @@ -// Copyright 2018 Google LLC -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// https://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -#ifndef ASTC_CODEC_ASTC_CODEC_H_ -#define ASTC_CODEC_ASTC_CODEC_H_ - -#include <cstddef> -#include <cstdint> - -namespace astc_codec { - -// These are the valid ASTC footprints according to the specification in -// Section C.2.7. -enum class FootprintType { - k4x4, - k5x4, - k5x5, - k6x5, - k6x6, - k8x5, - k8x6, - k10x5, - k10x6, - k8x8, - k10x8, - k10x10, - k12x10, - k12x12, - - kCount -}; - -// Decompresses ASTC LDR image data to a RGBA32 buffer. -// -// Supports formats defined in the KHR_texture_compression_astc_ldr spec and -// returns UNORM8 values. sRGB is not supported, and should be implemented -// by the caller. -// -// |astc_data| - Compressed ASTC image buffer, must be at least |astc_data_size| -// bytes long. -// |astc_data_size| - The size of |astc_data|, in bytes. -// |width| - Image width, in pixels. -// |height| - Image height, in pixels. -// |footprint| - The ASTC footprint (block size) of the compressed image buffer. -// |out_buffer| - Pointer to a buffer where the decompressed image will be -// stored, must be at least |out_buffer_size| bytes long. -// |out_buffer_size| - The size of |out_buffer|, in bytes, at least -// height*out_buffer_stride. If this is too small, this -// function will return false and no data will be -// decompressed. -// |out_buffer_stride| - The stride that should be used to store rows of the -// decoded image, must be at least 4*width bytes. -// -// Returns true if the decompression succeeded, or false if decompression -// failed, or if the astc_data_size was too small for the given width, height, -// and footprint, or if out_buffer_size is too small. -bool ASTCDecompressToRGBA(const uint8_t* astc_data, size_t astc_data_size, - size_t width, size_t height, FootprintType footprint, - uint8_t* out_buffer, size_t out_buffer_size, - size_t out_buffer_stride); - -} // namespace astc_codec - -#endif // ASTC_CODEC_ASTC_CODEC_H_ diff --git a/third-party/astc-codec/src/.clang-format b/third-party/astc-codec/src/.clang-format deleted file mode 100644 index 9a00ee25..00000000 --- a/third-party/astc-codec/src/.clang-format +++ /dev/null @@ -1,4 +0,0 @@ -BasedOnStyle: Google -AllowShortCaseLabelsOnASingleLine: true -AllowShortFunctionsOnASingleLine: Inline -SpaceAfterTemplateKeyword: false diff --git a/third-party/astc-codec/src/base/BUILD.bazel b/third-party/astc-codec/src/base/BUILD.bazel deleted file mode 100644 index 09f723d7..00000000 --- a/third-party/astc-codec/src/base/BUILD.bazel +++ /dev/null @@ -1,46 +0,0 @@ -# Copyright 2018 Google LLC -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# https://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. - -cc_library( - name = "base", - hdrs = [ - "bit_stream.h", - "bottom_n.h", - "math_utils.h", - "optional.h", - "string_utils.h", - "type_traits.h", - "uint128.h", - "utils.h", - ], - visibility = ["//src/decoder:__pkg__"], -) - -cc_test( - name = "base_test", - srcs = [ - "test/bit_stream_test.cpp", - "test/bottom_n_test.cpp", - "test/math_utils_test.cpp", - "test/optional_test.cpp", - "test/string_utils_test.cpp", - "test/type_traits_test.cpp", - "test/uint128_test.cpp", - ], - deps = [ - "@gtest//:gtest_main", - ":base", - ], -) - diff --git a/third-party/astc-codec/src/base/CMakeLists.txt b/third-party/astc-codec/src/base/CMakeLists.txt deleted file mode 100644 index 5a45f857..00000000 --- a/third-party/astc-codec/src/base/CMakeLists.txt +++ /dev/null @@ -1,27 +0,0 @@ -# Copyright 2018 Google LLC -# -# Licensed under the Apache License Version 2.0 (the License); you may not use -# this file except in compliance with the License. You may obtain a copy of the -# License at -# -# https://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing software distributed -# under the License is distributed on an AS IS BASIS WITHOUT WARRANTIES OR -# CONDITIONS OF ANY KIND either express or implied. See the License for the -# specific language governing permissions and limitations under the License. -add_library(base INTERFACE) -target_include_directories(base INTERFACE ../..) - -if(OPTION_ASTC_TESTS) - add_executable(base_test - test/bit_stream_test.cpp - test/bottom_n_test.cpp - test/math_utils_test.cpp - test/optional_test.cpp - test/string_utils_test.cpp - test/type_traits_test.cpp - test/uint128_test.cpp) - target_link_libraries(base_test base gmock_main) - add_test(NAME base_test COMMAND base_test WORKING_DIRECTORY ${PROJECT_SOURCE_DIR}) -endif() diff --git a/third-party/astc-codec/src/base/bit_stream.h b/third-party/astc-codec/src/base/bit_stream.h deleted file mode 100644 index 2cda0937..00000000 --- a/third-party/astc-codec/src/base/bit_stream.h +++ /dev/null @@ -1,77 +0,0 @@ -// Copyright 2018 Google LLC -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// https://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -#ifndef ASTC_CODEC_BASE_BIT_STREAM_H_ -#define ASTC_CODEC_BASE_BIT_STREAM_H_ - -#include <cassert> -#include <cstdint> - -namespace astc_codec { -namespace base { - -// Represents a stream of bits that can be read or written in arbitrary-sized -// chunks. -template<typename IntType = uint64_t> -class BitStream { - public: - // Creates an empty BitStream. - BitStream() = default; - BitStream(IntType data, uint32_t data_size) - : data_(data), data_size_(data_size) { - assert(data_size_ <= sizeof(data_) * 8); - } - - // Return the number of bits in the stream. - uint32_t Bits() const { return data_size_; } - - // Put |size| bits into the stream. - // Fails if there is not enough space in the buffer to store the bits. - template<typename ResultType> - void PutBits(ResultType x, uint32_t size) { - assert(data_size_ + size <= sizeof(data_) * 8); - - data_ |= (IntType(x) & MaskFor(size)) << data_size_; - data_size_ += size; - } - - // Get |count| bits from the stream. - // Returns true if |count| bits were successfully retrieved. - template<typename ResultType> - bool GetBits(uint32_t count, ResultType* result) { - if (count <= data_size_) { - *result = static_cast<ResultType>(data_ & MaskFor(count)); - data_ = data_ >> count; - data_size_ -= count; - return true; - } else { - *result = ResultType(); - return false; - } - } - - private: - IntType MaskFor(uint32_t bits) const { - return (bits == sizeof(IntType) * 8) ? ~IntType(0) - : (IntType(1) << bits) - 1; - } - - IntType data_ = IntType(); - uint32_t data_size_ = 0; -}; - -} // namespace base -} // namespace astc_codec - -#endif // ASTC_CODEC_BASE_BIT_STREAM_H_ diff --git a/third-party/astc-codec/src/base/bottom_n.h b/third-party/astc-codec/src/base/bottom_n.h deleted file mode 100644 index 4edc8efb..00000000 --- a/third-party/astc-codec/src/base/bottom_n.h +++ /dev/null @@ -1,78 +0,0 @@ -// Copyright 2018 Google LLC -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// https://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -#ifndef ASTC_CODEC_BASE_BOTTOM_N_H_ -#define ASTC_CODEC_BASE_BOTTOM_N_H_ - -#include <algorithm> -#include <functional> -#include <vector> - -namespace astc_codec { -namespace base { - -// Used to aggregate the lowest N values of data supplied. -template<typename T, typename CompareFn = std::less<T>> -class BottomN { - public: - typedef std::vector<T> ContainerType; - - // Creates an empty BottomN with limit |max_size|. - BottomN(size_t max_size) : max_size_(max_size) { } - - bool Empty() const { return data_.empty(); } - size_t Size() const { return data_.size(); } - - const T& Top() const { return data_.front(); } - - void Push(const T& value) { - if (data_.size() < max_size_ || compare_(value, Top())) { - data_.push_back(value); - std::push_heap(data_.begin(), data_.end(), compare_); - - if (Size() > max_size_) { - PopTop(); - } - } - } - - std::vector<T> Pop() { - const size_t len = Size(); - std::vector<T> result(len); - - for (size_t i = 0; i < len; ++i) { - result[len - i - 1] = PopTop(); - } - - return result; - } - - private: - T PopTop() { - std::pop_heap(data_.begin(), data_.end(), compare_); - T result = data_.back(); - data_.pop_back(); - return result; - } - - ContainerType data_; - CompareFn compare_; - - const size_t max_size_; -}; - -} // namespace base -} // namespace astc_codec - -#endif // ASTC_CODEC_BASE_BOTTOM_N_H_ diff --git a/third-party/astc-codec/src/base/math_utils.h b/third-party/astc-codec/src/base/math_utils.h deleted file mode 100644 index 48f1a24c..00000000 --- a/third-party/astc-codec/src/base/math_utils.h +++ /dev/null @@ -1,80 +0,0 @@ -// Copyright 2018 Google LLC -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// https://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -#ifndef ASTC_CODEC_BASE_MATH_UTILS_H_ -#define ASTC_CODEC_BASE_MATH_UTILS_H_ - -#include "src/base/uint128.h" - -#include <cassert> -#include <cstdint> -#include <type_traits> - -namespace astc_codec { -namespace base { - -inline int Log2Floor(uint32_t n) { - if (n == 0) { - return -1; - } - - int log = 0; - uint32_t value = n; - for (int i = 4; i >= 0; --i) { - int shift = (1 << i); - uint32_t x = value >> shift; - if (x != 0) { - value = x; - log += shift; - } - } - assert(value == 1); - return log; -} - -inline int CountOnes(uint32_t n) { - n -= ((n >> 1) & 0x55555555); - n = ((n >> 2) & 0x33333333) + (n & 0x33333333); - return static_cast<int>((((n + (n >> 4)) & 0xF0F0F0F) * 0x1010101) >> 24); -} - -template<typename T> -inline T ReverseBits(T value) { - uint32_t s = sizeof(value) * 8; - T mask = ~T(0); - while ((s >>= 1) > 0) { - mask ^= (mask << s); - value = ((value >> s) & mask) | ((value << s) & ~mask); - } - - return value; -} - -template<typename T> -inline T GetBits(T source, uint32_t offset, uint32_t count) { - static_assert(std::is_same<T, UInt128>::value || std::is_unsigned<T>::value, - "T must be unsigned."); - - const uint32_t total_bits = sizeof(T) * 8; - assert(count > 0); - assert(offset + count <= total_bits); - - const T mask = count == total_bits ? ~T(0) : ~T(0) >> (total_bits - count); - return (source >> offset) & mask; -} - -} // namespace base -} // namespace astc_codec - -#endif // ASTC_CODEC_BASE_MATH_UTILS_H_ diff --git a/third-party/astc-codec/src/base/optional.h b/third-party/astc-codec/src/base/optional.h deleted file mode 100644 index 5ede4af9..00000000 --- a/third-party/astc-codec/src/base/optional.h +++ /dev/null @@ -1,520 +0,0 @@ -// Copyright 2018 Google LLC -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// https://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -#ifndef ASTC_CODEC_BASE_OPTIONAL_H_ -#define ASTC_CODEC_BASE_OPTIONAL_H_ - -#include "src/base/type_traits.h" - -#include <cassert> -#include <initializer_list> -#include <type_traits> -#include <utility> - -#include <cstddef> - -// Optional<T> - a template class to store an optional value of type T. -// -// Usage examples: -// -// Initialization and construction: -// Optional<Foo> foo; // |foo| doesn't contain a value. -// Optional<Foo> foo(Foo(10)); // |foo| contains a copy-constructed value. -// Optional<Foo> foo2(foo); // |foo2| contains a copy of |foo|'s value. -// Optional<Foo> foo3(std::move(foo2)); // Guess what? -// -// Assignment: -// Foo foo_value(0); -// Optional<Foo> foo; // |foo| is empty. -// Optional<Foo> foo2; // |foo2| is empty. -// foo2 = foo; // |foo2| is still empty. -// foo = foo_value; // set value of |foo| to a copy of |foo_value| -// foo = std::move(foo_value); // move |foo_value| into |foo|. -// foo2 = foo; // now |foo2| has a copy of |foo|'s value. -// foo = kNullopt; // unset |foo|, it has no value. -// -// Checking and accessing value: -// if (foo) { -// // |foo| has a value. -// doStuff(*foo); // |*foo| is the value inside |foo|. -// foo->callMethod(); // Same as (*foo).callMethod(). -// } else { -// // |foo| is empty. -// } -// -// foo.value() // Same as *foo -// foo.valueOr(<default>) // Return <default> is |foo| has no value. -// -// In-place construction: -// -// Optional<Foo> foo; // |foo| is empty. -// foo.emplace(20); // |foo| now contains a value constructed as Foo(20) -// -// Optional<Foo> foo(kInplace, 20); // |foo| is initialized with a value -// // that is constructed in-place as -// // Foo(20). -// -// return makeOptional<Foo>(20); // Takes Foo constructor arguments -// // directly. -// -// Returning values: -// -// Optional<Foo> myFunc(...) { -// if (someCondition) { -// return Foo(10); // call Optional<Foo>(Foo&) constructor. -// } else { -// return {}; // call Optional<Foo>() constructor, which -// // builds an empty value. -// } -// } -// -// Memory layout: -// Optional<Foo> is equivalent to: -// -// struct { -// bool flag; -// Foo value; -// }; -// -// in terms of memory layout. This means it *doubles* the size of integral -// types. Also: -// -// - Optional<Foo> can be constructed from anything that constructs a Foo. -// -// - Same with Optional<Foo>(kInplace, Args...) where Args... matches any -// arguments that can be passed to a Foo constructor. -// -// - Comparison operators are provided. Beware: an empty Optional<Foo> -// is always smaller than any Foo value. - -namespace astc_codec { -namespace base { - -namespace details { - -// Base classes to reduce the number of instantiations of the Optional's -// internal members. -class OptionalFlagBase { - public: - void setConstructed(bool constructed) { mConstructed = constructed; } - constexpr bool constructed() const { return mConstructed; } - constexpr operator bool() const { return constructed(); } - bool hasValue() const { return constructed(); } - - constexpr OptionalFlagBase(bool constructed = false) - : mConstructed(constructed) { } - - private: - bool mConstructed = false; -}; - -template<size_t Size, size_t Align> -class OptionalStorageBase { - protected: - using StoreT = typename std::aligned_storage<Size, Align>::type; - StoreT mStorage = {}; -}; - -} // namespace details - -// A tag type for empty optional construction -struct NulloptT { - constexpr explicit NulloptT(int) { } -}; - -// A tag type for inplace value construction -struct InplaceT { - constexpr explicit InplaceT(int) { } -}; - -// Tag values for null optional and inplace construction -constexpr NulloptT kNullopt{1}; -constexpr InplaceT kInplace{1}; - -// Forward declaration for an early use -template<class T> -class Optional; - -// A type trait for checking if a type is an optional instantiation -// Note: if you want to refer to the template name inside the template, -// you need to declare this alias outside of it - because the -// class name inside of the template stands for an instantiated template -// E.g, for template <T> class Foo if you say 'Foo' inside the class, it -// actually means Foo<T>; -template<class U> -using is_any_optional = - is_template_instantiation_of<typename std::decay<U>::type, Optional>; - -template<class T> -class Optional - : private details::OptionalFlagBase, - private details::OptionalStorageBase<sizeof(T), - std::alignment_of<T>::value> { - // make sure all optionals are buddies - this is needed to implement - // conversion from optionals of other types - template<class U> - friend class Optional; - - template<class U> - using self = Optional<U>; - - using base_flag = details::OptionalFlagBase; - using base_storage = - details::OptionalStorageBase<sizeof(T), std::alignment_of<T>::value>; - - public: - // std::optional will have this, so let's provide it - using value_type = T; - - // make sure we forbid some Optional instantiations where things may get - // really messy - static_assert(!std::is_same<typename std::decay<T>::type, NulloptT>::value, - "Optional of NulloptT is not allowed"); - static_assert(!std::is_same<typename std::decay<T>::type, InplaceT>::value, - "Optional of InplaceT is not allowed"); - static_assert(!std::is_reference<T>::value, - "Optional references are not allowed: use a pointer instead"); - - // constructors - constexpr Optional() { } - constexpr Optional(NulloptT) { } - - Optional(const Optional& other) : base_flag(other.constructed()) { - if (this->constructed()) { - new (&get()) T(other.get()); - } - } - Optional(Optional&& other) : base_flag(other.constructed()) { - if (this->constructed()) { - new (&get()) T(std::move(other.get())); - } - } - - // Conversion constructor from optional of similar type - template<class U, class = enable_if_c<!is_any_optional<U>::value && - std::is_constructible<T, U>::value>> - Optional(const Optional<U>& other) : base_flag(other.constructed()) { - if (this->constructed()) { - new (&get()) T(other.get()); - } - } - - // Move-conversion constructor - template<class U, class = enable_if_c<!is_any_optional<U>::value && - std::is_constructible<T, U>::value>> - Optional(Optional<U>&& other) : base_flag(other.constructed()) { - if (this->constructed()) { - new (&get()) T(std::move(other.get())); - } - } - - // Construction from a raw value - Optional(const T& value) : base_flag(true) { new (&get()) T(value); } - // Move construction from a raw value - Optional(T&& value) : base_flag(true) { new (&get()) T(std::move(value)); } - - // Inplace construction from a list of |T|'s ctor arguments - template<class... Args> - Optional(InplaceT, Args&&... args) : base_flag(true) { - new (&get()) T(std::forward<Args>(args)...); - } - - // Inplace construction from an initializer list passed into |T|'s ctor - template<class U, class = enable_if< - std::is_constructible<T, std::initializer_list<U>>>> - Optional(InplaceT, std::initializer_list<U> il) : base_flag(true) { - new (&get()) T(il); - } - - // direct assignment - Optional& operator=(const Optional& other) { - if (&other == this) { - return *this; - } - - if (this->constructed()) { - if (other.constructed()) { - get() = other.get(); - } else { - destruct(); - this->setConstructed(false); - } - } else { - if (other.constructed()) { - new (&get()) T(other.get()); - this->setConstructed(true); - } else { - ; // we're good - } - } - return *this; - } - - // move assignment - Optional& operator=(Optional&& other) { - if (this->constructed()) { - if (other.constructed()) { - get() = std::move(other.get()); - } else { - destruct(); - this->setConstructed(false); - } - } else { - if (other.constructed()) { - new (&get()) T(std::move(other.get())); - this->setConstructed(true); - } else { - ; // we're good - } - } - return *this; - } - - // conversion assignment - template<class U, - class = enable_if_convertible<typename std::decay<U>::type, T>> - Optional& operator=(const Optional<U>& other) { - if (this->constructed()) { - if (other.constructed()) { - get() = other.get(); - } else { - destruct(); - this->setConstructed(false); - } - } else { - if (other.constructed()) { - new (&get()) T(other.get()); - this->setConstructed(true); - } else { - ; // we're good - } - } - return *this; - } - - // conversion move assignment - template<class U, - class = enable_if_convertible<typename std::decay<U>::type, T>> - Optional& operator=(Optional<U>&& other) { - if (this->constructed()) { - if (other.constructed()) { - get() = std::move(other.get()); - } else { - destruct(); - this->setConstructed(false); - } - } else { - if (other.constructed()) { - new (&get()) T(std::move(other.get())); - this->setConstructed(true); - } else { - ; // we're good - } - } - return *this; - } - - // the most complicated one: forwarding constructor for anything convertible - // to |T|, excluding the stuff implemented above explicitly - template<class U, - class = enable_if_c< - !is_any_optional<typename std::decay<U>::type>::value && - std::is_convertible<typename std::decay<U>::type, T>::value>> - Optional& operator=(U&& other) { - if (this->constructed()) { - get() = std::forward<U>(other); - } else { - new (&get()) T(std::forward<U>(other)); - this->setConstructed(true); - } - return *this; - } - - // Adopt value checkers from the parent - using base_flag::operator bool; - using base_flag::hasValue; - - T& value() { - assert(this->constructed()); - return get(); - } - constexpr const T& value() const { - assert(this->constructed()); - return get(); - } - - T* ptr() { return this->constructed() ? &get() : nullptr; } - constexpr const T* ptr() const { - return this->constructed() ? &get() : nullptr; - } - - // Value getter with fallback - template<class U = T, - class = enable_if_convertible<typename std::decay<U>::type, T>> - constexpr T valueOr(U&& defaultValue) const { - return this->constructed() ? get() : std::move(defaultValue); - } - - // Pointer-like operators - T& operator*() { - assert(this->constructed()); - return get(); - } - constexpr const T& operator*() const { - assert(this->constructed()); - return get(); - } - - T* operator->() { - assert(this->constructed()); - return &get(); - } - constexpr const T* operator->() const { - assert(this->constructed()); - return &get(); - } - - ~Optional() { - if (this->constructed()) { - destruct(); - } - } - - void clear() { - if (this->constructed()) { - destruct(); - this->setConstructed(false); - } - } - - template<class U, - class = enable_if_convertible<typename std::decay<U>::type, T>> - void reset(U&& u) { - *this = std::forward<U>(u); - } - - // In-place construction with possible destruction of the old value - template<class... Args> - void emplace(Args&&... args) { - if (this->constructed()) { - destruct(); - } - new (&get()) T(std::forward<Args>(args)...); - this->setConstructed(true); - } - - // In-place construction with possible destruction of the old value - // initializer-list version - template<class U, class = enable_if< - std::is_constructible<T, std::initializer_list<U>>>> - void emplace(std::initializer_list<U> il) { - if (this->constructed()) { - destruct(); - } - new (&get()) T(il); - this->setConstructed(true); - } - - private: - // A helper function to convert the internal raw storage to T& - constexpr const T& get() const { - return *reinterpret_cast<const T*>( - reinterpret_cast<const char*>(&this->mStorage)); - } - - // Same thing, mutable - T& get() { return const_cast<T&>(const_cast<const Optional*>(this)->get()); } - - // Shortcut for a destructor call for the stored object - void destruct() { get().T::~T(); } -}; - -template<class T> -Optional<typename std::decay<T>::type> makeOptional(T&& t) { - return Optional<typename std::decay<T>::type>(std::forward<T>(t)); -} - -template<class T, class... Args> -Optional<typename std::decay<T>::type> makeOptional(Args&&... args) { - return Optional<typename std::decay<T>::type>(kInplace, - std::forward<Args>(args)...); -} - -template<class T> -bool operator==(const Optional<T>& l, const Optional<T>& r) { - return l.hasValue() ? r.hasValue() && *l == *r : !r.hasValue(); -} -template<class T> -bool operator==(const Optional<T>& l, NulloptT) { - return !l; -} -template<class T> -bool operator==(NulloptT, const Optional<T>& r) { - return !r; -} -template<class T> -bool operator==(const Optional<T>& l, const T& r) { - return bool(l) && *l == r; -} -template<class T> -bool operator==(const T& l, const Optional<T>& r) { - return bool(r) && l == *r; -} - -template<class T> -bool operator!=(const Optional<T>& l, const Optional<T>& r) { - return !(l == r); -} -template<class T> -bool operator!=(const Optional<T>& l, NulloptT) { - return bool(l); -} -template<class T> -bool operator!=(NulloptT, const Optional<T>& r) { - return bool(r); -} -template<class T> -bool operator!=(const Optional<T>& l, const T& r) { - return !l || !(*l == r); -} -template<class T> -bool operator!=(const T& l, const Optional<T>& r) { - return !r || !(l == *r); -} - -template<class T> -bool operator<(const Optional<T>& l, const Optional<T>& r) { - return !r ? false : (!l ? true : *l < *r); -} -template<class T> -bool operator<(const Optional<T>&, NulloptT) { - return false; -} -template<class T> -bool operator<(NulloptT, const Optional<T>& r) { - return bool(r); -} -template<class T> -bool operator<(const Optional<T>& l, const T& r) { - return !l || *l < r; -} -template<class T> -bool operator<(const T& l, const Optional<T>& r) { - return bool(r) && l < *r; -} - -} // namespace base -} // namespace astc_codec - -#endif // ASTC_CODEC_BASE_OPTIONAL_H_ diff --git a/third-party/astc-codec/src/base/string_utils.h b/third-party/astc-codec/src/base/string_utils.h deleted file mode 100644 index c450b272..00000000 --- a/third-party/astc-codec/src/base/string_utils.h +++ /dev/null @@ -1,68 +0,0 @@ -// Copyright 2018 Google LLC -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// https://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -#ifndef ASTC_CODEC_BASE_STRING_UTILS_H_ -#define ASTC_CODEC_BASE_STRING_UTILS_H_ - -#include <limits> -#include <string> - -namespace astc_codec { -namespace base { - -// Iterates over a string's parts using |splitBy| as a delimiter. -// |splitBy| must be a nonempty string well, or it's a no-op. -// Otherwise, |func| is called on each of the splits, excluding the -// characters that are part of |splitBy|. If two |splitBy|'s occur in a row, -// |func| will be called on a StringView("") in between. See -// StringUtils_unittest.cpp for the full story. -template<class Func> -void Split(const std::string& str, const std::string& splitBy, Func func) { - if (splitBy.empty()) { - return; - } - - size_t splitSize = splitBy.size(); - size_t begin = 0; - size_t end = str.find(splitBy); - - while (true) { - func(str.substr(begin, end - begin)); - if (end == std::string::npos) { - return; - } - - begin = end + splitSize; - end = str.find(splitBy, begin); - } -} - -static int32_t ParseInt32(const char* str, int32_t deflt) { - using std::numeric_limits; - - char* error = nullptr; - int64_t value = strtol(str, &error, 0); - // Limit long values to int32 min/max. Needed for lp64; no-op on 32 bits. - if (value > std::numeric_limits<int32_t>::max()) { - value = std::numeric_limits<int32_t>::max(); - } else if (value < std::numeric_limits<int32_t>::min()) { - value = std::numeric_limits<int32_t>::min(); - } - return (error == str) ? deflt : static_cast<int32_t>(value); -} - -} // namespace base -} // namespace astc_codec - -#endif // ASTC_CODEC_BASE_STRING_UTILS_H_ diff --git a/third-party/astc-codec/src/base/test/bit_stream_test.cpp b/third-party/astc-codec/src/base/test/bit_stream_test.cpp deleted file mode 100644 index 0c4b3c94..00000000 --- a/third-party/astc-codec/src/base/test/bit_stream_test.cpp +++ /dev/null @@ -1,141 +0,0 @@ -// Copyright 2018 Google LLC -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// https://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -#include "src/base/bit_stream.h" - -#include <gtest/gtest.h> - -namespace astc_codec { -namespace base { - -namespace { - static constexpr uint64_t kAllBits = 0xFFFFFFFFFFFFFFFF; - static constexpr uint64_t k40Bits = 0x000000FFFFFFFFFF; -} - -TEST(BitStream, Decode) { - { - BitStream<uint64_t> stream(0, 1); - - uint64_t bits = kAllBits; - EXPECT_TRUE(stream.GetBits(1, &bits)); - EXPECT_EQ(bits, 0); - EXPECT_FALSE(stream.GetBits(1, &bits)); - } - - { - BitStream<uint64_t> stream(0b1010101010101010, 32); - EXPECT_EQ(stream.Bits(), 32); - - uint64_t bits = 0; - EXPECT_TRUE(stream.GetBits(1, &bits)); - EXPECT_EQ(bits, 0); - - EXPECT_TRUE(stream.GetBits(3, &bits)); - EXPECT_EQ(bits, 0b101); - - EXPECT_TRUE(stream.GetBits(8, &bits)); - EXPECT_EQ(bits, 0b10101010); - - EXPECT_EQ(stream.Bits(), 20); - - EXPECT_TRUE(stream.GetBits(20, &bits)); - EXPECT_EQ(bits, 0b1010); - EXPECT_EQ(stream.Bits(), 0); - } - - { - BitStream<uint64_t> stream(kAllBits, 64); - EXPECT_EQ(stream.Bits(), 64); - - uint64_t bits = 0; - EXPECT_TRUE(stream.GetBits(64, &bits)); - EXPECT_EQ(bits, kAllBits); - EXPECT_EQ(stream.Bits(), 0); - } - - { - BitStream<uint64_t> stream(kAllBits, 64); - EXPECT_EQ(stream.Bits(), 64); - - uint64_t bits = 0; - EXPECT_TRUE(stream.GetBits(40, &bits)); - EXPECT_EQ(bits, k40Bits); - EXPECT_EQ(stream.Bits(), 24); - } - - { - BitStream<uint64_t> stream(kAllBits, 32); - - uint64_t bits = 0; - EXPECT_TRUE(stream.GetBits(0, &bits)); - EXPECT_EQ(bits, 0); - EXPECT_TRUE(stream.GetBits(32, &bits)); - EXPECT_EQ(bits, k40Bits & 0xFFFFFFFF); - EXPECT_TRUE(stream.GetBits(0, &bits)); - EXPECT_EQ(bits, 0); - EXPECT_EQ(stream.Bits(), 0); - } -} - -TEST(BitStream, Encode) { - { - BitStream<uint64_t> stream; - - stream.PutBits(0, 1); - stream.PutBits(0b11, 2); - EXPECT_EQ(stream.Bits(), 3); - - uint64_t bits = 0; - EXPECT_TRUE(stream.GetBits(3, &bits)); - EXPECT_EQ(bits, 0b110); - } - - { - BitStream<uint64_t> stream; - - uint64_t bits = 0; - stream.PutBits(kAllBits, 64); - EXPECT_EQ(stream.Bits(), 64); - - EXPECT_TRUE(stream.GetBits(64, &bits)); - EXPECT_EQ(bits, kAllBits); - EXPECT_EQ(stream.Bits(), 0); - } - - { - BitStream<uint64_t> stream; - stream.PutBits(kAllBits, 40); - - uint64_t bits = 0; - EXPECT_TRUE(stream.GetBits(40, &bits)); - EXPECT_EQ(bits, k40Bits); - EXPECT_EQ(stream.Bits(), 0); - } - - { - BitStream<uint64_t> stream; - stream.PutBits(0, 0); - stream.PutBits(kAllBits, 32); - stream.PutBits(0, 0); - - uint64_t bits = 0; - EXPECT_TRUE(stream.GetBits(32, &bits)); - EXPECT_EQ(bits, k40Bits & 0xFFFFFFFF); - EXPECT_EQ(stream.Bits(), 0); - } -} - -} // namespace base -} // namespace astc_codec diff --git a/third-party/astc-codec/src/base/test/bottom_n_test.cpp b/third-party/astc-codec/src/base/test/bottom_n_test.cpp deleted file mode 100644 index 71265d75..00000000 --- a/third-party/astc-codec/src/base/test/bottom_n_test.cpp +++ /dev/null @@ -1,108 +0,0 @@ -// Copyright 2018 Google LLC -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// https://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -#include "src/base/bottom_n.h" - -#include <gmock/gmock.h> -#include <gtest/gtest.h> - -namespace astc_codec { -namespace base { - -using ::testing::ElementsAre; - -template<typename T, size_t N> -static void pushAll(BottomN<T>& heap, const T (&arr)[N]) { - for (auto i : arr) { - heap.Push(i); - } -} - -TEST(BottomN, Sort) { - { - BottomN<int> heap(10); - EXPECT_TRUE(heap.Empty()); - int list[] = { 1,2 }; - pushAll(heap, list); - - EXPECT_EQ(heap.Size(), 2); - EXPECT_FALSE(heap.Empty()); - EXPECT_THAT(heap.Pop(), ElementsAre(1, 2)); - } - - { - BottomN<int> heap(6); - int list[] = {1, 4, 3, 2, 2, 1}; - pushAll(heap, list); - - EXPECT_EQ(heap.Size(), 6); - EXPECT_THAT(heap.Pop(), ElementsAre(1, 1, 2, 2, 3, 4)); - } -} - -TEST(BottomN, Bounds) { - { - BottomN<int> heap(4); - int list[] = { 1, 2, 3, 4 }; - pushAll(heap, list); - EXPECT_EQ(heap.Size(), 4); - - heap.Push(0); - EXPECT_EQ(heap.Size(), 4); - - EXPECT_THAT(heap.Pop(), ElementsAre(0, 1, 2, 3)); - } - - { - BottomN<int> heap(4); - int list[] = { 4, 3, 2,1 }; - pushAll(heap, list); - EXPECT_EQ(heap.Size(), 4); - - int list2[] = { 4,4,4,4 }; - pushAll(heap, list2); - EXPECT_EQ(heap.Size(), 4); - - EXPECT_THAT(heap.Pop(), ElementsAre(1, 2, 3, 4)); - } - - { - BottomN<int> heap(4); - int list[] = { 4, 3, 2, 1 }; - pushAll(heap, list); - EXPECT_EQ(heap.Size(), 4); - - int list2[] = { 5, 5, 5, 5 }; - pushAll(heap, list2); - EXPECT_EQ(heap.Size(), 4); - - EXPECT_THAT(heap.Pop(), ElementsAre(1, 2, 3, 4)); - } - - { - BottomN<int> heap(4); - int list[] = { 4, 3, 2, 1 }; - pushAll(heap, list); - EXPECT_EQ(heap.Size(), 4); - - int list2[] = { 0, 0, 0, 0 }; - pushAll(heap, list2); - EXPECT_EQ(heap.Size(), 4); - - EXPECT_THAT(heap.Pop(), ElementsAre(0, 0, 0, 0)); - } -} - -} // namespace base -} // namespace astc_codec diff --git a/third-party/astc-codec/src/base/test/math_utils_test.cpp b/third-party/astc-codec/src/base/test/math_utils_test.cpp deleted file mode 100644 index 0371e118..00000000 --- a/third-party/astc-codec/src/base/test/math_utils_test.cpp +++ /dev/null @@ -1,78 +0,0 @@ -// Copyright 2018 Google LLC -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// https://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -#include "src/base/math_utils.h" - -#include <gtest/gtest.h> - -namespace astc_codec { -namespace base { - -TEST(MathUtils, Log2Floor) { - EXPECT_EQ(-1, Log2Floor(0)); - - for (int i = 0; i < 32; i++) { - uint32_t n = 1U << i; - EXPECT_EQ(i, Log2Floor(n)); - if (n > 2) { - EXPECT_EQ(i - 1, Log2Floor(n - 1)); - EXPECT_EQ(i, Log2Floor(n + 1)); - } - } -} - -TEST(MathUtils, CountOnes) { - EXPECT_EQ(0, CountOnes(0)); - EXPECT_EQ(1, CountOnes(1)); - EXPECT_EQ(32, CountOnes(static_cast<uint32_t>(~0U))); - EXPECT_EQ(1, CountOnes(0x8000000)); - - for (int i = 0; i < 32; i++) { - EXPECT_EQ(1, CountOnes(1U << i)); - EXPECT_EQ(31, CountOnes(static_cast<uint32_t>(~0U) ^ (1U << i))); - } -} - -TEST(MathUtils, ReverseBits) { - EXPECT_EQ(ReverseBits(0u), 0u); - EXPECT_EQ(ReverseBits(1u), 1u << 31); - EXPECT_EQ(ReverseBits(0xffffffff), 0xffffffff); - EXPECT_EQ(ReverseBits(0x00000001), 0x80000000); - EXPECT_EQ(ReverseBits(0x80000000), 0x00000001); - EXPECT_EQ(ReverseBits(0xaaaaaaaa), 0x55555555); - EXPECT_EQ(ReverseBits(0x55555555), 0xaaaaaaaa); - EXPECT_EQ(ReverseBits(0x7d5d7f53), 0xcafebabe); - EXPECT_EQ(ReverseBits(0xcafebabe), 0x7d5d7f53); -} - -TEST(MathUtils, GetBits) { - EXPECT_EQ(GetBits(0u, 0, 1), 0u); - EXPECT_EQ(GetBits(0u, 0, 32), 0u); - EXPECT_EQ(GetBits(0x00000001u, 0, 1), 0x00000001); - EXPECT_EQ(GetBits(0x00000001u, 0, 32), 0x00000001); - EXPECT_EQ(GetBits(0x00000001u, 1, 31), 0x00000000); - EXPECT_EQ(GetBits(0x00000001u, 31, 1), 0x00000000); - - EXPECT_DEBUG_DEATH(GetBits(0x00000000u, 1, 32), ""); - EXPECT_DEBUG_DEATH(GetBits(0x00000000u, 32, 0), ""); - EXPECT_DEBUG_DEATH(GetBits(0x00000000u, 32, 1), ""); - - EXPECT_EQ(GetBits(0XFFFFFFFFu, 0, 4), 0x0000000F); - EXPECT_EQ(GetBits(0XFFFFFFFFu, 16, 16), 0xFFFF); - EXPECT_EQ(GetBits(0x80000000u, 31, 1), 1); - EXPECT_EQ(GetBits(0xCAFEBABEu, 24, 8), 0xCA); -} - -} // namespace base -} // namespace astc_codec diff --git a/third-party/astc-codec/src/base/test/optional_test.cpp b/third-party/astc-codec/src/base/test/optional_test.cpp deleted file mode 100644 index 1eeefbdf..00000000 --- a/third-party/astc-codec/src/base/test/optional_test.cpp +++ /dev/null @@ -1,481 +0,0 @@ -// Copyright 2018 Google LLC -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// https://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -#include "src/base/optional.h" - -#include <gtest/gtest.h> - -#include <memory> -#include <vector> - -namespace astc_codec { -namespace base { - -TEST(Optional, TypeProperties) { - // Making sure optional has the correct alignment and doesn't waste too much - // space - - static_assert(sizeof(Optional<bool>) == 2, "bad Optional<bool> size"); - static_assert(std::alignment_of<Optional<bool>>::value == - std::alignment_of<bool>::value, - "bad Optional<bool> alignment"); - - static_assert(sizeof(Optional<char>) == 2, "bad Optional<char> size"); - static_assert(std::alignment_of<Optional<char>>::value == - std::alignment_of<char>::value, - "bad Optional<char> alignment"); - - static_assert(sizeof(Optional<int16_t>) == 4, "bad Optional<int16_t> size"); - static_assert(std::alignment_of<Optional<int16_t>>::value == - std::alignment_of<int16_t>::value, - "bad Optional<int16_t> alignment"); - - static_assert(sizeof(Optional<int32_t>) == 8, "bad Optional<int32_t> size"); - static_assert(std::alignment_of<Optional<int32_t>>::value == - std::alignment_of<int32_t>::value, - "bad Optional<int32_t> alignment"); - - static_assert(sizeof(Optional<int64_t>) == 16, "bad Optional<int64_t> size"); - static_assert(std::alignment_of<Optional<int64_t>>::value == - std::alignment_of<int64_t>::value, - "bad Optional<int64_t> alignment"); - - struct S128 { - int64_t data[2]; - }; - - static_assert(sizeof(Optional<S128>) == 3 * sizeof(int64_t), - "bad Optional<S128> size"); - static_assert(std::alignment_of<Optional<S128>>::value == - std::alignment_of<S128>::value, - "bad Optional<S128> alignment"); -} - -TEST(Optional, ConstructFromValue) { - { - Optional<int> o; - EXPECT_FALSE(o); - } - { - Optional<int> o = {}; - EXPECT_FALSE(o); - } - { - Optional<int> o = kNullopt; - EXPECT_FALSE(o); - } - { - Optional<int> o(1); - EXPECT_TRUE(o); - EXPECT_EQ(1, *o); - } - { - // check the std::decay<> constructor - Optional<int> o = static_cast<const short&>(1); - EXPECT_TRUE(o); - EXPECT_EQ(1, *o); - } - { - Optional<int> o = 1; - EXPECT_TRUE(o); - EXPECT_EQ(1, *o); - } - { - Optional<int> o{1}; - EXPECT_TRUE(o); - EXPECT_EQ(1, *o); - } - { - short val = 10; - Optional<int> o = val; - EXPECT_TRUE(o); - EXPECT_EQ(10, *o); - } - { - Optional<std::vector<int>> o(kInplace, 10); - EXPECT_TRUE(o); - EXPECT_EQ((std::vector<int>(10)), *o); - } - { - Optional<std::vector<int>> o(kInplace, {1, 2, 3, 4}); - EXPECT_TRUE(o); - EXPECT_EQ((std::vector<int>{1, 2, 3, 4}), *o); - } -} - -TEST(Optional, ConstructFromOptional) { - { - Optional<int> o = Optional<int>(); - EXPECT_FALSE(o); - } - { - Optional<short> o2; - Optional<int> o(o2); - EXPECT_FALSE(o); - } - { - Optional<short> o2 = 42; - Optional<int> o(o2); - EXPECT_TRUE(o); - EXPECT_EQ(42, *o); - } - { - Optional<int> o(Optional<int>(1)); - EXPECT_TRUE(o); - EXPECT_EQ(1, *o); - } - { - Optional<int> o2 = 2; - Optional<int> o = o2; - EXPECT_TRUE(o); - EXPECT_EQ(2, *o); - } - { - Optional<std::vector<int>> o2 = std::vector<int>{20, 30, 40}; - Optional<std::vector<int>> o = o2; - EXPECT_TRUE(o); - EXPECT_EQ((std::vector<int>{20, 30, 40}), *o); - } -} - -TEST(Optional, Assign) { - { - Optional<int> o; - o = 1; - EXPECT_TRUE(o); - EXPECT_EQ(1, *o); - - o = 2; - EXPECT_TRUE(o); - EXPECT_EQ(2, *o); - - o = kNullopt; - EXPECT_FALSE(o); - - o = Optional<int>(10); - EXPECT_TRUE(o); - EXPECT_EQ(10, *o); - - Optional<int> o2; - o = o2; - EXPECT_FALSE(o); - - o = 2u; - EXPECT_TRUE(o); - EXPECT_EQ(2, *o); - - o = Optional<short>(); - EXPECT_FALSE(o); - - o = Optional<short>(20); - EXPECT_TRUE(o); - EXPECT_EQ(20, *o); - - Optional<short> o3(200); - o = o3; - EXPECT_TRUE(o); - EXPECT_EQ(200, *o); - - o = {}; - EXPECT_FALSE(o); - - // check the std::decay<> assignment - o = static_cast<const short&>(1); - EXPECT_TRUE(o); - EXPECT_EQ(1, *o); - } -} - -TEST(Optional, MakeOptional) { - { - auto o = makeOptional(1); - static_assert(std::is_same<decltype(o), Optional<int>>::value, - "Bad type deduction in makeOptional()"); - EXPECT_TRUE(o); - EXPECT_EQ(1, *o); - } - { - auto o = makeOptional(std::vector<char>{'1', '2'}); - static_assert(std::is_same<decltype(o), Optional<std::vector<char>>>::value, - "Bad type deduction in makeOptional()"); - EXPECT_TRUE(o); - EXPECT_EQ((std::vector<char>{'1', '2'}), *o); - } - { - // check std::decay<> in the factory function - auto o = makeOptional("String"); - static_assert(std::is_same<decltype(o), Optional<const char*>>::value, - "Bad type deduction in makeOptional()"); - EXPECT_TRUE(o); - EXPECT_STREQ("String", *o); - } - { - auto o = makeOptional<std::string>("String"); - static_assert(std::is_same<decltype(o), Optional<std::string>>::value, - "Bad type deduction in makeOptional()"); - EXPECT_TRUE(o); - EXPECT_STREQ("String", o->c_str()); - } - { - auto o = makeOptional<std::string>(5, 'b'); - static_assert(std::is_same<decltype(o), Optional<std::string>>::value, - "Bad type deduction in makeOptional()"); - EXPECT_TRUE(o); - EXPECT_STREQ("bbbbb", o->c_str()); - } - { - auto o = makeOptional<std::string>(); - static_assert(std::is_same<decltype(o), Optional<std::string>>::value, - "Bad type deduction in makeOptional()"); - EXPECT_TRUE(o); - EXPECT_STREQ("", o->c_str()); - } -} - -TEST(Optional, Move) { - auto o = makeOptional(std::unique_ptr<int>(new int(10))); - { - decltype(o) o2 = std::move(o); - EXPECT_TRUE(o); - EXPECT_TRUE(o2); - EXPECT_FALSE(bool(*o)); - EXPECT_TRUE(bool(*o2)); - EXPECT_EQ(10, **o2); - - decltype(o) o3; - o3 = std::move(o2); - EXPECT_TRUE(o2); - EXPECT_TRUE(o3); - EXPECT_FALSE(bool(*o2)); - EXPECT_TRUE(bool(*o3)); - EXPECT_EQ(10, **o3); - - o3 = std::move(o2); - EXPECT_TRUE(o2); - EXPECT_TRUE(o3); - EXPECT_FALSE(bool(*o2)); - EXPECT_FALSE(bool(*o3)); - } - - { - decltype(o) o1; - decltype(o) o2 = std::move(o1); - EXPECT_FALSE(o1); - EXPECT_FALSE(o2); - - o2 = std::move(o1); - EXPECT_FALSE(o1); - EXPECT_FALSE(o2); - - decltype(o) o3{kInplace, new int(20)}; - o3 = std::move(o1); - EXPECT_FALSE(o1); - EXPECT_FALSE(o3); - } -} - -TEST(Optional, Value) { - auto o = makeOptional(1); - EXPECT_EQ(1, o.value()); - EXPECT_EQ(1, o.valueOr(2)); - - o = kNullopt; - EXPECT_EQ(2, o.valueOr(2)); -} - -TEST(Optional, Clear) { - auto o = makeOptional(1); - o.clear(); - EXPECT_FALSE(o); - - o.clear(); - EXPECT_FALSE(o); -} - -TEST(Optional, Emplace) { - auto o = makeOptional(std::vector<int>{1, 2, 3, 4}); - o.emplace(3, 1); - EXPECT_TRUE(o); - EXPECT_EQ((std::vector<int>{1, 1, 1}), *o); - EXPECT_EQ(3U, o->capacity()); - - o.clear(); - o.emplace({1, 2}); - EXPECT_TRUE(o); - EXPECT_EQ((std::vector<int>{1, 2}), *o); - EXPECT_EQ(2U, o->capacity()); -} - -TEST(Optional, Reset) { - auto o = makeOptional(std::vector<int>{1, 2, 3, 4}); - o.reset(std::vector<int>{4, 3}); - EXPECT_TRUE(o); - EXPECT_EQ((std::vector<int>{4, 3}), *o); - EXPECT_EQ(2U, o->capacity()); - - o.clear(); - o.reset(std::vector<int>{1}); - EXPECT_EQ((std::vector<int>{1}), *o); - EXPECT_EQ(1U, o->capacity()); -} - -TEST(Optional, CompareEqual) { - EXPECT_TRUE(makeOptional(1) == makeOptional(1)); - EXPECT_TRUE(makeOptional(1) == 1); - EXPECT_TRUE(1 == makeOptional(1)); - EXPECT_FALSE(makeOptional(1) == makeOptional(2)); - EXPECT_FALSE(makeOptional(2) == 1); - EXPECT_FALSE(2 == makeOptional(1)); - EXPECT_TRUE(makeOptional(1) != makeOptional(2)); - EXPECT_TRUE(makeOptional(1) != 2); - EXPECT_TRUE(1 != makeOptional(2)); - - EXPECT_FALSE(makeOptional(1) == kNullopt); - EXPECT_FALSE(makeOptional(1) == Optional<int>()); - EXPECT_FALSE(kNullopt == makeOptional(1)); - EXPECT_FALSE(Optional<int>() == makeOptional(1)); - EXPECT_TRUE(makeOptional(1) != kNullopt); - EXPECT_TRUE(makeOptional(1) != Optional<int>()); - EXPECT_TRUE(kNullopt != makeOptional(1)); - EXPECT_TRUE(Optional<int>() != makeOptional(1)); - - EXPECT_TRUE(kNullopt == Optional<int>()); - EXPECT_TRUE(kNullopt == Optional<char*>()); - EXPECT_FALSE(kNullopt != Optional<int>()); - EXPECT_FALSE(kNullopt != Optional<char*>()); - EXPECT_TRUE(Optional<int>() == Optional<int>()); - EXPECT_FALSE(Optional<int>() != Optional<int>()); -} - -TEST(Optional, CompareLess) { - EXPECT_TRUE(makeOptional(1) < makeOptional(2)); - EXPECT_TRUE(1 < makeOptional(2)); - EXPECT_TRUE(makeOptional(1) < 2); - - EXPECT_FALSE(makeOptional(1) < makeOptional(1)); - EXPECT_FALSE(1 < makeOptional(1)); - EXPECT_FALSE(makeOptional(1) < 1); - EXPECT_FALSE(makeOptional(2) < makeOptional(1)); - EXPECT_FALSE(2 < makeOptional(1)); - EXPECT_FALSE(makeOptional(2) < 1); - - EXPECT_TRUE(kNullopt < makeOptional(2)); - EXPECT_TRUE(Optional<int>() < makeOptional(2)); - EXPECT_TRUE(Optional<int>() < 2); - EXPECT_FALSE(makeOptional(2) < kNullopt); - EXPECT_FALSE(makeOptional(2) < Optional<int>()); - EXPECT_FALSE(2 < Optional<int>()); - - EXPECT_FALSE(kNullopt < Optional<int>()); - EXPECT_FALSE(Optional<int>() < kNullopt); -} - -TEST(Optional, Destruction) { - // create a reference counting class to check if we delete everything - // we've created - struct Track { - Track(int& val) : mVal(val) { ++mVal.get(); } - Track(std::initializer_list<int*> vals) : mVal(**vals.begin()) { - ++mVal.get(); - } - Track(const Track& other) : mVal(other.mVal) { ++mVal.get(); } - Track(Track&& other) : mVal(other.mVal) { ++mVal.get(); } - Track& operator=(const Track& other) { - --mVal.get(); - mVal = other.mVal; - ++mVal.get(); - return *this; - } - Track& operator=(Track&& other) { - --mVal.get(); - mVal = other.mVal; - ++mVal.get(); - return *this; - } - - ~Track() { --mVal.get(); } - - std::reference_wrapper<int> mVal; - }; - - int counter = 0; - { - auto o = makeOptional(Track(counter)); - EXPECT_EQ(1, counter); - } - EXPECT_EQ(0, counter); - - { - auto o = makeOptional(Track(counter)); - EXPECT_EQ(1, counter); - o.clear(); - EXPECT_EQ(0, counter); - } - EXPECT_EQ(0, counter); - - { - auto o = makeOptional(Track(counter)); - EXPECT_EQ(1, counter); - int counter2 = 0; - o.emplace(counter2); - EXPECT_EQ(0, counter); - EXPECT_EQ(1, counter2); - o = Track(counter); - EXPECT_EQ(1, counter); - EXPECT_EQ(0, counter2); - - auto o2 = o; - EXPECT_EQ(2, counter); - EXPECT_EQ(0, counter2); - } - EXPECT_EQ(0, counter); - - { - auto o = makeOptional(Track(counter)); - auto o2 = std::move(o); - EXPECT_EQ(2, counter); - o = o2; - EXPECT_EQ(2, counter); - } - EXPECT_EQ(0, counter); - - int counter2 = 0; - { - Optional<Track> o; - o.emplace(counter); - EXPECT_EQ(1, counter); - - o.emplace(counter2); - EXPECT_EQ(0, counter); - EXPECT_EQ(1, counter2); - } - EXPECT_EQ(0, counter); - EXPECT_EQ(0, counter2); - - { - Optional<Track> o; - o.emplace({&counter}); - EXPECT_EQ(1, counter); - - counter2 = 0; - o.emplace({&counter2}); - EXPECT_EQ(0, counter); - EXPECT_EQ(1, counter2); - } - EXPECT_EQ(0, counter); - EXPECT_EQ(0, counter2); -} - -} // namespace base -} // namespace astc_codec diff --git a/third-party/astc-codec/src/base/test/string_utils_test.cpp b/third-party/astc-codec/src/base/test/string_utils_test.cpp deleted file mode 100644 index 209da54d..00000000 --- a/third-party/astc-codec/src/base/test/string_utils_test.cpp +++ /dev/null @@ -1,110 +0,0 @@ -// Copyright 2018 Google LLC -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// https://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -#include "src/base/string_utils.h" - -#include <gtest/gtest.h> - -#include <list> -#include <string> -#include <vector> - -namespace astc_codec { -namespace base { - -TEST(StringUtils, Split) { - std::vector<std::string> results; - - auto testFunc = [&results](std::string&& s) { - results.push_back(std::move(s)); - }; - - Split("", "abc", testFunc); - EXPECT_EQ(results.size(), 1); - - Split("abc", "", testFunc); - EXPECT_EQ(results.size(), 1); - - results.clear(); - Split("abc", "a", testFunc); - EXPECT_EQ(results.size(), 2); - EXPECT_EQ(results[0], ""); - EXPECT_EQ(results[1], "bc"); - - results.clear(); - Split("aaa", "a", testFunc); - EXPECT_EQ(4, results.size()); - EXPECT_EQ("", results[0]); - EXPECT_EQ("", results[1]); - EXPECT_EQ("", results[2]); - EXPECT_EQ("", results[3]); - - results.clear(); - Split("1a2a3a4", "a", testFunc); - EXPECT_EQ(4, results.size()); - EXPECT_EQ("1", results[0]); - EXPECT_EQ("2", results[1]); - EXPECT_EQ("3", results[2]); - EXPECT_EQ("4", results[3]); - - results.clear(); - Split("1a2aa3a4", "a", testFunc); - EXPECT_EQ(5, results.size()); - EXPECT_EQ("1", results[0]); - EXPECT_EQ("2", results[1]); - EXPECT_EQ("", results[2]); - EXPECT_EQ("3", results[3]); - EXPECT_EQ("4", results[4]); - - results.clear(); - Split("The quick brown fox jumped over the lazy dog", - " ", testFunc); - EXPECT_EQ(9, results.size()); - EXPECT_EQ("The", results[0]); - EXPECT_EQ("quick", results[1]); - EXPECT_EQ("brown", results[2]); - EXPECT_EQ("fox", results[3]); - EXPECT_EQ("jumped", results[4]); - EXPECT_EQ("over", results[5]); - EXPECT_EQ("the", results[6]); - EXPECT_EQ("lazy", results[7]); - EXPECT_EQ("dog", results[8]); - - results.clear(); - Split("a; b; c; d", "; ", testFunc); - EXPECT_EQ(4, results.size()); - EXPECT_EQ("a", results[0]); - EXPECT_EQ("b", results[1]); - EXPECT_EQ("c", results[2]); - EXPECT_EQ("d", results[3]); -} - -TEST(StringUtils, ParseInt32) { - EXPECT_EQ(ParseInt32("0", -1), 0); - EXPECT_EQ(ParseInt32("100", -1), 100); - EXPECT_EQ(ParseInt32("-100", -1), -100); - - EXPECT_EQ(ParseInt32("", -1), -1); - EXPECT_EQ(ParseInt32("a", -1), -1); - EXPECT_EQ(ParseInt32("10x1", -1), 10); - - EXPECT_EQ(ParseInt32("2147483647", -1), 2147483647); - EXPECT_EQ(ParseInt32("2147483648", -1), 2147483647); - - EXPECT_EQ(ParseInt32("-2147483648", -1), -2147483648); - EXPECT_EQ(ParseInt32("-2147483649", -1), -2147483648); -} - -} // namespace base -} // namespace astc_codec diff --git a/third-party/astc-codec/src/base/test/type_traits_test.cpp b/third-party/astc-codec/src/base/test/type_traits_test.cpp deleted file mode 100644 index c724cbe7..00000000 --- a/third-party/astc-codec/src/base/test/type_traits_test.cpp +++ /dev/null @@ -1,130 +0,0 @@ -// Copyright 2018 Google LLC -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// https://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -#include "src/base/type_traits.h" - -#include <gtest/gtest.h> - -#include <array> -#include <functional> -#include <list> -#include <vector> - -namespace astc_codec { -namespace base { - -TEST(TypeTraits, IsCallable) { - class C; - C* c = nullptr; - - auto lambda = [c](bool) -> C* { return nullptr; }; - - static_assert(is_callable_as<void(), void()>::value, "simple function"); - static_assert(is_callable_as<void (&)(), void()>::value, - "function reference"); - static_assert(is_callable_as<void (*)(), void()>::value, "function pointer"); - static_assert(is_callable_as<int(C&, C*), int(C&, C*)>::value, - "function with arguments and return type"); - static_assert(is_callable_as<decltype(lambda), C*(bool)>::value, "lambda"); - static_assert(is_callable_as<std::function<bool(int)>, bool(int)>::value, - "std::function"); - - static_assert(!is_callable_as<int, void()>::value, - "int should not be callable"); - static_assert(!is_callable_as<C, void()>::value, "incomplete type"); - static_assert(!is_callable_as<void(), void(int)>::value, - "different arguments"); - static_assert(!is_callable_as<int(), void()>::value, - "different return types"); - static_assert(!is_callable_as<int(), short()>::value, - "slightly different return types"); - static_assert(!is_callable_as<int(int), int(int, int)>::value, - "more arguments"); - static_assert(!is_callable_as<int(int, int), int(int)>::value, - "less arguments"); - - static_assert(!is_callable_as<int(int), int>::value, - "bad required signature"); - - static_assert(is_callable_with_args<void(), void()>::value, - "simple function"); - static_assert(is_callable_with_args<void (&)(), void()>::value, - "function reference"); - static_assert(is_callable_with_args<void (*)(), void()>::value, - "function pointer"); - static_assert(is_callable_with_args<int(C&, C*), int(C&, C*)>::value, - "function with arguments and return type"); - static_assert(is_callable_with_args<decltype(lambda), C*(bool)>::value, - "lambda"); - static_assert( - is_callable_with_args<std::function<bool(int)>, bool(int)>::value, - "std::function"); - - static_assert(!is_callable_with_args<int, void()>::value, - "int should not be callable"); - static_assert(!is_callable_with_args<C, void()>::value, "incomplete type"); - static_assert(!is_callable_with_args<void(), void(int)>::value, - "different arguments"); - static_assert(is_callable_with_args<int(), void()>::value, - "different return types are ignored"); - static_assert(is_callable_with_args<int(), short()>::value, - "slightly different return types are ignored"); - static_assert(!is_callable_with_args<int(int), int(int, int)>::value, - "more arguments"); - static_assert(!is_callable_with_args<int(int, int), int(int)>::value, - "less arguments"); - - static_assert(!is_callable_with_args<int(int), int>::value, - "bad required signature"); -} - -TEST(TypeTraits, IsTemplateInstantiation) { - static_assert(!is_template_instantiation_of<int, std::vector>::value, - "int is not an instance of vector"); - static_assert(!is_template_instantiation_of<std::list<std::vector<int>>, - std::vector>::value, - "list is not an instance of vector"); - - static_assert( - is_template_instantiation_of<std::vector<int>, std::vector>::value, - "std::vector<int> is an instance of vector"); - static_assert( - is_template_instantiation_of<std::vector<std::vector<std::vector<int>>>, - std::vector>::value, - "nested std::vector<> is an instance of vector"); -} - -#ifndef _MSC_VER -TEST(TypeTraits, IsRange) { - static_assert(is_range<std::vector<int>>::value, - "vector<> should be detected as a range"); - static_assert(is_range<const std::list<std::function<void()>>>::value, - "const list<> should be detected as a range"); - static_assert(is_range<std::array<std::vector<int>, 10>>::value, - "array<> should be detected as a range"); - char arr[100]; - static_assert(is_range<decltype(arr)>::value, - "C array should be detected as a range"); - static_assert(is_range<decltype("string")>::value, - "String literal should be detected as a range"); - - static_assert(!is_range<int>::value, "int shouldn't be a range"); - static_assert(!is_range<int*>::value, "int* shouldn't be a range"); - static_assert(!is_range<const int*>::value, - "even const int* shouldn't be a range"); -} -#endif - -} // namespace base -} // namespace astc_codec diff --git a/third-party/astc-codec/src/base/test/uint128_test.cpp b/third-party/astc-codec/src/base/test/uint128_test.cpp deleted file mode 100644 index 0a52244c..00000000 --- a/third-party/astc-codec/src/base/test/uint128_test.cpp +++ /dev/null @@ -1,140 +0,0 @@ -// Copyright 2018 Google LLC -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// https://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -#include "src/base/uint128.h" - -#include <gtest/gtest.h> - -namespace astc_codec { -namespace base { - -TEST(UInt128, Equality) { - const UInt128 zero(0); - const UInt128 max64(~0ULL); - - EXPECT_EQ(zero, zero); - EXPECT_NE(zero, max64); - EXPECT_EQ(zero, UInt128(0)); - EXPECT_NE(zero, UInt128(1)); - EXPECT_EQ(max64, max64); -} - -TEST(UInt128, Shifting) { - const UInt128 max64(~0ULL); - const UInt128 upper64(~0ULL, 0); - EXPECT_EQ(upper64.HighBits(), ~0ULL); - EXPECT_EQ(upper64.LowBits(), 0); - - EXPECT_EQ(upper64 >> 64, max64); - - EXPECT_EQ(UInt128(1) << 1, UInt128(2)); - EXPECT_EQ(UInt128(0) << 0, UInt128(0)); - EXPECT_EQ(max64 << 0, max64); - EXPECT_EQ(max64 >> 0, max64); - EXPECT_EQ(upper64 << 0, upper64); - EXPECT_EQ(upper64 >> 0, upper64); - - { - const UInt128 bit63 = UInt128(1ULL << 62) << 1; - EXPECT_EQ(bit63.LowBits(), 1ULL << 63); - EXPECT_EQ(bit63.HighBits(), 0); - } - - { - const UInt128 bit64 = UInt128(1ULL << 63) << 1; - EXPECT_EQ(bit64.LowBits(), 0); - EXPECT_EQ(bit64.HighBits(), 1); - EXPECT_EQ(bit64 >> 1, UInt128(1ULL << 63)); - } - - { - const UInt128 overshift = max64 << 128; - EXPECT_EQ(overshift.HighBits(), 0); - EXPECT_EQ(overshift.LowBits(), 0); - } - - { - const UInt128 overlap = upper64 >> 32; - EXPECT_EQ(overlap.HighBits(), 0x00000000FFFFFFFF); - EXPECT_EQ(overlap.LowBits(), 0xFFFFFFFF00000000); - } - - { - const UInt128 overlap = max64 << 32; - EXPECT_EQ(overlap.HighBits(), 0x00000000FFFFFFFF); - EXPECT_EQ(overlap.LowBits(), 0xFFFFFFFF00000000); - } -} - -TEST(UInt128, LargeShift) { - const UInt128 base(0xFF); - EXPECT_EQ(base << 64, UInt128(0xFFULL, 0)); - EXPECT_EQ(base << 72, UInt128(0xFF00ULL, 0)); - EXPECT_EQ(base << 80, UInt128(0xFF0000ULL, 0)); - EXPECT_EQ(base << 88, UInt128(0xFF000000ULL, 0)); - EXPECT_EQ(base << 96, UInt128(0xFF00000000ULL, 0)); - EXPECT_EQ(base << 104, UInt128(0xFF0000000000ULL, 0)); - EXPECT_EQ(base << 112, UInt128(0xFF000000000000ULL, 0)); - EXPECT_EQ(base << 120, UInt128(0xFF00000000000000ULL, 0)); - - const UInt128 upper(0xFF00000000000000ULL, 0); - EXPECT_EQ(upper >> 64, UInt128(0, 0xFF00000000000000ULL)); - EXPECT_EQ(upper >> 72, UInt128(0, 0xFF000000000000ULL)); - EXPECT_EQ(upper >> 80, UInt128(0, 0xFF0000000000ULL)); - EXPECT_EQ(upper >> 88, UInt128(0, 0xFF00000000ULL)); - EXPECT_EQ(upper >> 96, UInt128(0, 0xFF000000ULL)); - EXPECT_EQ(upper >> 104, UInt128(0, 0xFF0000ULL)); - EXPECT_EQ(upper >> 112, UInt128(0, 0xFF00ULL)); - EXPECT_EQ(upper >> 120, UInt128(0, 0xFFULL)); -} - -TEST(UInt128, BooleanOperators) { - const UInt128 allOnes(~0ULL, ~0ULL); - EXPECT_EQ(allOnes.HighBits(), ~0ULL); - EXPECT_EQ(allOnes.LowBits(), ~0ULL); - - EXPECT_EQ(~allOnes, UInt128(0)); - EXPECT_EQ(~UInt128(0), allOnes); - - EXPECT_EQ(UInt128(0xFFFF00) & UInt128(0x00FFFF), UInt128(0x00FF00)); - EXPECT_EQ(UInt128(0xFFFF00) | UInt128(0x00FFFF), UInt128(0xFFFFFF)); - EXPECT_EQ(UInt128(0xFFFF00) ^ UInt128(0x00FFFF), UInt128(0xFF00FF)); -} - -TEST(UInt128, Addition) { - const UInt128 bit63(1ULL << 63); - - EXPECT_EQ(UInt128(1) + 1, UInt128(2)); - EXPECT_EQ(bit63 + bit63, UInt128(1) << 64); - - const UInt128 carryUp = UInt128(~0ULL) + 1; - EXPECT_EQ(carryUp.HighBits(), 1); - EXPECT_EQ(carryUp.LowBits(), 0); - - const UInt128 allOnes(~0ULL, ~0ULL); - EXPECT_EQ(allOnes + 1, UInt128(0)); -} - -TEST(UInt128, Subtraction) { - const UInt128 bit64 = UInt128(1) << 64; - EXPECT_EQ(bit64 - 1, UInt128(~0ULL)); - - EXPECT_EQ(UInt128(1) - 1, UInt128(0)); - - const UInt128 allOnes(~0ULL, ~0ULL); - EXPECT_EQ(UInt128(0) - 1, allOnes); -} - -} // namespace base -} // namespace astc_codec diff --git a/third-party/astc-codec/src/base/type_traits.h b/third-party/astc-codec/src/base/type_traits.h deleted file mode 100644 index 917125d2..00000000 --- a/third-party/astc-codec/src/base/type_traits.h +++ /dev/null @@ -1,172 +0,0 @@ -// Copyright 2018 Google LLC -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// https://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -#ifndef ASTC_CODEC_BASE_TYPE_TRAITS_H_ -#define ASTC_CODEC_BASE_TYPE_TRAITS_H_ - -#include <iterator> -#include <type_traits> - -namespace astc_codec { -namespace base { - -namespace details { - -// a simple helper class for SFINAE below. -template<class X = void> -struct dummy { - using type = X; -}; - -} // namespace details - -// add some convenience shortcuts for an overly complex std::enable_if syntax - -// Use 'enable_if<Predicate,Type>' instead of -// 'typename std::enable_if<Predicate::value,Type>::type' -template<class Predicate, class Type = void*> -using enable_if = typename std::enable_if<Predicate::value, Type>::type; - -// Use 'enable_if_c<BooleanFlag,Type>' instead of -// 'typename std::enable_if<BooleanFlag,Type>::type' -template<bool predicate, class Type = void*> -using enable_if_c = typename std::enable_if<predicate, Type>::type; - -// Use 'enable_if_convertible<From,To,Type>' instead of -// 'typename std::enable_if<std::is_convertible<From,To>::value, Type>::type' -template<class From, class To, class Type = void*> -using enable_if_convertible = enable_if<std::is_convertible<From, To>>; - -// ----------------------------------------------------------------------------- -// A predicate for checking if some object is callable with a specific -// signature. Examples: -// -// is_callable_as<int, void()>::value == false. -// is_callable_as<strcmp, void()>::value == false. -// is_callable_as<strcmp, int(const char*, const char*)>::value == true -// -template<class F, class Signature, class X = void> -struct is_callable_as : std::false_type {}; - -// This specialization is SFINAE-d out if template arguments can't be combined -// into a call expression F(), or if the result of that call is not |R| -template<class F, class R, class... Args> -struct is_callable_as<F, R(Args...), - typename std::enable_if<std::is_same< - typename details::dummy<decltype(std::declval<F>()( - std::declval<Args>()...))>::type, - R>::value>::type> : std::true_type {}; - -// -// A similar predicate to only check arguments of the function call and ignore -// the specified return type -// -// is_callable_as<strcmp, int(const char*, const char*)>::value == true -// is_callable_as<strcmp, void(const char*, const char*)>::value == false -// is_callable_with_args<strcmp, void(const char*, const char*)>::value == true -// -template<class F, class Signature, class X = void> -struct is_callable_with_args : std::false_type {}; - -template<class F, class R, class... Args> -struct is_callable_with_args< - F, R(Args...), - typename std::enable_if< - !std::is_same<typename details::dummy<decltype( - std::declval<F>()(std::declval<Args>()...))>::type, - F>::value>::type> : std::true_type {}; - -// ----------------------------------------------------------------------------- -// Check if a type |T| is any instantiation of a template |U|. Examples: -// -// is_template_instantiation_of<int, std::vector>::value == false -// is_template_instantiation_of< -// std::list<std::vector<int>>, std::vector>::value == false -// is_template_instantiation_of<std::vector<int>, std::vector>::value == true -// is_template_instantiation_of< -// std::vector<std::vector<int>>, std::vector>::value == true -// -template<class T, template<class...> class U> -struct is_template_instantiation_of : std::false_type {}; - -template<template<class...> class U, class... Args> -struct is_template_instantiation_of<U<Args...>, U> : std::true_type {}; -// ----------------------------------------------------------------------------- - -// -// is_range<T> - check if type |T| is a range-like type. -// -// It makes sure that expressions std::begin(t) and std::end(t) are well-formed -// and those return the same type. -// -// Note: with expression SFINAE from C++14 is_range_helper<> could be renamed to -// is_range<> with no extra code. C++11 needs an extra level of enable_if<> -// to make it work when the type isn't a range. -// - -namespace details { - -template<class T> -using is_range_helper = std::is_same< - decltype(std::begin( - std::declval<typename std::add_lvalue_reference<T>::type>())), - decltype( - std::end(std::declval<typename std::add_lvalue_reference<T>::type>()))>; - -} // namespace details - -template<class T, class = void> -struct is_range : std::false_type {}; - -template<class T> -struct is_range< - T, typename std::enable_if<details::is_range_helper<T>::value>::type> - : std::true_type {}; - -//////////////////////////////////////////////////////////////////////////////// -// -// A class to incapsulate integer sequence 0, 1, ..., <num_args> -// Seq<int...> -// Useful to pass function parameters in an array/tuple to call it later. -// - -template<int...> -struct Seq {}; - -// A 'maker' class to construct Seq<int...> given only <num_args> -// value. -// MakeSeq<N, S...> works this way, e.g. -// -// MakeSeq<2> inherits MakeSeq<2 - 1, 2 - 1> == MakeSeq<1, 1> -// MakeSeq<1, 1> : MakeSeq<1 - 1, 1 - 1, 1> == MakeSeq<0, 0, 1> -// MakeSeq<0, 0, 1> == MakeSeq<0, S...> and defines |type| = Seq<0, 1> - -template<int N, int... S> -struct MakeSeq : MakeSeq<N - 1, N - 1, S...> {}; - -template<int... S> -struct MakeSeq<0, S...> { - using type = Seq<S...>; -}; - -// -// MakeSeqT alias to quickly create Seq<...>: -// MakeSeqT<3> == Seq<0, 1, 2> -template<int... S> -using MakeSeqT = typename MakeSeq<S...>::type; - -} // namespace base -} // namespace astc_codec - -#endif // ASTC_CODEC_BASE_TYPE_TRAITS_H_ diff --git a/third-party/astc-codec/src/base/uint128.h b/third-party/astc-codec/src/base/uint128.h deleted file mode 100644 index 481e4eab..00000000 --- a/third-party/astc-codec/src/base/uint128.h +++ /dev/null @@ -1,175 +0,0 @@ -// Copyright 2018 Google LLC -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// https://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -#ifndef ASTC_CODEC_BASE_UINT128_H_ -#define ASTC_CODEC_BASE_UINT128_H_ - -#include <cassert> -#include <cstdint> - -namespace astc_codec { -namespace base { - -class UInt128 { - public: - UInt128() = default; - UInt128(uint64_t low) : low_(low) { } - UInt128(uint64_t high, uint64_t low) : low_(low), high_(high) { } - UInt128(const UInt128& other) : low_(other.low_), high_(other.high_) { } - - uint64_t LowBits() const { return low_; } - uint64_t HighBits() const { return high_; } - - // Allow explicit casts to uint64_t. - explicit operator uint64_t() const { return low_; } - - // Copy operators. - UInt128& operator=(const UInt128& other) { - high_ = other.high_; - low_ = other.low_; - return *this; - } - - // Equality operators. - bool operator==(const UInt128& other) const { - return high_ == other.high_ && low_ == other.low_; - } - - bool operator!=(const UInt128& other) const { - return high_ != other.high_ || low_ != other.low_; - } - - // Shifting. - UInt128& operator<<=(int shift) { - high_ = shift >= 64 ? (shift >= 128 ? 0 : low_ << (shift - 64)) - : high_ << shift; - - if (shift > 0 && shift < 64) { - const uint64_t overlappingBits = low_ >> (64 - shift); - high_ |= overlappingBits; - } - - low_ = shift >= 64 ? 0 : low_ << shift; - return *this; - } - - UInt128 operator<<(int shift) const { - UInt128 result = *this; - result <<= shift; - return result; - } - - UInt128& operator>>=(int shift) { - low_ = shift >= 64 ? (shift >= 128 ? 0 : high_ >> (shift - 64)) - : low_ >> shift; - - if (shift > 0 && shift < 64) { - const uint64_t overlappingBits = high_ << (64 - shift); - low_ |= overlappingBits; - } - - high_ = shift >= 64 ? 0 : high_ >> shift; - - return *this; - } - - UInt128 operator>>(int shift) const { - UInt128 result = *this; - result >>= shift; - return result; - } - - // Binary operations. - UInt128& operator|=(const UInt128& other) { - high_ |= other.high_; - low_ |= other.low_; - return *this; - } - - UInt128 operator|(const UInt128& other) const { - UInt128 result = *this; - result |= other; - return result; - } - - UInt128& operator&=(const UInt128& other) { - high_ &= other.high_; - low_ &= other.low_; - return *this; - } - - UInt128 operator&(const UInt128& other) const { - UInt128 result = *this; - result &= other; - return result; - } - - UInt128& operator^=(const UInt128& other) { - high_ ^= other.high_; - low_ ^= other.low_; - return *this; - } - - UInt128 operator^(const UInt128& other) const { - UInt128 result = *this; - result ^= other; - return result; - } - - UInt128 operator~() const { - UInt128 result = *this; - result.high_ = ~high_; - result.low_ = ~low_; - return result; - } - - // Addition/subtraction. - UInt128& operator+=(const UInt128& other) { - const uint64_t carry = - (((low_ & other.low_) & 1) + (low_ >> 1) + (other.low_ >> 1)) >> 63; - high_ += other.high_ + carry; - low_ += other.low_; - return *this; - } - - UInt128 operator+(const UInt128& other) const { - UInt128 result = *this; - result += other; - return result; - } - - UInt128& operator-=(const UInt128& other) { - low_ -= other.low_; - const uint64_t carry = - (((low_ & other.low_) & 1) + (low_ >> 1) + (other.low_ >> 1)) >> 63; - high_ -= other.high_ + carry; - return *this; - } - - UInt128 operator-(const UInt128& other) const { - UInt128 result = *this; - result -= other; - return result; - } - - private: - // TODO(google): Different order for little endian. - uint64_t low_ = 0; - uint64_t high_ = 0; -}; - -} // namespace base -} // namespace astc_codec - -#endif // ASTC_CODEC_BASE_UINT128_H_ diff --git a/third-party/astc-codec/src/base/utils.h b/third-party/astc-codec/src/base/utils.h deleted file mode 100644 index 0a4fabdc..00000000 --- a/third-party/astc-codec/src/base/utils.h +++ /dev/null @@ -1,35 +0,0 @@ -// Copyright 2018 Google LLC -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// https://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -#ifndef ASTC_CODEC_BASE_UTILS_H_ -#define ASTC_CODEC_BASE_UTILS_H_ - -#include <cassert> -#include <cstdio> -#include <cstdlib> - -#ifdef NDEBUG -#define UTILS_RELEASE_ASSERT(x) \ - do { \ - const bool result = (x); \ - if (!result) { \ - fprintf(stderr, "Error: UTILS_RELEASE_ASSERT failed: %s\n", #x); \ - abort(); \ - } \ - } while (false) -#else -#define UTILS_RELEASE_ASSERT(x) assert(x) -#endif - -#endif // ASTC_CODEC_BASE_UTILS_H_ diff --git a/third-party/astc-codec/src/decoder/Android.bp b/third-party/astc-codec/src/decoder/Android.bp deleted file mode 100644 index fb5d5c0b..00000000 --- a/third-party/astc-codec/src/decoder/Android.bp +++ /dev/null @@ -1,29 +0,0 @@ -package { - // See: http://go/android-license-faq - // A large-scale-change added 'default_applicable_licenses' to import - // all of the 'license_kinds' from "device_generic_vulkan-cereal_third-party_astc-codec_license" - // to get the below license kinds: - // SPDX-license-identifier-Apache-2.0 - default_applicable_licenses: [ - "device_generic_vulkan-cereal_third-party_astc-codec_license", - ], -} - -cc_library_static { - name: "gfxstream_astc_codec", - defaults: [ "gfxstream_defaults" ], - header_libs: [ "gfxstream_astc_codec_headers" ], - srcs: [ - "footprint.cc", - "astc_file.cc", - "endpoint_codec.cc", - "integer_sequence_codec.cc", - "intermediate_astc_block.cc", - "logical_astc_block.cc", - "partition.cc", - "physical_astc_block.cc", - "quantization.cc", - "weight_infill.cc", - "codec.cc", - ], -} diff --git a/third-party/astc-codec/src/decoder/BUILD.bazel b/third-party/astc-codec/src/decoder/BUILD.bazel deleted file mode 100644 index f2fded5e..00000000 --- a/third-party/astc-codec/src/decoder/BUILD.bazel +++ /dev/null @@ -1,238 +0,0 @@ -# Copyright 2018 Google LLC -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# https://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. - -cc_library( - name = "footprint", - srcs = ["footprint.cc"], - hdrs = ["footprint.h"], - deps = [ - "//:api", - "//src/base", - ], -) - -cc_library( - name = "astc_utils", - srcs = [ - "astc_file.cc", - "endpoint_codec.cc", - "integer_sequence_codec.cc", - "intermediate_astc_block.cc", - "logical_astc_block.cc", - "partition.cc", - "physical_astc_block.cc", - "quantization.cc", - "weight_infill.cc", - ], - hdrs = [ - "astc_file.h", - "endpoint_codec.h", - "integer_sequence_codec.h", - "intermediate_astc_block.h", - "logical_astc_block.h", - "partition.h", - "physical_astc_block.h", - "quantization.h", - "types.h", - "weight_infill.h", - ], - deps = [ - ":footprint", - "//src/base", - ], -) - -cc_library( - name = "codec", - srcs = ["codec.cc"], - hdrs = ["codec.h"], - deps = [ - ":astc_utils", - ":footprint", - "//src/base", - ], - visibility = ["//:__pkg__"], -) - -cc_binary( - name = "astc_inspector_cli", - srcs = ["tools/astc_inspector_cli.cc"], - deps = [ - ":astc_utils", - "//src/base", - ], -) - -################################################################################ -## -## Testing -## -################################################################################ - -cc_library( - name = "test", - hdrs = ["test/image_utils.h"], - deps = [ - "@gtest//:gtest_main", - ], -) - -cc_test( - name = "physical_astc_block_test", - size = "small", - srcs = ["test/physical_astc_block_test.cc"], - deps = [ - ":astc_utils", - "@gtest//:gtest_main", - ], -) - -cc_test( - name = "partition_test", - size = "small", - srcs = ["test/partition_test.cc"], - deps = [ - ":astc_utils", - "@gtest//:gtest_main", - ], -) - -cc_test( - name = "integer_sequence_codec_test", - size = "small", - srcs = ["test/integer_sequence_codec_test.cc"], - deps = [ - ":astc_utils", - "@gtest//:gtest_main", - ], -) - -cc_test( - name = "intermediate_astc_block_test", - size = "small", - srcs = ["test/intermediate_astc_block_test.cc"], - data = glob([ - "testdata/checkered_*.astc", - ]), - deps = [ - ":astc_utils", - ":test", - "@gtest//:gtest_main", - ], -) - -cc_test( - name = "quantization_test", - size = "medium", - srcs = ["test/quantization_test.cc"], - deps = [ - ":astc_utils", - "@gtest//:gtest_main", - ], -) - -cc_test( - name = "weight_infill_test", - size = "small", - srcs = ["test/weight_infill_test.cc"], - deps = [ - ":astc_utils", - ":footprint", - "@gtest//:gtest_main", - ], -) - -cc_test( - name = "endpoint_codec_test", - size = "small", - srcs = ["test/endpoint_codec_test.cc"], - data = [ - ":testdata/checkerboard.astc", - ], - deps = [ - ":astc_utils", - ":test", - "@gtest//:gtest_main", - ], -) - -cc_test( - name = "logical_astc_block_test", - size = "large", - srcs = ["test/logical_astc_block_test.cc"], - data = glob([ - "testdata/atlas_small_*.astc", - "testdata/atlas_small_*.bmp", - "testdata/footprint_*.astc", - "testdata/footprint_*.bmp", - "testdata/rgb_*.astc", - "testdata/rgb_*.bmp", - ]), - deps = [ - ":test", - ":astc_utils", - "@gtest//:gtest_main", - ], -) - -cc_test( - name = "codec_test", - size = "large", - srcs = ["test/codec_test.cc"], - data = glob([ - "testdata/atlas_small_*.astc", - "testdata/atlas_small_*.bmp", - ]), - deps = [ - ":test", - ":codec", - "@gtest//:gtest_main", - ], -) - -cc_test( - name = "footprint_test", - size = "small", - srcs = ["test/footprint_test.cc"], - deps = [ - ":footprint", - "@gtest//:gtest_main", - ], -) - -cc_test( - name = "astc_fuzzer", - srcs = ["test/astc_fuzzer.cc"], - copts = select({ - # Clang-only flags. TODO: Find a better way to detect GCC/clang. - "@bazel_tools//src/conditions:darwin_x86_64": [ - "-fsanitize-coverage=trace-pc-guard,indirect-calls,trace-cmp", - "-fsanitize-coverage=bb", - ], - "@bazel_tools//src/conditions:darwin": [ - "-fsanitize-coverage=trace-pc-guard,indirect-calls,trace-cmp", - "-fsanitize-coverage=bb", - ], - # GCC-only flags. - "//conditions:default": [ - "-finstrument-functions" - ], - }), - deps = [ - ":codec", - "@honggfuzz//:honggfuzz", - "@benchmark//:benchmark", - ], - linkstatic = 1, -) diff --git a/third-party/astc-codec/src/decoder/CMakeLists.txt b/third-party/astc-codec/src/decoder/CMakeLists.txt deleted file mode 100644 index e82a692c..00000000 --- a/third-party/astc-codec/src/decoder/CMakeLists.txt +++ /dev/null @@ -1,95 +0,0 @@ -# Copyright 2018 Google LLC -# -# Licensed under the Apache License, Version 2.0 (the "License"); you may not -# use this file except in compliance with the License. You may obtain a copy of -# the License at -# -# https://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT -# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the -# License for the specific language governing permissions and limitations under -# the License. -add_library(footprint footprint.cc) -target_link_libraries(footprint base) - -add_library(astc_utils - astc_file.cc - endpoint_codec.cc - integer_sequence_codec.cc - intermediate_astc_block.cc - logical_astc_block.cc - partition.cc - physical_astc_block.cc - quantization.cc - weight_infill.cc) -target_link_libraries(astc_utils PRIVATE base footprint) -target_include_directories(astc_utils PRIVATE ../..) - -add_library(astc-codec codec.cc) -target_link_libraries(astc-codec PRIVATE astc_utils) -target_include_directories(astc-codec PUBLIC ../../include) -target_include_directories(astc-codec PRIVATE ../..) - -add_executable(astc_inspector_cli tools/astc_inspector_cli.cc) -target_include_directories(astc_inspector_cli PRIVATE ../..) -target_link_libraries(astc_inspector_cli PRIVATE astc_utils) - -# -# Testing -# -if(OPTION_ASTC_TESTS) - # Note that we will execute all the tests in the project directory. - # We do this to ensure the unit tests can pick up the required test data - - # Create interface library exposing the root as an include directory - add_library(codec_test_dependencies INTERFACE) - target_include_directories(codec_test_dependencies INTERFACE ../..) - - add_executable(physical_astc_block_test test/physical_astc_block_test.cc) - add_test(NAME physical_astc_block_test COMMAND physical_astc_block_test WORKING_DIRECTORY ${PROJECT_SOURCE_DIR}) - target_link_libraries(physical_astc_block_test astc_utils codec_test_dependencies gmock_main) - - add_executable(partition_test test/partition_test.cc) - add_test(NAME partition_test COMMAND partition_test WORKING_DIRECTORY ${PROJECT_SOURCE_DIR}) - target_link_libraries(partition_test PRIVATE astc_utils codec_test_dependencies gmock_main) - - add_executable(integer_sequence_codec_test test/integer_sequence_codec_test.cc) - target_link_libraries(integer_sequence_codec_test PRIVATE astc_utils codec_test_dependencies gmock_main) - - add_executable(intermediate_astc_block_test test/intermediate_astc_block_test.cc) - add_test(NAME intermediate_astc_block_test COMMAND intermediate_astc_block_test WORKING_DIRECTORY ${PROJECT_SOURCE_DIR}) - target_link_libraries(intermediate_astc_block_test PRIVATE astc_utils codec_test_dependencies gmock_main) - - add_executable(quantization_test test/quantization_test.cc) - add_test(NAME quantization_test COMMAND quantization_test WORKING_DIRECTORY ${PROJECT_SOURCE_DIR}) - target_link_libraries(quantization_test PRIVATE astc_utils codec_test_dependencies gmock_main) - - add_executable(weight_infill_test test/weight_infill_test.cc) - add_test(NAME weight_infill_test COMMAND weight_infill_test WORKING_DIRECTORY ${PROJECT_SOURCE_DIR}) - target_link_libraries(weight_infill_test PRIVATE astc_utils footprint codec_test_dependencies gmock_main) - - add_executable(endpoint_codec_test test/endpoint_codec_test.cc) - add_test(NAME endpoint_codec_test COMMAND endpoint_codec_test WORKING_DIRECTORY ${PROJECT_SOURCE_DIR}) - target_link_libraries(endpoint_codec_test PRIVATE astc_utils codec_test_dependencies gmock_main) - - add_executable(logical_astc_block_test test/logical_astc_block_test.cc) - add_test(NAME logical_astc_block_test COMMAND logical_astc_block_test WORKING_DIRECTORY ${PROJECT_SOURCE_DIR}) - target_link_libraries(logical_astc_block_test PRIVATE astc_utils codec_test_dependencies gmock_main) - - add_executable(codec_test test/codec_test.cc) - add_test(NAME codec_test COMMAND codec_test WORKING_DIRECTORY ${PROJECT_SOURCE_DIR}) - - target_link_libraries(codec_test PRIVATE astc-codec codec_test_dependencies gmock_main) - - add_executable(footprint_test test/footprint_test.cc) - add_test(NAME footprint_test COMMAND footprint_test WORKING_DIRECTORY ${PROJECT_SOURCE_DIR}) - target_link_libraries(footprint_test PRIVATE footprint codec_test_dependencies gmock_main) - - if(OPTION_BUILD_FUZZER) - message(FATAL_ERROR "Not yet supported due to missing dependencies") - add_executable(astc_fuzzer test/astc_fuzzer.cc codec_test_dependencies gmock_main) - target_link_libraries(astc_fuzzer PRIVATE astc-codec honggfuzz benchmark) - endif() -endif() diff --git a/third-party/astc-codec/src/decoder/astc_file.cc b/third-party/astc-codec/src/decoder/astc_file.cc deleted file mode 100644 index 47700648..00000000 --- a/third-party/astc-codec/src/decoder/astc_file.cc +++ /dev/null @@ -1,185 +0,0 @@ -// Copyright 2018 Google LLC -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// https://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -#include "src/decoder/astc_file.h" - -#include <cstring> -#include <fstream> -#include <memory> -#include <sstream> - -namespace astc_codec { - -namespace { -static constexpr size_t kASTCHeaderSize = 16; - -// Reads a value of size T from the buffer at the current offset, then -// increments the offset. -template<typename T> -inline T ReadVal(const char* file_data, size_t& offset) { - T x; - memcpy(&x, &file_data[offset], sizeof(T)); - offset += sizeof(T); - return x; -} -} // namespace - -ASTCFile::ASTCFile(Header&& header, std::string&& blocks) - : header_(std::move(header)), blocks_(std::move(blocks)) {} - -std::unique_ptr<ASTCFile> ASTCFile::LoadFromMemory(const char* data, - size_t length, - std::string* error) { - if (length < kASTCHeaderSize) { - *error = "Incomplete header."; - return nullptr; - } - - base::Optional<Header> header_opt = ParseHeader(data); - if (!header_opt) { - *error = "Invalid ASTC header."; - return nullptr; - } - - Header header = header_opt.value(); - - if (header.block_width_ == 0 || header.block_height_ == 0) { - *error = "Invalid block size."; - return nullptr; - } - - std::string blocks(data + kASTCHeaderSize, data + length); - - // Check that this file has the expected number of blocks. - const size_t expected_block_count = - ((header.width_ + header.block_width_ - 1) / header.block_width_) * - ((header.height_ + header.block_height_ - 1) / header.block_height_); - - if (blocks.size() % PhysicalASTCBlock::kSizeInBytes != 0 || - blocks.size() / PhysicalASTCBlock::kSizeInBytes != expected_block_count) { - std::stringstream ss; - ss << "Unexpected file length " << blocks.size() << " expected " - << kASTCHeaderSize + - expected_block_count * PhysicalASTCBlock::kSizeInBytes - << " bytes."; - *error = ss.str(); - return nullptr; - } - - return std::unique_ptr<ASTCFile>( - new ASTCFile(std::move(header), std::move(blocks))); -} - -std::unique_ptr<ASTCFile> ASTCFile::LoadFile(const std::string& path, - std::string* error) { - std::ifstream is(path, std::ios::binary); - if (!is) { - *error = "File not found: " + path; - return nullptr; - } - - char header_data[kASTCHeaderSize] = {}; - if (!is.read(header_data, kASTCHeaderSize)) { - *error = "Failed to load ASTC header."; - return nullptr; - } - - base::Optional<Header> header_opt = ParseHeader(header_data); - if (!header_opt) { - *error = "Invalid ASTC header."; - return nullptr; - } - - Header header = header_opt.value(); - - std::string blocks; - { - std::ostringstream ss; - ss << is.rdbuf(); - blocks = ss.str(); - } - - // Check that this file has the expected number of blocks. - const size_t expected_block_count = - ((header.width_ + header.block_width_ - 1) / header.block_width_) * - ((header.height_ + header.block_height_ - 1) / header.block_height_); - - if (blocks.size() % PhysicalASTCBlock::kSizeInBytes != 0 || - blocks.size() / PhysicalASTCBlock::kSizeInBytes != expected_block_count) { - std::stringstream ss; - ss << "Unexpected file length " << blocks.size() << " expected " - << kASTCHeaderSize + - expected_block_count * PhysicalASTCBlock::kSizeInBytes - << " bytes."; - *error = ss.str(); - return nullptr; - } - - return std::unique_ptr<ASTCFile>( - new ASTCFile(std::move(header), std::move(blocks))); -} - -base::Optional<Footprint> ASTCFile::GetFootprint() const { - return Footprint::FromDimensions(header_.block_width_, header_.block_height_); -} - -std::string ASTCFile::GetFootprintString() const { - std::stringstream footprint; - footprint << header_.block_width_ << "x" << header_.block_height_; - return footprint.str(); -} - -const std::string& ASTCFile::GetRawBlockData() const { - return blocks_; -} - -PhysicalASTCBlock ASTCFile::GetBlock(size_t block_idx) const { - const size_t sz = PhysicalASTCBlock::kSizeInBytes; - const size_t offset = PhysicalASTCBlock::kSizeInBytes * block_idx; - assert(offset <= blocks_.size() - sz); - return PhysicalASTCBlock(blocks_.substr(offset, sz)); -} - -base::Optional<ASTCFile::Header> ASTCFile::ParseHeader(const char* header) { - size_t offset = 0; - // TODO(google): Handle endianness. - const uint32_t magic = ReadVal<uint32_t>(header, offset); - if (magic != 0x5CA1AB13) { - return {}; - } - - const uint32_t block_width = ReadVal<uint8_t>(header, offset); - const uint32_t block_height = ReadVal<uint8_t>(header, offset); - const uint32_t block_depth = ReadVal<uint8_t>(header, offset); - - uint32_t width = 0; - width |= ReadVal<uint8_t>(header, offset); - width |= ReadVal<uint8_t>(header, offset) << 8; - width |= ReadVal<uint8_t>(header, offset) << 16; - - uint32_t height = 0; - height |= ReadVal<uint8_t>(header, offset); - height |= ReadVal<uint8_t>(header, offset) << 8; - height |= ReadVal<uint8_t>(header, offset) << 16; - - uint32_t depth = 0; - depth |= ReadVal<uint8_t>(header, offset); - depth |= ReadVal<uint8_t>(header, offset) << 8; - depth |= ReadVal<uint8_t>(header, offset) << 16; - assert(offset == kASTCHeaderSize); - - return Header(width, height, depth, block_width, block_height, block_depth); -} - -} // namespace astc_codec diff --git a/third-party/astc-codec/src/decoder/astc_file.h b/third-party/astc-codec/src/decoder/astc_file.h deleted file mode 100644 index c31c2ba7..00000000 --- a/third-party/astc-codec/src/decoder/astc_file.h +++ /dev/null @@ -1,97 +0,0 @@ -// Copyright 2018 Google LLC -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// https://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -#ifndef ASTC_CODEC_DECODER_ASTC_FILE_H_ -#define ASTC_CODEC_DECODER_ASTC_FILE_H_ - -#include "src/base/optional.h" -#include "src/decoder/footprint.h" -#include "src/decoder/physical_astc_block.h" - -#include <memory> -#include <string> - -namespace astc_codec { - -// A thin wrapper around a .astc file on disk. This class simply reads the ASTC -// header, and stores the block data in memory. -class ASTCFile { - private: - struct Header { - Header(size_t width, size_t height, size_t depth, size_t block_width, - size_t block_height, size_t block_depth) - : width_(width), - height_(height), - depth_(depth), - block_width_(block_width), - block_height_(block_height), - block_depth_(block_depth) {} - - size_t width_; - size_t height_; - size_t depth_; - - size_t block_width_; - size_t block_height_; - size_t block_depth_; - }; - - ASTCFile(ASTCFile::Header&& header, std::string&& blocks); - - public: - // Load an ASTC file from memory. - // If loading failed, nullptr is returned and an error string is populated - // in the error parameter. - static std::unique_ptr<ASTCFile> LoadFromMemory(const char* data, - size_t length, - std::string* error); - - // Load an ASTC file from file. - // If loading failed, nullptr is returned and an error string is populated - // in the error parameter. - static std::unique_ptr<ASTCFile> LoadFile(const std::string& path, - std::string* error); - - // Returns the footprint for the file, if it is considered to be a valid - // footprint. - base::Optional<Footprint> GetFootprint() const; - - // Returns the string of the form "NxM" where N and M are the width and height - // of the block footprint, respectively. - std::string GetFootprintString() const; - - // Get the raw block data for the astc file. - const std::string& GetRawBlockData() const; - - // Returns the physical block at the associated block index. - PhysicalASTCBlock GetBlock(size_t block_idx) const; - - size_t GetWidth() const { return header_.width_; } - size_t GetHeight() const { return header_.height_; } - size_t GetDepth() const { return header_.depth_; } - - size_t NumBlocks() const { - return blocks_.size() / PhysicalASTCBlock::kSizeInBytes; - } - - private: - static base::Optional<ASTCFile::Header> ParseHeader(const char* header); - - const Header header_; - const std::string blocks_; -}; - -} // namespace astc_codec - -#endif // ASTC_CODEC_DECODER_ASTC_FILE_H_ diff --git a/third-party/astc-codec/src/decoder/codec.cc b/third-party/astc-codec/src/decoder/codec.cc deleted file mode 100644 index c0f8c07b..00000000 --- a/third-party/astc-codec/src/decoder/codec.cc +++ /dev/null @@ -1,132 +0,0 @@ -// Copyright 2018 Google LLC -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// https://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -#include "src/decoder/codec.h" -#include "src/base/uint128.h" -#include "src/decoder/logical_astc_block.h" -#include "src/decoder/physical_astc_block.h" - -#include <cstring> - -namespace astc_codec { - -namespace { -static constexpr size_t kBytesPerPixelUNORM8 = 4; -} - -bool DecompressToImage(const uint8_t* astc_data, size_t astc_data_size, - size_t width, size_t height, Footprint footprint, - uint8_t* out_buffer, size_t out_buffer_size, - size_t out_buffer_stride) { - const size_t block_width = footprint.Width(); - const size_t block_height = footprint.Height(); - assert(block_width != 0); - assert(block_height != 0); - - if (width == 0 || height == 0) { - return false; - } - - const size_t blocks_wide = (width + block_width - 1) / block_width; - assert(blocks_wide != 0); - - // Check that this buffer has the expected number of blocks. - const size_t expected_block_count = - ((width + block_width - 1) / block_width) * - ((height + block_height - 1) / block_height); - - if (astc_data_size % PhysicalASTCBlock::kSizeInBytes != 0 || - astc_data_size / PhysicalASTCBlock::kSizeInBytes != - expected_block_count) { - // TODO(google): Expose error? - return false; - } - - if (kBytesPerPixelUNORM8 * width > out_buffer_stride || - out_buffer_stride * height < out_buffer_size) { - // Output buffer too small. - return false; - } - - base::UInt128 block; - static_assert(sizeof(block) == PhysicalASTCBlock::kSizeInBytes, - "Block size mismatch"); - - for (size_t i = 0; i < astc_data_size; i += PhysicalASTCBlock::kSizeInBytes) { - const size_t block_index = i / PhysicalASTCBlock::kSizeInBytes; - const size_t block_x = block_index % blocks_wide; - const size_t block_y = block_index / blocks_wide; - memcpy(&block, astc_data + i, sizeof(block)); - - PhysicalASTCBlock physical_block(block); - auto lb = UnpackLogicalBlock(footprint, physical_block); - if (!lb) { - return false; - } - - LogicalASTCBlock logical_block = lb.value(); - - for (size_t y = 0; y < block_height; ++y) { - const size_t py = block_height * block_y + y; - uint8_t* out_row = out_buffer + py * out_buffer_stride; - - for (size_t x = 0; x < block_width; ++x) { - const size_t px = block_width * block_x + x; - - // Skip out of bounds. - if (px >= width || py >= height) { - continue; - } - - uint8_t* pixel = out_row + px * kBytesPerPixelUNORM8; - const RgbaColor decoded_color = logical_block.ColorAt(x, y); - for (size_t i = 0; i < kBytesPerPixelUNORM8; ++i) { - pixel[i] = static_cast<uint8_t>(decoded_color[i]); - } - } - } - } - - return true; -} - -bool DecompressToImage(const ASTCFile& file, uint8_t* out_buffer, - size_t out_buffer_size, size_t out_buffer_stride) { - base::Optional<Footprint> footprint = file.GetFootprint(); - if (!footprint) { - return false; - } - - return DecompressToImage( - reinterpret_cast<const uint8_t*>(file.GetRawBlockData().c_str()), - file.GetRawBlockData().size(), file.GetWidth(), file.GetHeight(), - footprint.value(), out_buffer, out_buffer_size, out_buffer_stride); -} - -bool ASTCDecompressToRGBA(const uint8_t* astc_data, size_t astc_data_size, - size_t width, size_t height, FootprintType footprint, - uint8_t* out_buffer, size_t out_buffer_size, - size_t out_buffer_stride) { - base::Optional<Footprint> footprint_opt = - Footprint::FromFootprintType(footprint); - if (!footprint_opt) { - return false; - } - - return DecompressToImage(astc_data, astc_data_size, width, height, - footprint_opt.value(), out_buffer, out_buffer_size, - out_buffer_stride); -} - -} // namespace astc_codec diff --git a/third-party/astc-codec/src/decoder/codec.h b/third-party/astc-codec/src/decoder/codec.h deleted file mode 100644 index eed601a4..00000000 --- a/third-party/astc-codec/src/decoder/codec.h +++ /dev/null @@ -1,41 +0,0 @@ -// Copyright 2018 Google LLC -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// https://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -#ifndef ASTC_CODEC_DECODER_CODEC_H_ -#define ASTC_CODEC_DECODER_CODEC_H_ - -#include "src/decoder/astc_file.h" -#include "src/decoder/footprint.h" - -#include <string> - -namespace astc_codec { - -// Decompresses ASTC blocks to an image buffer. -// Returns true if the decompression succeeded and the out buffer has been -// filled. -bool DecompressToImage(const uint8_t* astc_data, size_t astc_data_size, - size_t width, size_t height, Footprint footprint, - uint8_t* out_buffer, size_t out_buffer_size, - size_t out_buffer_stride); - -// Decompresses an ASTC file to an image buffer. -// Returns true if the decompression succeeded and the out buffer has been -// filled. -bool DecompressToImage(const ASTCFile& file, uint8_t* out_buffer, - size_t out_buffer_size, size_t out_buffer_stride); - -} // namespace astc_codec - -#endif // ASTC_CODEC_DECODER_CODEC_H_ diff --git a/third-party/astc-codec/src/decoder/endpoint_codec.cc b/third-party/astc-codec/src/decoder/endpoint_codec.cc deleted file mode 100644 index 1513d15a..00000000 --- a/third-party/astc-codec/src/decoder/endpoint_codec.cc +++ /dev/null @@ -1,967 +0,0 @@ -// Copyright 2018 Google LLC -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// https://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -#include "src/decoder/endpoint_codec.h" -#include "src/decoder/quantization.h" - -#include <algorithm> -#include <array> -#include <numeric> -#include <utility> - -namespace astc_codec { - -namespace { - -template<typename T> -T Clamp(T value, T min, T max) { - return value < min ? min : (value > max ? max : value); -} - -// This is the 'blue_contract' function defined in Section C.2.14 of the ASTC -// specification. -template<typename ArrayType> -void BlueContract(ArrayType* const cptr) { - ArrayType& c = *cptr; - c[0] = (c[0] + c[2]) >> 1; - c[1] = (c[1] + c[2]) >> 1; -} - -// Returns the inverse of values in BlueContract, subjected to the constraint -// that the new values are stored in the range [0, 255]. -template<typename ArrayType> -ArrayType InvertBlueContract(const ArrayType& c) { - ArrayType result = c; - result[0] = Clamp(2 * c[0] - c[2], 0, 255); - result[1] = Clamp(2 * c[1] - c[2], 0, 255); - return result; -} - -// This is the 'bit_transfer_signed' function defined in Section C.2.14 of the -// ASTC specification. -void BitTransferSigned(int* const a, int* const b) { - *b >>= 1; - *b |= *a & 0x80; - *a >>= 1; - *a &= 0x3F; - if ((*a & 0x20) != 0) { - *a -= 0x40; - } -} - -// Takes two values, |a| in the range [-32, 31], and |b| in the range [0, 255], -// and returns the two values in [0, 255] that will reconstruct |a| and |b| when -// passed to the BitTransferSigned function. -void InvertBitTransferSigned(int* const a, int* const b) { - assert(*a >= -32); assert(*a < 32); - assert(*b >= 0); assert(*b < 256); - - if (*a < 0) { - *a += 0x40; - } - *a <<= 1; - *a |= (*b & 0x80); - *b <<= 1; - *b &= 0xff; -} - -RgbColor StripAlpha(const RgbaColor& c) { - return RgbColor {{ c[0], c[1], c[2] }}; -} - -template<typename ContainerType> -void Quantize(ContainerType* const c, size_t max_value) { - for (auto& x : *c) { - x = QuantizeCEValueToRange(x, max_value); - } -} - -template<typename ArrayType> -ArrayType QuantizeColor(const ArrayType& c, size_t max_value) { - ArrayType result = c; - Quantize(&result, max_value); - return result; -} - -template<typename ContainerType> -void Unquantize(ContainerType* const c, size_t max_value) { - for (auto& x : *c) { - x = UnquantizeCEValueFromRange(x, max_value); - } -} - -template<typename ArrayType> -ArrayType UnquantizeColor(const ArrayType& c, size_t max_value) { - ArrayType result = c; - Unquantize(&result, max_value); - return result; -} - -// Returns the average of the three RGB channels. -template<typename ContainerType> -const int AverageRGB(const ContainerType& c) { - // Each channel can be in the range [0, 255], and we need to divide by three. - // However, we want to round the error properly. Both (x + 1) / 3 and - // (x + 2) / 3 are relatively imprecise when it comes to rounding, so instead - // we increase the precision by multiplying our numerator by some arbitrary - // number. Here, we choose 256 to get 8 additional bits and maintain - // performance since it turns into a shift rather than a multiply. Our - // denominator then becomes 3 * 256 = 768. - return (std::accumulate(c.begin(), c.begin() + 3, 0) * 256 + 384) / 768; -} - -// Returns the sum of squared differences between each element of |a| and |b|, -// which are assumed to contain the same number of elements. -template<typename ContainerType> -const typename ContainerType::value_type SquaredError( - const ContainerType& a, const ContainerType& b, - size_t num_channels = std::tuple_size<ContainerType>::value) { - using ValueTy = typename ContainerType::value_type; - static_assert(std::is_signed<ValueTy>::value, - "Value type assumed to be signed to avoid branch below."); - ValueTy result = ValueTy(0); - for (int i = 0; i < num_channels; ++i) { - ValueTy error = a[i] - b[i]; - result += error * error; - } - return result; -} - -constexpr int MaxValuesForModes(ColorEndpointMode mode_a, - ColorEndpointMode mode_b) { - return (NumColorValuesForEndpointMode(mode_a) > - NumColorValuesForEndpointMode(mode_b)) - ? NumColorValuesForEndpointMode(mode_a) - : NumColorValuesForEndpointMode(mode_b); -} - -// This function takes the two colors in |endpoint_low| and |endpoint_high| and -// encodes them into |vals| according to the ASTC spec in section C.2.14. It -// assumes that the two colors are close enough to grayscale that the encoding -// should use the ColorEndpointMode kLDRLumaBaseOffset or kLDRLumaDirect. Which -// one is chosen depends on which produces smaller error for the given -// quantization value stored in |max_value| -bool EncodeColorsLuma(const RgbaColor& endpoint_low, - const RgbaColor& endpoint_high, - int max_value, ColorEndpointMode* const astc_mode, - std::vector<int>* const vals) { - assert(vals->size() == - NumValuesForEncodingMode(EndpointEncodingMode::kDirectLuma)); - int avg1 = AverageRGB(endpoint_low); - int avg2 = AverageRGB(endpoint_high); - - // For the offset mode, L1 is strictly greater than L2, so if we are using - // it to encode the color values, we need to swap the weights and - // endpoints so that the larger of the two is the second endpoint. - bool needs_weight_swap = false; - if (avg1 > avg2) { - needs_weight_swap = true; - std::swap(avg1, avg2); - } - assert(avg1 <= avg2); - - // Now, the first endpoint is based on the low-order six bits of the first - // value, and the high order two bits of the second value. The low order - // six bits of the second value are used as the (strictly positive) offset - // from the first value. - const int offset = std::min(avg2 - avg1, 0x3F); - const int quant_off_low = - QuantizeCEValueToRange((avg1 & 0x3F) << 2, max_value); - const int quant_off_high = - QuantizeCEValueToRange((avg1 & 0xC0) | offset, max_value); - - const int quant_low = QuantizeCEValueToRange(avg1, max_value); - const int quant_high = QuantizeCEValueToRange(avg2, max_value); - - RgbaColor unquant_off_low, unquant_off_high; - RgbaColor unquant_low, unquant_high; - - (*vals)[0] = quant_off_low; - (*vals)[1] = quant_off_high; - DecodeColorsForMode( - *vals, max_value, ColorEndpointMode::kLDRLumaBaseOffset, - &unquant_off_low, &unquant_off_high); - - (*vals)[0] = quant_low; - (*vals)[1] = quant_high; - DecodeColorsForMode(*vals, max_value, ColorEndpointMode::kLDRLumaDirect, - &unquant_low, &unquant_high); - - const auto calculate_error = - [needs_weight_swap, &endpoint_low, &endpoint_high] - (const RgbaColor& low, const RgbaColor& high) { - int error = 0; - if (needs_weight_swap) { - error += SquaredError(low, endpoint_high); - error += SquaredError(high, endpoint_low); - } else { - error += SquaredError(low, endpoint_low); - error += SquaredError(high, endpoint_high); - } - return error; - }; - - const int direct_error = calculate_error(unquant_low, unquant_high); - const int off_error = calculate_error(unquant_off_low, unquant_off_high); - - if (direct_error <= off_error) { - (*vals)[0] = quant_low; - (*vals)[1] = quant_high; - *astc_mode = ColorEndpointMode::kLDRLumaDirect; - } else { - (*vals)[0] = quant_off_low; - (*vals)[1] = quant_off_high; - *astc_mode = ColorEndpointMode::kLDRLumaBaseOffset; - } - - return needs_weight_swap; -} - -class QuantizedEndpointPair { - public: - QuantizedEndpointPair(const RgbaColor& c_low, const RgbaColor& c_high, - int max_value) - : orig_low_(c_low), - orig_high_(c_high), - quant_low_(QuantizeColor(c_low, max_value)), - quant_high_(QuantizeColor(c_high, max_value)), - unquant_low_(UnquantizeColor(quant_low_, max_value)), - unquant_high_(UnquantizeColor(quant_high_, max_value)) { } - - const RgbaColor& QuantizedLow() const { return quant_low_; } - const RgbaColor& QuantizedHigh() const { return quant_high_; } - - const RgbaColor& UnquantizedLow() const { return unquant_low_; } - const RgbaColor& UnquantizedHigh() const { return unquant_high_; } - - const RgbaColor& OriginalLow() const { return orig_low_; } - const RgbaColor& OriginalHigh() const { return orig_high_; } - - private: - RgbaColor orig_low_; - RgbaColor orig_high_; - - RgbaColor quant_low_; - RgbaColor quant_high_; - - RgbaColor unquant_low_; - RgbaColor unquant_high_; -}; - -class CEEncodingOption { - public: - CEEncodingOption() { } - CEEncodingOption( - int squared_error, const QuantizedEndpointPair* quantized_endpoints, - bool swap_endpoints, bool blue_contract, bool use_offset_mode) - : squared_error_(squared_error), - quantized_endpoints_(quantized_endpoints), - swap_endpoints_(swap_endpoints), - blue_contract_(blue_contract), - use_offset_mode_(use_offset_mode) { } - - // Returns true if able to generate valid |astc_mode| and |vals|. In some - // instances, such as if the endpoints reprsent a base/offset pair, we may not - // be able to guarantee blue-contract encoding due to how the base/offset pair - // are represented and the specifics of the decoding procedure. Similarly, - // some direct RGBA encodings also may not be able to emit blue-contract modes - // due to an unlucky combination of channels. In these instances, this - // function will return false, and all pointers will remain unmodified. - bool Pack(bool with_alpha, ColorEndpointMode* const astc_mode, - std::vector<int>* const vals, bool* const needs_weight_swap) const { - auto unquantized_low = quantized_endpoints_->UnquantizedLow(); - auto unquantized_high = quantized_endpoints_->UnquantizedHigh(); - - // In offset mode, we do BitTransferSigned before analyzing the values - // of the endpoints in order to determine whether or not we're going to - // be using blue-contract mode. - if (use_offset_mode_) { - for (int i = 0; i < std::tuple_size<RgbaColor>::value; ++i) { - BitTransferSigned(&unquantized_high[i], &unquantized_low[i]); - } - } - - // Define variables as outlined in the ASTC spec C.2.14 for the RGB[A] - // direct and base-offset modes - int s0 = 0, s1 = 0; - for (int i = 0; i < 3; ++i) { - s0 += unquantized_low[i]; - s1 += unquantized_high[i]; - } - - // Can we guarantee a blue-contract mode if we want it? In other words, - // if we swap which endpoint is high and which endpoint is low, can we - // guarantee that we will hit the corresponding decode path? - bool swap_vals = false; - if (use_offset_mode_) { - if (blue_contract_) { - swap_vals = s1 >= 0; - } else { - swap_vals = s1 < 0; - } - - // In offset mode, we have two different measurements that swap the - // endpoints prior to encoding, so we don't need to swap them here. - // If we need to swap them to guarantee a blue-contract mode, then - // abort and wait until we get the other error measurement. - if (swap_vals) { - return false; - } - } else { - if (blue_contract_) { - // If we want a blue_contract path, but s1 == s0, then swapping the - // values will have no effect. - if (s1 == s0) { - return false; - } - - swap_vals = s1 > s0; - // If we're encoding blue contract mode directly, then we implicitly - // swap the endpoints during decode, meaning that we need to take - // note of that here. - *needs_weight_swap = !(*needs_weight_swap); - } else { - swap_vals = s1 < s0; - } - } - - const auto* quantized_low = &(quantized_endpoints_->QuantizedLow()); - const auto* quantized_high = &(quantized_endpoints_->QuantizedHigh()); - - if (swap_vals) { - assert(!use_offset_mode_); - std::swap(quantized_low, quantized_high); - *needs_weight_swap = !(*needs_weight_swap); - } - - (*vals)[0] = quantized_low->at(0); - (*vals)[1] = quantized_high->at(0); - (*vals)[2] = quantized_low->at(1); - (*vals)[3] = quantized_high->at(1); - (*vals)[4] = quantized_low->at(2); - (*vals)[5] = quantized_high->at(2); - - if (use_offset_mode_) { - *astc_mode = ColorEndpointMode::kLDRRGBBaseOffset; - } else { - *astc_mode = ColorEndpointMode::kLDRRGBDirect; - } - - if (with_alpha) { - (*vals)[6] = quantized_low->at(3); - (*vals)[7] = quantized_high->at(3); - - if (use_offset_mode_) { - *astc_mode = ColorEndpointMode::kLDRRGBABaseOffset; - } else { - *astc_mode = ColorEndpointMode::kLDRRGBADirect; - } - } - - // If we swapped them to measure, then they need to be swapped after - // decoding - if (swap_endpoints_) { - *needs_weight_swap = !(*needs_weight_swap); - } - - return true; - } - - bool BlueContract() const { return blue_contract_; } - int Error() const { return squared_error_; } - - private: - int squared_error_; - const QuantizedEndpointPair* quantized_endpoints_; - bool swap_endpoints_; - bool blue_contract_; - bool use_offset_mode_; -}; - -bool EncodeColorsRGBA(const RgbaColor& endpoint_low_rgba, - const RgbaColor& endpoint_high_rgba, - int max_value, bool with_alpha, - ColorEndpointMode* const astc_mode, - std::vector<int>* const vals) { - const int num_channels = with_alpha ? std::tuple_size<RgbaColor>::value : 3; - // The difficulty of encoding into this mode is determining whether or - // not we'd like to use the 'blue contract' function to reconstruct - // the endpoints and whether or not we'll be more accurate by using the - // base/offset color modes instead of quantizing the color channels - // directly. With that in mind, we: - // 1. Generate the inverted values for blue-contract and offset modes. - // 2. Quantize all of the different endpoints. - // 3. Unquantize each sets and decide which one gives least error - // 4. Encode the values correspondingly. - - // 1. Generate the inverted values for blue-contract and offset modes. - const auto inv_bc_low = InvertBlueContract(endpoint_low_rgba); - const auto inv_bc_high = InvertBlueContract(endpoint_high_rgba); - - RgbaColor direct_base, direct_offset; - for (int i = 0; i < std::tuple_size<RgbaColor>::value; ++i) { - direct_base[i] = endpoint_low_rgba[i]; - direct_offset[i] = - Clamp(endpoint_high_rgba[i] - endpoint_low_rgba[i], -32, 31); - InvertBitTransferSigned(&direct_offset[i], &direct_base[i]); - } - - RgbaColor inv_bc_base, inv_bc_offset; - for (int i = 0; i < std::tuple_size<RgbaColor>::value; ++i) { - // Remember, for blue-contract'd offset modes, the base is compared - // against the second endpoint and not the first. - inv_bc_base[i] = inv_bc_high[i]; - inv_bc_offset[i] = Clamp(inv_bc_low[i] - inv_bc_high[i], -32, 31); - InvertBitTransferSigned(&inv_bc_offset[i], &inv_bc_base[i]); - } - - // The order of the endpoints for offset modes may determine how well they - // approximate the given endpoints. It may be that the quantization value - // produces more accurate values for the base than the offset or - // vice/versa. For this reason, we need to generate quantized versions of - // the endpoints as if they were swapped to see if we get better error - // out of it. - - RgbaColor direct_base_swapped, direct_offset_swapped; - for (int i = 0; i < std::tuple_size<RgbaColor>::value; ++i) { - direct_base_swapped[i] = endpoint_high_rgba[i]; - direct_offset_swapped[i] = - Clamp(endpoint_low_rgba[i] - endpoint_high_rgba[i], -32, 31); - InvertBitTransferSigned(&direct_offset_swapped[i], &direct_base_swapped[i]); - } - - RgbaColor inv_bc_base_swapped, inv_bc_offset_swapped; - for (int i = 0; i < std::tuple_size<RgbaColor>::value; ++i) { - // Remember, for blue-contract'd offset modes, the base is compared - // against the second endpoint and not the first. Hence, the swapped - // version will compare the base against the first endpoint. - inv_bc_base_swapped[i] = inv_bc_low[i]; - inv_bc_offset_swapped[i] = Clamp(inv_bc_high[i] - inv_bc_low[i], -32, 31); - InvertBitTransferSigned(&inv_bc_offset_swapped[i], &inv_bc_base_swapped[i]); - } - - // 2. Quantize the endpoints directly. - const QuantizedEndpointPair direct_quantized( - endpoint_low_rgba, endpoint_high_rgba, max_value); - const QuantizedEndpointPair bc_quantized( - inv_bc_low, inv_bc_high, max_value); - - const QuantizedEndpointPair offset_quantized( - direct_base, direct_offset, max_value); - const QuantizedEndpointPair bc_offset_quantized( - inv_bc_base, inv_bc_offset, max_value); - - const QuantizedEndpointPair offset_swapped_quantized( - direct_base_swapped, direct_offset_swapped, max_value); - const QuantizedEndpointPair bc_offset_swapped_quantized( - inv_bc_base_swapped, inv_bc_offset_swapped, max_value); - - // 3. Unquantize each set and decide which one gives least error. - std::array<CEEncodingOption, 6> errors; - auto errors_itr = errors.begin(); - - // 3.1 regular unquantized error - { - const auto rgba_low = direct_quantized.UnquantizedLow(); - const auto rgba_high = direct_quantized.UnquantizedHigh(); - - const int sq_rgb_error = - SquaredError(rgba_low, endpoint_low_rgba, num_channels) + - SquaredError(rgba_high, endpoint_high_rgba, num_channels); - - const bool swap_endpoints = false; - const bool blue_contract = false; - const bool offset_mode = false; - *(errors_itr++) = CEEncodingOption( - sq_rgb_error, &direct_quantized, - swap_endpoints, blue_contract, offset_mode); - } - - // 3.2 Compute blue-contract'd error. - { - auto bc_low = bc_quantized.UnquantizedLow(); - auto bc_high = bc_quantized.UnquantizedHigh(); - BlueContract(&bc_low); - BlueContract(&bc_high); - - const int sq_bc_error = - SquaredError(bc_low, endpoint_low_rgba, num_channels) + - SquaredError(bc_high, endpoint_high_rgba, num_channels); - - const bool swap_endpoints = false; - const bool blue_contract = true; - const bool offset_mode = false; - *(errors_itr++) = CEEncodingOption( - sq_bc_error, &bc_quantized, - swap_endpoints, blue_contract, offset_mode); - } - - // 3.3 Compute base/offset unquantized error. - const auto compute_base_offset_error = - [num_channels, &errors_itr, &endpoint_low_rgba, &endpoint_high_rgba] - (const QuantizedEndpointPair& pair, bool swapped) { - auto base = pair.UnquantizedLow(); - auto offset = pair.UnquantizedHigh(); - - for (int i = 0; i < num_channels; ++i) { - BitTransferSigned(&offset[i], &base[i]); - offset[i] = Clamp(base[i] + offset[i], 0, 255); - } - - int base_offset_error = 0; - // If we swapped the endpoints going in, then without blue contract - // we should be comparing the base against the high endpoint. - if (swapped) { - base_offset_error = - SquaredError(base, endpoint_high_rgba, num_channels) + - SquaredError(offset, endpoint_low_rgba, num_channels); - } else { - base_offset_error = - SquaredError(base, endpoint_low_rgba, num_channels) + - SquaredError(offset, endpoint_high_rgba, num_channels); - } - - const bool blue_contract = false; - const bool offset_mode = true; - *(errors_itr++) = CEEncodingOption( - base_offset_error, &pair, swapped, blue_contract, offset_mode); - }; - - compute_base_offset_error(offset_quantized, false); - - // 3.4 Compute base/offset blue-contract error. - const auto compute_base_offset_blue_contract_error = - [num_channels, &errors_itr, &endpoint_low_rgba, &endpoint_high_rgba] - (const QuantizedEndpointPair& pair, bool swapped) { - auto base = pair.UnquantizedLow(); - auto offset = pair.UnquantizedHigh(); - - for (int i = 0; i < num_channels; ++i) { - BitTransferSigned(&offset[i], &base[i]); - offset[i] = Clamp(base[i] + offset[i], 0, 255); - } - - BlueContract(&base); - BlueContract(&offset); - - int sq_bc_error = 0; - // Remember, for blue-contract'd offset modes, the base is compared - // against the second endpoint and not the first. So, we compare - // against the first if we swapped the endpoints going in. - if (swapped) { - sq_bc_error = - SquaredError(base, endpoint_low_rgba, num_channels) + - SquaredError(offset, endpoint_high_rgba, num_channels); - } else { - sq_bc_error = - SquaredError(base, endpoint_high_rgba, num_channels) + - SquaredError(offset, endpoint_low_rgba, num_channels); - } - - const bool blue_contract = true; - const bool offset_mode = true; - *(errors_itr++) = CEEncodingOption(sq_bc_error, &pair, - swapped, blue_contract, offset_mode); - }; - - compute_base_offset_blue_contract_error(bc_offset_quantized, false); - - // 3.5 Compute swapped base/offset error. - compute_base_offset_error(offset_swapped_quantized, true); - - // 3.6 Compute swapped base/offset blue-contract error. - compute_base_offset_blue_contract_error( - bc_offset_swapped_quantized, true); - - std::sort(errors.begin(), errors.end(), - [](const CEEncodingOption& a, const CEEncodingOption& b) { - return a.Error() < b.Error(); - }); - - // 4. Encode the values correspondingly. - // For this part, we go through each measurement in order of increasing - // error. Based on the properties of each measurement, we decide how to - // best encode the quantized endpoints that produced that error value. If - // for some reason we cannot encode that metric, then we skip it and move - // to the next one. - for (const auto& measurement : errors) { - bool needs_weight_swap = false; - if (measurement.Pack(with_alpha, astc_mode, vals, &needs_weight_swap)) { - // Make sure that if we ask for a blue-contract mode that we get it *and* - // if we don't ask for it then we don't get it. - assert(!(measurement.BlueContract() ^ - UsesBlueContract(max_value, *astc_mode, *vals))); - - // We encoded what we got. - return needs_weight_swap; - } - } - - assert(false && "Shouldn't have reached this point -- some combination of " - "endpoints should be possible to encode!"); - return false; -} - -} // namespace - -//////////////////////////////////////////////////////////////////////////////// - -bool UsesBlueContract(int max_value, ColorEndpointMode mode, - const std::vector<int>& vals) { - assert(vals.size() >= NumColorValuesForEndpointMode(mode)); - - switch (mode) { - case ColorEndpointMode::kLDRRGBDirect: - case ColorEndpointMode::kLDRRGBADirect: { - constexpr int kNumVals = MaxValuesForModes( - ColorEndpointMode::kLDRRGBDirect, ColorEndpointMode::kLDRRGBADirect); - std::array<int, kNumVals> v {}; - std::copy(vals.begin(), vals.end(), v.begin()); - Unquantize(&v, max_value); - - const int s0 = v[0] + v[2] + v[4]; - const int s1 = v[1] + v[3] + v[5]; - - return s0 > s1; - } - - case ColorEndpointMode::kLDRRGBBaseOffset: - case ColorEndpointMode::kLDRRGBABaseOffset: { - constexpr int kNumVals = MaxValuesForModes( - ColorEndpointMode::kLDRRGBBaseOffset, - ColorEndpointMode::kLDRRGBABaseOffset); - std::array<int, kNumVals> v {}; - std::copy(vals.begin(), vals.end(), v.begin()); - Unquantize(&v, max_value); - - BitTransferSigned(&v[1], &v[0]); - BitTransferSigned(&v[3], &v[2]); - BitTransferSigned(&v[5], &v[4]); - - return v[1] + v[3] + v[5] < 0; - } - - default: - return false; - } -} - -bool EncodeColorsForMode( - const RgbaColor& endpoint_low_rgba, const RgbaColor& endpoint_high_rgba, - int max_value, EndpointEncodingMode encoding_mode, - ColorEndpointMode* const astc_mode, std::vector<int>* const vals) { - bool needs_weight_swap = false; - vals->resize(NumValuesForEncodingMode(encoding_mode)); - - switch (encoding_mode) { - case EndpointEncodingMode::kDirectLuma: - return EncodeColorsLuma( - endpoint_low_rgba, endpoint_high_rgba, max_value, astc_mode, vals); - - case EndpointEncodingMode::kDirectLumaAlpha: { - // TODO(google): See if luma-alpha base-offset is better - const int avg1 = AverageRGB(endpoint_low_rgba); - const int avg2 = AverageRGB(endpoint_high_rgba); - - (*vals)[0] = QuantizeCEValueToRange(avg1, max_value); - (*vals)[1] = QuantizeCEValueToRange(avg2, max_value); - (*vals)[2] = QuantizeCEValueToRange(endpoint_low_rgba[3], max_value); - (*vals)[3] = QuantizeCEValueToRange(endpoint_high_rgba[3], max_value); - *astc_mode = ColorEndpointMode::kLDRLumaAlphaDirect; - } - break; - - case EndpointEncodingMode::kBaseScaleRGB: - case EndpointEncodingMode::kBaseScaleRGBA: { - RgbaColor base = endpoint_high_rgba; - RgbaColor scaled = endpoint_low_rgba; - - // Similar to luma base-offset, the scaled value is strictly less than - // the base value here according to the decode procedure. In this case, - // if the base is larger than the scale then we need to swap. - int num_channels_ge = 0; - for (int i = 0; i < 3; ++i) { - num_channels_ge += - static_cast<int>(endpoint_high_rgba[i] >= endpoint_low_rgba[i]); - } - - if (num_channels_ge < 2) { - needs_weight_swap = true; - std::swap(base, scaled); - } - - // Since the second endpoint is just a direct copy of the RGB values, we - // can start by quantizing them. - const auto q_base = QuantizeColor(base, max_value); - const auto uq_base = UnquantizeColor(q_base, max_value); - - // The first endpoint (scaled) is defined by piecewise multiplying the - // second endpoint (base) by the scale factor and then dividing by 256. - // This means that the inverse operation is to first piecewise multiply - // the first endpoint by 256 and then divide by the unquantized second - // endpoint. We take the average of each of each of these scale values as - // our final scale value. - // TODO(google): Is this the best way to determine the scale factor? - int num_samples = 0; - int scale_sum = 0; - for (int i = 0; i < 3; ++i) { - int x = uq_base[i]; - if (x != 0) { - ++num_samples; - scale_sum += (scaled[i] * 256) / x; - } - } - - (*vals)[0] = q_base[0]; - (*vals)[1] = q_base[1]; - (*vals)[2] = q_base[2]; - if (num_samples > 0) { - const int avg_scale = Clamp(scale_sum / num_samples, 0, 255); - (*vals)[3] = QuantizeCEValueToRange(avg_scale, max_value); - } else { - // In this case, all of the base values are zero, so we can use whatever - // we want as the scale -- it won't affect the outcome. - (*vals)[3] = max_value; - } - *astc_mode = ColorEndpointMode::kLDRRGBBaseScale; - - if (encoding_mode == EndpointEncodingMode::kBaseScaleRGBA) { - (*vals)[4] = QuantizeCEValueToRange(scaled[3], max_value); - (*vals)[5] = QuantizeCEValueToRange(base[3], max_value); - *astc_mode = ColorEndpointMode::kLDRRGBBaseScaleTwoA; - } - } - break; - - case EndpointEncodingMode::kDirectRGB: - case EndpointEncodingMode::kDirectRGBA: - return EncodeColorsRGBA( - endpoint_low_rgba, endpoint_high_rgba, max_value, - encoding_mode == EndpointEncodingMode::kDirectRGBA, astc_mode, vals); - - default: - assert(false && "Unimplemented color encoding."); - } - - return needs_weight_swap; -} - -// These decoding procedures follow the code outlined in Section C.2.14 of -// the ASTC specification. -void DecodeColorsForMode(const std::vector<int>& vals, - int max_value, ColorEndpointMode mode, - RgbaColor* const endpoint_low_rgba, - RgbaColor* const endpoint_high_rgba) { - assert(vals.size() >= NumColorValuesForEndpointMode(mode)); - switch (mode) { - case ColorEndpointMode::kLDRLumaDirect: { - const int l0 = UnquantizeCEValueFromRange(vals[0], max_value); - const int l1 = UnquantizeCEValueFromRange(vals[1], max_value); - - *endpoint_low_rgba = {{ l0, l0, l0, 255 }}; - *endpoint_high_rgba = {{ l1, l1, l1, 255 }}; - } - break; - - case ColorEndpointMode::kLDRLumaBaseOffset: { - const int v0 = UnquantizeCEValueFromRange(vals[0], max_value); - const int v1 = UnquantizeCEValueFromRange(vals[1], max_value); - - const int l0 = (v0 >> 2) | (v1 & 0xC0); - const int l1 = std::min(l0 + (v1 & 0x3F), 0xFF); - - *endpoint_low_rgba = {{ l0, l0, l0, 255 }}; - *endpoint_high_rgba = {{ l1, l1, l1, 255 }}; - } - break; - - case ColorEndpointMode::kLDRLumaAlphaDirect: { - constexpr int kNumVals = - NumColorValuesForEndpointMode(ColorEndpointMode::kLDRLumaAlphaDirect); - - std::array<int, kNumVals> v; - std::copy(vals.begin(), vals.end(), v.begin()); - Unquantize(&v, max_value); - - *endpoint_low_rgba = {{ v[0], v[0], v[0], v[2] }}; - *endpoint_high_rgba = {{ v[1], v[1], v[1], v[3] }}; - } - break; - - case ColorEndpointMode::kLDRLumaAlphaBaseOffset: { - constexpr int kNumVals = NumColorValuesForEndpointMode( - ColorEndpointMode::kLDRLumaAlphaBaseOffset); - - std::array<int, kNumVals> v; - std::copy(vals.begin(), vals.end(), v.begin()); - Unquantize(&v, max_value); - - BitTransferSigned(&v[1], &v[0]); - BitTransferSigned(&v[3], &v[2]); - - *endpoint_low_rgba = {{ v[0], v[0], v[0], v[2] }}; - const int high_luma = v[0] + v[1]; - *endpoint_high_rgba = {{ high_luma, high_luma, high_luma, v[2] + v[3] }}; - - for (auto& c : *endpoint_low_rgba) { c = Clamp(c, 0, 255); } - for (auto& c : *endpoint_high_rgba) { c = Clamp(c, 0, 255); } - } - break; - - case ColorEndpointMode::kLDRRGBBaseScale: { - constexpr int kNumVals = - NumColorValuesForEndpointMode(ColorEndpointMode::kLDRRGBBaseScale); - - std::array<int, kNumVals> v; - std::copy(vals.begin(), vals.end(), v.begin()); - Unquantize(&v, max_value); - - *endpoint_high_rgba = {{ v[0], v[1], v[2], 255 }}; - for (int i = 0; i < 3; ++i) { - const int x = endpoint_high_rgba->at(i); - endpoint_low_rgba->at(i) = (x * v[3]) >> 8; - } - endpoint_low_rgba->at(3) = 255; - } - break; - - case ColorEndpointMode::kLDRRGBDirect: { - constexpr int kNumVals = - NumColorValuesForEndpointMode(ColorEndpointMode::kLDRRGBDirect); - - std::array<int, kNumVals> v; - std::copy(vals.begin(), vals.end(), v.begin()); - Unquantize(&v, max_value); - - const int s0 = v[0] + v[2] + v[4]; - const int s1 = v[1] + v[3] + v[5]; - - *endpoint_low_rgba = {{ v[0], v[2], v[4], 255 }}; - *endpoint_high_rgba = {{ v[1], v[3], v[5], 255 }}; - - if (s1 < s0) { - std::swap(*endpoint_low_rgba, *endpoint_high_rgba); - BlueContract(endpoint_low_rgba); - BlueContract(endpoint_high_rgba); - } - } - break; - - case ColorEndpointMode::kLDRRGBBaseOffset: { - constexpr int kNumVals = - NumColorValuesForEndpointMode(ColorEndpointMode::kLDRRGBBaseOffset); - - std::array<int, kNumVals> v; - std::copy(vals.begin(), vals.end(), v.begin()); - Unquantize(&v, max_value); - - BitTransferSigned(&v[1], &v[0]); - BitTransferSigned(&v[3], &v[2]); - BitTransferSigned(&v[5], &v[4]); - - *endpoint_low_rgba = {{ v[0], v[2], v[4], 255 }}; - *endpoint_high_rgba = {{ v[0] + v[1], v[2] + v[3], v[4] + v[5], 255 }}; - - if (v[1] + v[3] + v[5] < 0) { - std::swap(*endpoint_low_rgba, *endpoint_high_rgba); - BlueContract(endpoint_low_rgba); - BlueContract(endpoint_high_rgba); - } - - for (auto& c : *endpoint_low_rgba) { c = Clamp(c, 0, 255); } - for (auto& c : *endpoint_high_rgba) { c = Clamp(c, 0, 255); } - } - break; - - case ColorEndpointMode::kLDRRGBBaseScaleTwoA: { - constexpr int kNumVals = NumColorValuesForEndpointMode( - ColorEndpointMode::kLDRRGBBaseScaleTwoA); - - std::array<int, kNumVals> v; - std::copy(vals.begin(), vals.end(), v.begin()); - Unquantize(&v, max_value); - - // Base - *endpoint_low_rgba = *endpoint_high_rgba = {{ v[0], v[1], v[2], 255 }}; - - // Scale - for (int i = 0; i < 3; ++i) { - auto& x = endpoint_low_rgba->at(i); - x = (x * v[3]) >> 8; - } - - // Two A - endpoint_low_rgba->at(3) = v[4]; - endpoint_high_rgba->at(3) = v[5]; - } - break; - - case ColorEndpointMode::kLDRRGBADirect: { - constexpr int kNumVals = - NumColorValuesForEndpointMode(ColorEndpointMode::kLDRRGBADirect); - - std::array<int, kNumVals> v; - std::copy(vals.begin(), vals.end(), v.begin()); - Unquantize(&v, max_value); - - const int s0 = v[0] + v[2] + v[4]; - const int s1 = v[1] + v[3] + v[5]; - - *endpoint_low_rgba = {{ v[0], v[2], v[4], v[6] }}; - *endpoint_high_rgba = {{ v[1], v[3], v[5], v[7] }}; - - if (s1 < s0) { - std::swap(*endpoint_low_rgba, *endpoint_high_rgba); - BlueContract(endpoint_low_rgba); - BlueContract(endpoint_high_rgba); - } - } - break; - - case ColorEndpointMode::kLDRRGBABaseOffset: { - constexpr int kNumVals = - NumColorValuesForEndpointMode(ColorEndpointMode::kLDRRGBABaseOffset); - - std::array<int, kNumVals> v; - std::copy(vals.begin(), vals.end(), v.begin()); - Unquantize(&v, max_value); - - BitTransferSigned(&v[1], &v[0]); - BitTransferSigned(&v[3], &v[2]); - BitTransferSigned(&v[5], &v[4]); - BitTransferSigned(&v[7], &v[6]); - - *endpoint_low_rgba = {{ v[0], v[2], v[4], v[6] }}; - *endpoint_high_rgba = {{ - v[0] + v[1], v[2] + v[3], v[4] + v[5], v[6] + v[7] }}; - - if (v[1] + v[3] + v[5] < 0) { - std::swap(*endpoint_low_rgba, *endpoint_high_rgba); - BlueContract(endpoint_low_rgba); - BlueContract(endpoint_high_rgba); - } - - for (auto& c : *endpoint_low_rgba) { c = Clamp(c, 0, 255); } - for (auto& c : *endpoint_high_rgba) { c = Clamp(c, 0, 255); } - } - break; - - default: - // Unimplemented color encoding. - // TODO(google): Is this the correct error handling? - *endpoint_high_rgba = *endpoint_low_rgba = {{ 0, 0, 0, 0 }}; - } -} - -} // namespace astc_codec diff --git a/third-party/astc-codec/src/decoder/endpoint_codec.h b/third-party/astc-codec/src/decoder/endpoint_codec.h deleted file mode 100644 index a1232d06..00000000 --- a/third-party/astc-codec/src/decoder/endpoint_codec.h +++ /dev/null @@ -1,90 +0,0 @@ -// Copyright 2018 Google LLC -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// https://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -#ifndef ASTC_CODEC_DECODER_ENDPOINT_CODEC_H_ -#define ASTC_CODEC_DECODER_ENDPOINT_CODEC_H_ - -#include "src/decoder/physical_astc_block.h" -#include "src/decoder/types.h" - -#include <array> -#include <vector> - -namespace astc_codec { - -// We use a special distinction for encode modes used to pass to the -// EncodeColorsForMode function below. The reason is that some of the color -// modes have sub-modes (like blue-contract) that change whether or not it is -// useful to encode an endpoint pair using one mode versus another. To avoid -// this problem, we approach the problem of encoding by specifying some -// high-level encoding modes. These eventually choose one of the low level -// ColorEndpointModes from Section C.2.14 when used in EncodeColorsForMode. -enum class EndpointEncodingMode { - kDirectLuma, - kDirectLumaAlpha, - kBaseScaleRGB, - kBaseScaleRGBA, - kDirectRGB, - kDirectRGBA -}; - -// Returns the number of values in the encoded endpoint pair after encoding -// to a specific high-level encoding mode. -constexpr int NumValuesForEncodingMode(EndpointEncodingMode mode) { - return - mode == EndpointEncodingMode::kDirectLuma ? 2 : - mode == EndpointEncodingMode::kDirectLumaAlpha ? 4 : - mode == EndpointEncodingMode::kBaseScaleRGB ? 4 : - mode == EndpointEncodingMode::kBaseScaleRGBA ? 6 : - mode == EndpointEncodingMode::kDirectRGB ? 6 : 8; -} - -// Fills |vals| with the quantized endpoint colors values defined in the ASTC -// specification. The values are quantized to the range [0, max_value]. These -// quantization limits can be obtained by querying the associated functions in -// integer_sequence_codec. The returned |astc_mode| will be the ASTC mode used -// to encode the resulting sequence. -// -// The |encoding_mode| is used to determine the way that we encode the values. -// Each encoding mode is used to determine which ASTC mode best corresponds -// to the pair of endpoints. It is a necessary hint to the encoding function -// in order to process the endpoints. Each encoding mode gurantees a certain -// number of values generated per endpoints. -// -// The return value will be true if the endpoints have been switched in order to -// reap the most benefit from the way the hardware decodes the given mode. In -// this case, the associated weights that interpolate this color must also be -// switched. In other words, for each w, it should change to 64 - w. -bool EncodeColorsForMode( - const RgbaColor& endpoint_low_rgba, const RgbaColor& endpoint_high_rgba, - int max_value, EndpointEncodingMode encoding_mode, - ColorEndpointMode* astc_mode, std::vector<int>* vals); - -// Decodes the color values quantized to the range [0, max_value] into RGBA -// endpoints for the given mode. This function is the inverse of -// EncodeColorsForMode -- see that function for details. This function should -// work on all LDR endpoint modes, but no HDR modes. -void DecodeColorsForMode(const std::vector<int>& vals, - int max_value, ColorEndpointMode mode, - RgbaColor* endpoint_low_rgba, - RgbaColor* endpoint_high_rgba); - -// Returns true if the quantized |vals| in the range [0, max_value] use the -// 'blue_contract' modification during decoding for the given |mode|. -bool UsesBlueContract(int max_value, ColorEndpointMode mode, - const std::vector<int>& vals); - -} // namespace astc_codec - -#endif // ASTC_CODEC_DECODER_ENDPOINT_CODEC_H_ diff --git a/third-party/astc-codec/src/decoder/footprint.cc b/third-party/astc-codec/src/decoder/footprint.cc deleted file mode 100644 index e4f076e3..00000000 --- a/third-party/astc-codec/src/decoder/footprint.cc +++ /dev/null @@ -1,162 +0,0 @@ -// Copyright 2018 Google LLC -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// https://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -#include "src/decoder/footprint.h" -#include "src/base/string_utils.h" - -#include <map> -#include <string> -#include <utility> -#include <vector> - -namespace astc_codec { - -namespace { - -// Encodes the width and height into an integer so that we can use a switch -// statement instead of a costly lookup map. -constexpr int EncodeDims(int width, int height) { - return (width << 16) | height; -} - -} // namespace - -base::Optional<FootprintType> -Footprint::GetValidFootprintForDimensions(int width, int height) { - switch (EncodeDims(width, height)) { - case EncodeDims(4, 4): return FootprintType::k4x4; - case EncodeDims(5, 4): return FootprintType::k5x4; - case EncodeDims(5, 5): return FootprintType::k5x5; - case EncodeDims(6, 5): return FootprintType::k6x5; - case EncodeDims(6, 6): return FootprintType::k6x6; - case EncodeDims(8, 5): return FootprintType::k8x5; - case EncodeDims(8, 6): return FootprintType::k8x6; - case EncodeDims(8, 8): return FootprintType::k8x8; - case EncodeDims(10, 5): return FootprintType::k10x5; - case EncodeDims(10, 6): return FootprintType::k10x6; - case EncodeDims(10, 8): return FootprintType::k10x8; - case EncodeDims(10, 10): return FootprintType::k10x10; - case EncodeDims(12, 10): return FootprintType::k12x10; - case EncodeDims(12, 12): return FootprintType::k12x12; - default: return {}; - } -} - -int Footprint::GetWidthForFootprint(FootprintType footprint) { - switch (footprint) { - case FootprintType::k4x4: return 4; - case FootprintType::k5x4: return 5; - case FootprintType::k5x5: return 5; - case FootprintType::k6x5: return 6; - case FootprintType::k6x6: return 6; - case FootprintType::k8x5: return 8; - case FootprintType::k8x6: return 8; - case FootprintType::k10x5: return 10; - case FootprintType::k10x6: return 10; - case FootprintType::k8x8: return 8; - case FootprintType::k10x8: return 10; - case FootprintType::k10x10: return 10; - case FootprintType::k12x10: return 12; - case FootprintType::k12x12: return 12; - default: - assert(false); - return -1; - } -} - -int Footprint::GetHeightForFootprint(FootprintType footprint) { - switch (footprint) { - case FootprintType::k4x4: return 4; - case FootprintType::k5x4: return 4; - case FootprintType::k5x5: return 5; - case FootprintType::k6x5: return 5; - case FootprintType::k6x6: return 6; - case FootprintType::k8x5: return 5; - case FootprintType::k8x6: return 6; - case FootprintType::k10x5: return 5; - case FootprintType::k10x6: return 6; - case FootprintType::k8x8: return 8; - case FootprintType::k10x8: return 8; - case FootprintType::k10x10: return 10; - case FootprintType::k12x10: return 10; - case FootprintType::k12x12: return 12; - default: - assert(false); - return -1; - } -} - -Footprint::Footprint(FootprintType footprint) - : footprint_(footprint), width_(GetWidthForFootprint(footprint)), - height_(GetHeightForFootprint(footprint)) { } - -//////////////////////////////////////////////////////////////////////////////// - -base::Optional<Footprint> Footprint::Parse(const char* footprint_string) { - assert(footprint_string && footprint_string[0] != '\0'); - - std::vector<std::string> dimension_strings; - base::Split(footprint_string, "x", [&dimension_strings](std::string&& s) { - dimension_strings.push_back(std::move(s)); - }); - - if (dimension_strings.size() != 2) { - assert(false && "Invalid format for footprint"); - return {}; - } - - const int width = base::ParseInt32(dimension_strings[0].c_str(), 0); - const int height = base::ParseInt32(dimension_strings[1].c_str(), 0); - - assert(width > 0 && height > 0 && "Invalid width or height."); - - return FromDimensions(width, height); -} - -base::Optional<Footprint> Footprint::FromDimensions(int width, int height) { - base::Optional<FootprintType> valid_footprint = - GetValidFootprintForDimensions(width, height); - if (valid_footprint) { - return Footprint(valid_footprint.value()); - } else { - return {}; - } -} - -// Returns a Footprint for the given FootprintType. -base::Optional<Footprint> Footprint::FromFootprintType(FootprintType type) { - if (type >= FootprintType::k4x4 && type < FootprintType::kCount) { - return Footprint(type); - } else { - return {}; - } -} - -size_t Footprint::StorageRequirements(int width, int height) const { - const int blocks_wide = (width + width_ - 1) / width_; - const int blocks_high = (height + height_ - 1) / height_; - - constexpr size_t kASTCBlockSizeInBytes = 16; - return blocks_wide * blocks_high * kASTCBlockSizeInBytes; -} - -// Returns bits/pixel for a given footprint. -float Footprint::Bitrate() const { - const int kASTCBlockBitCount = 128; - const int footprint_pixel_count = width_ * height_; - return static_cast<float>(kASTCBlockBitCount) / - static_cast<float>(footprint_pixel_count); -} - -} // namespace astc_codec diff --git a/third-party/astc-codec/src/decoder/footprint.h b/third-party/astc-codec/src/decoder/footprint.h deleted file mode 100644 index 47302cc3..00000000 --- a/third-party/astc-codec/src/decoder/footprint.h +++ /dev/null @@ -1,106 +0,0 @@ -// Copyright 2018 Google LLC -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// https://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -#ifndef ASTC_CODEC_DECODER_FOOTPRINT_H_ -#define ASTC_CODEC_DECODER_FOOTPRINT_H_ - -#include "include/astc-codec/astc-codec.h" -#include "src/base/optional.h" - -#include <cstddef> - -namespace astc_codec { - -// An ASTC texture can be encoded with varying choices in block size. A set of -// predefined block sizes are specified in the ASTC specification. These are -// referred to in the literature as "footprints" available to an encoder when -// constructing an ASTC bitstream. This class provides various utility functions -// for interacting with these footprints. -class Footprint { - public: - Footprint() = delete; - Footprint(const Footprint& footprint) = default; - - // Return the footprint type. - FootprintType Type() const { return footprint_; } - - // Return logical descriptions of the dimensions. - int Width() const { return width_; } - int Height() const { return height_; } - - // Returns the number of pixels for a block with this footprint. - int NumPixels() const { return width_ * height_; } - - // Returns the number of bytes needed to store an ASTC encoded image with the - // given width and height. - size_t StorageRequirements(int width, int height) const; - - // Returns the number of bits used per pixel. - float Bitrate() const; - - static constexpr int NumValidFootprints() { - return static_cast<int>(FootprintType::kCount); - } - - bool operator==(const Footprint& other) const { - return footprint_ == other.footprint_; - } - - // These are the valid and available ASTC footprints. - static Footprint Get4x4() { return Footprint(FootprintType::k4x4); } - static Footprint Get5x4() { return Footprint(FootprintType::k5x4); } - static Footprint Get5x5() { return Footprint(FootprintType::k5x5); } - static Footprint Get6x5() { return Footprint(FootprintType::k6x5); } - static Footprint Get6x6() { return Footprint(FootprintType::k6x6); } - static Footprint Get8x5() { return Footprint(FootprintType::k8x5); } - static Footprint Get8x6() { return Footprint(FootprintType::k8x6); } - static Footprint Get8x8() { return Footprint(FootprintType::k8x8); } - static Footprint Get10x5() { return Footprint(FootprintType::k10x5); } - static Footprint Get10x6() { return Footprint(FootprintType::k10x6); } - static Footprint Get10x8() { return Footprint(FootprintType::k10x8); } - static Footprint Get10x10() { return Footprint(FootprintType::k10x10); } - static Footprint Get12x10() { return Footprint(FootprintType::k12x10); } - static Footprint Get12x12() { return Footprint(FootprintType::k12x12); } - - // Constructs a footprint from a string of the form "NxM", or no value if - // width and height are not a valid footprint. - static base::Optional<Footprint> Parse(const char* footprint_string); - - // Returns a footprint corresponding to a block of the given width and height, - // or no value if it does not. - static base::Optional<Footprint> FromDimensions(int width, int height); - - // Returns a Footprint for the given FootprintType. - static base::Optional<Footprint> FromFootprintType(FootprintType type); - - private: - // The only constructor. - explicit Footprint(FootprintType footprint); - - // Returns the valid footprint for the width and height if possible. - static base::Optional<FootprintType> GetValidFootprintForDimensions( - int width, int height); - - // Returns the associated dimension for the given valid footprint. - static int GetWidthForFootprint(FootprintType footprint); - static int GetHeightForFootprint(FootprintType footprint); - - FootprintType footprint_; - int width_; - int height_; -}; - -} // namespace astc_codec - -#endif // ASTC_CODEC_DECODER_FOOTPRINT_H_ diff --git a/third-party/astc-codec/src/decoder/integer_sequence_codec.cc b/third-party/astc-codec/src/decoder/integer_sequence_codec.cc deleted file mode 100644 index c2cd5119..00000000 --- a/third-party/astc-codec/src/decoder/integer_sequence_codec.cc +++ /dev/null @@ -1,570 +0,0 @@ -// Copyright 2018 Google LLC -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// https://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -#include "src/decoder/integer_sequence_codec.h" -#include "src/base/math_utils.h" -#include "src/base/utils.h" - -#include <algorithm> -#include <iostream> - -namespace astc_codec { - -namespace { - -// Tables of trit and quint encodings generated by the implementation in -// http://cs/aosp-master/external/skia/src/utils/SkTextureCompressor_ASTC.cpp -// -// These tables are used to decode the blocks of values encoded using the ASTC -// integer sequence encoding. The theory is that five trits (values that can -// take any number in the range [0, 2]) can take on a total of 3^5 = 243 total -// values, which can be stored in eight bits. These eight bits are used to -// decode the five trits based on the ASTC specification in Section C.2.12. -// For simplicity, we have stored a look-up table here so that we don't need -// to implement the decoding logic. Similarly, seven bits are used to decode -// three quints (since 5^3 = 125 < 128). -static const std::array<int, 5> kTritEncodings[256] = { - {{ 0, 0, 0, 0, 0 }}, {{ 1, 0, 0, 0, 0 }}, {{ 2, 0, 0, 0, 0 }}, - {{ 0, 0, 2, 0, 0 }}, {{ 0, 1, 0, 0, 0 }}, {{ 1, 1, 0, 0, 0 }}, - {{ 2, 1, 0, 0, 0 }}, {{ 1, 0, 2, 0, 0 }}, {{ 0, 2, 0, 0, 0 }}, - {{ 1, 2, 0, 0, 0 }}, {{ 2, 2, 0, 0, 0 }}, {{ 2, 0, 2, 0, 0 }}, - {{ 0, 2, 2, 0, 0 }}, {{ 1, 2, 2, 0, 0 }}, {{ 2, 2, 2, 0, 0 }}, - {{ 2, 0, 2, 0, 0 }}, {{ 0, 0, 1, 0, 0 }}, {{ 1, 0, 1, 0, 0 }}, - {{ 2, 0, 1, 0, 0 }}, {{ 0, 1, 2, 0, 0 }}, {{ 0, 1, 1, 0, 0 }}, - {{ 1, 1, 1, 0, 0 }}, {{ 2, 1, 1, 0, 0 }}, {{ 1, 1, 2, 0, 0 }}, - {{ 0, 2, 1, 0, 0 }}, {{ 1, 2, 1, 0, 0 }}, {{ 2, 2, 1, 0, 0 }}, - {{ 2, 1, 2, 0, 0 }}, {{ 0, 0, 0, 2, 2 }}, {{ 1, 0, 0, 2, 2 }}, - {{ 2, 0, 0, 2, 2 }}, {{ 0, 0, 2, 2, 2 }}, {{ 0, 0, 0, 1, 0 }}, - {{ 1, 0, 0, 1, 0 }}, {{ 2, 0, 0, 1, 0 }}, {{ 0, 0, 2, 1, 0 }}, - {{ 0, 1, 0, 1, 0 }}, {{ 1, 1, 0, 1, 0 }}, {{ 2, 1, 0, 1, 0 }}, - {{ 1, 0, 2, 1, 0 }}, {{ 0, 2, 0, 1, 0 }}, {{ 1, 2, 0, 1, 0 }}, - {{ 2, 2, 0, 1, 0 }}, {{ 2, 0, 2, 1, 0 }}, {{ 0, 2, 2, 1, 0 }}, - {{ 1, 2, 2, 1, 0 }}, {{ 2, 2, 2, 1, 0 }}, {{ 2, 0, 2, 1, 0 }}, - {{ 0, 0, 1, 1, 0 }}, {{ 1, 0, 1, 1, 0 }}, {{ 2, 0, 1, 1, 0 }}, - {{ 0, 1, 2, 1, 0 }}, {{ 0, 1, 1, 1, 0 }}, {{ 1, 1, 1, 1, 0 }}, - {{ 2, 1, 1, 1, 0 }}, {{ 1, 1, 2, 1, 0 }}, {{ 0, 2, 1, 1, 0 }}, - {{ 1, 2, 1, 1, 0 }}, {{ 2, 2, 1, 1, 0 }}, {{ 2, 1, 2, 1, 0 }}, - {{ 0, 1, 0, 2, 2 }}, {{ 1, 1, 0, 2, 2 }}, {{ 2, 1, 0, 2, 2 }}, - {{ 1, 0, 2, 2, 2 }}, {{ 0, 0, 0, 2, 0 }}, {{ 1, 0, 0, 2, 0 }}, - {{ 2, 0, 0, 2, 0 }}, {{ 0, 0, 2, 2, 0 }}, {{ 0, 1, 0, 2, 0 }}, - {{ 1, 1, 0, 2, 0 }}, {{ 2, 1, 0, 2, 0 }}, {{ 1, 0, 2, 2, 0 }}, - {{ 0, 2, 0, 2, 0 }}, {{ 1, 2, 0, 2, 0 }}, {{ 2, 2, 0, 2, 0 }}, - {{ 2, 0, 2, 2, 0 }}, {{ 0, 2, 2, 2, 0 }}, {{ 1, 2, 2, 2, 0 }}, - {{ 2, 2, 2, 2, 0 }}, {{ 2, 0, 2, 2, 0 }}, {{ 0, 0, 1, 2, 0 }}, - {{ 1, 0, 1, 2, 0 }}, {{ 2, 0, 1, 2, 0 }}, {{ 0, 1, 2, 2, 0 }}, - {{ 0, 1, 1, 2, 0 }}, {{ 1, 1, 1, 2, 0 }}, {{ 2, 1, 1, 2, 0 }}, - {{ 1, 1, 2, 2, 0 }}, {{ 0, 2, 1, 2, 0 }}, {{ 1, 2, 1, 2, 0 }}, - {{ 2, 2, 1, 2, 0 }}, {{ 2, 1, 2, 2, 0 }}, {{ 0, 2, 0, 2, 2 }}, - {{ 1, 2, 0, 2, 2 }}, {{ 2, 2, 0, 2, 2 }}, {{ 2, 0, 2, 2, 2 }}, - {{ 0, 0, 0, 0, 2 }}, {{ 1, 0, 0, 0, 2 }}, {{ 2, 0, 0, 0, 2 }}, - {{ 0, 0, 2, 0, 2 }}, {{ 0, 1, 0, 0, 2 }}, {{ 1, 1, 0, 0, 2 }}, - {{ 2, 1, 0, 0, 2 }}, {{ 1, 0, 2, 0, 2 }}, {{ 0, 2, 0, 0, 2 }}, - {{ 1, 2, 0, 0, 2 }}, {{ 2, 2, 0, 0, 2 }}, {{ 2, 0, 2, 0, 2 }}, - {{ 0, 2, 2, 0, 2 }}, {{ 1, 2, 2, 0, 2 }}, {{ 2, 2, 2, 0, 2 }}, - {{ 2, 0, 2, 0, 2 }}, {{ 0, 0, 1, 0, 2 }}, {{ 1, 0, 1, 0, 2 }}, - {{ 2, 0, 1, 0, 2 }}, {{ 0, 1, 2, 0, 2 }}, {{ 0, 1, 1, 0, 2 }}, - {{ 1, 1, 1, 0, 2 }}, {{ 2, 1, 1, 0, 2 }}, {{ 1, 1, 2, 0, 2 }}, - {{ 0, 2, 1, 0, 2 }}, {{ 1, 2, 1, 0, 2 }}, {{ 2, 2, 1, 0, 2 }}, - {{ 2, 1, 2, 0, 2 }}, {{ 0, 2, 2, 2, 2 }}, {{ 1, 2, 2, 2, 2 }}, - {{ 2, 2, 2, 2, 2 }}, {{ 2, 0, 2, 2, 2 }}, {{ 0, 0, 0, 0, 1 }}, - {{ 1, 0, 0, 0, 1 }}, {{ 2, 0, 0, 0, 1 }}, {{ 0, 0, 2, 0, 1 }}, - {{ 0, 1, 0, 0, 1 }}, {{ 1, 1, 0, 0, 1 }}, {{ 2, 1, 0, 0, 1 }}, - {{ 1, 0, 2, 0, 1 }}, {{ 0, 2, 0, 0, 1 }}, {{ 1, 2, 0, 0, 1 }}, - {{ 2, 2, 0, 0, 1 }}, {{ 2, 0, 2, 0, 1 }}, {{ 0, 2, 2, 0, 1 }}, - {{ 1, 2, 2, 0, 1 }}, {{ 2, 2, 2, 0, 1 }}, {{ 2, 0, 2, 0, 1 }}, - {{ 0, 0, 1, 0, 1 }}, {{ 1, 0, 1, 0, 1 }}, {{ 2, 0, 1, 0, 1 }}, - {{ 0, 1, 2, 0, 1 }}, {{ 0, 1, 1, 0, 1 }}, {{ 1, 1, 1, 0, 1 }}, - {{ 2, 1, 1, 0, 1 }}, {{ 1, 1, 2, 0, 1 }}, {{ 0, 2, 1, 0, 1 }}, - {{ 1, 2, 1, 0, 1 }}, {{ 2, 2, 1, 0, 1 }}, {{ 2, 1, 2, 0, 1 }}, - {{ 0, 0, 1, 2, 2 }}, {{ 1, 0, 1, 2, 2 }}, {{ 2, 0, 1, 2, 2 }}, - {{ 0, 1, 2, 2, 2 }}, {{ 0, 0, 0, 1, 1 }}, {{ 1, 0, 0, 1, 1 }}, - {{ 2, 0, 0, 1, 1 }}, {{ 0, 0, 2, 1, 1 }}, {{ 0, 1, 0, 1, 1 }}, - {{ 1, 1, 0, 1, 1 }}, {{ 2, 1, 0, 1, 1 }}, {{ 1, 0, 2, 1, 1 }}, - {{ 0, 2, 0, 1, 1 }}, {{ 1, 2, 0, 1, 1 }}, {{ 2, 2, 0, 1, 1 }}, - {{ 2, 0, 2, 1, 1 }}, {{ 0, 2, 2, 1, 1 }}, {{ 1, 2, 2, 1, 1 }}, - {{ 2, 2, 2, 1, 1 }}, {{ 2, 0, 2, 1, 1 }}, {{ 0, 0, 1, 1, 1 }}, - {{ 1, 0, 1, 1, 1 }}, {{ 2, 0, 1, 1, 1 }}, {{ 0, 1, 2, 1, 1 }}, - {{ 0, 1, 1, 1, 1 }}, {{ 1, 1, 1, 1, 1 }}, {{ 2, 1, 1, 1, 1 }}, - {{ 1, 1, 2, 1, 1 }}, {{ 0, 2, 1, 1, 1 }}, {{ 1, 2, 1, 1, 1 }}, - {{ 2, 2, 1, 1, 1 }}, {{ 2, 1, 2, 1, 1 }}, {{ 0, 1, 1, 2, 2 }}, - {{ 1, 1, 1, 2, 2 }}, {{ 2, 1, 1, 2, 2 }}, {{ 1, 1, 2, 2, 2 }}, - {{ 0, 0, 0, 2, 1 }}, {{ 1, 0, 0, 2, 1 }}, {{ 2, 0, 0, 2, 1 }}, - {{ 0, 0, 2, 2, 1 }}, {{ 0, 1, 0, 2, 1 }}, {{ 1, 1, 0, 2, 1 }}, - {{ 2, 1, 0, 2, 1 }}, {{ 1, 0, 2, 2, 1 }}, {{ 0, 2, 0, 2, 1 }}, - {{ 1, 2, 0, 2, 1 }}, {{ 2, 2, 0, 2, 1 }}, {{ 2, 0, 2, 2, 1 }}, - {{ 0, 2, 2, 2, 1 }}, {{ 1, 2, 2, 2, 1 }}, {{ 2, 2, 2, 2, 1 }}, - {{ 2, 0, 2, 2, 1 }}, {{ 0, 0, 1, 2, 1 }}, {{ 1, 0, 1, 2, 1 }}, - {{ 2, 0, 1, 2, 1 }}, {{ 0, 1, 2, 2, 1 }}, {{ 0, 1, 1, 2, 1 }}, - {{ 1, 1, 1, 2, 1 }}, {{ 2, 1, 1, 2, 1 }}, {{ 1, 1, 2, 2, 1 }}, - {{ 0, 2, 1, 2, 1 }}, {{ 1, 2, 1, 2, 1 }}, {{ 2, 2, 1, 2, 1 }}, - {{ 2, 1, 2, 2, 1 }}, {{ 0, 2, 1, 2, 2 }}, {{ 1, 2, 1, 2, 2 }}, - {{ 2, 2, 1, 2, 2 }}, {{ 2, 1, 2, 2, 2 }}, {{ 0, 0, 0, 1, 2 }}, - {{ 1, 0, 0, 1, 2 }}, {{ 2, 0, 0, 1, 2 }}, {{ 0, 0, 2, 1, 2 }}, - {{ 0, 1, 0, 1, 2 }}, {{ 1, 1, 0, 1, 2 }}, {{ 2, 1, 0, 1, 2 }}, - {{ 1, 0, 2, 1, 2 }}, {{ 0, 2, 0, 1, 2 }}, {{ 1, 2, 0, 1, 2 }}, - {{ 2, 2, 0, 1, 2 }}, {{ 2, 0, 2, 1, 2 }}, {{ 0, 2, 2, 1, 2 }}, - {{ 1, 2, 2, 1, 2 }}, {{ 2, 2, 2, 1, 2 }}, {{ 2, 0, 2, 1, 2 }}, - {{ 0, 0, 1, 1, 2 }}, {{ 1, 0, 1, 1, 2 }}, {{ 2, 0, 1, 1, 2 }}, - {{ 0, 1, 2, 1, 2 }}, {{ 0, 1, 1, 1, 2 }}, {{ 1, 1, 1, 1, 2 }}, - {{ 2, 1, 1, 1, 2 }}, {{ 1, 1, 2, 1, 2 }}, {{ 0, 2, 1, 1, 2 }}, - {{ 1, 2, 1, 1, 2 }}, {{ 2, 2, 1, 1, 2 }}, {{ 2, 1, 2, 1, 2 }}, - {{ 0, 2, 2, 2, 2 }}, {{ 1, 2, 2, 2, 2 }}, {{ 2, 2, 2, 2, 2 }}, - {{ 2, 1, 2, 2, 2 }} -}; - -static const std::array<int, 3> kQuintEncodings[128] = { - {{ 0, 0, 0 }}, {{ 1, 0, 0 }}, {{ 2, 0, 0 }}, {{ 3, 0, 0 }}, {{ 4, 0, 0 }}, - {{ 0, 4, 0 }}, {{ 4, 4, 0 }}, {{ 4, 4, 4 }}, {{ 0, 1, 0 }}, {{ 1, 1, 0 }}, - {{ 2, 1, 0 }}, {{ 3, 1, 0 }}, {{ 4, 1, 0 }}, {{ 1, 4, 0 }}, {{ 4, 4, 1 }}, - {{ 4, 4, 4 }}, {{ 0, 2, 0 }}, {{ 1, 2, 0 }}, {{ 2, 2, 0 }}, {{ 3, 2, 0 }}, - {{ 4, 2, 0 }}, {{ 2, 4, 0 }}, {{ 4, 4, 2 }}, {{ 4, 4, 4 }}, {{ 0, 3, 0 }}, - {{ 1, 3, 0 }}, {{ 2, 3, 0 }}, {{ 3, 3, 0 }}, {{ 4, 3, 0 }}, {{ 3, 4, 0 }}, - {{ 4, 4, 3 }}, {{ 4, 4, 4 }}, {{ 0, 0, 1 }}, {{ 1, 0, 1 }}, {{ 2, 0, 1 }}, - {{ 3, 0, 1 }}, {{ 4, 0, 1 }}, {{ 0, 4, 1 }}, {{ 4, 0, 4 }}, {{ 0, 4, 4 }}, - {{ 0, 1, 1 }}, {{ 1, 1, 1 }}, {{ 2, 1, 1 }}, {{ 3, 1, 1 }}, {{ 4, 1, 1 }}, - {{ 1, 4, 1 }}, {{ 4, 1, 4 }}, {{ 1, 4, 4 }}, {{ 0, 2, 1 }}, {{ 1, 2, 1 }}, - {{ 2, 2, 1 }}, {{ 3, 2, 1 }}, {{ 4, 2, 1 }}, {{ 2, 4, 1 }}, {{ 4, 2, 4 }}, - {{ 2, 4, 4 }}, {{ 0, 3, 1 }}, {{ 1, 3, 1 }}, {{ 2, 3, 1 }}, {{ 3, 3, 1 }}, - {{ 4, 3, 1 }}, {{ 3, 4, 1 }}, {{ 4, 3, 4 }}, {{ 3, 4, 4 }}, {{ 0, 0, 2 }}, - {{ 1, 0, 2 }}, {{ 2, 0, 2 }}, {{ 3, 0, 2 }}, {{ 4, 0, 2 }}, {{ 0, 4, 2 }}, - {{ 2, 0, 4 }}, {{ 3, 0, 4 }}, {{ 0, 1, 2 }}, {{ 1, 1, 2 }}, {{ 2, 1, 2 }}, - {{ 3, 1, 2 }}, {{ 4, 1, 2 }}, {{ 1, 4, 2 }}, {{ 2, 1, 4 }}, {{ 3, 1, 4 }}, - {{ 0, 2, 2 }}, {{ 1, 2, 2 }}, {{ 2, 2, 2 }}, {{ 3, 2, 2 }}, {{ 4, 2, 2 }}, - {{ 2, 4, 2 }}, {{ 2, 2, 4 }}, {{ 3, 2, 4 }}, {{ 0, 3, 2 }}, {{ 1, 3, 2 }}, - {{ 2, 3, 2 }}, {{ 3, 3, 2 }}, {{ 4, 3, 2 }}, {{ 3, 4, 2 }}, {{ 2, 3, 4 }}, - {{ 3, 3, 4 }}, {{ 0, 0, 3 }}, {{ 1, 0, 3 }}, {{ 2, 0, 3 }}, {{ 3, 0, 3 }}, - {{ 4, 0, 3 }}, {{ 0, 4, 3 }}, {{ 0, 0, 4 }}, {{ 1, 0, 4 }}, {{ 0, 1, 3 }}, - {{ 1, 1, 3 }}, {{ 2, 1, 3 }}, {{ 3, 1, 3 }}, {{ 4, 1, 3 }}, {{ 1, 4, 3 }}, - {{ 0, 1, 4 }}, {{ 1, 1, 4 }}, {{ 0, 2, 3 }}, {{ 1, 2, 3 }}, {{ 2, 2, 3 }}, - {{ 3, 2, 3 }}, {{ 4, 2, 3 }}, {{ 2, 4, 3 }}, {{ 0, 2, 4 }}, {{ 1, 2, 4 }}, - {{ 0, 3, 3 }}, {{ 1, 3, 3 }}, {{ 2, 3, 3 }}, {{ 3, 3, 3 }}, {{ 4, 3, 3 }}, - {{ 3, 4, 3 }}, {{ 0, 3, 4 }}, {{ 1, 3, 4 }} -}; - -// A cached table containing the max ranges for values encoded using ASTC's -// Bounded Integer Sequence Encoding. These are the numbers between 1 and 255 -// that can be represented exactly as a number in the ranges -// [0, 2^k), [0, 3 * 2^k), and [0, 5 * 2^k). -static const std::array<int, kNumPossibleRanges> kMaxRanges = []() { - std::array<int, kNumPossibleRanges> ranges; - - // Initialize the table that we need for determining value encodings. - auto next_max_range = ranges.begin(); - auto add_val = [&next_max_range](int val) { - if (val <= 0 || (1 << kLog2MaxRangeForBits) <= val) { - return; - } - - *(next_max_range++) = val; - }; - - for (int i = 0; i <= kLog2MaxRangeForBits; ++i) { - add_val(3 * (1 << i) - 1); - add_val(5 * (1 << i) - 1); - add_val((1 << i) - 1); - } - - assert(std::distance(next_max_range, ranges.end()) == 0); - std::sort(ranges.begin(), ranges.end()); - return ranges; -}(); - -// Returns true if x == 0 or if x is a power of two. This function is only used -// in the GetCountsForRange function, where we need to have it return true -// on zero since we can have single trit/quint ISE encodings according to -// Table C.2.7. -template<typename T, - typename std::enable_if<std::is_integral<T>::value, T>::type = 0> -inline constexpr bool IsPow2(T x) { return (x & (x - 1)) == 0; } - -// For the ISE block encoding, these arrays determine how many bits are -// used after each value to store the interleaved quint/trit block. -const int kInterleavedQuintBits[3] = { 3, 2, 2 }; -const int kInterleavedTritBits[5] = { 2, 2, 1, 2, 1 }; - -// Some template meta programming to get around the fact that MSVC -// will not allow (ValRange == 5) ? 3 : 5 as a template parameter -template<int ValRange> -struct DecodeBlockSize { - enum { value = (ValRange == 5 ? 3 : 5) }; -}; - -// Decodes either a trit or quint block using the BISE (Bounded Integer Sequence -// Encoding) defined in Section C.2.12 of the ASTC specification. ValRange is -// expected to be either 3 or 5 depending on whether or not we're encoding trits -// or quints respectively. In other words, it is the remaining factor in whether -// the passed blocks contain encoded values of the form 3*2^k or 5*2^k. -template<int ValRange> -std::array<int, /* kNumVals = */ DecodeBlockSize<ValRange>::value> DecodeISEBlock( - uint64_t block_bits, int num_bits) { - static_assert(ValRange == 3 || ValRange == 5, - "We only know about trits and quints"); - - // We either have three quints or five trits - constexpr const int kNumVals = (ValRange == 5) ? 3 : 5; - - // Depending on whether or not we're using quints or trits will determine - // the positions of the interleaved bits in the encoded block. - constexpr const int* const kInterleavedBits = - (ValRange == 5) ? kInterleavedQuintBits : kInterleavedTritBits; - - // Set up the bits for reading - base::BitStream<base::UInt128> block_bit_src(block_bits, sizeof(block_bits) * 8); - - // Decode the block - std::array<int, kNumVals> m; - uint64_t encoded = 0; - uint32_t encoded_bits_read = 0; - for (int i = 0; i < kNumVals; ++i) { - { - uint64_t bits = 0; - const bool result = block_bit_src.GetBits(num_bits, &bits); - assert(result); - - m[i] = static_cast<int>(bits); - } - - uint64_t encoded_bits; - { - const bool result = block_bit_src.GetBits(kInterleavedBits[i], &encoded_bits); - assert(result); - } - encoded |= encoded_bits << encoded_bits_read; - encoded_bits_read += kInterleavedBits[i]; - } - - // Make sure that our encoded trit/quint doesn't exceed its bounds - assert(ValRange != 3 || encoded < 256); - assert(ValRange != 5 || encoded < 128); - - const int* const kEncodings = (ValRange == 5) ? - kQuintEncodings[encoded].data() : kTritEncodings[encoded].data(); - - std::array<int, kNumVals> result; - for (int i = 0; i < kNumVals; ++i) { - assert(m[i] < 1 << num_bits); - result[i] = kEncodings[i] << num_bits | m[i]; - } - return result; -} - -// Encode a single trit or quint block using the BISE (Bounded Integer Sequence -// Encoding) defined in Section C.2.12 of the ASTC specification. ValRange is -// expected to be either 3 or 5 depending on whether or not we're encoding trits -// or quints respectively. In other words, it is the remaining factor in whether -// the passed blocks contain encoded values of the form 3*2^k or 5*2^k. -template <int ValRange> -void EncodeISEBlock(const std::vector<int>& vals, int bits_per_val, - base::BitStream<base::UInt128>* bit_sink) { - static_assert(ValRange == 3 || ValRange == 5, - "We only know about trits and quints"); - - // We either have three quints or five trits - constexpr const int kNumVals = (ValRange == 5) ? 3 : 5; - - // Three quints in seven bits or five trits in eight bits - constexpr const int kNumEncodedBitsPerBlock = (ValRange == 5) ? 7 : 8; - - // Depending on whether or not we're using quints or trits will determine - // the positions of the interleaved bits in the encoding - constexpr const int* const kInterleavedBits = - (ValRange == 5) ? kInterleavedQuintBits : kInterleavedTritBits; - - // ISE blocks can only have up to a specific number of values... - assert(vals.size() <= kNumVals); - - // Split up into bits and non bits. Non bits are used to find the quint/trit - // encoding that we need. - std::array<int, kNumVals> non_bits = {{ 0 }}; - std::array<int, kNumVals> bits = {{ 0 }}; - for (size_t i = 0; i < vals.size(); ++i) { - bits[i] = vals[i] & ((1 << bits_per_val) - 1); - non_bits[i] = vals[i] >> bits_per_val; - assert(non_bits[i] < ValRange); - } - - // We only need to add as many bits as necessary, so let's limit it based - // on the computation described in Section C.2.22 of the ASTC specification - const int total_num_bits = - ((vals.size() * kNumEncodedBitsPerBlock + kNumVals - 1) / kNumVals) - + vals.size() * bits_per_val; - int bits_added = 0; - - // The number of bits used for the quint/trit encoding is necessary to know - // in order to properly select the encoding we need to represent. - int num_encoded_bits = 0; - for (int i = 0; i < kNumVals; ++i) { - bits_added += bits_per_val; - if (bits_added >= total_num_bits) { - break; - } - - num_encoded_bits += kInterleavedBits[i]; - bits_added += kInterleavedBits[i]; - if (bits_added >= total_num_bits) { - break; - } - } - bits_added = 0; - assert(num_encoded_bits <= kNumEncodedBitsPerBlock); - - // TODO(google): The faster way to do this would be to construct trees out - // of the quint/trit encoding patterns, or just invert the decoding logic. - // Here we go from the end backwards because it makes our tests are more - // deterministic. - int non_bit_encoding = -1; - for (int j = (1 << num_encoded_bits) - 1; j >= 0; --j) { - bool matches = true; - - // We don't need to match all trits here, just the ones that correspond - // to the values that we passed in - for (size_t i = 0; i < kNumVals; ++i) { - if ((ValRange == 5 && kQuintEncodings[j][i] != non_bits[i]) || - (ValRange == 3 && kTritEncodings[j][i] != non_bits[i])) { - matches = false; - break; - } - } - - if (matches) { - non_bit_encoding = j; - break; - } - } - - assert(non_bit_encoding >= 0); - - // Now pack the bits into the block - for (int i = 0; i < vals.size(); ++i) { - // First add the base bits for this value - if (bits_added + bits_per_val <= total_num_bits) { - bit_sink->PutBits(bits[i], bits_per_val); - bits_added += bits_per_val; - } - - // Now add the interleaved bits from the quint/trit - int num_int_bits = kInterleavedBits[i]; - int int_bits = non_bit_encoding & ((1 << num_int_bits) - 1); - if (bits_added + num_int_bits <= total_num_bits) { - bit_sink->PutBits(int_bits, num_int_bits); - bits_added += num_int_bits; - non_bit_encoding >>= num_int_bits; - } - } -} - -inline void CHECK_COUNTS(int trits, int quints) { - assert(trits == 0 || quints == 0); // Either trits or quints - assert(trits == 0 || trits == 1); // At most one trit - assert(quints == 0 || quints == 1); // At most one quint -} - -} // namespace - -//////////////////////////////////////////////////////////////////////////////// - -std::array<int, kNumPossibleRanges>::const_iterator ISERangeBegin() { - return kMaxRanges.cbegin(); -} - -std::array<int, kNumPossibleRanges>::const_iterator ISERangeEnd() { - return kMaxRanges.cend(); -} - -void IntegerSequenceCodec::GetCountsForRange( - int range, int* const trits, int* const quints, int* const bits) { - // Make sure the passed pointers are valid - assert(trits != nullptr); - assert(quints != nullptr); - assert(bits != nullptr); - - // These are generally errors -- there should never be any ASTC values - // outside of this range - UTILS_RELEASE_ASSERT(range > 0); - UTILS_RELEASE_ASSERT(range < 1 << kLog2MaxRangeForBits); - - *bits = 0; - *trits = 0; - *quints = 0; - - // Search through the numbers of the form 2^n, 3 * 2^n and 5 * 2^n - const int max_vals_for_range = - *std::lower_bound(kMaxRanges.begin(), kMaxRanges.end(), range) + 1; - - // Make sure we found something - assert(max_vals_for_range > 1); - - // Find out what kind of range it is - if ((max_vals_for_range % 3 == 0) && IsPow2(max_vals_for_range / 3)) { - *bits = base::Log2Floor(max_vals_for_range / 3); - *trits = 1; - *quints = 0; - } else if ((max_vals_for_range % 5 == 0) && IsPow2(max_vals_for_range / 5)) { - *bits = base::Log2Floor(max_vals_for_range / 5); - *trits = 0; - *quints = 1; - } else if (IsPow2(max_vals_for_range)) { - *bits = base::Log2Floor(max_vals_for_range); - *trits = 0; - *quints = 0; - } - - // If we set any of these values then we're done. - if ((*bits | *trits | *quints) != 0) { - CHECK_COUNTS(*trits, *quints); - } -} - -// Returns the overall bit count for a range of val_count values encoded -// using the specified number of trits, quints and straight bits (respectively) -int IntegerSequenceCodec::GetBitCount(int num_vals, - int trits, int quints, int bits) { - CHECK_COUNTS(trits, quints); - - // See section C.2.22 for the formula used here. - const int trit_bit_count = ((num_vals * 8 * trits) + 4) / 5; - const int quint_bit_count = ((num_vals * 7 * quints) + 2) / 3; - const int base_bit_count = num_vals * bits; - return trit_bit_count + quint_bit_count + base_bit_count; -} - -IntegerSequenceCodec::IntegerSequenceCodec(int range) { - int trits, quints, bits; - GetCountsForRange(range, &trits, &quints, &bits); - InitializeWithCounts(trits, quints, bits); -} - -IntegerSequenceCodec::IntegerSequenceCodec( - int trits, int quints, int bits) { - InitializeWithCounts(trits, quints, bits); -} - -void IntegerSequenceCodec::InitializeWithCounts( - int trits, int quints, int bits) { - CHECK_COUNTS(trits, quints); - - if (trits > 0) { - encoding_ = EncodingMode::kTritEncoding; - } else if (quints > 0) { - encoding_ = EncodingMode::kQuintEncoding; - } else { - encoding_ = EncodingMode::kBitEncoding; - } - - bits_ = bits; -} - -int IntegerSequenceCodec::NumValsPerBlock() const { - const std::array<int, 3> kNumValsByEncoding = {{ 5, 3, 1 }}; - return kNumValsByEncoding[static_cast<int>(encoding_)]; -} - -int IntegerSequenceCodec::EncodedBlockSize() const { - const std::array<int, 3> kExtraBlockSizeByEncoding = {{ 8, 7, 0 }}; - const int num_vals = NumValsPerBlock(); - return kExtraBlockSizeByEncoding[static_cast<int>(encoding_)] - + num_vals * bits_; -} - -std::vector<int> IntegerSequenceDecoder::Decode( - int num_vals, base::BitStream<base::UInt128> *bit_src) const { - int trits = (encoding_ == kTritEncoding)? 1 : 0; - int quints = (encoding_ == kQuintEncoding)? 1 : 0; - const int total_num_bits = GetBitCount(num_vals, trits, quints, bits_); - const int bits_per_block = EncodedBlockSize(); - assert(bits_per_block < 64); - - int bits_left = total_num_bits; - std::vector<int> result; - while (bits_left > 0) { - uint64_t block_bits; - { - const bool result = bit_src->GetBits(std::min(bits_left, bits_per_block), &block_bits); - assert(result); - } - - switch (encoding_) { - case kTritEncoding: { - auto trit_vals = DecodeISEBlock<3>(block_bits, bits_); - result.insert(result.end(), trit_vals.begin(), trit_vals.end()); - } - break; - - case kQuintEncoding: { - auto quint_vals = DecodeISEBlock<5>(block_bits, bits_); - result.insert(result.end(), quint_vals.begin(), quint_vals.end()); - } - break; - - case kBitEncoding: - result.push_back(static_cast<int>(block_bits)); - break; - } - - bits_left -= bits_per_block; - } - - // Resize result to only contain as many values as requested - assert(result.size() >= static_cast<size_t>(num_vals)); - result.resize(num_vals); - - // Encoded all the values - return result; -} - -void IntegerSequenceEncoder::Encode(base::BitStream<base::UInt128>* bit_sink) const { - // Go through all of the values and chop them up into blocks. The properties - // of the trit and quint encodings mean that if we need to encode fewer values - // in a block than the number of values encoded in the block then we need to - // consider the last few values to be zero. - - auto next_val = vals_.begin(); - while (next_val != vals_.end()) { - switch (encoding_) { - case kTritEncoding: { - std::vector<int> trit_vals; - for (int i = 0; i < 5; ++i) { - if (next_val != vals_.end()) { - trit_vals.push_back(*next_val); - ++next_val; - } - } - - EncodeISEBlock<3>(trit_vals, bits_, bit_sink); - } - break; - - case kQuintEncoding: { - std::vector<int> quint_vals; - for (int i = 0; i < 3; ++i) { - if (next_val != vals_.end()) { - quint_vals.push_back(*next_val); - ++next_val; - } - } - - EncodeISEBlock<5>(quint_vals, bits_, bit_sink); - } - break; - - case kBitEncoding: { - bit_sink->PutBits(*next_val, EncodedBlockSize()); - ++next_val; - } - break; - } - } -} - -} // namespace astc_codec diff --git a/third-party/astc-codec/src/decoder/integer_sequence_codec.h b/third-party/astc-codec/src/decoder/integer_sequence_codec.h deleted file mode 100644 index a815e096..00000000 --- a/third-party/astc-codec/src/decoder/integer_sequence_codec.h +++ /dev/null @@ -1,169 +0,0 @@ -// Copyright 2018 Google LLC -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// https://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -#ifndef ASTC_CODEC_DECODER_INTEGER_SEQUENCE_CODEC_H_ -#define ASTC_CODEC_DECODER_INTEGER_SEQUENCE_CODEC_H_ - -#include "src/base/bit_stream.h" -#include "src/base/uint128.h" - -#include <array> -#include <string> -#include <vector> - -namespace astc_codec { - -// The maximum number of bits that we would need to encode an ISE value. The -// ASTC specification does not give a maximum number, however unquantized color -// values have a maximum range of 255, meaning that we can't feasibly have more -// than eight bits per value. -constexpr int kLog2MaxRangeForBits = 8; - -// Ranges can take any of the the forms 2^k, 3*2^k, or 5*2^k for k up to -// kLog2MaxRangeForBits. Hence we have three types of ranges. Since the -// maximum encoded value is 255, k won't go larger than 8. We don't have quints -// that accompany [6, 8]-bits, as (5 * 2^6 = 320 > 255) and we don't have trits -// that accompany [7, 8]-bits, as (3 * 2^7 = 384 > 255). But we do have trits -// and quints that accompany no bits. Hence we have a total of -// 3 * kLog2MaxRangeForBits - 3 - 2 + 2 total ranges. -constexpr int kNumPossibleRanges = 3 * kLog2MaxRangeForBits - 3; - -// Returns an iterator through the available ASTC ranges. -std::array<int, kNumPossibleRanges>::const_iterator ISERangeBegin(); -std::array<int, kNumPossibleRanges>::const_iterator ISERangeEnd(); - -// Base class for ASTC integer sequence encoders and decoders. These codecs -// operate on sequences of integers and produce bit patterns that pack the -// integers based on the encoding scheme specified in the ASTC specification -// Section C.2.12. The resulting bit pattern is a sequence of encoded blocks. -// All blocks in a sequence are one of the following encodings: -// -// (1 -- bit encoding) one encoded value of the form 2^k -// (2 -- trit encoding) five encoded values of the form 3*2^k -// (3 -- quint encoding) three encoded values of the form 5*2^k -// -// The layouts of each block are designed such that the blocks can be truncated -// during encoding in order to support variable length input sequences (i.e. a -// sequence of values that are encoded using trit encoded blocks does not -// need to have a multiple-of-five length). -class IntegerSequenceCodec { - public: - // Returns the number of trits, quints, and bits needed to encode values in - // [0, range]. This is used to determine the layout of ISE encoded bit - // streams. The returned array holds the number of trits, quints, and bits - // respectively. range is expected to be within the interval [1, 5242879] - static void GetCountsForRange(int range, int* trits, int* quints, int* bits); - - // Returns the number of bits needed to encode the given number of values with - // respect to the number of trits, quints, and bits specified in ise_counts - // (in that order). It is expected that either trits or quints can be - // nonzero, but not both, and neither can be larger than one. Anything else is - // undefined. - static int GetBitCount(int num_vals, int trits, int quints, int bits); - - // Convenience function that returns the number of bits needed to encoded - // num_vals within the range [0, range] (inclusive). - static inline int GetBitCountForRange(int num_vals, int range) { - int trits, quints, bits; - GetCountsForRange(range, &trits, &quints, &bits); - return GetBitCount(num_vals, trits, quints, bits); - } - - protected: - explicit IntegerSequenceCodec(int range); - IntegerSequenceCodec(int trits, int quints, int bits); - - // The encoding mode -- since having trits and quints are mutually exclusive, - // we can store the encoding we decide on in this enum. - enum EncodingMode { - kTritEncoding = 0, - kQuintEncoding, - kBitEncoding, - }; - - EncodingMode encoding_; - int bits_; - - // Returns the number of values stored in a single ISE block. Since quints and - // trits are packed three/five to a bit pattern (respectively), each sequence - // is chunked into blocks in order to encode it. For only bit-encodings, the - // block size is one. - int NumValsPerBlock() const; - - // Returns the size of a single ISE block in bits (see NumValsPerBlock). - int EncodedBlockSize() const; - - private: - // Determines the encoding mode. - void InitializeWithCounts(int trits, int quints, int bits); -}; - -// The integer sequence decoder. The decoder only remembers the given encoding -// but each invocation of Decode operates independently on the input bits. -class IntegerSequenceDecoder : public IntegerSequenceCodec { - public: - // Creates a decoder that decodes values within [0, range] (inclusive). - explicit IntegerSequenceDecoder(int range) - : IntegerSequenceCodec(range) { } - - // Creates a decoder based on the number of trits, quints, and bits expected - // in the bit stream passed to Decode. - IntegerSequenceDecoder(int trits, int quints, int bits) - : IntegerSequenceCodec(trits, quints, bits) { } - - // Decodes num_vals from the bit_src. The number of bits read is dependent - // on the number of bits required to encode num_vals based on the calculation - // provided in Section C.2.22 of the ASTC specification. The return value - // always contains exactly num_vals. - std::vector<int> Decode(int num_vals, - base::BitStream<base::UInt128>* bit_src) const; -}; - -// The integer sequence encoder. The encoder accepts values one by one and -// places them into a temporary array that it holds. When needed the user -// may call Encode to produce an encoded bit stream of the associated values. -class IntegerSequenceEncoder : public IntegerSequenceCodec { - public: - // Creates an encoder that encodes values within [0, range] (inclusive). - explicit IntegerSequenceEncoder(int range) - : IntegerSequenceCodec(range) { } - - // Creates an encoder based on the number of trits, quints, and bits for - // the bit stream produced by Encode. - IntegerSequenceEncoder(int trits, int quints, int bits) - : IntegerSequenceCodec(trits, quints, bits) { } - - // Adds a value to the encoding sequence. - void AddValue(int val) { - // Make sure it's within bounds - assert(encoding_ != EncodingMode::kTritEncoding || val < 3 * (1 << bits_)); - assert(encoding_ != EncodingMode::kQuintEncoding || val < 5 * (1 << bits_)); - assert(encoding_ != EncodingMode::kBitEncoding || val < (1 << bits_)); - vals_.push_back(val); - } - - // Writes the encoding for vals_ to the bit_sink. Multiple calls to Encode - // will produce the same result. - void Encode(base::BitStream<base::UInt128>* bit_sink) const; - - // Removes all of the previously added values to the encoder. - void Reset() { vals_.clear(); } - - private: - std::vector<int> vals_; -}; - -} // namespace astc_codec - -#endif // ASTC_CODEC_DECODER_INTEGER_SEQUENCE_CODEC_H_ diff --git a/third-party/astc-codec/src/decoder/intermediate_astc_block.cc b/third-party/astc-codec/src/decoder/intermediate_astc_block.cc deleted file mode 100644 index e03af1eb..00000000 --- a/third-party/astc-codec/src/decoder/intermediate_astc_block.cc +++ /dev/null @@ -1,591 +0,0 @@ -// Copyright 2018 Google LLC -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// https://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -#include "src/decoder/intermediate_astc_block.h" -#include "src/decoder/integer_sequence_codec.h" -#include "src/base/bit_stream.h" -#include "src/base/math_utils.h" -#include "src/base/optional.h" -#include "src/base/uint128.h" - -#include <algorithm> -#include <numeric> -#include <sstream> - -namespace astc_codec { - -namespace { - -constexpr int kEndpointRange_ReturnInvalidWeightDims = -1; -constexpr int kEndpointRange_ReturnNotEnoughColorBits = -2; - -base::UInt128 PackVoidExtentBlock(uint16_t r, uint16_t g, uint16_t b, - uint16_t a, std::array<uint16_t, 4> coords) { - base::BitStream<base::UInt128> bit_sink; - - // Put void extent mode... - bit_sink.PutBits(0xDFC, 12); - - // Each of the coordinates goes in 13 bits at a time. - for (auto coord : coords) { - assert(coord < 1 << 13); - bit_sink.PutBits(coord, 13); - } - assert(bit_sink.Bits() == 64); - - // Then we add R, G, B, and A in order - bit_sink.PutBits(r, 16); - bit_sink.PutBits(g, 16); - bit_sink.PutBits(b, 16); - bit_sink.PutBits(a, 16); - - assert(bit_sink.Bits() == 128); - - base::UInt128 result; - bit_sink.GetBits(128, &result); - return result; -} - -base::Optional<std::string> GetEncodedWeightRange(int range, - std::array<int, 3>* const r) { - const std::array<std::array<int, 3>, 12> kValidRangeEncodings = - {{ {{ 0, 1, 0 }}, {{ 1, 1, 0 }}, {{ 0, 0, 1 }}, - {{ 1, 0, 1 }}, {{ 0, 1, 1 }}, {{ 1, 1, 1 }}, - {{ 0, 1, 0 }}, {{ 1, 1, 0 }}, {{ 0, 0, 1 }}, - {{ 1, 0, 1 }}, {{ 0, 1, 1 }}, {{ 1, 1, 1 }} }}; - - // If our range is larger than all available ranges, this is an error. - const int smallest_range = kValidWeightRanges.front(); - const int largest_range = kValidWeightRanges.back(); - if (range < smallest_range || largest_range < range) { - std::stringstream strm; - strm << "Could not find block mode. Invalid weight range: " - << range << " not in [" << smallest_range << ", " - << largest_range << std::endl; - return strm.str(); - } - - // Find the upper bound on the range, otherwise. - const auto range_iter = std::lower_bound( - kValidWeightRanges.cbegin(), kValidWeightRanges.cend(), range); - auto enc_iter = kValidRangeEncodings.cbegin(); - enc_iter += std::distance(kValidWeightRanges.cbegin(), range_iter); - *r = *enc_iter; - return {}; -} - -struct BlockModeInfo { - int min_weight_grid_dim_x; - int max_weight_grid_dim_x; - int min_weight_grid_dim_y; - int max_weight_grid_dim_y; - int r0_bit_pos; - int r1_bit_pos; - int r2_bit_pos; - int weight_grid_x_offset_bit_pos; - int weight_grid_y_offset_bit_pos; - bool require_single_plane_low_prec; -}; - -constexpr int kNumBlockModes = 10; -const std::array<BlockModeInfo, kNumBlockModes> kBlockModeInfo {{ - { 4, 7, 2, 5, 4, 0, 1, 7, 5, false }, // B+4 A+2 - { 8, 11, 2, 5, 4, 0, 1, 7, 5, false }, // B+8 A+2 - { 2, 5, 8, 11, 4, 0, 1, 5, 7, false }, // A+2 B+8 - { 2, 5, 6, 7, 4, 0, 1, 5, 7, false }, // A+2 B+6 - { 2, 3, 2, 5, 4, 0, 1, 7, 5, false }, // B+2 A+2 - { 12, 12, 2, 5, 4, 2, 3, -1, 5, false }, // 12 A+2 - { 2, 5, 12, 12, 4, 2, 3, 5, -1, false }, // A+2 12 - { 6, 6, 10, 10, 4, 2, 3, -1, -1, false }, // 6 10 - { 10, 10, 6, 6, 4, 2, 3, -1, -1, false }, // 10 6 - { 6, 9, 6, 9, 4, 2, 3, 5, 9, true } // A+6 B+6 -}}; - -// These are the bits that must be set for ASTC to recognize a given -// block mode. They are the 1's set in table C.2.8 of the spec. -const std::array<int, kNumBlockModes> kBlockModeMask = {{ - 0x0, 0x4, 0x8, 0xC, 0x10C, 0x0, 0x80, 0x180, 0x1A0, 0x100 -}}; - -static base::Optional<std::string> PackBlockMode(int dim_x, int dim_y, int range, - bool dual_plane, - base::BitStream<base::UInt128>* const bit_sink) { - // We need to set the high precision bit if our range is too high... - bool high_prec = range > 7; - - std::array<int, 3> r; - const auto result = GetEncodedWeightRange(range, &r); - if (result) { - return result; - } - - // The high two bits of R must not be zero. If this happens then it's - // an illegal encoding according to Table C.2.7 that should have gotten - // caught in GetEncodedWeightRange - assert((r[1] | r[2]) > 0); - - // Just go through the table and see if any of the modes can handle - // the given dimensions. - for (int mode = 0; mode < kNumBlockModes; ++mode) { - const BlockModeInfo& block_mode = kBlockModeInfo[mode]; - - bool is_valid_mode = true; - is_valid_mode &= block_mode.min_weight_grid_dim_x <= dim_x; - is_valid_mode &= dim_x <= block_mode.max_weight_grid_dim_x; - is_valid_mode &= block_mode.min_weight_grid_dim_y <= dim_y; - is_valid_mode &= dim_y <= block_mode.max_weight_grid_dim_y; - is_valid_mode &= !(block_mode.require_single_plane_low_prec && dual_plane); - is_valid_mode &= !(block_mode.require_single_plane_low_prec && high_prec); - - if (!is_valid_mode) { - continue; - } - - // Initialize to the bits we must set. - uint32_t encoded_mode = kBlockModeMask[mode]; - auto setBit = [&encoded_mode](const uint32_t value, const uint32_t offset) { - encoded_mode = (encoded_mode & ~(1 << offset)) | ((value & 1) << offset); - }; - - // Set all the bits we need to set - setBit(r[0], block_mode.r0_bit_pos); - setBit(r[1], block_mode.r1_bit_pos); - setBit(r[2], block_mode.r2_bit_pos); - - // Find our width and height offset from the base width and height weight - // grid dimension for the given block mode. These are the 1-2 bits that - // get encoded in the block mode used to calculate the final weight grid - // width and height. - const int offset_x = dim_x - block_mode.min_weight_grid_dim_x; - const int offset_y = dim_y - block_mode.min_weight_grid_dim_y; - - // If we don't have an offset position then our offset better be zero. - // If this isn't the case, then this isn't a viable block mode and we - // should have caught this sooner. - assert(block_mode.weight_grid_x_offset_bit_pos >= 0 || offset_x == 0); - assert(block_mode.weight_grid_y_offset_bit_pos >= 0 || offset_y == 0); - - encoded_mode |= offset_x << block_mode.weight_grid_x_offset_bit_pos; - encoded_mode |= offset_y << block_mode.weight_grid_y_offset_bit_pos; - - if (!block_mode.require_single_plane_low_prec) { - setBit(high_prec, 9); - setBit(dual_plane, 10); - } - - // Make sure that the mode is the first thing the bit sink is writing to - assert(bit_sink->Bits() == 0); - bit_sink->PutBits(encoded_mode, 11); - - return {}; - } - - return std::string("Could not find viable block mode"); -} - -// Returns true if all endpoint modes are equal. -bool SharedEndpointModes(const IntermediateBlockData& data) { - return std::accumulate( - data.endpoints.begin(), data.endpoints.end(), true, - [&data](const bool& a, const IntermediateEndpointData& b) { - return a && b.mode == data.endpoints[0].mode; - }); -} - -// Returns the starting bit (between 0 and 128) where the extra CEM and -// dual plane info is stored in the ASTC block. -int ExtraConfigBitPosition(const IntermediateBlockData& data) { - const bool has_dual_channel = data.dual_plane_channel.hasValue(); - const int num_weights = data.weight_grid_dim_x * data.weight_grid_dim_y * - (has_dual_channel ? 2 : 1); - const int num_weight_bits = - IntegerSequenceCodec::GetBitCountForRange(num_weights, data.weight_range); - - int extra_config_bits = 0; - if (!SharedEndpointModes(data)) { - const int num_encoded_cem_bits = 2 + data.endpoints.size() * 3; - extra_config_bits = num_encoded_cem_bits - 6; - } - - if (has_dual_channel) { - extra_config_bits += 2; - } - - return 128 - num_weight_bits - extra_config_bits; -} - -} // namespace - -//////////////////////////////////////////////////////////////////////////////// - -base::Optional<IntermediateBlockData> UnpackIntermediateBlock( - const PhysicalASTCBlock& pb) { - if (pb.IsIllegalEncoding()) { - return {}; - } - - if (pb.IsVoidExtent()) { - return {}; - } - - // Non void extent? Then let's try to decode everything else. - IntermediateBlockData data; - - // All blocks have color values... - const base::UInt128 color_bits_mask = - (base::UInt128(1) << pb.NumColorBits().value()) - 1; - const base::UInt128 color_bits = - (pb.GetBlockBits() >> pb.ColorStartBit().value()) & color_bits_mask; - base::BitStream<base::UInt128> bit_src(color_bits, 128); - - IntegerSequenceDecoder color_decoder(pb.ColorValuesRange().value()); - const int num_colors_in_block = pb.NumColorValues().value(); - std::vector<int> colors = color_decoder.Decode(num_colors_in_block, &bit_src); - - // Decode simple info - const auto weight_dims = pb.WeightGridDims(); - data.weight_grid_dim_x = weight_dims->at(0); - data.weight_grid_dim_y = weight_dims->at(1); - data.weight_range = pb.WeightRange().value(); - - data.partition_id = pb.PartitionID(); - data.dual_plane_channel = pb.DualPlaneChannel(); - - auto colors_iter = colors.begin(); - for (int i = 0; i < pb.NumPartitions().value(); ++i) { - IntermediateEndpointData ep_data; - ep_data.mode = pb.GetEndpointMode(i).value(); - - const int num_colors = NumColorValuesForEndpointMode(ep_data.mode); - ep_data.colors.insert(ep_data.colors.end(), colors_iter, - colors_iter + num_colors); - colors_iter += num_colors; - - data.endpoints.push_back(ep_data); - } - assert(colors_iter == colors.end()); - data.endpoint_range = pb.ColorValuesRange().value(); - - // Finally decode the weights - const base::UInt128 weight_bits_mask = - (base::UInt128(1) << pb.NumWeightBits().value()) - 1; - const base::UInt128 weight_bits = - base::ReverseBits(pb.GetBlockBits()) & weight_bits_mask; - bit_src = base::BitStream<base::UInt128>(weight_bits, 128); - - IntegerSequenceDecoder weight_decoder(data.weight_range); - int num_weights = data.weight_grid_dim_x * data.weight_grid_dim_y; - num_weights *= pb.IsDualPlane() ? 2 : 1; - data.weights = weight_decoder.Decode(num_weights, &bit_src); - - return data; -} - -int EndpointRangeForBlock(const IntermediateBlockData& data) { - // First check to see if we exceed the number of bits allotted for weights, as - // specified in C.2.24. If so, then the endpoint range is meaningless, but not - // because we had an overzealous color endpoint mode, so return a different - // error code. - if (IntegerSequenceCodec::GetBitCountForRange( - data.weight_grid_dim_x * data.weight_grid_dim_y * - (data.dual_plane_channel.hasValue() ? 2 : 1), - data.weight_range) > 96) { - return kEndpointRange_ReturnInvalidWeightDims; - } - - const int num_partitions = data.endpoints.size(); - - // Calculate the number of bits that we would write prior to getting to the - // color endpoint data - const int bits_written = - 11 // Block mode - + 2 // Num partitions - + ((num_partitions > 1) ? 10 : 0) // Partition ID - + ((num_partitions == 1) ? 4 : 6); // Shared CEM bits - - // We can determine the range based on how many bits we have between the start - // of the color endpoint data and the next section, which is the extra config - // bit position - const int color_bits_available = ExtraConfigBitPosition(data) - bits_written; - - int num_color_values = 0; - for (const auto& ep_data : data.endpoints) { - num_color_values += NumColorValuesForEndpointMode(ep_data.mode); - } - - // There's no way any valid ASTC encoding has no room left for any color - // values. If we hit this then something is wrong in the caller -- abort. - // According to section C.2.24, the smallest number of bits available is - // ceil(13*C/5), where C is the number of color endpoint integers needed. - const int bits_needed = (13 * num_color_values + 4) / 5; - if (color_bits_available < bits_needed) { - return kEndpointRange_ReturnNotEnoughColorBits; - } - - int color_value_range = 255; - for (; color_value_range > 1; --color_value_range) { - const int bits_for_range = IntegerSequenceCodec::GetBitCountForRange( - num_color_values, color_value_range); - if (bits_for_range <= color_bits_available) { - break; - } - } - - return color_value_range; -} - -base::Optional<VoidExtentData> UnpackVoidExtent(const PhysicalASTCBlock& pb) { - if (pb.IsIllegalEncoding()) { - return {}; - } - - if (!pb.IsVoidExtent()) { - return {}; - } - - // All blocks have color values... - const base::UInt128 color_bits_mask = - (base::UInt128(1) << pb.NumColorBits().value()) - 1; - const uint64_t color_bits = ( - (pb.GetBlockBits() >> pb.ColorStartBit().value()) & color_bits_mask).LowBits(); - - assert(pb.NumColorValues().value() == 4); - VoidExtentData data; - data.r = static_cast<uint16_t>((color_bits >> 0) & 0xFFFF); - data.g = static_cast<uint16_t>((color_bits >> 16) & 0xFFFF); - data.b = static_cast<uint16_t>((color_bits >> 32) & 0xFFFF); - data.a = static_cast<uint16_t>((color_bits >> 48) & 0xFFFF); - - const auto void_extent_coords = pb.VoidExtentCoords(); - if (void_extent_coords) { - data.coords[0] = void_extent_coords->at(0); - data.coords[1] = void_extent_coords->at(1); - data.coords[2] = void_extent_coords->at(2); - data.coords[3] = void_extent_coords->at(3); - } else { - uint16_t all_ones = (1 << 13) - 1; - for (auto& coord : data.coords) { - coord = all_ones; - } - } - - return data; -} - -// Packs the given intermediate block into a physical block. Returns false if -// the provided values in the intermediate block emit an illegal ASTC -// encoding. -base::Optional<std::string> Pack(const IntermediateBlockData& data, - base::UInt128* pb) { - if (data.weights.size() != - data.weight_grid_dim_x * data.weight_grid_dim_y * - (data.dual_plane_channel.hasValue() ? 2 : 1)) { - return std::string("Incorrect number of weights!"); - } - - // If it's not a void extent block, then it gets a bit more tricky... - base::BitStream<base::UInt128> bit_sink; - - // First we need to encode the block mode. - const auto error_string = PackBlockMode( - data.weight_grid_dim_x, data.weight_grid_dim_y, data.weight_range, - data.dual_plane_channel.hasValue(), &bit_sink); - if (error_string) { - return error_string; - } - - // Next, we place the number of partitions minus one. - const int num_partitions = data.endpoints.size(); - bit_sink.PutBits(num_partitions - 1, 2); - - // If we have more than one partition, then we also have a partition ID. - if (num_partitions > 1) { - const int id = data.partition_id.value(); - assert(id >= 0); - bit_sink.PutBits(id, 10); - } - - // Take a detour, let's encode the weights so that we know how many bits they - // consume. - base::BitStream<base::UInt128> weight_sink; - - IntegerSequenceEncoder weight_enc(data.weight_range); - for (auto weight : data.weights) { - weight_enc.AddValue(weight); - } - weight_enc.Encode(&weight_sink); - - const int num_weight_bits = weight_sink.Bits(); - assert(num_weight_bits == - IntegerSequenceCodec::GetBitCountForRange( - data.weights.size(), data.weight_range)); - - // Let's continue... how much after the color data do we need to write? - int extra_config = 0; - - // Determine if all endpoint pairs share the same endpoint mode - assert(data.endpoints.size() > 0); - bool shared_endpoint_mode = SharedEndpointModes(data); - - // The first part of the endpoint mode (CEM) comes directly after the - // partition info, if it exists. If there is no partition info, the CEM comes - // right after the block mode. In the single-partition case, we just write out - // the entire singular CEM, but in the multi-partition case, if all CEMs are - // the same then their shared CEM is specified directly here, too. In both - // cases, shared_endpoint_mode is true (in the singular case, - // shared_endpoint_mode is trivially true). - if (shared_endpoint_mode) { - if (num_partitions > 1) { - bit_sink.PutBits(0, 2); - } - bit_sink.PutBits(static_cast<int>(data.endpoints[0].mode), 4); - } else { - // Here, the CEM is not shared across all endpoint pairs, and we need to - // figure out what to place here, and what to place in the extra config - // bits before the weight data... - - // Non-shared config modes must all be within the same class (out of four) - // See Section C.2.11 - int min_class = 2; // We start with 2 here instead of three because it's - // the highest that can be encoded -- even if all modes - // are class 3. - int max_class = 0; - for (const auto& ep_data : data.endpoints) { - const int ep_mode_class = static_cast<int>(ep_data.mode) >> 2; - min_class = std::min(min_class, ep_mode_class); - max_class = std::max(max_class, ep_mode_class); - } - - assert(max_class >= min_class); - - if (max_class - min_class > 1) { - return std::string("Endpoint modes are invalid"); - } - - // Construct the CEM mode -- six of its bits will fit here, but otherwise - // the rest will go in the extra configuration bits. - base::BitStream<uint32_t> cem_encoder; - - // First encode the base class - assert(min_class >= 0); - assert(min_class < 3); - cem_encoder.PutBits(min_class + 1, 2); - - // Next, encode the class selector bits -- this is simply the offset - // from the base class - for (const auto& ep_data : data.endpoints) { - const int ep_mode_class = static_cast<int>(ep_data.mode) >> 2; - const int class_selector_bit = ep_mode_class - min_class; - assert(class_selector_bit == 0 || class_selector_bit == 1); - cem_encoder.PutBits(class_selector_bit, 1); - } - - // Finally, we need to choose from each class which actual mode - // we belong to and encode those. - for (const auto& ep_data : data.endpoints) { - const int ep_mode = static_cast<int>(ep_data.mode) & 3; - assert(ep_mode < 4); - cem_encoder.PutBits(ep_mode, 2); - } - assert(cem_encoder.Bits() == 2 + num_partitions * 3); - - uint32_t encoded_cem; - cem_encoder.GetBits(2 + num_partitions * 3, &encoded_cem); - - // Since only six bits fit here before the color endpoint data, the rest - // need to go in the extra config data. - extra_config = encoded_cem >> 6; - - // Write out the six bits we had - bit_sink.PutBits(encoded_cem, 6); - } - - // If we have a dual-plane channel, we can tack that onto our extra config - // data - if (data.dual_plane_channel.hasValue()) { - const int channel = data.dual_plane_channel.value(); - assert(channel < 4); - extra_config <<= 2; - extra_config |= channel; - } - - // Get the range of endpoint values. It can't be -1 because we should have - // checked for that much earlier. - const int color_value_range = data.endpoint_range - ? data.endpoint_range.value() - : EndpointRangeForBlock(data); - - assert(color_value_range != kEndpointRange_ReturnInvalidWeightDims); - if (color_value_range == kEndpointRange_ReturnNotEnoughColorBits) { - return { "Intermediate block emits illegal color range" }; - } - - IntegerSequenceEncoder color_enc(color_value_range); - for (const auto& ep_data : data.endpoints) { - for (int color : ep_data.colors) { - if (color > color_value_range) { - return { "Color outside available color range!" }; - } - - color_enc.AddValue(color); - } - } - color_enc.Encode(&bit_sink); - - // Now we need to skip some bits to get to the extra configuration bits. The - // number of bits we need to skip depends on where we are in the stream and - // where we need to get to. - const int extra_config_bit_position = ExtraConfigBitPosition(data); - const int extra_config_bits = - 128 - num_weight_bits - extra_config_bit_position; - assert(extra_config_bits >= 0); - assert(extra_config < 1 << extra_config_bits); - - // Make sure the color encoder didn't write more than we thought it would. - int bits_to_skip = extra_config_bit_position - bit_sink.Bits(); - assert(bits_to_skip >= 0); - - while (bits_to_skip > 0) { - const int skipping = std::min(32, bits_to_skip); - bit_sink.PutBits(0, skipping); - bits_to_skip -= skipping; - } - - // Finally, write out the rest of the config bits. - bit_sink.PutBits(extra_config, extra_config_bits); - - // We should be right up to the weight bits... - assert(bit_sink.Bits() == 128 - num_weight_bits); - - // Flush out our bit writer and write out the weight bits - base::UInt128 astc_bits; - bit_sink.GetBits(128 - num_weight_bits, &astc_bits); - - base::UInt128 rev_weight_bits; - weight_sink.GetBits(weight_sink.Bits(), &rev_weight_bits); - - astc_bits |= base::ReverseBits(rev_weight_bits); - - // And we're done! Whew! - *pb = astc_bits; - return PhysicalASTCBlock(*pb).IsIllegalEncoding(); -} - -base::Optional<std::string> Pack(const VoidExtentData& data, - base::UInt128* pb) { - *pb = PackVoidExtentBlock(data.r, data.g, data.b, data.a, data.coords); - return PhysicalASTCBlock(*pb).IsIllegalEncoding(); -} - -} // namespace astc_codec diff --git a/third-party/astc-codec/src/decoder/intermediate_astc_block.h b/third-party/astc-codec/src/decoder/intermediate_astc_block.h deleted file mode 100644 index ec6eb3ea..00000000 --- a/third-party/astc-codec/src/decoder/intermediate_astc_block.h +++ /dev/null @@ -1,128 +0,0 @@ -// Copyright 2018 Google LLC -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// https://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -#ifndef ASTC_CODEC_DECODER_INTERMEDIATE_ASTC_BLOCK_H_ -#define ASTC_CODEC_DECODER_INTERMEDIATE_ASTC_BLOCK_H_ - -#include "src/base/optional.h" -#include "src/base/uint128.h" -#include "src/decoder/physical_astc_block.h" - -#include <array> -#include <vector> - -namespace astc_codec { - -// From Table C.2.7 -- These are the only valid ranges that weight -// values can take. -constexpr std::array<int, 12> kValidWeightRanges = -{{ 1, 2, 3, 4, 5, 7, 9, 11, 15, 19, 23, 31 }}; - -// Void extent data are all the ASTC blocks that are labeled for having a -// constant color. In the ASTC spec, some of these blocks may optionally -// have "void extent coordinates" that describe how far in texture space -// the constant color should span. If these coordinates are not valid, -// then the coordinates are all set to a fully saturated bit mask -// ((1 << 13) - 1) and the block is treated as a singular constant color. -// We call both types of these blocks "void extent" to remove confusion -// in our code. -struct VoidExtentData { - uint16_t r; - uint16_t g; - uint16_t b; - uint16_t a; - std::array<uint16_t, 4> coords; -}; - -// Intermediate endpoint data. Really this is just an endpoint mode -// and a couple of values that represent the data used to decode the -// RGB values from the color endpoint mode. -struct IntermediateEndpointData { - ColorEndpointMode mode; - std::vector<int> colors; -}; - -// This is an unpacked physical ASTC block, but it does not have enough -// information to be worked with logically. It is simply a container of -// all of the unpacked ASTC information. It is used as a staging area -// for the information that is later Pack()'d into a PhysicalASTCBlock. -struct IntermediateBlockData { - int weight_grid_dim_x; - int weight_grid_dim_y; - int weight_range; - - // Quantized, non-interpolated weights - std::vector<int> weights; - - // The 10-bit partition ID if we need one - base::Optional<int> partition_id; - - // The dual-plane channel in [0, 3] if it exists. - base::Optional<int> dual_plane_channel; - - // The quantized/encoded endpoint values for this block. The range of each - // endpoint value is specified by |endpoint_range|, if it exists. If not, the - // range can be queried by calling EndpointRangeForBlock - std::vector<IntermediateEndpointData> endpoints; - - // The range [0, endpoint_range] that any one endpoint value can take. Users - // should not write to this value themselves. If it is empty at the time - // someone calls Pack(), it will be automatically inferred. Otherwise, it is - // set by Unpack() based on what the underlying encoding specified. - base::Optional<int> endpoint_range; -}; - -// Returns the maximum value that a given endpoint value can take according to -// the other settings in the block. Ignores the |endpoint_range| member -// variable. Returns negative values on error: -// -1 : Too many bits required to store weight grid -// -2 : There are too few bits allocated for color endpoint data according to -// C.2.24 in the ASTC spec -int EndpointRangeForBlock(const IntermediateBlockData& data); -inline int EndpointRangeForBlock(const VoidExtentData& data); - -// Unpacks the physical ASTC block into the intermediate block. Returns false -// if the physical block is an error encoded block, or if the physical block -// is a void extent block. On error the contents of ib are undefined. -base::Optional<IntermediateBlockData> UnpackIntermediateBlock( - const PhysicalASTCBlock& pb); - -// Unpacks the physical ASTC block into a void extent block. Returns false -// if the physical block is an error encoded block, or if the physical block -// is an intermediate block. On error the contents of ib are undefined. -base::Optional<VoidExtentData> UnpackVoidExtent(const PhysicalASTCBlock& pb); - -// Packs the given intermediate block into a physical block. Returns an error -// string if the provided values in the intermediate block emit an illegal ASTC -// encoding. In this case the results in the physical block are undefined. -base::Optional<std::string> Pack(const IntermediateBlockData& data, - base::UInt128* pb); - -// Packs the given void extent block into a physical block. Returns an error -// string if the provided values in the void extent block emit an illegal ASTC -// encoding. In this case the results in the physical block are undefined. -base::Optional<std::string> Pack(const VoidExtentData& data, base::UInt128* pb); - -//////////////////////////////////////////////////////////////////////////////// -// -// Impl - -inline int EndpointRangeForBlock(const VoidExtentData& data) { - // Void extent blocks use 16-bit ARGB definitions - return (1 << 16) - 1; -} - -} // namespace astc_codec - -#endif // ASTC_CODEC_DECODER_INTERMEDIATE_ASTC_BLOCK_H_ diff --git a/third-party/astc-codec/src/decoder/logical_astc_block.cc b/third-party/astc-codec/src/decoder/logical_astc_block.cc deleted file mode 100644 index 9271e181..00000000 --- a/third-party/astc-codec/src/decoder/logical_astc_block.cc +++ /dev/null @@ -1,262 +0,0 @@ -// Copyright 2018 Google LLC -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// https://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -#include "src/decoder/logical_astc_block.h" -#include "src/decoder/endpoint_codec.h" -#include "src/decoder/footprint.h" -#include "src/decoder/integer_sequence_codec.h" -#include "src/decoder/quantization.h" -#include "src/decoder/weight_infill.h" - -namespace astc_codec { - -namespace { - -Partition GenerateSinglePartition(Footprint footprint) { - return Partition { footprint, /* num_parts = */ 1, /* partition_id = */ 0, - std::vector<int>(footprint.NumPixels(), 0) }; -} - -static std::vector<EndpointPair> DecodeEndpoints(const IntermediateBlockData& block) { - const int endpoint_range = block.endpoint_range - ? block.endpoint_range.value() - : EndpointRangeForBlock(block); - assert(endpoint_range > 0); - - std::vector<EndpointPair> endpoints; - for (const auto& eps : block.endpoints) { - RgbaColor decmp_one_rgba, decmp_two_rgba; - DecodeColorsForMode(eps.colors, endpoint_range, eps.mode, - &decmp_one_rgba, &decmp_two_rgba); - endpoints.emplace_back(decmp_one_rgba, decmp_two_rgba); - } - return endpoints; -} - -static std::vector<EndpointPair> DecodeEndpoints(const VoidExtentData& block) { - EndpointPair eps; - eps.first[0] = eps.second[0] = (block.r * 255) / 65535; - eps.first[1] = eps.second[1] = (block.g * 255) / 65535; - eps.first[2] = eps.second[2] = (block.b * 255) / 65535; - eps.first[3] = eps.second[3] = (block.a * 255) / 65535; - - std::vector<EndpointPair> endpoints; - endpoints.emplace_back(eps); - return endpoints; -} - -Partition ComputePartition(const Footprint& footprint, - const IntermediateBlockData& block) { - if (block.partition_id) { - const int part_id = block.partition_id.value(); - const size_t num_parts = block.endpoints.size(); - return GetASTCPartition(footprint, num_parts, part_id); - } else { - return GenerateSinglePartition(footprint); - } -} - -Partition ComputePartition(const Footprint& footprint, const VoidExtentData&) { - return GenerateSinglePartition(footprint); -} - -} // namespace - -//////////////////////////////////////////////////////////////////////////////// - -LogicalASTCBlock::LogicalASTCBlock(const Footprint& footprint) - : endpoints_(1), - weights_(footprint.NumPixels(), 0), - partition_(GenerateSinglePartition(footprint)) { } - -LogicalASTCBlock::LogicalASTCBlock(const Footprint& footprint, - const IntermediateBlockData& block) - : endpoints_(DecodeEndpoints(block)), - partition_(ComputePartition(footprint, block)) { - CalculateWeights(footprint, block); -} - -LogicalASTCBlock::LogicalASTCBlock(const Footprint& footprint, - const VoidExtentData& block) - : endpoints_(DecodeEndpoints(block)), - partition_(ComputePartition(footprint, block)) { - CalculateWeights(footprint, block); -} - -void LogicalASTCBlock::CalculateWeights(const Footprint& footprint, - const IntermediateBlockData& block) { - const int grid_size_x = block.weight_grid_dim_x; - const int grid_size_y = block.weight_grid_dim_y; - const int weight_grid_size = grid_size_x * grid_size_y; - - // Either we have a dual plane and we have twice as many weights as - // specified or we don't - assert(block.dual_plane_channel - ? block.weights.size() == weight_grid_size * 2 - : block.weights.size() == weight_grid_size); - - std::vector<int> unquantized; - unquantized.reserve(weight_grid_size); - - // According to C.2.16, if we have dual-plane weights, then we have two - // weights per texel -- one adjacent to the other. Hence, we have to skip - // some when we decode the separate weight values. - const int weight_frequency = (block.dual_plane_channel) ? 2 : 1; - const int weight_range = block.weight_range; - - for (int i = 0; i < weight_grid_size; ++i) { - const int weight = block.weights[i * weight_frequency]; - unquantized.push_back(UnquantizeWeightFromRange(weight, weight_range)); - } - weights_ = InfillWeights(unquantized, footprint, grid_size_x, grid_size_y); - - if (block.dual_plane_channel) { - SetDualPlaneChannel(block.dual_plane_channel.value()); - for (int i = 0; i < weight_grid_size; ++i) { - const int weight = block.weights[i * weight_frequency + 1]; - unquantized[i] = UnquantizeWeightFromRange(weight, weight_range); - } - dual_plane_->weights = - InfillWeights(unquantized, footprint, grid_size_x, grid_size_y); - } -} - -void LogicalASTCBlock::CalculateWeights(const Footprint& footprint, - const VoidExtentData&) { - weights_ = std::vector<int>(footprint.NumPixels(), 0); -} - -void LogicalASTCBlock::SetWeightAt(int x, int y, int weight) { - assert(weight >= 0); - assert(weight <= 64); - weights_.at(y * GetFootprint().Width() + x) = weight; -} - -int LogicalASTCBlock::WeightAt(int x, int y) const { - return weights_.at(y * GetFootprint().Width() + x); -} - -void LogicalASTCBlock::SetDualPlaneWeightAt(int channel, int x, int y, - int weight) { - assert(weight >= 0); - assert(weight <= 64); - - // If it's not a dual plane, then this has no logical meaning - assert(IsDualPlane()); - - // If it is a dual plane and the passed channel matches the query, then we - // return the specialized weights - if (dual_plane_->channel == channel) { - dual_plane_->weights.at(y * GetFootprint().Width() + x) = weight; - } else { - // If the channel is not the special channel, then return the general weight - SetWeightAt(x, y, weight); - } -} - -int LogicalASTCBlock::DualPlaneWeightAt(int channel, int x, int y) const { - // If it's not a dual plane, then we just return the weight for all channels - if (!IsDualPlane()) { - // TODO(google): Log warning, Requesting dual-plane channel for a non - // dual-plane block! - return WeightAt(x, y); - } - - // If it is a dual plane and the passed channel matches the query, then we - // return the specialized weights - if (dual_plane_->channel == channel) { - return dual_plane_->weights.at(y * GetFootprint().Width() + x); - } - - // If the channel is not the special channel, then return the general weight - return WeightAt(x, y); -} - -void LogicalASTCBlock::SetDualPlaneChannel(int channel) { - if (channel < 0) { - dual_plane_.clear(); - } else if (dual_plane_) { - dual_plane_->channel = channel; - } else { - dual_plane_ = DualPlaneData {channel, weights_}; - } -} - -RgbaColor LogicalASTCBlock::ColorAt(int x, int y) const { - const auto footprint = GetFootprint(); - assert(x >= 0); assert(x < footprint.Width()); - assert(y >= 0); assert(y < footprint.Height()); - - const int texel_idx = y * footprint.Width() + x; - const int part = partition_.assignment[texel_idx]; - const auto& endpoints = endpoints_[part]; - - RgbaColor result; - for (int channel = 0; channel < 4; ++channel) { - const int weight = (dual_plane_ && dual_plane_->channel == channel) - ? dual_plane_->weights[texel_idx] - : weights_[texel_idx]; - const int p0 = endpoints.first[channel]; - const int p1 = endpoints.second[channel]; - - assert(p0 >= 0); assert(p0 < 256); - assert(p1 >= 0); assert(p1 < 256); - - // According to C.2.19 - const int c0 = (p0 << 8) | p0; - const int c1 = (p1 << 8) | p1; - const int c = (c0 * (64 - weight) + c1 * weight + 32) / 64; - // TODO(google): Handle conversion to sRGB or FP16 per C.2.19. - const int quantized = ((c * 255) + 32767) / 65536; - assert(quantized < 256); - result[channel] = quantized; - } - - return result; -} - -void LogicalASTCBlock::SetPartition(const Partition& p) { - assert(p.footprint == partition_.footprint && - "New partitions may not be for a different footprint"); - partition_ = p; - endpoints_.resize(p.num_parts); -} - -void LogicalASTCBlock::SetEndpoints(const EndpointPair& eps, int subset) { - assert(subset < partition_.num_parts); - assert(subset < endpoints_.size()); - - endpoints_[subset] = eps; -} - -base::Optional<LogicalASTCBlock> UnpackLogicalBlock( - const Footprint& footprint, const PhysicalASTCBlock& pb) { - if (pb.IsVoidExtent()) { - base::Optional<VoidExtentData> ve = UnpackVoidExtent(pb); - if (!ve) { - return {}; - } - - return LogicalASTCBlock(footprint, ve.value()); - } else { - base::Optional<IntermediateBlockData> ib = UnpackIntermediateBlock(pb); - if (!ib) { - return {}; - } - - return LogicalASTCBlock(footprint, ib.value()); - } -} - -} // namespace astc_codec diff --git a/third-party/astc-codec/src/decoder/logical_astc_block.h b/third-party/astc-codec/src/decoder/logical_astc_block.h deleted file mode 100644 index 2243eb4e..00000000 --- a/third-party/astc-codec/src/decoder/logical_astc_block.h +++ /dev/null @@ -1,127 +0,0 @@ -// Copyright 2018 Google LLC -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// https://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -#ifndef ASTC_CODEC_DECODER_LOGICAL_ASTC_BLOCK_H_ -#define ASTC_CODEC_DECODER_LOGICAL_ASTC_BLOCK_H_ - -#include "src/base/optional.h" -#include "src/decoder/footprint.h" -#include "src/decoder/intermediate_astc_block.h" -#include "src/decoder/partition.h" -#include "src/decoder/physical_astc_block.h" - -#include <array> -#include <utility> -#include <vector> - -namespace astc_codec { - -// A logical ASTC block holds the endpoints, indices, and partition information -// of a compressed block. These values generally do not adhere to any -// quality-for-bitrate-imposed limits and are solely logical entities for -// determining the best representation of a given block. -class LogicalASTCBlock { - public: - LogicalASTCBlock(const LogicalASTCBlock&) = default; - LogicalASTCBlock(LogicalASTCBlock&&) = default; - - // Unpack an intermediate block into a logical one. - LogicalASTCBlock(const Footprint& footprint, - const IntermediateBlockData& block); - - // Unpack a void extent intermediate block into a logical one. - LogicalASTCBlock(const Footprint& footprint, const VoidExtentData& block); - - // Create a new, empty ASTC block - explicit LogicalASTCBlock(const Footprint& footprint); - - // Returns the footprint associated with this block. The footprint is defined - // via the partition, because the partition definition is dependent on the - // footprint. - const Footprint& GetFootprint() const { return partition_.footprint; } - - // Returns the unquantized and infilled weight in the range [0, 64] for the - // given texel location. Assumes that the block is a single-plane block, - // meaning that weights are used equally across all channels. - void SetWeightAt(int x, int y, int weight); - int WeightAt(int x, int y) const; - - // Returns the unquantized and infilled weight in the range [0, 64] for the - // given channel at the given texel location. If the block does not have a - // dual-plane channel then the reference-returning version will fail, as it - // cannot return a reference to a value that (potentially) doesn't exist. - void SetDualPlaneWeightAt(int channel, int x, int y, int weight); - int DualPlaneWeightAt(int channel, int x, int y) const; - - // Returns the color as it would be in the given pixel coordinates of the - // block. Fails if the coordinates are outside of the range of the block - // footprint - RgbaColor ColorAt(int x, int y) const; - - // Sets the current partition for the block. |p|'s footprint must match the - // return value of GetFootprint() or else this call will fail. - void SetPartition(const Partition& p); - - // Sets the endpoints for the given subset. - void SetEndpoints(const EndpointPair& eps, int subset); - void SetEndpoints(const Endpoint& ep1, const Endpoint& ep2, int subset) { - SetEndpoints(std::make_pair(ep1, ep2), subset); - } - - // Sets the dual plane channel for the block. Value must be within the range - // [0, 3]. If a negative value is passed, then the dual-plane data for the - // block is removed, and the block is treated as a single-plane block. - void SetDualPlaneChannel(int channel); - bool IsDualPlane() const { return dual_plane_.hasValue(); } - - private: - // A block may have up to four endpoint pairs. - std::vector<EndpointPair> endpoints_; - - // Weights are stored as values in the interval [0, 64]. - std::vector<int> weights_; - - // The partition information for this block. This determines the - // appropriate subsets that each pixel should belong to. - Partition partition_; - - // Dual plane data holds both the channel and the weights that describe - // the dual plane data for the given block. If a block has a dual plane, then - // we need to know both the channel and the weights associated with it. - struct DualPlaneData { - int channel; - std::vector<int> weights; - }; - - // The dual-plane data is optional from a logical representation of the block. - base::Optional<DualPlaneData> dual_plane_; - - // Calculates the unquantized and interpolated weights from the encoded weight - // values and possibly dual-plane weights specified in the passed ASTC block. - void CalculateWeights(const Footprint& footprint, - const IntermediateBlockData& block); - - // Calculates the weights for a VoidExtentBlock. - void CalculateWeights(const Footprint& footprint, - const VoidExtentData& block); -}; - -// Unpacks the physical ASTC block into a logical block. Returns false if the -// physical block is an error encoded block. -base::Optional<LogicalASTCBlock> UnpackLogicalBlock( - const Footprint& footprint, const PhysicalASTCBlock& pb); - -} // namespace astc_codec - -#endif // ASTC_CODEC_DECODER_LOGICAL_ASTC_BLOCK_H_ diff --git a/third-party/astc-codec/src/decoder/partition.cc b/third-party/astc-codec/src/decoder/partition.cc deleted file mode 100644 index 43ff6f02..00000000 --- a/third-party/astc-codec/src/decoder/partition.cc +++ /dev/null @@ -1,601 +0,0 @@ -// Copyright 2018 Google LLC -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// https://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -#include "src/decoder/partition.h" -#include "src/base/bottom_n.h" -#include "src/base/utils.h" -#include "src/decoder/footprint.h" - -#include <algorithm> -#include <array> -#include <limits> -#include <memory> -#include <numeric> -#include <queue> -#include <set> -#include <unordered_set> -#include <utility> - -namespace astc_codec { - -namespace { - -// The maximum number of partitions supported by ASTC is four. -constexpr int kMaxNumSubsets = 4; - -// Partition selection function based on the ASTC specification. -// See section C.2.21 -int SelectASTCPartition(int seed, int x, int y, int z, int partitioncount, - int num_pixels) { - if (partitioncount <= 1) { - return 0; - } - - if (num_pixels < 31) { - x <<= 1; - y <<= 1; - z <<= 1; - } - - seed += (partitioncount - 1) * 1024; - - uint32_t rnum = seed; - rnum ^= rnum >> 15; - rnum -= rnum << 17; - rnum += rnum << 7; - rnum += rnum << 4; - rnum ^= rnum >> 5; - rnum += rnum << 16; - rnum ^= rnum >> 7; - rnum ^= rnum >> 3; - rnum ^= rnum << 6; - rnum ^= rnum >> 17; - - uint8_t seed1 = rnum & 0xF; - uint8_t seed2 = (rnum >> 4) & 0xF; - uint8_t seed3 = (rnum >> 8) & 0xF; - uint8_t seed4 = (rnum >> 12) & 0xF; - uint8_t seed5 = (rnum >> 16) & 0xF; - uint8_t seed6 = (rnum >> 20) & 0xF; - uint8_t seed7 = (rnum >> 24) & 0xF; - uint8_t seed8 = (rnum >> 28) & 0xF; - uint8_t seed9 = (rnum >> 18) & 0xF; - uint8_t seed10 = (rnum >> 22) & 0xF; - uint8_t seed11 = (rnum >> 26) & 0xF; - uint8_t seed12 = ((rnum >> 30) | (rnum << 2)) & 0xF; - - seed1 *= seed1; - seed2 *= seed2; - seed3 *= seed3; - seed4 *= seed4; - seed5 *= seed5; - seed6 *= seed6; - seed7 *= seed7; - seed8 *= seed8; - seed9 *= seed9; - seed10 *= seed10; - seed11 *= seed11; - seed12 *= seed12; - - int sh1, sh2, sh3; - if (seed & 1) { - sh1 = (seed & 2 ? 4 : 5); - sh2 = (partitioncount == 3 ? 6 : 5); - } else { - sh1 = (partitioncount == 3 ? 6 : 5); - sh2 = (seed & 2 ? 4 : 5); - } - sh3 = (seed & 0x10) ? sh1 : sh2; - - seed1 >>= sh1; - seed2 >>= sh2; - seed3 >>= sh1; - seed4 >>= sh2; - seed5 >>= sh1; - seed6 >>= sh2; - seed7 >>= sh1; - seed8 >>= sh2; - - seed9 >>= sh3; - seed10 >>= sh3; - seed11 >>= sh3; - seed12 >>= sh3; - - int a = seed1 * x + seed2 * y + seed11 * z + (rnum >> 14); - int b = seed3 * x + seed4 * y + seed12 * z + (rnum >> 10); - int c = seed5 * x + seed6 * y + seed9 * z + (rnum >> 06); - int d = seed7 * x + seed8 * y + seed10 * z + (rnum >> 02); - - a &= 0x3F; - b &= 0x3F; - c &= 0x3F; - d &= 0x3F; - - if (partitioncount <= 3) { - d = 0; - } - if (partitioncount <= 2) { - c = 0; - } - - if (a >= b && a >= c && a >= d) { - return 0; - } else if (b >= c && b >= d) { - return 1; - } else if (c >= d) { - return 2; - } else { - return 3; - } -} - -// A partition hash that we can pass to containers like std::unordered_set -struct PartitionHasher { - size_t operator()(const Partition& part) const { - // The issue here is that if we have two different partitions, A and B, then - // their hash should be equal if A and B are equal. We define the distance - // between A and B using PartitionMetric, but internally that finds a 1-1 - // mapping from labels in A to labels in B. - // - // With that in mind, when we define a hash for partitions, we need to find - // a 1-1 mapping to a 'universal' labeling scheme. Here we define that as - // the heuristic: the first encountered label will be 0, the second will be - // 1, etc. This creates a unique 1-1 mapping scheme from any partition. - // - // Note, we can't use this heuristic for the PartitionMetric, as it will - // generate very large discrepancies between similar labellings (for example - // 000...001 vs 011...111). We are just looking for a boolean distinction - // whether or not two partitions are different and don't care how different - // they are. - std::array<int, kMaxNumSubsets> mapping {{ -1, -1, -1, -1 }}; - int next_subset = 0; - for (int subset : part.assignment) { - if (mapping[subset] < 0) { - mapping[subset] = next_subset++; - } - } - assert(next_subset <= kMaxNumSubsets); - - // The return value will be the hash of the assignment according to this - // mapping - const auto seed = 0; - return std::accumulate(part.assignment.begin(), part.assignment.end(), seed, - [&mapping](size_t seed, const int& subset) { - std::hash<size_t> hasher; - const int s = mapping[subset]; - return hasher(seed) ^ hasher(static_cast<size_t>(s)); - }); - } -}; - -// Construct a VP-Tree of partitions. Since our PartitionMetric satisfies -// the triangle inequality, we can use this general higher-dimensional space -// partitioning tree to organize our partitions. -// -// TODO(google): !SPEED! Right now this tree stores an actual linked -// structure of pointers which is likely very slow during construction and -// very not cache-coherent during traversal, so it'd probably be good to -// switch to a flattened binary tree structure if performance becomes an -// issue. -class PartitionTree { - public: - // Unclear what it means to have an uninitialized tree, so delete default - // constructors, but allow the tree to be moved - PartitionTree() = delete; - PartitionTree(const PartitionTree&) = delete; - PartitionTree(PartitionTree&& t) = default; - - // Generate a PartitionTree from iterators over |Partition|s - template<typename Itr> - PartitionTree(Itr begin, Itr end) : parts_(begin, end) { - std::vector<int> part_indices(parts_.size()); - std::iota(part_indices.begin(), part_indices.end(), 0); - root_ = std::unique_ptr<PartitionTreeNode>( - new PartitionTreeNode(parts_, part_indices)); - } - - // Search for the k-nearest partitions that are closest to part based on - // the result of PartitionMetric - void Search(const Partition& part, int k, - std::vector<const Partition*>* const results, - std::vector<int>* const distances) const { - ResultHeap heap(k); - SearchNode(root_, part, &heap); - - results->clear(); - if (nullptr != distances) { - distances->clear(); - } - - std::vector<ResultNode> search_results = heap.Pop(); - for (const auto& result : search_results) { - results->push_back(&parts_[result.part_idx]); - if (nullptr != distances) { - distances->push_back(result.distance); - } - } - - assert(results->size() == k); - } - - private: - // Heap elements to be stored while searching the tree. The two relevant - // pieces of information are the partition index and it's distance from the - // queried partition. - struct ResultNode { - int part_idx; - int distance; - - // Heap based on distance from query point. - bool operator<(const ResultNode& other) const { - return distance < other.distance; - } - }; - - using ResultHeap = base::BottomN<ResultNode>; - - struct PartitionTreeNode { - int part_idx; - int split_dist; - - std::unique_ptr<PartitionTreeNode> left; - std::unique_ptr<PartitionTreeNode> right; - - PartitionTreeNode(const std::vector<Partition> &parts, - const std::vector<int> &part_indices) - : split_dist(-1) { - assert(part_indices.size() > 0); - - right.reset(nullptr); - left.reset(nullptr); - - // Store the first node as our vantage point - part_idx = part_indices[0]; - const Partition& vantage_point = parts[part_indices[0]]; - - // Calculate the distances of the remaining nodes against the vantage - // point. - std::vector<std::pair<int, int>> part_dists; - for (int i = 1; i < part_indices.size(); ++i) { - const int idx = part_indices[i]; - const int dist = PartitionMetric(vantage_point, parts[idx]); - if (dist > 0) { - part_dists.push_back(std::make_pair(idx, dist)); - } - } - - // If there are no more different parts, then this is a leaf node - if (part_dists.empty()) { - return; - } - - struct OrderBySecond { - typedef std::pair<int, int> PairType; - bool operator()(const PairType& lhs, const PairType& rhs) { - return lhs.second < rhs.second; - } - }; - - // We want to partition the set such that the points are ordered - // based on their distances from the vantage point. We can do this - // using the partial sort of nth element. - std::nth_element( - part_dists.begin(), part_dists.begin() + part_dists.size() / 2, - part_dists.end(), OrderBySecond()); - - // Once that's done, our split position is in the middle - const auto split_iter = part_dists.begin() + part_dists.size() / 2; - split_dist = split_iter->second; - - // Recurse down the right and left sub-trees with the indices of the - // parts that are farther and closer respectively - std::vector<int> right_indices; - for (auto itr = split_iter; itr != part_dists.end(); ++itr) { - right_indices.push_back(itr->first); - } - - if (!right_indices.empty()) { - right.reset(new PartitionTreeNode(parts, right_indices)); - } - - std::vector<int> left_indices; - for (auto itr = part_dists.begin(); itr != split_iter; ++itr) { - left_indices.push_back(itr->first); - } - - if (!left_indices.empty()) { - left.reset(new PartitionTreeNode(parts, left_indices)); - } - } - }; - - void SearchNode(const std::unique_ptr<PartitionTreeNode>& node, - const Partition& p, ResultHeap* const heap) const { - if (nullptr == node) { - return; - } - - // Calculate distance against current node - const int dist = PartitionMetric(parts_[node->part_idx], p); - - // Push it onto the heap and remove the top-most nodes to maintain - // closest k indices. - ResultNode result; - result.part_idx = node->part_idx; - result.distance = dist; - heap->Push(result); - - // If the split distance is uninitialized, it means we have no children. - if (node->split_dist < 0) { - assert(nullptr == node->left); - assert(nullptr == node->right); - return; - } - - // Next we need to check the left and right trees if their distance - // is closer/farther than the farthest element on the heap - const int tau = heap->Top().distance; - if (dist + tau < node->split_dist || dist - tau < node->split_dist) { - SearchNode(node->left, p, heap); - } - - if (dist + tau > node->split_dist || dist - tau > node->split_dist) { - SearchNode(node->right, p, heap); - } - } - - std::vector<Partition> parts_; - std::unique_ptr<PartitionTreeNode> root_; -}; - -// A helper function that generates all of the partitions for each number of -// subsets in ASTC blocks and stores them in a PartitionTree for fast retrieval. -const int kNumASTCPartitionIDBits = 10; -PartitionTree GenerateASTCPartitionTree(Footprint footprint) { - std::unordered_set<Partition, PartitionHasher> parts; - for (int num_parts = 2; num_parts <= kMaxNumSubsets; ++num_parts) { - for (int id = 0; id < (1 << kNumASTCPartitionIDBits); ++id) { - Partition part = GetASTCPartition(footprint, num_parts, id); - - // Make sure we're not using a degenerate partition assignment that wastes - // an endpoint pair... - bool valid_part = true; - for (int i = 0; i < num_parts; ++i) { - if (std::find(part.assignment.begin(), part.assignment.end(), i) == - part.assignment.end()) { - valid_part = false; - break; - } - } - - if (valid_part) { - parts.insert(std::move(part)); - } - } - } - - return PartitionTree(parts.begin(), parts.end()); -} - -// To avoid needing any fancy boilerplate for mapping from a width, height -// tuple, we can define a simple encoding for the block mode: -constexpr int EncodeDims(int width, int height) { - return (width << 16) | height; -} - -} // namespace - -//////////////////////////////////////////////////////////////////////////////// - -int PartitionMetric(const Partition& a, const Partition& b) { - // Make sure that one partition is at least a subset of the other... - UTILS_RELEASE_ASSERT(a.footprint == b.footprint); - - // Make sure that the number of parts is within our limits. ASTC has a maximum - // of four subsets per block according to the specification. - UTILS_RELEASE_ASSERT(a.num_parts <= kMaxNumSubsets); - UTILS_RELEASE_ASSERT(b.num_parts <= kMaxNumSubsets); - - const int w = a.footprint.Width(); - const int h = b.footprint.Height(); - - struct PairCount { - int a; - int b; - int count; - - // Comparison needed for sort below. - bool operator>(const PairCount& other) const { - return count > other.count; - } - }; - - // Since we need to find the smallest mapping from labels in A to labels in B, - // we need to store each label pair in a structure that can later be sorted. - // The maximum number of subsets in an ASTC block is four, meaning that - // between the two partitions, we can have up to sixteen different pairs. - std::array<PairCount, 16> pair_counts; - for (int y = 0; y < 4; ++y) { - for (int x = 0; x < 4; ++x) { - const int idx = y * 4 + x; - pair_counts[idx].a = x; - pair_counts[idx].b = y; - pair_counts[idx].count = 0; - } - } - - // Count how many times we see each pair of assigned values (order matters!) - for (int y = 0; y < h; ++y) { - for (int x = 0; x < w; ++x) { - const int idx = y * w + x; - - const int a_val = a.assignment[idx]; - const int b_val = b.assignment[idx]; - - assert(a_val >= 0); - assert(b_val >= 0); - - assert(a_val < 4); - assert(b_val < 4); - - ++(pair_counts[b_val * 4 + a_val].count); - } - } - - // Sort the pairs in descending order based on their count - std::sort(pair_counts.begin(), pair_counts.end(), std::greater<PairCount>()); - - // Now assign pairs one by one until we have no more pairs to assign. Once - // a value from A is assigned to a value in B, it can no longer be reassigned, - // so we can keep track of this in a matrix. Similarly, to keep the assignment - // one-to-one, once a value in B has been assigned to, it cannot be assigned - // to again. - std::array<std::array<bool, kMaxNumSubsets>, kMaxNumSubsets> assigned { }; - - int pixels_matched = 0; - for (const auto& pair_count : pair_counts) { - bool is_assigned = false; - for (int i = 0; i < kMaxNumSubsets; ++i) { - is_assigned |= assigned.at(pair_count.a).at(i); - is_assigned |= assigned.at(i).at(pair_count.b); - } - - if (!is_assigned) { - assigned.at(pair_count.a).at(pair_count.b) = true; - pixels_matched += pair_count.count; - } - } - - // The difference is the number of pixels that had an assignment versus the - // total number of pixels. - return w * h - pixels_matched; -} - -// Generates the partition assignment for the given block attributes. -Partition GetASTCPartition(const Footprint& footprint, int num_parts, - int partition_id) { - // Partitions must have at least one subset but may have at most four - assert(num_parts >= 0); - assert(num_parts <= kMaxNumSubsets); - - // Partition ID can be no more than 10 bits. - assert(partition_id >= 0); - assert(partition_id < 1 << 10); - - Partition part = {footprint, num_parts, partition_id, /* assignment = */ {}}; - part.assignment.reserve(footprint.NumPixels()); - - // Maintain column-major order so that we match all of the image processing - // algorithms that depend on this class. - for (int y = 0; y < footprint.Height(); ++y) { - for (int x = 0; x < footprint.Width(); ++x) { - const int p = SelectASTCPartition(partition_id, x, y, 0, num_parts, - footprint.NumPixels()); - part.assignment.push_back(p); - } - } - - return part; -} - -const std::vector<const Partition*> FindKClosestASTCPartitions( - const Partition& candidate, int k) { - const int encoded_dims = EncodeDims(candidate.footprint.Width(), - candidate.footprint.Height()); - - int index = 0; - switch (encoded_dims) { - case EncodeDims(4, 4): index = 0; break; - case EncodeDims(5, 4): index = 1; break; - case EncodeDims(5, 5): index = 2; break; - case EncodeDims(6, 5): index = 3; break; - case EncodeDims(6, 6): index = 4; break; - case EncodeDims(8, 5): index = 5; break; - case EncodeDims(8, 6): index = 6; break; - case EncodeDims(8, 8): index = 7; break; - case EncodeDims(10, 5): index = 8; break; - case EncodeDims(10, 6): index = 9; break; - case EncodeDims(10, 8): index = 10; break; - case EncodeDims(10, 10): index = 11; break; - case EncodeDims(12, 10): index = 12; break; - case EncodeDims(12, 12): index = 13; break; - default: - assert(false && "Unknown footprint dimensions. This should have been caught sooner."); - break; - } - - static const auto* const kASTCPartitionTrees = - new std::array<PartitionTree, Footprint::NumValidFootprints()> {{ - GenerateASTCPartitionTree(Footprint::Get4x4()), - GenerateASTCPartitionTree(Footprint::Get5x4()), - GenerateASTCPartitionTree(Footprint::Get5x5()), - GenerateASTCPartitionTree(Footprint::Get6x5()), - GenerateASTCPartitionTree(Footprint::Get6x6()), - GenerateASTCPartitionTree(Footprint::Get8x5()), - GenerateASTCPartitionTree(Footprint::Get8x6()), - GenerateASTCPartitionTree(Footprint::Get8x8()), - GenerateASTCPartitionTree(Footprint::Get10x5()), - GenerateASTCPartitionTree(Footprint::Get10x6()), - GenerateASTCPartitionTree(Footprint::Get10x8()), - GenerateASTCPartitionTree(Footprint::Get10x10()), - GenerateASTCPartitionTree(Footprint::Get12x10()), - GenerateASTCPartitionTree(Footprint::Get12x12()), - }}; - - const PartitionTree& parts_vptree = kASTCPartitionTrees->at(index); - std::vector<const Partition*> results; - parts_vptree.Search(candidate, k, &results, nullptr); - return results; -} - -// Returns the valid ASTC partition that is closest to the candidate based on -// the PartitionMetric defined above. -const Partition& FindClosestASTCPartition(const Partition& candidate) { - // Given a candidate, the closest valid partition will likely not be an exact - // match. Consider all of the texels for which this valid partition differs - // with the candidate. - // - // If the valid partition has more subsets than the candidate, then all of the - // highest subset will be included in the mismatched texels. Since the number - // of possible partitions with increasing subsets grows exponentially, the - // chance that a valid partition with fewer subsets appears within the first - // few closest partitions is relatively high. Empirically, we can usually find - // a partition with at most |candidate.num_parts| number of subsets within the - // first four closest partitions. - constexpr int kSearchItems = 4; - - const std::vector<const Partition*> results = - FindKClosestASTCPartitions(candidate, kSearchItems); - - // Optimistically, look for result with the same number of subsets. - for (const auto& result : results) { - if (result->num_parts == candidate.num_parts) { - return *result; - } - } - - // If all else fails, then at least find the result with fewer subsets than - // we asked for. - for (const auto& result : results) { - if (result->num_parts < candidate.num_parts) { - return *result; - } - } - - assert(false && - "Could not find partition with acceptable number of subsets!"); - return *(results[0]); -} - -} // namespace astc_codec diff --git a/third-party/astc-codec/src/decoder/partition.h b/third-party/astc-codec/src/decoder/partition.h deleted file mode 100644 index 4f64acb8..00000000 --- a/third-party/astc-codec/src/decoder/partition.h +++ /dev/null @@ -1,97 +0,0 @@ -// Copyright 2018 Google LLC -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// https://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -#ifndef ASTC_CODEC_DECODER_PARTITION_H_ -#define ASTC_CODEC_DECODER_PARTITION_H_ - -#include "src/base/optional.h" -#include "src/decoder/footprint.h" - -#include <vector> - -namespace astc_codec { - -struct Partition; - -// Determines the "difference" between any two partitions of the same size. -// This metric attempts to find the best one to one mapping from the labels in -// partition a against the labels in partition b. Once that mapping is found, it -// returns the number of pixels that are mismatched between the two. Each -// partition is expected to start in the upper left corner of the block and -// proceed in raster-scan order. Two partitions are equal if the mapping is -// bijective. This metric is a metric in the mathematical sense. In other words -// it has the following properties: -// -// 1) PartitionMetric(a, b) >= 0 -// 2) PartitionMetric(a, b) == PartitionMetric(b, a) -// 3) PartitionMetric(a, b) == 0 iff a == b -// 4) PartitionMetric(a, b) + PartitionMetric(b, c) >= PartitionMetric(a, c) -// -// Throws an error if one partition's footprint is not equal to the other. -int PartitionMetric(const Partition& a, const Partition& b); - -// A partition is a way to divide up an ASTC block into disjoint subsets such -// that each subset uses a different set of endpoints. This is used to increase -// the compression quality of blocks. One way to store such a partition is to -// assign an ID to use with a predetermined decoding method. Here we store the -// logical representation of partitions by keeping a per-pixel label. All pixels -// that share a label belong to the same subset. -struct Partition { - // The footprint width and height of this partition. This determines the size - // of the assignment array. - Footprint footprint; - - // The number of subsets in this partition. The values in the partition - // assignment fall within the range [0, num_parts). The maximum number of - // parts supported is four. - int num_parts; - - // The 10-bit partition ID as stored in bits 13-22 of multi-part ASTC blocks. - // (See Section C.2.9) If there is no guarantee that this partition is a valid - // ASTC partition, this should be set to absl::nullopt. - base::Optional<int> partition_id; - - // A value in the range [0, num_parts) corresponding to the label for - // the given texel (x, y) in [0, footprint_width) x [0, footprint_height) - // using a raster-order layout. - std::vector<int> assignment; - - // Returns true only if their "distance" is zero, i.e. if they have compatible - // subset assignments. - bool operator==(const Partition& other) const { - return PartitionMetric(*this, other) == 0; - } -}; - -// Generates the ASTC partition assignment for the given block attributes. -Partition GetASTCPartition(const Footprint& footprint, int num_parts, - int partition_id); - -// Returns the |k| valid ASTC partitions that are closest to the candidate based -// on the PartitionMetric defined above. -const std::vector<const Partition*> FindKClosestASTCPartitions( - const Partition& candidate, int k); - -// Returns the valid ASTC partition closest to the candidate with at most as -// many subsets as the |candidate|. Note: this is not a deterministic function, -// as the underlying valid partitions are sorted using a hash map and a distance -// function whose range is the natural numbers. The chances that two or more -// partitions are equally 'closest' is possible, in which case this function -// makes no guarantees about which one it will return. For more control, use -// FindKClosestASTCPartitions above. -const Partition& FindClosestASTCPartition(const Partition& candidate); - -} // namespace astc_codec - -#endif // ASTC_CODEC_DECODER_PARTITION_H_ diff --git a/third-party/astc-codec/src/decoder/physical_astc_block.cc b/third-party/astc-codec/src/decoder/physical_astc_block.cc deleted file mode 100644 index 7cc4d8e5..00000000 --- a/third-party/astc-codec/src/decoder/physical_astc_block.cc +++ /dev/null @@ -1,761 +0,0 @@ -// Copyright 2018 Google LLC -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// https://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -#include "src/decoder/physical_astc_block.h" -#include "src/base/math_utils.h" -#include "src/base/optional.h" -#include "src/base/uint128.h" -#include "src/decoder/integer_sequence_codec.h" - -#include <array> -#include <cmath> - -namespace astc_codec { - -namespace { - -static_assert(static_cast<int>(ColorEndpointMode::kNumColorEndpointModes) == 16, - "There are only sixteen color endpoint modes defined in the " - "ASTC specification. If this is false, then the enum may be " - "incorrect."); - -constexpr int kASTCBlockSizeBits = 128; -constexpr int kASTCBlockSizeBytes = kASTCBlockSizeBits / 8; -constexpr uint32_t kVoidExtentMaskBits = 9; -constexpr uint32_t kVoidExtentMask = 0x1FC; -constexpr int kWeightGridMinBitLength = 24; -constexpr int kWeightGridMaxBitLength = 96; -constexpr int kMaxNumPartitions = 4; -constexpr int kMaxNumWeights = 64; - -// These are the overall block modes defined in table C.2.8. There are 10 -// weight grid encoding schemes + void extent. -enum class BlockMode { - kB4_A2, - kB8_A2, - kA2_B8, - kA2_B6, - kB2_A2, - k12_A2, - kA2_12, - k6_10, - k10_6, - kA6_B6, - kVoidExtent, -}; - -struct WeightGridProperties { - int width; - int height; - int range; -}; - -// Local function prototypes -base::Optional<BlockMode> DecodeBlockMode(const base::UInt128 astc_bits); -base::Optional<WeightGridProperties> DecodeWeightProps( - const base::UInt128 astc_bits, std::string* error); -std::array<int, 4> DecodeVoidExtentCoords(const base::UInt128 astc_bits); -bool DecodeDualPlaneBit(const base::UInt128 astc_bits); -int DecodeNumPartitions(const base::UInt128 astc_bits); -int DecodeNumWeightBits(const base::UInt128 astc_bits); -int DecodeDualPlaneBitStartPos(const base::UInt128 astc_bits); -ColorEndpointMode DecodeEndpointMode(const base::UInt128 astc_bits, - int partition); -int DecodeNumColorValues(const base::UInt128 astc_bits); - -// Returns the block mode, if it's valid. -base::Optional<BlockMode> DecodeBlockMode(const base::UInt128 astc_bits) { - using Result = base::Optional<BlockMode>; - const uint64_t low_bits = astc_bits.LowBits(); - if (base::GetBits(low_bits, 0, kVoidExtentMaskBits) == kVoidExtentMask) { - return Result(BlockMode::kVoidExtent); - } - - if (base::GetBits(low_bits, 0, 2) != 0) { - const uint64_t mode_bits = base::GetBits(low_bits, 2, 2); - switch (mode_bits) { - case 0: return Result(BlockMode::kB4_A2); - case 1: return Result(BlockMode::kB8_A2); - case 2: return Result(BlockMode::kA2_B8); - case 3: return base::GetBits(low_bits, 8, 1) ? - Result(BlockMode::kB2_A2) : Result(BlockMode::kA2_B6); - } - } else { - const uint64_t mode_bits = base::GetBits(low_bits, 5, 4); - if ((mode_bits & 0xC) == 0x0) { - if (base::GetBits(low_bits, 0, 4) == 0) { - // Reserved. - return Result(); - } else { - return Result(BlockMode::k12_A2); - } - } else if ((mode_bits & 0xC) == 0x4) { - return Result(BlockMode::kA2_12); - } else if (mode_bits == 0xC) { - return Result(BlockMode::k6_10); - } else if (mode_bits == 0xD) { - return Result(BlockMode::k10_6); - } else if ((mode_bits & 0xC) == 0x8) { - return Result(BlockMode::kA6_B6); - } - } - - return Result(); -} - -base::Optional<WeightGridProperties> DecodeWeightProps( - const base::UInt128 astc_bits, std::string* error) { - auto block_mode = DecodeBlockMode(astc_bits); - if (!block_mode) { - *error = "Reserved block mode"; - return {}; - } - - // The dimensions of the weight grid and their range - WeightGridProperties props; - - // Determine the weight extents based on the block mode - const uint32_t low_bits = - static_cast<uint32_t>(astc_bits.LowBits() & 0xFFFFFFFF); - switch (block_mode.value()) { - case BlockMode::kB4_A2: { - int a = base::GetBits(low_bits, 5, 2); - int b = base::GetBits(low_bits, 7, 2); - props.width = b + 4; - props.height = a + 2; - } - break; - - case BlockMode::kB8_A2: { - int a = base::GetBits(low_bits, 5, 2); - int b = base::GetBits(low_bits, 7, 2); - props.width = b + 8; - props.height = a + 2; - } - break; - - case BlockMode::kA2_B8: { - int a = base::GetBits(low_bits, 5, 2); - int b = base::GetBits(low_bits, 7, 2); - props.width = a + 2; - props.height = b + 8; - } - break; - - case BlockMode::kA2_B6: { - int a = base::GetBits(low_bits, 5, 2); - int b = base::GetBits(low_bits, 7, 1); - props.width = a + 2; - props.height = b + 6; - } - break; - - case BlockMode::kB2_A2: { - int a = base::GetBits(low_bits, 5, 2); - int b = base::GetBits(low_bits, 7, 1); - props.width = b + 2; - props.height = a + 2; - } - break; - - case BlockMode::k12_A2: { - int a = base::GetBits(low_bits, 5, 2); - props.width = 12; - props.height = a + 2; - } - break; - - case BlockMode::kA2_12: { - int a = base::GetBits(low_bits, 5, 2); - props.width = a + 2; - props.height = 12; - } - break; - - case BlockMode::k6_10: { - props.width = 6; - props.height = 10; - } - break; - - case BlockMode::k10_6: { - props.width = 10; - props.height = 6; - } - break; - - case BlockMode::kA6_B6: { - int a = base::GetBits(low_bits, 5, 2); - int b = base::GetBits(low_bits, 9, 2); - props.width = a + 6; - props.height = b + 6; - } - break; - - // Void extent blocks have no weight grid. - case BlockMode::kVoidExtent: - *error = "Void extent block has no weight grid"; - return {}; - - // We have a valid block mode which isn't a void extent? We - // should be able to decode the weight grid dimensions. - default: - assert(false && "Error decoding weight grid"); - *error = "Internal error"; - return {}; - } - - // Determine the weight range based on the block mode - uint32_t r = base::GetBits(low_bits, 4, 1); - switch (block_mode.value()) { - case BlockMode::kB4_A2: - case BlockMode::kB8_A2: - case BlockMode::kA2_B8: - case BlockMode::kA2_B6: - case BlockMode::kB2_A2: { - r |= base::GetBits(low_bits, 0, 2) << 1; - } - break; - - case BlockMode::k12_A2: - case BlockMode::kA2_12: - case BlockMode::k6_10: - case BlockMode::k10_6: - case BlockMode::kA6_B6: { - r |= base::GetBits(low_bits, 2, 2) << 1; - } - break; - - // We have a valid block mode which doesn't have weights? We - // should have caught this earlier. - case BlockMode::kVoidExtent: - default: - assert(false && "Error decoding weight grid"); - *error = "Internal error"; - return {}; - } - - // Decode the range... - // High bit is in bit 9 unless we're using a particular block mode - uint32_t h = base::GetBits(low_bits, 9, 1); - if (block_mode == BlockMode::kA6_B6) { - h = 0; - } - - // Figure out the range of the weights (Table C.2.7) - constexpr std::array<int, 16> kWeightRanges = {{ - -1, -1, 1, 2, 3, 4, 5, 7, -1, -1, 9, 11, 15, 19, 23, 31 - }}; - - assert(((h << 3) | r) < kWeightRanges.size()); - - props.range = kWeightRanges.at((h << 3) | r); - if (props.range < 0) { - *error = "Reserved range for weight bits"; - return {}; - } - - // Error checking -- do we have too many weights? - int num_weights = props.width * props.height; - if (DecodeDualPlaneBit(astc_bits)) { - num_weights *= 2; - } - - if (kMaxNumWeights < num_weights) { - *error = "Too many weights specified"; - return {}; - } - - // Do we have too many weight bits? - const int bit_count = - IntegerSequenceCodec::GetBitCountForRange(num_weights, props.range); - - if (bit_count < kWeightGridMinBitLength) { - *error = "Too few bits required for weight grid"; - return {}; - } - - if (kWeightGridMaxBitLength < bit_count) { - *error = "Too many bits required for weight grid"; - return {}; - } - - return props; -} - -// Returns the four 13-bit integers that define the range of texture -// coordinates present in a void extent block as defined in Section -// C.2.23 of the specification. The coordinates returned are of -// the form (min_s, max_s, min_t, max_t) -std::array<int, 4> DecodeVoidExtentCoords(const base::UInt128 astc_bits) { - const uint64_t low_bits = astc_bits.LowBits(); - - std::array<int, 4> coords; - for (int i = 0; i < 4; ++i) { - coords[i] = static_cast<int>(base::GetBits(low_bits, 12 + 13 * i, 13)); - } - - return coords; -} - -bool DecodeDualPlaneBit(const base::UInt128 astc_bits) { - base::Optional<BlockMode> block_mode = DecodeBlockMode(astc_bits); - - // Void extent blocks certainly aren't dual-plane. - if (block_mode == BlockMode::kVoidExtent) { - return false; - } - - // One special block mode doesn't have any dual plane bit - if (block_mode == BlockMode::kA6_B6) { - return false; - } - - // Otherwise, dual plane is determined by the 10th bit. - constexpr int kDualPlaneBitPosition = 10; - return base::GetBits(astc_bits, kDualPlaneBitPosition, 1) != 0; -} - -int DecodeNumPartitions(const base::UInt128 astc_bits) { - constexpr int kNumPartitionsBitPosition = 11; - constexpr int kNumPartitionsBitLength = 2; - - // Non-void extent blocks - const uint64_t low_bits = astc_bits.LowBits(); - const int num_partitions = 1 + static_cast<int>( - base::GetBits(low_bits, - kNumPartitionsBitPosition, - kNumPartitionsBitLength)); - assert(num_partitions > 0); - assert(num_partitions <= kMaxNumPartitions); - - return num_partitions; -} - -int DecodeNumWeightBits(const base::UInt128 astc_bits) { - std::string error; - auto maybe_weight_props = DecodeWeightProps(astc_bits, &error); - if (!maybe_weight_props.hasValue()) { - return 0; // No weights? No weight bits... - } - - const auto weight_props = maybe_weight_props.value(); - - // Figure out the number of weights - int num_weights = weight_props.width * weight_props.height; - if (DecodeDualPlaneBit(astc_bits)) { - num_weights *= 2; - } - - // The number of bits is determined by the number of values - // that are going to be encoded using the given ise_counts. - return IntegerSequenceCodec::GetBitCountForRange( - num_weights, weight_props.range); -} - -// Returns the number of bits after the weight data used to -// store additional CEM bits. -int DecodeNumExtraCEMBits(const base::UInt128 astc_bits) { - const int num_partitions = DecodeNumPartitions(astc_bits); - - // Do we only have one partition? - if (num_partitions == 1) { - return 0; - } - - // Do we have a shared CEM? - constexpr int kSharedCEMBitPosition = 23; - constexpr int kSharedCEMBitLength = 2; - const base::UInt128 shared_cem = - base::GetBits(astc_bits, kSharedCEMBitPosition, kSharedCEMBitLength); - if (shared_cem == 0) { - return 0; - } - - const std::array<int, 4> extra_cem_bits_for_partition = {{ 0, 2, 5, 8 }}; - return extra_cem_bits_for_partition[num_partitions - 1]; -} - -// Returns the starting position of the dual plane channel. This comes -// before the weight data and extra CEM bits. -int DecodeDualPlaneBitStartPos(const base::UInt128 astc_bits) { - const int start_pos = kASTCBlockSizeBits - - DecodeNumWeightBits(astc_bits) - - DecodeNumExtraCEMBits(astc_bits); - - if (DecodeDualPlaneBit(astc_bits)) { - return start_pos - 2; - } else { - return start_pos; - } -} - -// Decodes a CEM mode based on the partition number. -ColorEndpointMode DecodeEndpointMode(const base::UInt128 astc_bits, - int partition) { - int num_partitions = DecodeNumPartitions(astc_bits); - assert(partition >= 0); - assert(partition < num_partitions); - - // Do we only have one partition? - uint64_t low_bits = astc_bits.LowBits(); - if (num_partitions == 1) { - uint64_t cem = base::GetBits(low_bits, 13, 4); - return static_cast<ColorEndpointMode>(cem); - } - - // More than one partition ... do we have a shared CEM? - if (DecodeNumExtraCEMBits(astc_bits) == 0) { - const uint64_t shared_cem = base::GetBits(low_bits, 25, 4); - return static_cast<ColorEndpointMode>(shared_cem); - } - - // More than one partition and no shared CEM... - uint64_t cem = base::GetBits(low_bits, 23, 6); - const int base_cem = static_cast<int>(((cem & 0x3) - 1) * 4); - cem >>= 2; // Skip the base CEM bits - - // The number of extra CEM bits at the end of the weight grid is - // determined by the number of partitions and what the base cem mode is... - const int num_extra_cem_bits = DecodeNumExtraCEMBits(astc_bits); - const int extra_cem_start_pos = kASTCBlockSizeBits - - num_extra_cem_bits - - DecodeNumWeightBits(astc_bits); - - base::UInt128 extra_cem = - base::GetBits(astc_bits, extra_cem_start_pos, num_extra_cem_bits); - cem |= extra_cem.LowBits() << 4; - - // Decode C and M per Figure C.4 - int c = -1, m = -1; - for (int i = 0; i < num_partitions; ++i) { - if (i == partition) { - c = cem & 0x1; - } - cem >>= 1; - } - - for (int i = 0; i < num_partitions; ++i) { - if (i == partition) { - m = cem & 0x3; - } - cem >>= 2; - } - - assert(c >= 0); - assert(m >= 0); - - // Compute the mode based on C and M - const int mode = base_cem + 4 * c + m; - assert(mode < static_cast<int>(ColorEndpointMode::kNumColorEndpointModes)); - return static_cast<ColorEndpointMode>(mode); -} - -int DecodeNumColorValues(const base::UInt128 astc_bits) { - int num_color_values = 0; - auto num_partitions = DecodeNumPartitions(astc_bits); - for (int i = 0; i < num_partitions; ++i) { - ColorEndpointMode endpoint_mode = DecodeEndpointMode(astc_bits, i); - num_color_values += NumColorValuesForEndpointMode(endpoint_mode); - } - - return num_color_values; -} - -} // namespace - -//////////////////////////////////////////////////////////////////////////////// - -static_assert(sizeof(PhysicalASTCBlock) == PhysicalASTCBlock::kSizeInBytes, - "The size of the struct should be the size of the block so that" - "we can effectively use them contiguously in memory."); - -PhysicalASTCBlock::PhysicalASTCBlock(const base::UInt128 astc_block) - : astc_bits_(astc_block) {} - -PhysicalASTCBlock::PhysicalASTCBlock(const std::string& encoded_block) - : astc_bits_([&encoded_block]() { - assert(encoded_block.size() == PhysicalASTCBlock::kSizeInBytes); - base::UInt128 astc_bits = 0; - int shift = 0; - for (const unsigned char c : encoded_block) { - astc_bits |= base::UInt128(static_cast<uint64_t>(c)) << shift; - shift += 8; - } - return astc_bits; - }()) -{ } - -base::Optional<std::string> PhysicalASTCBlock::IsIllegalEncoding() const { - // If the block is not a void extent block, then it must have - // weights specified. DecodeWeightProps will return the weight specifications - // if they exist and are legal according to C.2.24, and will otherwise be - // empty. - base::Optional<BlockMode> block_mode = DecodeBlockMode(astc_bits_); - if (block_mode != BlockMode::kVoidExtent) { - std::string error; - auto maybe_weight_props = DecodeWeightProps(astc_bits_, &error); - if (!maybe_weight_props.hasValue()) { - return error; - } - } - - // Check void extent blocks... - if (block_mode == BlockMode::kVoidExtent) { - // ... for reserved bits incorrectly set - if (base::GetBits(astc_bits_, 10, 2) != 0x3) { - return std::string("Reserved bits set for void extent block"); - } - - // ... for incorrectly defined texture coordinates - std::array<int, 4> coords = DecodeVoidExtentCoords(astc_bits_); - - bool coords_all_1s = true; - for (const auto coord : coords) { - coords_all_1s &= coord == ((1 << 13) - 1); - } - - if (!coords_all_1s && (coords[0] >= coords[1] || coords[2] >= coords[3])) { - return std::string("Void extent texture coordinates are invalid"); - } - } - - // If the number of color values exceeds a threshold and it isn't a void - // extent block then we've run into an error - if (block_mode != BlockMode::kVoidExtent) { - int num_color_vals = DecodeNumColorValues(astc_bits_); - if (num_color_vals > 18) { - return std::string("Too many color values"); - } - - // The maximum number of available color bits is the number of - // bits between the dual plane bits and the base CEM. This must - // be larger than a threshold defined in C.2.24. - - // Dual plane bit starts after weight bits and CEM - const int num_partitions = DecodeNumPartitions(astc_bits_); - const int dual_plane_start_pos = DecodeDualPlaneBitStartPos(astc_bits_); - const int color_start_bit = (num_partitions == 1) ? 17 : 29; - - const int required_color_bits = ((13 * num_color_vals) + 4) / 5; - const int available_color_bits = dual_plane_start_pos - color_start_bit; - if (available_color_bits < required_color_bits) { - return std::string("Not enough color bits"); - } - - // If we have four partitions and a dual plane then we have a problem. - if (num_partitions == 4 && DecodeDualPlaneBit(astc_bits_)) { - return std::string("Both four partitions and dual plane specified"); - } - } - - // Otherwise we're OK - return { }; -} - -bool PhysicalASTCBlock::IsVoidExtent() const { - // If it's an error block, it's not a void extent block. - if (IsIllegalEncoding()) { - return false; - } - - return DecodeBlockMode(astc_bits_) == BlockMode::kVoidExtent; -} - -base::Optional<std::array<int, 4>> PhysicalASTCBlock::VoidExtentCoords() const { - if (IsIllegalEncoding() || !IsVoidExtent()) { - return { }; - } - - // If void extent coords are all 1's then these are not valid void extent - // coords - const uint64_t ve_mask = 0xFFFFFFFFFFFFFDFFULL; - const uint64_t const_blk_mode = 0xFFFFFFFFFFFFFDFCULL; - if ((ve_mask & astc_bits_.LowBits()) == const_blk_mode) { - return {}; - } - - return DecodeVoidExtentCoords(astc_bits_); -} - -bool PhysicalASTCBlock::IsDualPlane() const { - // If it's an error block, then we aren't a dual plane block - if (IsIllegalEncoding()) { - return false; - } - - return DecodeDualPlaneBit(astc_bits_); -} - -// Returns the number of weight bits present in this block -base::Optional<int> PhysicalASTCBlock::NumWeightBits() const { - // If it's an error block, then we have no weight bits. - if (IsIllegalEncoding()) return { }; - - // If it's a void extent block, we have no weight bits - if (IsVoidExtent()) return { }; - - return DecodeNumWeightBits(astc_bits_); -} - -base::Optional<int> PhysicalASTCBlock::WeightStartBit() const { - if (IsIllegalEncoding()) return { }; - if (IsVoidExtent()) return { }; - - return kASTCBlockSizeBits - DecodeNumWeightBits(astc_bits_); -} - -base::Optional<std::array<int, 2>> PhysicalASTCBlock::WeightGridDims() const { - std::string error; - auto weight_props = DecodeWeightProps(astc_bits_, &error); - - if (!weight_props.hasValue()) return { }; - if (IsIllegalEncoding()) return { }; - - const auto props = weight_props.value(); - return {{{ props.width, props.height }}}; -} - -base::Optional<int> PhysicalASTCBlock::WeightRange() const { - std::string error; - auto weight_props = DecodeWeightProps(astc_bits_, &error); - - if (!weight_props.hasValue()) return { }; - if (IsIllegalEncoding()) return { }; - - return weight_props.value().range; -} - -base::Optional<int> PhysicalASTCBlock::DualPlaneChannel() const { - if (!IsDualPlane()) return { }; - - int dual_plane_start_pos = DecodeDualPlaneBitStartPos(astc_bits_); - auto plane_bits = base::GetBits(astc_bits_, dual_plane_start_pos, 2); - return base::Optional<int>(static_cast<int>(plane_bits.LowBits())); -} - -base::Optional<int> PhysicalASTCBlock::ColorStartBit() const { - if (IsVoidExtent()) { - return 64; - } - - auto num_partitions = NumPartitions(); - if (!num_partitions) return { }; - - return (num_partitions == 1) ? 17 : 29; -} - -base::Optional<int> PhysicalASTCBlock::NumColorValues() const { - // If we have a void extent block, then we have four color values - if (IsVoidExtent()) { - return 4; - } - - // If we have an illegal encoding, then we have no color values - if (IsIllegalEncoding()) return { }; - - return DecodeNumColorValues(astc_bits_); -} - -void PhysicalASTCBlock::GetColorValuesInfo(int* const color_bits, - int* const color_range) const { - // Figure out the range possible for the number of values we have... - const int dual_plane_start_pos = DecodeDualPlaneBitStartPos(astc_bits_); - const int max_color_bits = dual_plane_start_pos - ColorStartBit().value(); - const int num_color_values = NumColorValues().value(); - for (int range = 255; range > 0; --range) { - const int bitcount = - IntegerSequenceCodec::GetBitCountForRange(num_color_values, range); - if (bitcount <= max_color_bits) { - if (color_bits != nullptr) { - *color_bits = bitcount; - } - - if (color_range != nullptr) { - *color_range = range; - } - return; - } - } - - assert(false && - "This means that even if we have a range of one there aren't " - "enough bits to store the color values, and our encoding is " - "illegal."); -} - -base::Optional<int> PhysicalASTCBlock::NumColorBits() const { - if (IsIllegalEncoding()) return { }; - - if (IsVoidExtent()) { - return 64; - } - - int color_bits; - GetColorValuesInfo(&color_bits, nullptr); - return color_bits; -} - -base::Optional<int> PhysicalASTCBlock::ColorValuesRange() const { - if (IsIllegalEncoding()) return { }; - - if (IsVoidExtent()) { - return (1 << 16) - 1; - } - - int color_range; - GetColorValuesInfo(nullptr, &color_range); - return color_range; -} - -base::Optional<int> PhysicalASTCBlock::NumPartitions() const { - // Error blocks have no partitions - if (IsIllegalEncoding()) return { }; - - // Void extent blocks have no partitions either - if (DecodeBlockMode(astc_bits_) == BlockMode::kVoidExtent) { - return { }; - } - - // All others have some number of partitions - return DecodeNumPartitions(astc_bits_); -} - -base::Optional<int> PhysicalASTCBlock::PartitionID() const { - auto num_partitions = NumPartitions(); - if (!num_partitions || num_partitions == 1) return { }; - - const uint64_t low_bits = astc_bits_.LowBits(); - return static_cast<int>(base::GetBits(low_bits, 13, 10)); -} - -base::Optional<ColorEndpointMode> PhysicalASTCBlock::GetEndpointMode( - int partition) const { - // Error block? - if (IsIllegalEncoding()) return { }; - - // Void extent blocks have no endpoint modes - if (DecodeBlockMode(astc_bits_) == BlockMode::kVoidExtent) { - return { }; - } - - // Do we even have a CEM for this partition? - if (partition < 0 || DecodeNumPartitions(astc_bits_) <= partition) { - return { }; - } - - return DecodeEndpointMode(astc_bits_, partition); -} - -} // namespace astc_codec diff --git a/third-party/astc-codec/src/decoder/physical_astc_block.h b/third-party/astc-codec/src/decoder/physical_astc_block.h deleted file mode 100644 index 1b04bdda..00000000 --- a/third-party/astc-codec/src/decoder/physical_astc_block.h +++ /dev/null @@ -1,128 +0,0 @@ -// Copyright 2018 Google LLC -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// https://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -#ifndef ASTC_CODEC_DECODER_PHYSICAL_ASTC_BLOCK_H_ -#define ASTC_CODEC_DECODER_PHYSICAL_ASTC_BLOCK_H_ - -// The logic in this file is based on the ASTC specification, which can be -// found here: -// https://www.opengl.org/registry/specs/KHR/texture_compression_astc_hdr.txt - -#include "src/base/optional.h" -#include "src/base/uint128.h" -#include "src/decoder/types.h" - -#include <string> - -namespace astc_codec { - -// A PhysicalASTCBlock contains all 128 bits and the logic for decoding the -// various internals of an ASTC block. -class PhysicalASTCBlock { - public: - // The physical size in bytes of an ASTC block - static const size_t kSizeInBytes = 16; - - // Initializes an ASTC block based on the encoded string. - explicit PhysicalASTCBlock(const std::string& encoded_block); - explicit PhysicalASTCBlock(const base::UInt128 astc_block); - - // Returns the 128 bits of this ASTC block. - base::UInt128 GetBlockBits() const { return astc_bits_; } - - // Weights are stored in a grid that may not have the same dimensions - // as the block dimensions. This allows us to see what the physical - // dimensions are of the grid. - base::Optional<std::array<int, 2>> WeightGridDims() const; - - // The weight range is the maximum value a weight can take in the - // weight grid. - base::Optional<int> WeightRange() const; - - // Returns true if the block encoding specifies a void-extent block. This - // kind of block stores a single color to be used for every pixel in the - // block. - bool IsVoidExtent() const; - - // Returns the values (min_s, max_s, min_t, max_t) as defined in the void - // extent block as the range of texture coordinates for which this block is - // defined. (See Section C.2.23) - base::Optional<std::array<int, 4>> VoidExtentCoords() const; - - // Returns true if the block contains two separate weight grids. One used - // for the channel returned by DualPlaneChannel() and one used by the other - // channels. - bool IsDualPlane() const; - - // Returns the channel used as the "dual plane". The return value is only - // meaningful if IsDualPlane() returns true... - base::Optional<int> DualPlaneChannel() const; - - // Returns a reason that the encoding doesn't adhere to the specification. - // If the encoding is legal, then this returns a nullptr. This allows us to - // still use code of the form: - // - // if (IsIllegalEncoding()) { - // ... error ... - // } - // ... no error ... - // - // However, it also helps with debugging since we can find problems with - // encodings a lot faster. - base::Optional<std::string> IsIllegalEncoding() const; - - // Returns the number of weight bits present in this block. - base::Optional<int> NumWeightBits() const; - - // Returns the starting position within the range [0, 127] of the - // weight data within the block. - base::Optional<int> WeightStartBit() const; - - // Returns the number of endpoint pairs used in this block. - base::Optional<int> NumPartitions() const; - - // Returns the seed used to determine the partition for a given - // (x, y) coordinate within the block. Determined using the - // block size and the function as described in the specification. - base::Optional<int> PartitionID() const; - - // Returns the color endpoint mode for the given partition index. - base::Optional<ColorEndpointMode> GetEndpointMode(int partition) const; - - // Returns the starting position within the range [0, 127] of the - // color data within the block. - base::Optional<int> ColorStartBit() const; - - // Returns the number of integers used to represent the color endpoints. - base::Optional<int> NumColorValues() const; - - // Returns the number of bits used to represent the color endpoints. - base::Optional<int> NumColorBits() const; - - // Returns the maximum value that each of the encoded integers used to - // represent the color endpoints can take. - base::Optional<int> ColorValuesRange() const; - - private: - const base::UInt128 astc_bits_; - - // The logic to return the number of color bits and the color values range - // is very similar, so it's probably best to abstract it away into its own - // function. - void GetColorValuesInfo(int* color_bits, int* color_range) const; -}; - -} // namespace astc_codec - -#endif // ASTC_CODEC_DECODER_PHYSICAL_ASTC_BLOCK_H_ diff --git a/third-party/astc-codec/src/decoder/quantization.cc b/third-party/astc-codec/src/decoder/quantization.cc deleted file mode 100644 index db996826..00000000 --- a/third-party/astc-codec/src/decoder/quantization.cc +++ /dev/null @@ -1,462 +0,0 @@ -// Copyright 2018 Google LLC -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// https://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -#include "src/decoder/quantization.h" -#include "src/base/math_utils.h" - -#include <algorithm> -#include <array> -#include <cassert> -#include <map> -#include <memory> -#include <vector> - -namespace astc_codec { - -namespace { - -// Trit unquantization procedure as described in Section C.2.13 -int GetUnquantizedTritValue(int trit, int bits, int range) { - int a = (bits & 1) ? 0x1FF : 0; - int b = 0, c = 0; - switch (range) { - case 5: { - b = 0; - c = 204; - } - break; - - case 11: { - int x = (bits >> 1) & 0x1; - b = (x << 1) | (x << 2) | (x << 4) | (x << 8); - c = 93; - } - break; - - case 23: { - int x = (bits >> 1) & 0x3; - b = x | (x << 2) | (x << 7); - c = 44; - } - break; - - case 47: { - int x = (bits >> 1) & 0x7; - b = x | (x << 6); - c = 22; - } - break; - - case 95: { - int x = (bits >> 1) & 0xF; - b = (x >> 2) | (x << 5); - c = 11; - } - break; - - case 191: { - int x = (bits >> 1) & 0x1F; - b = (x >> 4) | (x << 4); - c = 5; - } - break; - - default: - assert(false && "Illegal trit encoding"); - break; - } - - int t = trit * c + b; - t ^= a; - t = (a & 0x80) | (t >> 2); - return t; -} - -// Quint unquantization procedure as described in Section C.2.13 -int GetUnquantizedQuintValue(int quint, int bits, int range) { - int a = (bits & 1) ? 0x1FF : 0; - int b = 0, c = 0; - switch (range) { - case 9: { - b = 0; - c = 113; - } - break; - - case 19: { - int x = (bits >> 1) & 0x1; - b = (x << 2) | (x << 3) | (x << 8); - c = 54; - } - break; - - case 39: { - int x = (bits >> 1) & 0x3; - b = (x >> 1) | (x << 1) | (x << 7); - c = 26; - } - break; - - case 79: { - int x = (bits >> 1) & 0x7; - b = (x >> 1) | (x << 6); - c = 13; - } - break; - - case 159: { - int x = (bits >> 1) & 0xF; - b = (x >> 3) | (x << 5); - c = 6; - } - break; - - default: - assert(false && "Illegal quint encoding"); - break; - } - - int t = quint * c + b; - t ^= a; - t = (a & 0x80) | (t >> 2); - return t; -} - -// Trit unquantization procedure as described in Section C.2.17. In the code -// below, the variables a, b, and c correspond to the columns A, B, and C in -// the specification. -int GetUnquantizedTritWeight(int trit, int bits, int range) { - int a = (bits & 1) ? 0x7F : 0; - int b = 0, c = 0; - switch (range) { - case 2: - return (std::array<int, 3> {{ 0, 32, 63 }})[trit]; - - case 5: - c = 50; - b = 0; - break; - - case 11: { - c = 23; - b = (bits >> 1) & 1; - b |= (b << 2) | (b << 6); - } - break; - - case 23: { - c = 11; - b = (bits >> 1) & 0x3; - b |= (b << 5); - } - break; - - default: - assert(false && "Illegal trit encoding"); - break; - } - - int t = trit * c + b; - t ^= a; - t = (a & 0x20) | (t >> 2); - return t; -} - -// Quint unquantization procedure as described in Section C.2.17. In the code -// below, the variables a, b, and c correspond to the columns A, B, and C in -// the specification. -int GetUnquantizedQuintWeight(int quint, int bits, int range) { - int a = (bits & 1) ? 0x7F : 0; - int b = 0, c = 0; - switch (range) { - case 4: - return (std::array<int, 5> {{ 0, 16, 32, 47, 63 }})[quint]; - - case 9: - c = 28; - b = 0; - break; - - case 19: { - c = 13; - b = (bits >> 1) & 0x1; - b = (b << 1) | (b << 6); - } - break; - - default: - assert(false && "Illegal quint encoding"); - break; - } - - int t = quint * c + b; - t ^= a; - t = (a & 0x20) | (t >> 2); - return t; -} - -// A Quantization map allows us to convert to/from values that are quantized -// according to the ASTC spec. -class QuantizationMap { - public: - int Quantize(int x) const { - return x < quantization_map_.size() ? quantization_map_.at(x) : 0; - } - - int Unquantize(int x) const { - return x < unquantization_map_.size() ? unquantization_map_.at(x) : 0; - } - - protected: - QuantizationMap() { } - std::vector<int> quantization_map_; - std::vector<int> unquantization_map_; - - void GenerateQuantizationMap() { - assert(unquantization_map_.size() > 1); - quantization_map_.clear(); - - // TODO(google) For weights, we don't need quantization values all the - // way up to 256, but it doesn't hurt -- just wastes memory, but the code - // is much cleaner this way - for (int i = 0; i < 256; ++i) { - int best_idx = 0; - int best_idx_score = 256; - int idx = 0; - for (int unquantized_val : unquantization_map_) { - const int diff = i - unquantized_val; - const int idx_score = diff * diff; - if (idx_score < best_idx_score) { - best_idx = idx; - best_idx_score = idx_score; - } - idx++; - } - - quantization_map_.push_back(best_idx); - } - } -}; - -template<int (*UnquantizationFunc)(int, int, int)> -class TritQuantizationMap : public QuantizationMap { - public: - explicit TritQuantizationMap(int range) : QuantizationMap() { - assert((range + 1) % 3 == 0); - const int num_bits_pow_2 = (range + 1) / 3; - const int num_bits = - num_bits_pow_2 == 0 ? 0 : base::Log2Floor(num_bits_pow_2); - - for (int trit = 0; trit < 3; ++trit) { - for (int bits = 0; bits < (1 << num_bits); ++bits) { - unquantization_map_.push_back(UnquantizationFunc(trit, bits, range)); - } - } - - GenerateQuantizationMap(); - } -}; - -template<int (*UnquantizationFunc)(int, int, int)> -class QuintQuantizationMap : public QuantizationMap { - public: - explicit QuintQuantizationMap(int range) : QuantizationMap() { - assert((range + 1) % 5 == 0); - const int num_bits_pow_2 = (range + 1) / 5; - const int num_bits = - num_bits_pow_2 == 0 ? 0 : base::Log2Floor(num_bits_pow_2); - - for (int quint = 0; quint < 5; ++quint) { - for (int bits = 0; bits < (1 << num_bits); ++bits) { - unquantization_map_.push_back(UnquantizationFunc(quint, bits, range)); - } - } - - GenerateQuantizationMap(); - } -}; - -template<int TotalUnquantizedBits> -class BitQuantizationMap : public QuantizationMap { - public: - explicit BitQuantizationMap<TotalUnquantizedBits>(int range) - : QuantizationMap() { - // Make sure that if we're using bits then we have a positive power of two. - assert(base::CountOnes(range + 1) == 1); - - const int num_bits = base::Log2Floor(range + 1); - for (int bits = 0; bits <= range; ++bits) { - // Need to replicate bits until we fill up the bits - int unquantized = bits; - int num_unquantized_bits = num_bits; - while (num_unquantized_bits < TotalUnquantizedBits) { - const int num_dst_bits_to_shift_up = - std::min(num_bits, TotalUnquantizedBits - num_unquantized_bits); - const int num_src_bits_to_shift_down = - num_bits - num_dst_bits_to_shift_up; - unquantized <<= num_dst_bits_to_shift_up; - unquantized |= bits >> num_src_bits_to_shift_down; - num_unquantized_bits += num_dst_bits_to_shift_up; - } - assert(num_unquantized_bits == TotalUnquantizedBits); - - unquantization_map_.push_back(unquantized); - - // Fill half of the quantization map with the previous value for bits - // and the other half with the current value for bits - if (bits > 0) { - const int prev_unquant = unquantization_map_.at(bits - 1); - while (quantization_map_.size() <= (prev_unquant + unquantized) / 2) { - quantization_map_.push_back(bits - 1); - } - } - while (quantization_map_.size() <= unquantized) { - quantization_map_.push_back(bits); - } - } - - assert(quantization_map_.size() == 1 << TotalUnquantizedBits); - } -}; - -using QMap = std::shared_ptr<QuantizationMap>; - -// Returns the quantization map for quantizing color values in [0, 255] with the -// smallest range that can accommodate |r| -static const QuantizationMap* GetQuantMapForValueRange(int r) { - // Endpoint values can be quantized using bits, trits, or quints. Here we - // store the quantization maps for each of the ranges that are supported by - // such an encoding. That way we can choose the proper quantization procedure - // based on the range of values rather than by having complicated switches and - // logic. We must use a std::map here instead of a std::unordered_map because - // of the assumption made in std::upper_bound about the iterators being from a - // poset. - static const auto* const kASTCEndpointQuantization = new std::map<int, QMap> { - { 5, QMap(new TritQuantizationMap<GetUnquantizedTritValue>(5)) }, - { 7, QMap(new BitQuantizationMap<8>(7)) }, - { 9, QMap(new QuintQuantizationMap<GetUnquantizedQuintValue>(9)) }, - { 11, QMap(new TritQuantizationMap<GetUnquantizedTritValue>(11)) }, - { 15, QMap(new BitQuantizationMap<8>(15)) }, - { 19, QMap(new QuintQuantizationMap<GetUnquantizedQuintValue>(19)) }, - { 23, QMap(new TritQuantizationMap<GetUnquantizedTritValue>(23)) }, - { 31, QMap(new BitQuantizationMap<8>(31)) }, - { 39, QMap(new QuintQuantizationMap<GetUnquantizedQuintValue>(39)) }, - { 47, QMap(new TritQuantizationMap<GetUnquantizedTritValue>(47)) }, - { 63, QMap(new BitQuantizationMap<8>(63)) }, - { 79, QMap(new QuintQuantizationMap<GetUnquantizedQuintValue>(79)) }, - { 95, QMap(new TritQuantizationMap<GetUnquantizedTritValue>(95)) }, - { 127, QMap(new BitQuantizationMap<8>(127)) }, - { 159, QMap(new QuintQuantizationMap<GetUnquantizedQuintValue>(159)) }, - { 191, QMap(new TritQuantizationMap<GetUnquantizedTritValue>(191)) }, - { 255, QMap(new BitQuantizationMap<8>(255)) }, - }; - - assert(r < 256); - auto itr = kASTCEndpointQuantization->upper_bound(r); - if (itr != kASTCEndpointQuantization->begin()) { - return (--itr)->second.get(); - } - return nullptr; -} - -// Returns the quantization map for weight values in [0, 63] with the smallest -// range that can accommodate |r| -static const QuantizationMap* GetQuantMapForWeightRange(int r) { - // Similar to endpoint quantization, weights can also be stored using trits, - // quints, or bits. Here we store the quantization maps for each of the ranges - // that are supported by such an encoding. - static const auto* const kASTCWeightQuantization = new std::map<int, QMap> { - { 1, QMap(new BitQuantizationMap<6>(1)) }, - { 2, QMap(new TritQuantizationMap<GetUnquantizedTritWeight>(2)) }, - { 3, QMap(new BitQuantizationMap<6>(3)) }, - { 4, QMap(new QuintQuantizationMap<GetUnquantizedQuintWeight>(4)) }, - { 5, QMap(new TritQuantizationMap<GetUnquantizedTritWeight>(5)) }, - { 7, QMap(new BitQuantizationMap<6>(7)) }, - { 9, QMap(new QuintQuantizationMap<GetUnquantizedQuintWeight>(9)) }, - { 11, QMap(new TritQuantizationMap<GetUnquantizedTritWeight>(11)) }, - { 15, QMap(new BitQuantizationMap<6>(15)) }, - { 19, QMap(new QuintQuantizationMap<GetUnquantizedQuintWeight>(19)) }, - { 23, QMap(new TritQuantizationMap<GetUnquantizedTritWeight>(23)) }, - { 31, QMap(new BitQuantizationMap<6>(31)) }, - }; - - assert(r < 32); - auto itr = kASTCWeightQuantization->upper_bound(r); - if (itr != kASTCWeightQuantization->begin()) { - return (--itr)->second.get(); - } - return nullptr; -} - -} // namespace - -//////////////////////////////////////////////////////////////////////////////// - -int QuantizeCEValueToRange(int value, int range_max_value) { - assert(range_max_value >= kEndpointRangeMinValue); - assert(range_max_value <= 255); - assert(value >= 0); - assert(value <= 255); - - const QuantizationMap* map = GetQuantMapForValueRange(range_max_value); - return map ? map->Quantize(value) : 0; -} - -int UnquantizeCEValueFromRange(int value, int range_max_value) { - assert(range_max_value >= kEndpointRangeMinValue); - assert(range_max_value <= 255); - assert(value >= 0); - assert(value <= range_max_value); - - const QuantizationMap* map = GetQuantMapForValueRange(range_max_value); - return map ? map->Unquantize(value) : 0; -} - -int QuantizeWeightToRange(int weight, int range_max_value) { - assert(range_max_value >= 1); - assert(range_max_value <= kWeightRangeMaxValue); - assert(weight >= 0); - assert(weight <= 64); - - // The quantization maps that define weight unquantization expect values in - // the range [0, 64), but the specification quantizes them to the range - // [0, 64] according to C.2.17. This is a slight hack similar to the one in - // the unquantization procedure to return the passed in unquantized value to - // [0, 64) prior to running it through the quantization procedure. - if (weight > 33) { - weight -= 1; - } - const QuantizationMap* map = GetQuantMapForWeightRange(range_max_value); - return map ? map->Quantize(weight) : 0; -} - -int UnquantizeWeightFromRange(int weight, int range_max_value) { - assert(range_max_value >= 1); - assert(range_max_value <= kWeightRangeMaxValue); - assert(weight >= 0); - assert(weight <= range_max_value); - const QuantizationMap* map = GetQuantMapForWeightRange(range_max_value); - int dq = map ? map->Unquantize(weight) : 0; - - // Quantized weights are returned in the range [0, 64), but they should be - // returned in the range [0, 64], so according to C.2.17 we need to add one - // to the result. - assert(dq < 64); - if (dq > 32) { - dq += 1; - } - return dq; -} - -} // namespace astc_codec diff --git a/third-party/astc-codec/src/decoder/quantization.h b/third-party/astc-codec/src/decoder/quantization.h deleted file mode 100644 index 5f7239f1..00000000 --- a/third-party/astc-codec/src/decoder/quantization.h +++ /dev/null @@ -1,65 +0,0 @@ -// Copyright 2018 Google LLC -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// https://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -#ifndef ASTC_CODEC_DECODER_QUANTIZATION_H_ -#define ASTC_CODEC_DECODER_QUANTIZATION_H_ - -//////////////////////////////////////////////////////////////////////////////// -// -// ASTC Quantization procedures. -// -// The values stored in ASTC blocks tend to be stored in a range much more -// restricted than the logical range used. For example, sometimes weights are -// stored in the range from [0, 3] but are used in the range [0, 64]. The -// process of translating a value to or from this range is known as quantization -// and dequantization. The ranges to which these values can be (de)quantized -// are defined by ISERange[Begin|End]() in integer_sequence_codec.h - -namespace astc_codec { - -// The minimum possible range for a pair of endpoints. If endpoints are -// quantized to something smaller than this, then it would constitute an -// illegal ASTC encoding. -constexpr int kEndpointRangeMinValue = 5; - -// The maximum possible range for a weight value. If weights are quantized to -// something larger than this, then it would constitute an illegal ASTC -// encoding. -constexpr int kWeightRangeMaxValue = 31; - -// Quantizes a value in the range [0, 255] to [0, |range|]. The quantized values -// have no correlation to the input values, and there should be no implicit -// assumptions made about their ordering. Valid values of |range_max_value| are -// in the interval [5, 255] -int QuantizeCEValueToRange(int value, int range_max_value); - -// Unquantizes a value in the range [0, |range|] to [0, 255]. Performs the -// inverse procedure of QuantizeValueToRange. Valid values of |range_max_value| -// are in the interval [5, 255] -int UnquantizeCEValueFromRange(int value, int range_max_value); - -// Quantizes a weight in the range [0, 64] to [0, |range_max_value|]. The -// quantized values have no correlation to the input values, and there should -// be no implicit assumptions made about their ordering. Valid values of -// |range_max_value| are in the interval [1, 31] -int QuantizeWeightToRange(int weight, int range_max_value); - -// Unquantizes a weight in the range [0, |range_max_value|] to [0, 64]. Performs -// the inverse procedure of QuantizeWeightToRange. Valid values of -// |range_max_value| are in the interval [1, 31] -int UnquantizeWeightFromRange(int weight, int range_max_value); - -} // namespace astc_codec - -#endif // ASTC_CODEC_DECODER_QUANTIZATION_H_ diff --git a/third-party/astc-codec/src/decoder/test/astc_fuzzer.cc b/third-party/astc-codec/src/decoder/test/astc_fuzzer.cc deleted file mode 100644 index f152675d..00000000 --- a/third-party/astc-codec/src/decoder/test/astc_fuzzer.cc +++ /dev/null @@ -1,36 +0,0 @@ -// Copyright 2018 Google LLC -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// https://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -// ASTC fuzzing wrapper to help with fuzz testing. - -#include "src/decoder/codec.h" - -#include <benchmark/benchmark.h> - -#include <vector> - -extern "C" int LLVMFuzzerTestOneInput(const uint8_t* data, size_t size) { - std::string error; - std::unique_ptr<astc_codec::ASTCFile> file = - astc_codec::ASTCFile::LoadFromMemory(reinterpret_cast<const char*>(data), - size, &error); - if (file) { - std::vector<uint8_t> out_buffer(file->GetWidth() * file->GetHeight() * 4); - bool result = astc_codec::DecompressToImage( - *file, out_buffer.data(), out_buffer.size(), file->GetWidth() * 4); - benchmark::DoNotOptimize(result); - } - - return 0; -} diff --git a/third-party/astc-codec/src/decoder/test/codec_test.cc b/third-party/astc-codec/src/decoder/test/codec_test.cc deleted file mode 100644 index 936eed3e..00000000 --- a/third-party/astc-codec/src/decoder/test/codec_test.cc +++ /dev/null @@ -1,181 +0,0 @@ -// Copyright 2018 Google LLC -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// https://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -#include "src/decoder/codec.h" -#include "include/astc-codec/astc-codec.h" -#include "src/decoder/test/image_utils.h" - -#include <gtest/gtest.h> - -#include <string> - -namespace astc_codec { - -static void PrintTo(FootprintType footprint, std::ostream* os) { - switch (footprint) { - case FootprintType::k4x4: *os << "FootprintType::k4x4"; break; - case FootprintType::k5x4: *os << "FootprintType::k5x4"; break; - case FootprintType::k5x5: *os << "FootprintType::k5x5"; break; - case FootprintType::k6x5: *os << "FootprintType::k6x5"; break; - case FootprintType::k6x6: *os << "FootprintType::k6x6"; break; - case FootprintType::k8x5: *os << "FootprintType::k8x5"; break; - case FootprintType::k8x6: *os << "FootprintType::k8x6"; break; - case FootprintType::k10x5: *os << "FootprintType::k10x5"; break; - case FootprintType::k10x6: *os << "FootprintType::k10x6"; break; - case FootprintType::k8x8: *os << "FootprintType::k8x8"; break; - case FootprintType::k10x8: *os << "FootprintType::k10x8"; break; - case FootprintType::k10x10: *os << "FootprintType::k10x10"; break; - case FootprintType::k12x10: *os << "FootprintType::k12x10"; break; - case FootprintType::k12x12: *os << "FootprintType::k12x12"; break; - default: - *os << "<Unexpected FootprintType " - << static_cast<uint32_t>(footprint) << ">"; - } -} - -namespace { - -using ::testing::TestWithParam; -using ::testing::ValuesIn; - -ImageBuffer LoadGoldenImageWithAlpha(std::string basename) { - const std::string filename = - std::string("src/decoder/testdata/") + basename + ".bmp"; - ImageBuffer result; - LoadGoldenBmp(filename, &result); - EXPECT_EQ(result.BytesPerPixel(), 4); - return result; -} - -struct ImageTestParams { - std::string image_name; - FootprintType footprint; - size_t width; - size_t height; -}; - -static void PrintTo(const ImageTestParams& params, std::ostream* os) { - *os << "ImageTestParams(" << params.image_name << ", " << params.width << "x" - << params.height << ", "; - PrintTo(params.footprint, os); - *os << ")"; -} - -TEST(CodecTest, InvalidInput) { - const size_t valid_width = 16; - const size_t valid_height = 16; - const size_t valid_stride = valid_width * 4; - - const std::vector<uint8_t> data(256); - std::vector<uint8_t> output(valid_width * valid_height * 4); - - // Invalid footprint. - EXPECT_FALSE(ASTCDecompressToRGBA( - data.data(), data.size(), valid_width, valid_height, - FootprintType::kCount, output.data(), output.size(), valid_stride)); - - // Fail for 0 width or height. - EXPECT_FALSE(ASTCDecompressToRGBA(data.data(), data.size(), 0, valid_height, - FootprintType::k4x4, output.data(), - output.size(), valid_stride)); - EXPECT_FALSE(ASTCDecompressToRGBA(data.data(), data.size(), valid_width, 0, - FootprintType::k4x4, output.data(), - output.size(), valid_stride)); - - // Fail for data size that's not a multiple of block size. - EXPECT_FALSE(ASTCDecompressToRGBA( - data.data(), data.size() - 1, valid_width, valid_height, - FootprintType::k4x4, output.data(), output.size(), valid_stride)); - // Fail for data size that doesn't match the block count. - EXPECT_FALSE(ASTCDecompressToRGBA( - data.data(), data.size() - 16, valid_width, valid_height, - FootprintType::k4x4, output.data(), output.size(), valid_stride)); - - // Fail for invalid stride. - EXPECT_FALSE(ASTCDecompressToRGBA( - data.data(), data.size(), valid_width, valid_height, FootprintType::k4x4, - output.data(), output.size(), valid_stride - 1)); - - // Fail for invalid output size. - EXPECT_FALSE(ASTCDecompressToRGBA( - data.data(), data.size(), valid_width, valid_height, FootprintType::k4x4, - output.data(), output.size() - 1, valid_stride)); -} - -class CodecTest : public TestWithParam<ImageTestParams> {}; - -TEST_P(CodecTest, PublicAPI) { - const auto& params = GetParam(); - const std::string astc = LoadASTCFile(params.image_name); - - ImageBuffer our_decoded_image; - our_decoded_image.Allocate(params.width, params.height, 4); - ASSERT_TRUE(ASTCDecompressToRGBA( - reinterpret_cast<const uint8_t*>(astc.data()), astc.size(), params.width, - params.height, params.footprint, our_decoded_image.Data().data(), - our_decoded_image.DataSize(), our_decoded_image.Stride())); - - // Check that the decoded image is *very* similar to the library decoding - // of an ASTC texture. They may not be exact due to differences in how we - // convert a 16-bit float to an 8-bit integer. - ImageBuffer decoded_image = LoadGoldenImageWithAlpha(params.image_name); - CompareSumOfSquaredDifferences(decoded_image, our_decoded_image, 1.0); -} - -TEST_P(CodecTest, DecompressToImage) { - const auto& params = GetParam(); - - std::string error; - std::unique_ptr<ASTCFile> image_file = ASTCFile::LoadFile( - std::string("src/decoder/testdata/") + params.image_name + ".astc", - &error); - ASSERT_TRUE(image_file) << "Failed to load " << params.image_name << ": " - << error; - - ASSERT_TRUE(image_file->GetFootprint()); - EXPECT_EQ(params.footprint, image_file->GetFootprint().value().Type()); - - ImageBuffer our_decoded_image; - our_decoded_image.Allocate(image_file->GetWidth(), image_file->GetHeight(), - 4); - - ASSERT_TRUE(DecompressToImage(*image_file, our_decoded_image.Data().data(), - our_decoded_image.DataSize(), - our_decoded_image.Stride())); - - // Check that the decoded image is *very* similar to the library decoding - // of an ASTC texture. They may not be exact due to differences in how we - // convert a 16-bit float to an 8-bit integer. - ImageBuffer decoded_image = LoadGoldenImageWithAlpha(params.image_name); - CompareSumOfSquaredDifferences(decoded_image, our_decoded_image, 1.0); -} - -// Test to make sure that reading out color values from blocks in a real-world -// image isn't terribly wrong, either. -std::vector<ImageTestParams> GetTransparentImageTestParams() { - return { - // image_name astc footprint width height - { "atlas_small_4x4", FootprintType::k4x4, 256, 256 }, - { "atlas_small_5x5", FootprintType::k5x5, 256, 256 }, - { "atlas_small_6x6", FootprintType::k6x6, 256, 256 }, - { "atlas_small_8x8", FootprintType::k8x8, 256, 256 }, - }; -} - -INSTANTIATE_TEST_CASE_P(Transparent, CodecTest, - ValuesIn(GetTransparentImageTestParams())); - -} // namespace - -} // namespace astc_codec diff --git a/third-party/astc-codec/src/decoder/test/endpoint_codec_test.cc b/third-party/astc-codec/src/decoder/test/endpoint_codec_test.cc deleted file mode 100644 index de7d9cab..00000000 --- a/third-party/astc-codec/src/decoder/test/endpoint_codec_test.cc +++ /dev/null @@ -1,463 +0,0 @@ -// Copyright 2018 Google LLC -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// https://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -#include "src/decoder/endpoint_codec.h" -#include "src/decoder/intermediate_astc_block.h" -#include "src/decoder/test/image_utils.h" - -#include <random> -#include <string> -#include <utility> -#include <vector> - -#include <gtest/gtest.h> -#include <gmock/gmock.h> - -namespace astc_codec { - -namespace { - -using ::testing::AllOf; -using ::testing::AnyOf; -using ::testing::Each; -using ::testing::Eq; -using ::testing::Ge; -using ::testing::Le; -using ::testing::Ne; -using ::testing::Pointwise; -using ::testing::SizeIs; -using ::testing::Pair; - -constexpr std::array<EndpointEncodingMode, 6> kEndpointEncodingModes = {{ - EndpointEncodingMode::kDirectLuma, - EndpointEncodingMode::kDirectLumaAlpha, - EndpointEncodingMode::kBaseScaleRGB, - EndpointEncodingMode::kBaseScaleRGBA, - EndpointEncodingMode::kDirectRGB, - EndpointEncodingMode::kDirectRGBA }}; - -const std::array<std::pair<RgbaColor, RgbaColor>, 3> kBlueContractPairs = {{ - std::make_pair(RgbaColor{{ 22, 18, 30, 59 }}, - RgbaColor{{ 162, 148, 155, 59 }}), - std::make_pair(RgbaColor{{ 22, 30, 27, 36 }}, - RgbaColor{{ 228, 221, 207, 36 }}), - std::make_pair(RgbaColor{{ 54, 60, 55, 255 }}, - RgbaColor{{ 23, 30, 27, 255 }}) - }}; - -// Used to directly initialize std::pairs of colors with initializer lists -// e.g. MakeColors({{ r, g, b, a }}, {{ r, g, b, a }}); -std::pair<RgbaColor, RgbaColor> MakeColors(RgbaColor&& a, RgbaColor&& b) { - return std::make_pair(a, b); -} - -// Returns |high| and |low| as they would be decoded using the quantization -// factor |quant| for the ColorEndpointMode |mode|. -std::pair<RgbaColor, RgbaColor> TestColors( - RgbaColor low, RgbaColor high, int quant, EndpointEncodingMode mode) { - ColorEndpointMode astc_mode; - std::vector<int> encoded; - const bool needs_swap = - EncodeColorsForMode(low, high, quant, mode, &astc_mode, &encoded); - - RgbaColor decoded_low, decoded_high; - DecodeColorsForMode(encoded, quant, astc_mode, &decoded_low, &decoded_high); - - if (needs_swap) { - return std::make_pair(decoded_high, decoded_low); - } else { - return std::make_pair(decoded_low, decoded_high); - } -} - -// Returns true if the argument tuple entries only differ by at most x. -MATCHER_P(IsCloseTo, x, "") { - const auto& a = ::testing::get<0>(arg); - const auto& b = ::testing::get<1>(arg); - return (a > b) ? ((a - b) <= x) : ((b - a) <= x); -} - -// Test to make sure that the range of values that we get as they are -// quantized remains within what we pass as |quant|. -TEST(EndpointCodecTest, QuantRanges) { - const RgbaColor low {{ 0, 0, 0, 0 }}; - const RgbaColor high {{ 255, 255, 255, 255 }}; - - std::vector<int> result; - for (const auto& mode : kEndpointEncodingModes) { - for (int i = 5; i < 256; ++i) { - ColorEndpointMode astc_mode; - const bool needs_swap = - EncodeColorsForMode(low, high, i, mode, &astc_mode, &result); - EXPECT_EQ(result.size(), NumValuesForEncodingMode(mode)) << i; - EXPECT_EQ(result.size(), NumColorValuesForEndpointMode(astc_mode)) << i; - - // ASTC mode shouldn't use base/offset when endpoints are so far apart. - EXPECT_THAT(astc_mode, Ne(ColorEndpointMode::kLDRRGBBaseOffset)); - EXPECT_THAT(astc_mode, Ne(ColorEndpointMode::kLDRRGBABaseOffset)); - - EXPECT_THAT(result, Each(AllOf(Ge(0), Le(i)))) - << "Mode: " << static_cast<int>(mode); - // We don't care if we need to swap the weights in this test - EXPECT_TRUE(needs_swap || !needs_swap); - } - } -} - -// Test to make sure that each mode that directly encodes colors can effectively -// encode both black and white -TEST(EndpointCodecTest, ExtremeDirectEncodings) { - const RgbaColor kWhite {{ 255, 255, 255, 255 }}; - const RgbaColor kBlack {{ 0, 0, 0, 255 }}; - - std::vector<int> encoded; - for (const auto& mode : kEndpointEncodingModes) { - for (int i = 5; i < 256; ++i) { - const auto expected = std::make_pair(kWhite, kBlack); - EXPECT_EQ(TestColors(kWhite, kBlack, i, mode), expected) - << "Range: " << i << ", Mode: " << static_cast<int>(mode); - } - } -} - -// According to the spec, this is used for colors close to gray. The values -// chosen here were according to the spec. -TEST(EndpointCodecTest, UsesBlueContract) { - std::vector<int> vals = { 132, 127, 116, 112, 183, 180, 31, 22 }; - EXPECT_TRUE(UsesBlueContract(255, ColorEndpointMode::kLDRRGBDirect, vals)); - EXPECT_TRUE(UsesBlueContract(255, ColorEndpointMode::kLDRRGBADirect, vals)); - - // For the offset modes the only way to trigger the blue contract mode is if - // we force the subtraction in the decoding procedure (See section C.2.14 of - // the spec), so we need to set the 7th bit to 1 for all of the odd-numbered - // values - vals[1] &= 0xBF; - vals[3] &= 0xBF; - vals[5] &= 0xBF; - vals[7] &= 0xBF; - - EXPECT_FALSE( - UsesBlueContract(255, ColorEndpointMode::kLDRRGBBaseOffset, vals)); - EXPECT_FALSE( - UsesBlueContract(255, ColorEndpointMode::kLDRRGBABaseOffset, vals)); - - vals[1] |= 0x40; - vals[3] |= 0x40; - vals[5] |= 0x40; - vals[7] |= 0x40; - - EXPECT_TRUE( - UsesBlueContract(255, ColorEndpointMode::kLDRRGBBaseOffset, vals)); - EXPECT_TRUE( - UsesBlueContract(255, ColorEndpointMode::kLDRRGBABaseOffset, vals)); - - // All other LDR endpoint modes should return no blue contract - for (int max_val : { 255, 127, 11 }) { - for (auto mode : { ColorEndpointMode::kLDRLumaDirect, - ColorEndpointMode::kLDRLumaBaseOffset, - ColorEndpointMode::kLDRLumaAlphaDirect, - ColorEndpointMode::kLDRLumaAlphaBaseOffset, - ColorEndpointMode::kLDRRGBBaseScale, - ColorEndpointMode::kLDRRGBBaseScaleTwoA }) { - EXPECT_FALSE(UsesBlueContract(max_val, mode, vals)); - } - } -} - -// Make sure that encoding and decoding for the direct luminance mode works. -TEST(EndpointCodecTest, LumaDirect) { - const auto mode = EndpointEncodingMode::kDirectLuma; - - // With a 255 quantizer, all greys should be exact. - for (int i = 0; i < 255; ++i) { - for (int j = 0; j < 255; ++j) { - EXPECT_EQ(TestColors({{ i, i, i, 255 }}, {{ j, j, j, 255 }}, 255, mode), - MakeColors({{ i, i, i, 255 }}, {{ j, j, j, 255 }})); - } - } - - // If we have almost grey, then they should encode to grey. - EXPECT_EQ(TestColors({{ 247, 248, 246, 255 }}, {{ 2, 3, 1, 255 }}, 255, mode), - MakeColors({{ 247, 247, 247, 255 }}, {{ 2, 2, 2, 255 }})); - - EXPECT_EQ(TestColors({{ 80, 80, 50, 255 }}, {{ 99, 255, 6, 255 }}, 255, mode), - MakeColors({{ 70, 70, 70, 255 }}, {{ 120, 120, 120, 255 }})); - - // If we have almost greys and a really small quantizer, it should be white - // and black (literally). - EXPECT_EQ(TestColors({{ 247, 248, 246, 255 }}, {{ 2, 3, 1, 255 }}, 15, mode), - MakeColors({{ 255, 255, 255, 255 }}, {{ 0, 0, 0, 255 }})); - - // The average of 64, 127, and 192 is 127.666..., so it should round to - // 130 instead of 125. - EXPECT_EQ(TestColors({{ 64, 127, 192, 255 }}, {{ 0, 0, 0, 255 }}, 63, mode), - MakeColors({{ 130, 130, 130, 255 }}, {{ 0, 0, 0, 255 }})); - - // If we have almost grey, then they should encode to grey -- similar to - // direct encoding since the encoded colors differ by < 63. - EXPECT_EQ(TestColors({{ 80, 80, 50, 255 }}, {{ 99, 255, 6, 255 }}, 255, mode), - MakeColors({{ 70, 70, 70, 255 }}, {{ 120, 120, 120, 255 }})); - - // Low precision colors should still encode pretty well with base/offset. - EXPECT_EQ(TestColors({{ 35, 36, 38, 255 }}, {{ 42, 43, 40, 255 }}, 47, mode), - MakeColors({{ 38, 38, 38, 255 }}, {{ 43, 43, 43, 255 }})); - - EXPECT_EQ(TestColors({{ 39, 42, 40, 255 }}, {{ 18, 20, 21, 255 }}, 39, mode), - MakeColors({{ 39, 39, 39, 255 }}, {{ 19, 19, 19, 255 }})); -} - -// Test encoding and decoding for the base-offset luminance mode. -TEST(EndpointCodecTest, LumaAlphaDirect) { - const auto mode = EndpointEncodingMode::kDirectLumaAlpha; - - // With a 255 quantizer, all greys should be exact. - for (int i = 0; i < 255; ++i) { - for (int j = 0; j < 255; ++j) { - EXPECT_EQ(TestColors({{ i, i, i, j }}, {{ j, j, j, i }}, 255, mode), - MakeColors({{ i, i, i, j }}, {{ j, j, j, i }})); - } - } - - // If we have almost grey, then they should encode to grey. - EXPECT_EQ(TestColors({{ 247, 248, 246, 250 }}, {{ 2, 3, 1, 172 }}, 255, mode), - MakeColors({{ 247, 247, 247, 250 }}, {{ 2, 2, 2, 172 }})); - - EXPECT_EQ(TestColors({{ 80, 80, 50, 0 }}, {{ 99, 255, 6, 255 }}, 255, mode), - MakeColors({{ 70, 70, 70, 0 }}, {{ 120, 120, 120, 255 }})); - - // If we have almost greys and a really small quantizer, it should be white - // and black (literally). - EXPECT_EQ(TestColors({{ 247, 248, 246, 253 }}, {{ 2, 3, 1, 3 }}, 15, mode), - MakeColors({{ 255, 255, 255, 255 }}, {{ 0, 0, 0, 0 }})); - - // The average of 64, 127, and 192 is 127.666..., so it should round to - // 130 instead of 125. The alpha in this case is independent. - EXPECT_EQ(TestColors({{ 64, 127, 192, 127 }}, {{ 0, 0, 0, 20 }}, 63, mode), - MakeColors({{ 130, 130, 130, 125 }}, {{ 0, 0, 0, 20 }})); -} - -// Test encoding for the direct RGB mode. -TEST(EndpointCodecTest, RGBDirect) { - const auto mode = EndpointEncodingMode::kDirectRGB; - - // Colors should be encoded exactly with a 255 quantizer. - std::mt19937 random(0xdeadbeef); - std::uniform_int_distribution<int> byte_distribution(0, 255); - - for (int i = 0; i < 100; ++i) { - RgbaColor low, high; - for (auto& x : high) { x = byte_distribution(random); } - for (auto& x : low) { x = byte_distribution(random); } - high[3] = low[3] = 255; // RGB Direct mode has opaque alpha. - - EXPECT_EQ(TestColors(low, high, 255, mode), std::make_pair(low, high)) - << "Random iter: " << i; - } - - // For each of the following tests, order of endpoints shouldn't have any - // bearing on the quantization properties, so we should be able to switch - // endpoints as we see fit and have them generate the same flipped encoded - // pairs. - - EXPECT_EQ(TestColors({{ 64, 127, 192, 255 }}, {{ 0, 0, 0, 255 }}, 63, mode), - MakeColors({{ 65, 125, 190, 255 }}, {{ 0, 0, 0, 255 }})); - - EXPECT_EQ(TestColors({{ 0, 0, 0, 255 }}, {{ 64, 127, 192, 255 }}, 63, mode), - MakeColors({{ 0, 0, 0, 255 }}, {{ 65, 125, 190, 255 }})); - - EXPECT_EQ(TestColors({{ 1, 2, 94, 255 }}, {{ 168, 255, 13, 255 }}, 7, mode), - MakeColors({{ 0, 0, 109, 255 }}, {{ 182, 255, 0, 255 }})); - - // Colors close to grey will likely need a blue contract. - EXPECT_EQ(TestColors(kBlueContractPairs[0].first, - kBlueContractPairs[0].second, 31, mode), - MakeColors({{ 24, 20, 33, 255 }}, {{ 160, 148, 156, 255 }})); - - EXPECT_EQ(TestColors(kBlueContractPairs[0].second, - kBlueContractPairs[0].first, 31, mode), - MakeColors({{ 160, 148, 156, 255 }}, {{ 24, 20, 33, 255 }})); - - EXPECT_EQ(TestColors(kBlueContractPairs[1].first, - kBlueContractPairs[1].second, 7, mode), - MakeColors({{ 18, 36, 36, 255 }}, {{ 237, 219, 219, 255 }})); - - EXPECT_EQ(TestColors(kBlueContractPairs[1].second, - kBlueContractPairs[1].first, 7, mode), - MakeColors({{ 237, 219, 219, 255 }}, {{ 18, 36, 36, 255 }})); - - // Colors close to grey (and each other) will likely need a blue contract AND - // use the offset mode for encoding - EXPECT_EQ(TestColors(kBlueContractPairs[2].first, - kBlueContractPairs[2].second, 31, mode), - MakeColors({{ 53, 59, 53, 255 }}, {{ 24, 30, 26, 255 }})); - - EXPECT_EQ(TestColors(kBlueContractPairs[2].second, - kBlueContractPairs[2].first, 31, mode), - MakeColors({{ 24, 30, 26, 255 }}, {{ 53, 59, 53, 255 }})); - - // Colors close to each other, but not to grey will likely only use the offset - // mode and not the blue-contract modes. - EXPECT_EQ(TestColors({{ 22, 148, 30, 59 }}, {{ 162, 18, 155, 59 }}, 31, mode), - MakeColors({{ 24, 148, 33, 255 }}, {{ 165, 16, 156, 255 }})); - - EXPECT_EQ(TestColors({{ 162, 18, 155, 59 }}, {{ 22, 148, 30, 59 }}, 31, mode), - MakeColors({{ 165, 16, 156, 255 }}, {{ 24, 148, 33, 255 }})); -} - -// Make sure that certain endpoint pairs result in the blue-contract path as -// we'd expect, such that we can make sure that we're hitting all of the encode -// paths. -TEST(EndpointCodecTest, RGBDirectMakesBlueContract) { - constexpr int kEndpointRange = 31; - for (const auto& endpoint_pair : kBlueContractPairs) { - ColorEndpointMode astc_mode; - std::vector<int> vals; - bool needs_swap = EncodeColorsForMode( - endpoint_pair.first, endpoint_pair.second, - kEndpointRange, EndpointEncodingMode::kDirectRGB, &astc_mode, &vals); - (void)(needs_swap); // Don't really care. - - EXPECT_TRUE(UsesBlueContract(kEndpointRange, astc_mode, vals)); - } -} - -// Make sure that encoding and decoding for the RGB base-scale mode works. -TEST(EndpointCodecTest, RGBBaseScale) { - const auto mode = EndpointEncodingMode::kBaseScaleRGB; - const auto close_to = [](RgbaColor c, int x) { - return Pointwise(IsCloseTo(x), c); - }; - - // Identical colors should be encoded with a 255 scale factor. Since ASTC - // decodes the scaled color by doing (x * s) >> 8, the decoded color will be - // multiplied by 255/256. This might cause rounding errors sometimes, so we - // check that every channel only deviates by 1. - std::mt19937 random(0xdeadbeef); - std::uniform_int_distribution<int> byte_distribution(0, 255); - - for (int i = 0; i < 100; ++i) { - RgbaColor color{{byte_distribution(random), byte_distribution(random), - byte_distribution(random), 255}}; - const auto test_result = TestColors(color, color, 255, mode); - EXPECT_THAT(test_result, Pair(close_to(color, 1), close_to(color, 1))); - } - - // Make sure that if we want to scale by e.g. 1/4 then we can do that exactly: - const RgbaColor low = {{ 20, 4, 40, 255 }}; - const RgbaColor high = {{ 80, 16, 160, 255 }}; - EXPECT_THAT(TestColors(low, high, 255, mode), - Pair(close_to(low, 0), close_to(high, 0))); - - // And if we quantize it, then we get roughly the same thing. The scale factor - // should be representable with most quantization levels. The problem is that - // if we're off on the 'high' color, then we will be off on the 'low' color. - EXPECT_THAT(TestColors(low, high, 127, mode), - Pair(close_to(low, 1), close_to(high, 1))); - - EXPECT_THAT(TestColors(low, high, 63, mode), - Pair(close_to(low, 1), close_to(high, 2))); - - EXPECT_THAT(TestColors(low, high, 31, mode), - Pair(close_to(low, 1), close_to(high, 4))); - - EXPECT_THAT(TestColors(low, high, 15, mode), - Pair(close_to(low, 2), close_to(high, 8))); -} - -// Make sure that encoding and decoding for the RGB base-offset mode works. -// Since we don't have a decoder, this is currently only a test that should work -// based on reasoning about what's written in the spec. -// TODO(krajcevski): Write an encoder. -TEST(EndpointCodecTest, RGBBaseOffset) { - const auto test_colors = [](const RgbaColor& low, const RgbaColor& high) { - const RgbaColor diff = {{ high[0] - low[0], high[1] - low[1], - high[2] - low[2], high[3] - low[3] }}; - - std::vector<int> vals; - for (int i = 0; i < 3; ++i) { - // If the base is "large", then it grabs it's most significant bit from - // the offset value. Hence, we need to save it here. - const bool is_large = low[i] >= 128; - vals.push_back((low[i] * 2) & 0xFF); - vals.push_back(diff[i] * 2); - - // Give the "large" bases their bits back. - if (is_large) { - vals.back() |= 0x80; - } - } - - RgbaColor dec_low, dec_high; - DecodeColorsForMode(vals, 255, ColorEndpointMode::kLDRRGBBaseOffset, - &dec_low, &dec_high); - - EXPECT_THAT(std::make_pair(dec_low, dec_high), Pair(Eq(low), Eq(high))); - }; - - // Test the "direct encoding" path. - test_colors({{ 80, 16, 112, 255 }}, {{ 87, 18, 132, 255 }}); - test_colors({{ 80, 74, 82, 255 }}, {{ 90, 92, 110, 255 }}); - test_colors({{ 0, 0, 0, 255 }}, {{ 2, 2, 2, 255 }}); - - // Identical endpoints should always encode exactly, provided they satisfy the - // requirements for the base encoding. - std::mt19937 random(0xdeadbeef); - std::uniform_int_distribution<int> byte_distribution(0, 255); - for (int i = 0; i < 100; ++i) { - RgbaColor color{{byte_distribution(random), byte_distribution(random), - byte_distribution(random), 255}}; - if ((color[0] | color[1] | color[2]) & 1) { - continue; - } - test_colors(color, color); - } - - // TODO(google): Test the "blue contract" path. -} - -// Make sure that we can decode colors that are given to us straight out of the -// ASTC codec. -TEST(EndpointCodecTest, DecodeCheckerboard) { - const RgbaColor kWhite {{ 255, 255, 255, 255 }}; - const RgbaColor kBlack {{ 0, 0, 0, 255 }}; - - const std::string astc = LoadASTCFile("checkerboard"); - for (int i = 0; i < astc.size(); i += 16) { - base::UInt128 block; - memcpy(&block, &astc[i], sizeof(block)); - - const auto intermediate = UnpackIntermediateBlock(PhysicalASTCBlock(block)); - ASSERT_TRUE(intermediate) << "Block is void extent???"; - - const auto block_data = &intermediate.value(); - ASSERT_THAT(block_data->endpoints, SizeIs(Eq(1))); - - const int color_range = EndpointRangeForBlock(*block_data); - const auto& endpoints = block_data->endpoints[0]; - - RgbaColor low, high; - DecodeColorsForMode(endpoints.colors, color_range, endpoints.mode, - &low, &high); - - // Expect that the endpoints are black and white, but either order. - EXPECT_THAT(std::make_pair(low, high), - AnyOf( - Pair(Eq(kWhite), Eq(kBlack)), - Pair(Eq(kBlack), Eq(kWhite)))); - } -} - -} // namespace - -} // namespace astc_codec diff --git a/third-party/astc-codec/src/decoder/test/footprint_test.cc b/third-party/astc-codec/src/decoder/test/footprint_test.cc deleted file mode 100644 index 6aef98a7..00000000 --- a/third-party/astc-codec/src/decoder/test/footprint_test.cc +++ /dev/null @@ -1,97 +0,0 @@ -// Copyright 2018 Google LLC -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// https://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -#include "src/decoder/footprint.h" - -#include <array> -#include <tuple> -#include <vector> - -#include <gtest/gtest.h> - -namespace astc_codec { - -namespace { - -TEST(FootprintTest, ParseAstcFootprintString) { - using ASTCTestPair = std::pair<std::string, Footprint>; - const std::array<ASTCTestPair, Footprint::NumValidFootprints()> - valid_footprints {{ - std::make_pair("4x4", Footprint::Get4x4()), - std::make_pair("5x4", Footprint::Get5x4()), - std::make_pair("5x5", Footprint::Get5x5()), - std::make_pair("6x5", Footprint::Get6x5()), - std::make_pair("6x6", Footprint::Get6x6()), - std::make_pair("8x5", Footprint::Get8x5()), - std::make_pair("8x6", Footprint::Get8x6()), - std::make_pair("8x8", Footprint::Get8x8()), - std::make_pair("10x5", Footprint::Get10x5()), - std::make_pair("10x6", Footprint::Get10x6()), - std::make_pair("10x8", Footprint::Get10x8()), - std::make_pair("10x10", Footprint::Get10x10()), - std::make_pair("12x10", Footprint::Get12x10()), - std::make_pair("12x12", Footprint::Get12x12()) - }}; - - for (const auto& test : valid_footprints) { - base::Optional<Footprint> footprint = Footprint::Parse(test.first.c_str()); - EXPECT_TRUE(footprint); - EXPECT_EQ(test.second, footprint.value()); - } - - EXPECT_DEBUG_DEATH(EXPECT_FALSE(Footprint::Parse("")), ""); - EXPECT_DEBUG_DEATH(EXPECT_FALSE(Footprint::Parse("3")), ""); - EXPECT_DEBUG_DEATH(EXPECT_FALSE(Footprint::Parse("x")), ""); - // Validly formed but out-of-bounds dimensions do not assert, otherwise - // malformed ASTC files could crash the decoder in debug builds. - EXPECT_FALSE(Footprint::Parse("9999999999x10")); - EXPECT_DEBUG_DEATH(EXPECT_FALSE(Footprint::Parse("ax8")), ""); - EXPECT_DEBUG_DEATH(EXPECT_FALSE(Footprint::Parse("2x3x4")), ""); - EXPECT_DEBUG_DEATH(EXPECT_FALSE(Footprint::Parse("-3x4")), ""); - EXPECT_FALSE(Footprint::Parse("10x4")); -} - -TEST(FootprintTest, Bitrates) { - EXPECT_NEAR(Footprint::Get4x4().Bitrate(), 8.f, 0.01f); - EXPECT_NEAR(Footprint::Get5x4().Bitrate(), 6.4f, 0.01f); - EXPECT_NEAR(Footprint::Get5x5().Bitrate(), 5.12f, 0.01f); - EXPECT_NEAR(Footprint::Get6x5().Bitrate(), 4.27f, 0.01f); - EXPECT_NEAR(Footprint::Get6x6().Bitrate(), 3.56f, 0.01f); - EXPECT_NEAR(Footprint::Get8x5().Bitrate(), 3.20f, 0.01f); - EXPECT_NEAR(Footprint::Get8x6().Bitrate(), 2.67f, 0.01f); - EXPECT_NEAR(Footprint::Get8x8().Bitrate(), 2.00f, 0.01f); - EXPECT_NEAR(Footprint::Get10x5().Bitrate(), 2.56f, 0.01f); - EXPECT_NEAR(Footprint::Get10x6().Bitrate(), 2.13f, 0.01f); - EXPECT_NEAR(Footprint::Get10x8().Bitrate(), 1.60f, 0.01f); - EXPECT_NEAR(Footprint::Get10x10().Bitrate(), 1.28f, 0.01f); - EXPECT_NEAR(Footprint::Get12x10().Bitrate(), 1.07f, 0.01f); - EXPECT_NEAR(Footprint::Get12x12().Bitrate(), 0.89f, 0.01f); -} - -TEST(FootprintTest, StorageRequirements) { - auto footprint = Footprint::Get10x8(); - EXPECT_EQ(footprint.Width(), 10); - EXPECT_EQ(footprint.Height(), 8); - - // If we have 8x8 blocks, then we have 64*16 = 1024 bytes. - EXPECT_EQ(footprint.StorageRequirements(80, 64), 1024); - - // If our block is a little smaller this still counts because we need to - // cover a partial block with a fully encoded one. - EXPECT_EQ(footprint.StorageRequirements(79, 63), 1024); -} - -} // namespace - -} // namespace astc_codec diff --git a/third-party/astc-codec/src/decoder/test/image_utils.h b/third-party/astc-codec/src/decoder/test/image_utils.h deleted file mode 100644 index 1e5000a3..00000000 --- a/third-party/astc-codec/src/decoder/test/image_utils.h +++ /dev/null @@ -1,217 +0,0 @@ -// Copyright 2018 Google LLC -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// https://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -#include <gtest/gtest.h> - -#include <fstream> -#include <vector> - -static constexpr size_t kMaxVectorOutput = 128; - -class ImageBuffer { - public: - static constexpr size_t Align = 4; - - void Allocate(size_t width, size_t height, size_t bytes_per_pixel) { - width_ = width; - height_ = height; - bytes_per_pixel_ = bytes_per_pixel; - stride_ = AlignBytes(width * bytes_per_pixel); - data_.resize(stride_ * height); - } - - uint8_t* operator()(size_t x, size_t y) { - assert(x < width_ && y < height_); - return &data_[y * Stride() + x * bytes_per_pixel_]; - } - - size_t Stride() const { return stride_; } - size_t BytesPerPixel() const { return bytes_per_pixel_; } - - std::vector<uint8_t>& Data() { return data_; } - const std::vector<uint8_t>& Data() const { return data_; } - size_t DataSize() const { return data_.size(); } - - private: - size_t AlignBytes(size_t bytes) const { - return (bytes + (Align - 1)) / Align * Align; - } - - size_t width_ = 0; - size_t height_ = 0; - size_t stride_ = 0; - size_t bytes_per_pixel_ = 0; - std::vector<uint8_t> data_; -}; - -namespace std { -static void PrintTo(const vector<uint8_t>& vec, ostream* os) { - ios::fmtflags origFlags(os->flags()); - - *os << '{'; - size_t count = 0; - for (vector<uint8_t>::const_iterator it = vec.begin(); it != vec.end(); - ++it, ++count) { - if (count > 0) { - *os << ", "; - } - - if (count == kMaxVectorOutput) { - *os << "... "; - break; - } - - if ((count % 16) == 0) { - *os << "\n"; - } - - if (*it == 0) { - *os << " "; - } else { - *os << "0x" << std::hex << std::uppercase << std::setw(2) - << std::setfill('0') << int(*it) << std::dec; - } - } - - *os << '}'; - - os->flags(origFlags); -} -} // namespace std - -static inline std::string LoadFile(const std::string& path) { - std::ifstream is(path, std::ios::binary); - EXPECT_TRUE(is) << "Failed to load file " << path; - if (!is) { - return ""; - } - - std::ostringstream ss; - ss << is.rdbuf(); - return ss.str(); -} - -static inline std::string LoadASTCFile(const std::string& basename) { - const std::string filename = - std::string("src/decoder/testdata/") + basename + ".astc"; - - std::string result = LoadFile(filename); - // Don't parse the header here, we already know what kind of astc encoding it - // is. - if (result.size() < 16) { - return ""; - } else { - return result.substr(16); - } -} - -static inline void LoadGoldenBmp(const std::string& path, ImageBuffer* result) { - constexpr size_t kBmpHeaderSize = 54; - - SCOPED_TRACE(testing::Message() << "LoadGoldenBmp " << path); - - const std::string data = LoadFile(path); - ASSERT_FALSE(data.empty()) << "Failed to open golden image: " << path; - - ASSERT_GE(data.size(), kBmpHeaderSize); - ASSERT_EQ('B', data[0]); - ASSERT_EQ('M', data[1]); - - uint32_t dataPos = *reinterpret_cast<const uint32_t*>(&data[0x0A]); - uint32_t imageSize = *reinterpret_cast<const uint32_t*>(&data[0x22]); - const uint16_t bitsPerPixel = *reinterpret_cast<const uint16_t*>(&data[0x1C]); - int width = *reinterpret_cast<const int*>(&data[0x12]); - int height = *reinterpret_cast<const int*>(&data[0x16]); - - SCOPED_TRACE(testing::Message() - << "dataPos=" << dataPos << ", imageSize=" << imageSize - << ", bitsPerPixel=" << bitsPerPixel << ", width=" << width - << ", height=" << height); - - if (height < 0) { - height = -height; - } - - if (imageSize == 0) { - imageSize = width * height * 3; - } - - if (dataPos < kBmpHeaderSize) { - dataPos = kBmpHeaderSize; - } - - ASSERT_TRUE(bitsPerPixel == 24 || bitsPerPixel == 32) - << "BMP bits per pixel mismatch, expected 24 or 32"; - - result->Allocate(width, height, bitsPerPixel == 24 ? 3 : 4); - ASSERT_LE(imageSize, result->DataSize()); - - std::vector<uint8_t>& resultData = result->Data(); - const size_t stride = result->Stride(); - - // Copy the data row-by-row to make sure that stride is right. - for (size_t row = 0; row < static_cast<size_t>(height); ++row) { - memcpy(&resultData[row * stride], &data[dataPos + row * stride], - width * bitsPerPixel / 8); - } - - if (bitsPerPixel == 32) { - // Swizzle the data from ABGR to ARGB. - for (size_t row = 0; row < static_cast<size_t>(height); ++row) { - uint8_t* rowData = resultData.data() + row * stride; - - for (size_t i = 3; i < stride; i += 4) { - const uint8_t b = rowData[i - 3]; - rowData[i - 3] = rowData[i - 1]; - rowData[i - 1] = b; - } - } - } else { - // Swizzle the data from BGR to RGB. - for (size_t row = 0; row < static_cast<size_t>(height); ++row) { - uint8_t* rowData = resultData.data() + row * stride; - - for (size_t i = 2; i < stride; i += 3) { - const uint8_t tmp = rowData[i - 2]; - rowData[i - 2] = rowData[i]; - rowData[i] = tmp; - } - } - } -} - -static inline void CompareSumOfSquaredDifferences(const ImageBuffer& golden, - const ImageBuffer& image, - double threshold) { - ASSERT_EQ(golden.DataSize(), image.DataSize()); - ASSERT_EQ(golden.Stride(), image.Stride()); - ASSERT_EQ(golden.BytesPerPixel(), image.BytesPerPixel()); - - const std::vector<uint8_t>& image_data = image.Data(); - const std::vector<uint8_t>& golden_data = golden.Data(); - - double sum = 0.0; - for (size_t i = 0; i < image_data.size(); ++i) { - const double diff = static_cast<double>(image_data[i]) - golden_data[i]; - sum += diff * diff; - } - - EXPECT_LE(sum, threshold * image_data.size()) - << "Per pixel " << (sum / image_data.size()) - << ", expected <= " << threshold; - if (sum > threshold * image_data.size()) { - // Fall back to comparison which will dump first chunk of vector. - EXPECT_EQ(golden_data, image_data); - } -} diff --git a/third-party/astc-codec/src/decoder/test/integer_sequence_codec_test.cc b/third-party/astc-codec/src/decoder/test/integer_sequence_codec_test.cc deleted file mode 100644 index 120e8b07..00000000 --- a/third-party/astc-codec/src/decoder/test/integer_sequence_codec_test.cc +++ /dev/null @@ -1,336 +0,0 @@ -// Copyright 2018 Google LLC -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// https://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -#include "src/decoder/integer_sequence_codec.h" -#include "src/base/uint128.h" - -#include <random> -#include <string> -#include <vector> - -#include <gtest/gtest.h> - -using astc_codec::base::UInt128; -using astc_codec::base::BitStream; -using astc_codec::IntegerSequenceCodec; -using astc_codec::IntegerSequenceEncoder; -using astc_codec::IntegerSequenceDecoder; - -namespace { - -// Make sure that the counts returned for a specific range match what's -// expected. In particular, make sure that it fits with Table C.2.7 -TEST(ASTCIntegerSequenceCodecTest, TestGetCountsForRange) { - std::array<int, 3> kExpectedCounts[31] = { - {{ 0, 0, 1 }}, // 1 - {{ 1, 0, 0 }}, // 2 - {{ 0, 0, 2 }}, // 3 - {{ 0, 1, 0 }}, // 4 - {{ 1, 0, 1 }}, // 5 - {{ 0, 0, 3 }}, // 6 - {{ 0, 0, 3 }}, // 7 - {{ 0, 1, 1 }}, // 8 - {{ 0, 1, 1 }}, // 9 - {{ 1, 0, 2 }}, // 10 - {{ 1, 0, 2 }}, // 11 - {{ 0, 0, 4 }}, // 12 - {{ 0, 0, 4 }}, // 13 - {{ 0, 0, 4 }}, // 14 - {{ 0, 0, 4 }}, // 15 - {{ 0, 1, 2 }}, // 16 - {{ 0, 1, 2 }}, // 17 - {{ 0, 1, 2 }}, // 18 - {{ 0, 1, 2 }}, // 19 - {{ 1, 0, 3 }}, // 20 - {{ 1, 0, 3 }}, // 21 - {{ 1, 0, 3 }}, // 22 - {{ 1, 0, 3 }}, // 23 - {{ 0, 0, 5 }}, // 24 - {{ 0, 0, 5 }}, // 25 - {{ 0, 0, 5 }}, // 26 - {{ 0, 0, 5 }}, // 27 - {{ 0, 0, 5 }}, // 28 - {{ 0, 0, 5 }}, // 29 - {{ 0, 0, 5 }}, // 30 - {{ 0, 0, 5 }}, // 31 - }; - - int t, q, b; - for (int i = 1; i < 32; ++i) { - IntegerSequenceCodec::GetCountsForRange(i, &t, &q, &b); - EXPECT_EQ(t, kExpectedCounts[i - 1][0]); - EXPECT_EQ(q, kExpectedCounts[i - 1][1]); - EXPECT_EQ(b, kExpectedCounts[i - 1][2]); - } - - ASSERT_DEATH(IntegerSequenceCodec::GetCountsForRange(0, &t, &q, &b), ""); - ASSERT_DEATH(IntegerSequenceCodec::GetCountsForRange(256, &t, &q, &b), ""); - - IntegerSequenceCodec::GetCountsForRange(1, &t, &q, &b); - EXPECT_EQ(t, 0); - EXPECT_EQ(q, 0); - EXPECT_EQ(b, 1); -} - -// Test to make sure that we're calculating the number of bits needed to -// encode a given number of values based on the range of the values. -TEST(ASTCIntegerSequenceCodecTest, TestNumBitsForCounts) { - int trits = 0; - int quints = 0; - int bits = 0; - - // A range of one should have single bits, so n 1-bit values should be n bits. - trits = 0; - quints = 0; - bits = 1; - for (int i = 0; i < 64; ++i) { - EXPECT_EQ(IntegerSequenceCodec::GetBitCount(i, trits, quints, bits), i); - EXPECT_EQ(IntegerSequenceCodec::GetBitCountForRange(i, 1), i); - } - - // Similarly, N two-bit values should be 2n bits... - trits = 0; - quints = 0; - bits = 2; - for (int i = 0; i < 64; ++i) { - int bit_counts = IntegerSequenceCodec::GetBitCount(i, trits, quints, bits); - EXPECT_EQ(bit_counts, 2 * i); - EXPECT_EQ(IntegerSequenceCodec::GetBitCountForRange(i, 3), 2 * i); - } - - // Trits are a bit more complicated -- there are five trits in a block, so - // if we encode 15 values with 3 bits each in trits, we'd get three blocks, - // each with eight bits of trits. - trits = 1; - quints = 0; - bits = 3; - EXPECT_EQ(IntegerSequenceCodec::GetBitCount(15, trits, quints, bits), - 8 * 3 + 15 * 3); - EXPECT_EQ(IntegerSequenceCodec::GetBitCountForRange(15, 23), - IntegerSequenceCodec::GetBitCount(15, trits, quints, bits)); - - // However, if instead we encode 13 values, we don't need to use the remaining - // two values, so we only need bits as they will be encoded. As it turns out, - // this means we can avoid three bits in the final block (one for the high - // order trit encoding and two for one of the values), resulting in 47 bits. - trits = 1; - quints = 0; - bits = 2; - EXPECT_EQ(IntegerSequenceCodec::GetBitCount(13, trits, quints, bits), 47); - EXPECT_EQ(IntegerSequenceCodec::GetBitCountForRange(13, 11), - IntegerSequenceCodec::GetBitCount(13, trits, quints, bits)); - - // Quints have a similar property -- if we encode six values using a quint and - // four bits, then we have two quint blocks each with three values and a seven - // bit encoded quint triplet... - trits = 0; - quints = 1; - bits = 4; - EXPECT_EQ(IntegerSequenceCodec::GetBitCount(6, trits, quints, bits), - 7 * 2 + 6 * 4); - EXPECT_EQ(IntegerSequenceCodec::GetBitCountForRange(6, 79), - IntegerSequenceCodec::GetBitCount(6, trits, quints, bits)); - - // If we have fewer values than blocks we can again avoid about 2 + nbits - // bits... - trits = 0; - quints = 1; - bits = 3; - EXPECT_EQ(IntegerSequenceCodec::GetBitCount(7, trits, quints, bits), - /* first two quint blocks */ 7 * 2 + - /* first two blocks of bits */ 6 * 3 + - /* last quint block without the high order four bits */ 3 + - /* last block with one set of three bits */ 3); -} - -// Tests that the encoder knows how to encode values of the form 5*2^k. -TEST(ASTCIntegerSequenceCodecTest, TestQuintCodec) { - // In this case, k = 4 - - // Setup bit src/sink - BitStream<UInt128> bit_sink; - - const int kValueRange = 79; - IntegerSequenceEncoder enc(kValueRange); - enc.AddValue(3); - enc.AddValue(79); - enc.AddValue(37); - enc.Encode(&bit_sink); - - // quint: 1000101 m0: 0011 m1: 1111 m2: 0101 - // 100 0100 0111 1101 0010 - // interleaved 10m200m1101m0 - // should be 100 1010 0111 1101 0011 = 0x4A7D3 - EXPECT_EQ(bit_sink.Bits(), 19); - - uint64_t encoded = 0; - bit_sink.GetBits(19, &encoded); - EXPECT_EQ(encoded, 0x4A7D3); - - // Now check that decoding it works as well - BitStream<UInt128> bit_src(encoded, 19); - - IntegerSequenceDecoder dec(kValueRange); - auto decoded_vals = dec.Decode(3, &bit_src); - ASSERT_EQ(decoded_vals.size(), 3); - EXPECT_EQ(decoded_vals[0], 3); - EXPECT_EQ(decoded_vals[1], 79); - EXPECT_EQ(decoded_vals[2], 37); -} - -// Tests that the encoder knows how to encode values of the form 3*2^k. -TEST(ASTCIntegerSequenceCodecTest, TestTritCodec) { - uint64_t encoded = 0; - - // Setup bit src/sink - BitStream<UInt128> bit_sink(encoded, 0); - - const int kValueRange = 11; - IntegerSequenceEncoder enc(kValueRange); - enc.AddValue(7); - enc.AddValue(5); - enc.AddValue(3); - enc.AddValue(6); - enc.AddValue(10); - enc.Encode(&bit_sink); - - EXPECT_EQ(bit_sink.Bits(), 18); - - bit_sink.GetBits(18, &encoded); - EXPECT_EQ(encoded, 0x37357); - - // Now check that decoding it works as well - BitStream<UInt128> bit_src(encoded, 19); - - IntegerSequenceDecoder dec(kValueRange); - auto decoded_vals = dec.Decode(5, &bit_src); - ASSERT_EQ(decoded_vals.size(), 5); - EXPECT_EQ(decoded_vals[0], 7); - EXPECT_EQ(decoded_vals[1], 5); - EXPECT_EQ(decoded_vals[2], 3); - EXPECT_EQ(decoded_vals[3], 6); - EXPECT_EQ(decoded_vals[4], 10); -} - -// Test a specific quint encoding/decoding. This test makes sure that the way we -// encode and decode integer sequences matches what we should expect out of the -// reference ASTC encoder. -TEST(ASTCIntegerSequenceCodecTest, TestDecodeThenEncode) { - std::vector<int> vals = {{ 16, 18, 17, 4, 7, 14, 10, 0 }}; - const uint64_t kValEncoding = 0x2b9c83dc; - - BitStream<UInt128> bit_src(kValEncoding, 64); - IntegerSequenceDecoder dec(19); - auto decoded_vals = dec.Decode(8, &bit_src); - ASSERT_EQ(decoded_vals.size(), vals.size()); - for (size_t i = 0; i < decoded_vals.size(); ++i) { - EXPECT_EQ(decoded_vals[i], vals[i]); - } - - // Setup bit src/sink - BitStream<UInt128> bit_sink; - IntegerSequenceEncoder enc(19); - for (const auto& v : vals) { - enc.AddValue(v); - } - enc.Encode(&bit_sink); - EXPECT_EQ(bit_sink.Bits(), 35); - - uint64_t encoded = 0; - EXPECT_TRUE(bit_sink.GetBits(35, &encoded)); - EXPECT_EQ(encoded, kValEncoding) - << std::hex << encoded << " -- " << kValEncoding; -} - -// Same as the previous test, except it uses a trit encoding rather than a -// quint encoding. -TEST(ASTCIntegerSequenceCodecTest, TestDecodeThenEncodeTrits) { - std::vector<int> vals = {{ 6, 0, 0, 2, 0, 0, 0, 0, 8, 0, 0, 0, 0, 8, 8, 0 }}; - const uint64_t kValEncoding = 0x0004c0100001006ULL; - - BitStream<UInt128> bit_src(kValEncoding, 64); - IntegerSequenceDecoder dec(11); - auto decoded_vals = dec.Decode(vals.size(), &bit_src); - ASSERT_EQ(decoded_vals.size(), vals.size()); - for (size_t i = 0; i < decoded_vals.size(); ++i) { - EXPECT_EQ(decoded_vals[i], vals[i]); - } - - // Setup bit src/sink - BitStream<UInt128> bit_sink; - IntegerSequenceEncoder enc(11); - for (const auto& v : vals) { - enc.AddValue(v); - } - enc.Encode(&bit_sink); - EXPECT_EQ(bit_sink.Bits(), 58); - - uint64_t encoded = 0; - EXPECT_TRUE(bit_sink.GetBits(58, &encoded)); - EXPECT_EQ(encoded, kValEncoding) - << std::hex << encoded << " -- " << kValEncoding; -} - -// Generate a random sequence of integer codings with different ranges to test -// the reciprocability of our codec (encoded sequences should be able to -// decoded) -TEST(ASTCIntegerSequenceCodecTest, TestRandomReciprocation) { - std::mt19937 mt(0xbad7357); - std::uniform_int_distribution<int> rand(0, 255); - - for (int test = 0; test < 1600; ++test) { - // Generate a random number of values and a random range - int num_vals = 4 + rand(mt) % 44; // Up to 48 weights in a grid - int range = 1 + rand(mt) % 63; - - // If this produces a bit pattern larger than our buffer, then ignore - // it... we already know what our bounds are for the integer sequences - int num_bits = IntegerSequenceCodec::GetBitCountForRange(num_vals, range); - if (num_bits >= 64) { - continue; - } - - std::vector<int> generated_vals(num_vals); - for (auto& val : generated_vals) { - val = rand(mt) % (range + 1); - } - - // Encode the values using the - BitStream<UInt128> bit_sink; - - // Add them to the encoder - IntegerSequenceEncoder enc(range); - for (int v : generated_vals) { - enc.AddValue(v); - } - enc.Encode(&bit_sink); - - uint64_t encoded = 0; - bit_sink.GetBits(bit_sink.Bits(), &encoded); - ASSERT_GE(encoded, 0); - EXPECT_LT(encoded, 1ULL << num_bits); - - BitStream<UInt128> bit_src(encoded, 64); - - IntegerSequenceDecoder dec(range); - auto decoded_vals = dec.Decode(num_vals, &bit_src); - - ASSERT_EQ(decoded_vals.size(), generated_vals.size()); - for (size_t i = 0; i < decoded_vals.size(); ++i) { - EXPECT_EQ(decoded_vals[i], generated_vals[i]); - } - } -} - -} // namespace diff --git a/third-party/astc-codec/src/decoder/test/intermediate_astc_block_test.cc b/third-party/astc-codec/src/decoder/test/intermediate_astc_block_test.cc deleted file mode 100644 index 41861cb9..00000000 --- a/third-party/astc-codec/src/decoder/test/intermediate_astc_block_test.cc +++ /dev/null @@ -1,454 +0,0 @@ -// Copyright 2018 Google LLC -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// https://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -#include "src/decoder/intermediate_astc_block.h" -#include "src/decoder/test/image_utils.h" - -#include <gmock/gmock.h> -#include <gtest/gtest.h> - -#include <string> - -namespace astc_codec { - -namespace { - -using ::testing::ElementsAre; -using ::testing::Eq; -using ::testing::HasSubstr; -using ::testing::SizeIs; -using ::testing::TestWithParam; -using ::testing::ValuesIn; - -// Test to make sure that unpacking an error block returns false. -TEST(IntermediateASTCBlockTest, TestUnpackError) { - const PhysicalASTCBlock kErrorBlock(base::UInt128(0)); - EXPECT_FALSE(UnpackVoidExtent(kErrorBlock)); - EXPECT_FALSE(UnpackIntermediateBlock(kErrorBlock)); -} - -// Test to make sure that if we don't populate our weight data in the -// intermediate block than the resulting color range should error due to the -// mismatch. -TEST(IntermediateASTCBlockTest, TestEndpointRangeErrorOnNotSettingWeights) { - IntermediateBlockData data; - data.weight_range = 15; - for (auto& ep : data.endpoints) { - ep.mode = ColorEndpointMode::kLDRRGBDirect; - } - data.weight_grid_dim_x = 6; - data.weight_grid_dim_y = 6; - EXPECT_EQ(-1, EndpointRangeForBlock(data)); - - base::UInt128 dummy; - auto err_str = Pack(data, &dummy); - EXPECT_TRUE(err_str.hasValue()); - EXPECT_THAT(err_str.value(), HasSubstr("Incorrect number of weights")); -} - -// Test to make sure that if we run out of bits, then we should say so. -TEST(IntermediateASTCBlockTest, TestEndpointRangeErrorOnNotEnoughBits) { - IntermediateBlockData data; - data.weight_range = 1; - data.partition_id = 0; - data.endpoints.resize(3); - for (auto& ep : data.endpoints) { - ep.mode = ColorEndpointMode::kLDRRGBDirect; - } - data.weight_grid_dim_x = 8; - data.weight_grid_dim_y = 8; - EXPECT_EQ(-2, EndpointRangeForBlock(data)); - - // Resize the weights to get past the error that they do not match the grid - // dimensions. - data.weights.resize(64); - - base::UInt128 dummy; - auto err_str = Pack(data, &dummy); - EXPECT_TRUE(err_str.hasValue()); - EXPECT_THAT(err_str.value(), HasSubstr("illegal color range")); -} - -// Test to make sure that as we increase the number of weights, we decrease the -// allowable range of colors -TEST(IntermediateASTCBlockTest, TestEndpointRangeForBlock) { - IntermediateBlockData data; - data.weight_range = 2; - data.endpoints.resize(2); - data.dual_plane_channel.clear(); - for (auto& ep : data.endpoints) { - ep.mode = ColorEndpointMode::kLDRRGBDirect; - } - - // Weight params control how many weights are present in a block - struct WeightParams { - int width; - int height; - - // We should sort based on number of weights for these params - int NumWeights() const { return width * height; } - bool operator<(const WeightParams& other) const { - return NumWeights() < other.NumWeights(); - } - }; - - std::vector<WeightParams> weight_params; - for (int y = 2; y < 8; ++y) { - for (int x = 2; x < 8; ++x) { - weight_params.emplace_back(WeightParams{x, y}); - } - } - - // Sort weights from fewest to largest such that the allowable color range - // should be monotonically decreasing - std::sort(weight_params.begin(), weight_params.end()); - - // Keep track of the largest available color range and measure that it - // decreases as we add more weights to our block - int last_color_range = 255; - for (const auto& params : weight_params) { - data.weight_grid_dim_x = params.width; - data.weight_grid_dim_y = params.height; - - const int color_range = EndpointRangeForBlock(data); - EXPECT_LE(color_range, last_color_range); - last_color_range = std::min(color_range, last_color_range); - } - - // Make sure that we actually changed it at some point. - EXPECT_LT(last_color_range, 255); -} - -// Test to make sure that unpacking an legitimate ASTC block returns the encoded -// values that we expect. -TEST(IntermediateASTCBlockTest, TestUnpackNonVoidExtentBlock) { - PhysicalASTCBlock blk(0x0000000001FE000173ULL); - auto b = UnpackIntermediateBlock(blk); - ASSERT_TRUE(b); - - const auto& data = b.value(); - EXPECT_EQ(data.weight_grid_dim_x, 6); - EXPECT_EQ(data.weight_grid_dim_y, 5); - EXPECT_EQ(data.weight_range, 7); - - EXPECT_FALSE(data.partition_id); - EXPECT_FALSE(data.dual_plane_channel); - - ASSERT_EQ(data.weights.size(), 30); - for (auto weight : data.weights) { - EXPECT_EQ(weight, 0); - } - - ASSERT_EQ(data.endpoints.size(), 1); - for (const auto& ep_data : data.endpoints) { - EXPECT_EQ(ep_data.mode, ColorEndpointMode::kLDRLumaDirect); - ASSERT_EQ(ep_data.colors.size(), 2); - EXPECT_EQ(ep_data.colors[0], 0); - EXPECT_EQ(ep_data.colors[1], 255); - } -} - -// Make sure that we can pack blocks that aren't void extent blocks. (In other -// words, can we actually deal with intermediate ASTC data). -TEST(IntermediateASTCBlockTest, TestPackNonVoidExtentBlock) { - IntermediateBlockData data; - - data.weight_grid_dim_x = 6; - data.weight_grid_dim_y = 5; - data.weight_range = 7; - - data.partition_id = {}; - data.dual_plane_channel = {}; - - data.weights.resize(30); - for (auto& weight : data.weights) { - weight = 0; - } - - data.endpoints.resize(1); - for (auto& ep_data : data.endpoints) { - ep_data.mode = ColorEndpointMode::kLDRLumaDirect; - ep_data.colors.resize(2); - ep_data.colors[0] = 0; - ep_data.colors[1] = 255; - } - - base::UInt128 packed; - auto error_str = Pack(data, &packed); - ASSERT_FALSE(error_str) << (error_str ? error_str.value() : std::string("")); - EXPECT_EQ(packed, 0x0000000001FE000173ULL); -} - -// Make sure that we can unpack void extent blocks -TEST(IntermediateASTCBlockTest, TestUnpackVoidExtentBlock) { - PhysicalASTCBlock void_extent_block(0xFFFFFFFFFFFFFDFCULL); - - auto b = UnpackVoidExtent(void_extent_block); - ASSERT_TRUE(b); - - const auto& data = b.value(); - EXPECT_EQ(data.r, 0); - EXPECT_EQ(data.g, 0); - EXPECT_EQ(data.b, 0); - EXPECT_EQ(data.a, 0); - for (const auto& coord : data.coords) { - EXPECT_EQ(coord, (1 << 13) - 1); - } - - base::UInt128 more_interesting(0xdeadbeefdeadbeefULL, 0xFFF8003FFE000DFCULL); - b = UnpackVoidExtent(PhysicalASTCBlock(more_interesting)); - ASSERT_TRUE(b); - - const auto& other_data = b.value(); - EXPECT_EQ(other_data.r, 0xbeef); - EXPECT_EQ(other_data.g, 0xdead); - EXPECT_EQ(other_data.b, 0xbeef); - EXPECT_EQ(other_data.a, 0xdead); - EXPECT_EQ(other_data.coords[0], 0); - EXPECT_EQ(other_data.coords[1], 8191); - EXPECT_EQ(other_data.coords[2], 0); - EXPECT_EQ(other_data.coords[3], 8191); -} - -// Make sure that we can pack void extent blocks and void extent data. -TEST(IntermediateASTCBlockTest, TestPackVoidExtentBlock) { - VoidExtentData data; - data.r = 0; - data.g = 0; - data.b = 0; - data.a = 0; - for (auto& coord : data.coords) { - coord = (1 << 13) - 1; - } - - base::UInt128 packed; - auto error_str = Pack(data, &packed); - ASSERT_FALSE(error_str) << (error_str ? error_str.value() : std::string("")); - EXPECT_EQ(packed, 0xFFFFFFFFFFFFFDFCULL); - - data.r = 0xbeef; - data.g = 0xdead; - data.b = 0xbeef; - data.a = 0xdead; - data.coords[0] = 0; - data.coords[1] = 8191; - data.coords[2] = 0; - data.coords[3] = 8191; - - error_str = Pack(data, &packed); - ASSERT_FALSE(error_str) << (error_str ? error_str.value() : std::string("")); - EXPECT_EQ(packed, - base::UInt128(0xdeadbeefdeadbeefULL, 0xFFF8003FFE000DFCULL)); -} - -// Make sure that the color endpoint mode is properly repacked. This test case -// was created as a bug during testing. -TEST(IntermediateASTCBlockTest, TestPackUnpackWithSameCEM) { - base::UInt128 orig(0xe8e8eaea20000980ULL, 0x20000200cb73f045ULL); - - auto b = UnpackIntermediateBlock(PhysicalASTCBlock(orig)); - ASSERT_TRUE(b); - - base::UInt128 repacked; - auto err_str = Pack(b.value(), &repacked); - ASSERT_FALSE(err_str) << (err_str ? err_str.value() : std::string("")); - - EXPECT_EQ(repacked, orig); - - // Test case #2 - orig = base::UInt128(0x3300c30700cb01c5ULL, 0x0573907b8c0f6879ULL); - b = UnpackIntermediateBlock(PhysicalASTCBlock(orig)); - ASSERT_TRUE(b); - - err_str = Pack(b.value(), &repacked); - ASSERT_FALSE(err_str) << (err_str ? err_str.value() : std::string("")); - EXPECT_EQ(repacked, orig); -} - -// Test that we can encode/decode a block that uses a very large gap -// between weight and endpoint data. -TEST(IntermediateASTCBlockTest, TestPackingWithLargeGap) { - // We can construct this block by doing the following: - // -- choose a block mode that only gives 24 weight bits - // -- choose the smallest endpoint mode: grayscale direct - // -- make sure there are no partitions - const base::UInt128 orig(0xBEDEAD0000000000ULL, 0x0000000001FE032EULL); - const auto b = UnpackIntermediateBlock(PhysicalASTCBlock(orig)); - ASSERT_TRUE(b); - - const auto& data = b.value(); - EXPECT_EQ(data.weight_grid_dim_x, 2); - EXPECT_EQ(data.weight_grid_dim_y, 3); - EXPECT_EQ(data.weight_range, 15); - - EXPECT_FALSE(data.partition_id); - EXPECT_FALSE(data.dual_plane_channel); - - ASSERT_EQ(data.endpoints.size(), 1); - EXPECT_EQ(data.endpoints.at(0).mode, ColorEndpointMode::kLDRLumaDirect); - - ASSERT_EQ(data.endpoints.at(0).colors.size(), 2); - EXPECT_EQ(data.endpoints.at(0).colors.at(0), 255); - EXPECT_EQ(data.endpoints.at(0).colors.at(1), 0); - - // Now encode it again - base::UInt128 repacked; - const auto err_str = Pack(b.value(), &repacked); - EXPECT_EQ(orig, repacked) << (err_str ? err_str.value() : std::string("")); -} - -// Take a block that is encoded using direct luma with full byte values and see -// if we properly set the endpoint range. -TEST(IntermediateASTCBlockTest, TestEndpointRange) { - PhysicalASTCBlock blk(0x0000000001FE000173ULL); - EXPECT_TRUE(blk.ColorValuesRange().hasValue()); - EXPECT_EQ(blk.ColorValuesRange().valueOr(0), 255); - - auto b = UnpackIntermediateBlock(blk); - ASSERT_TRUE(b); - - const auto& data = b.value(); - ASSERT_THAT(data.endpoints, SizeIs(1)); - EXPECT_THAT(data.endpoints[0].mode, Eq(ColorEndpointMode::kLDRLumaDirect)); - EXPECT_THAT(data.endpoints[0].colors, ElementsAre(0, 255)); - EXPECT_TRUE(data.endpoint_range.hasValue()); - EXPECT_EQ(data.endpoint_range.valueOr(0), 255); -} - -struct ImageTestParams { - std::string image_name; - int checkered_dim; -}; - -static void PrintTo(const ImageTestParams& params, std::ostream* os) { - *os << "ImageTestParams(" << params.image_name << ")"; -} - -class IntermediateASTCBlockTest : public TestWithParam<ImageTestParams> { }; - -// Test whether or not a real-world ASTC implementation can be unpacked and -// then repacked into the same implementation. In conjunction with the other -// tests, we make sure that we can recreate ASTC blocks that we have previously -// unpacked. -TEST_P(IntermediateASTCBlockTest, TestPackUnpack) { - const auto& params = GetParam(); - const int astc_dim = 8; - const int img_dim = params.checkered_dim * astc_dim; - const std::string astc = LoadASTCFile(params.image_name); - - // Make sure that unpacking and repacking all of the blocks works... - const int kNumASTCBlocks = (img_dim / astc_dim) * (img_dim / astc_dim); - for (int i = 0; i < kNumASTCBlocks; ++i) { - base::UInt128 block_bits; - memcpy(&block_bits, astc.data() + PhysicalASTCBlock::kSizeInBytes * i, - PhysicalASTCBlock::kSizeInBytes); - - const PhysicalASTCBlock block(block_bits); - - base::UInt128 repacked; - if (block.IsVoidExtent()) { - auto b = UnpackVoidExtent(block); - ASSERT_TRUE(b); - - auto err_str = Pack(b.value(), &repacked); - ASSERT_FALSE(err_str) << (err_str ? err_str.value() : std::string("")); - } else { - auto b = UnpackIntermediateBlock(block); - ASSERT_TRUE(b); - - // Check to see that we properly set the endpoint range when we decoded - // the block. - auto& block_data = b.value(); - EXPECT_EQ(block_data.endpoint_range, block.ColorValuesRange()); - - // Reset the endpoint range here to see if we correctly reconstruct it - // below - block_data.endpoint_range = {}; - - auto err_str = Pack(b.value(), &repacked); - ASSERT_FALSE(err_str) << (err_str ? err_str.value() : std::string("")); - } - - // You would expect the following line to be enough: - // EXPECT_EQ(repacked, block.GetBlockBits()) - // ... except that the ASTC encoder makes some interesting decisions - // about how to encode the same logical bits. One example is that - // sometimes if all partitions share an endpoint mode, the encoded - // block will not use the shared CEM mode, and rather list each - // partition's mode explicitly. For that reason, we just need to make as - // close of an approximation as possible that we decode to the same - // physical values. - - PhysicalASTCBlock pb(repacked); - ASSERT_FALSE(pb.IsIllegalEncoding()); - - base::UInt128 pb_color_mask = - (base::UInt128(1) << pb.NumColorBits().value()) - 1; - base::UInt128 pb_color_bits = - pb.GetBlockBits() >> pb.ColorStartBit().value(); - pb_color_bits &= pb_color_mask; - - base::UInt128 b_color_mask = - (base::UInt128(1) << pb.NumColorBits().value()) - 1; - base::UInt128 b_color_bits = - block.GetBlockBits() >> block.ColorStartBit().value(); - b_color_bits &= b_color_mask; - - EXPECT_EQ(pb_color_mask, b_color_mask); - EXPECT_EQ(pb_color_bits, b_color_bits); - - EXPECT_EQ(pb.IsVoidExtent(), block.IsVoidExtent()); - EXPECT_EQ(pb.VoidExtentCoords(), block.VoidExtentCoords()); - - EXPECT_EQ(pb.WeightGridDims(), block.WeightGridDims()); - EXPECT_EQ(pb.WeightRange(), block.WeightRange()); - EXPECT_EQ(pb.NumWeightBits(), block.NumWeightBits()); - EXPECT_EQ(pb.WeightStartBit(), block.WeightStartBit()); - - EXPECT_EQ(pb.IsDualPlane(), block.IsDualPlane()); - EXPECT_EQ(pb.DualPlaneChannel(), block.DualPlaneChannel()); - - EXPECT_EQ(pb.NumPartitions(), block.NumPartitions()); - EXPECT_EQ(pb.PartitionID(), block.PartitionID()); - - EXPECT_EQ(pb.NumColorValues(), block.NumColorValues()); - EXPECT_EQ(pb.ColorValuesRange(), block.ColorValuesRange()); - - for (int j = 0; j < pb.NumPartitions().valueOr(0); ++j) { - EXPECT_EQ(pb.GetEndpointMode(j), block.GetEndpointMode(j)); - } - } -} - -std::vector<ImageTestParams> GetImageTestParams() { - return { - // image_name checkered_dim - { "checkered_4", 4 }, - { "checkered_5", 5 }, - { "checkered_6", 6 }, - { "checkered_7", 7 }, - { "checkered_8", 8 }, - { "checkered_9", 9 }, - { "checkered_10", 10 }, - { "checkered_11", 11 }, - { "checkered_12", 12 }, - }; -} - -INSTANTIATE_TEST_CASE_P(Checkered, IntermediateASTCBlockTest, - ValuesIn(GetImageTestParams())); - -} // namespace - -} // namespace astc_codec diff --git a/third-party/astc-codec/src/decoder/test/logical_astc_block_test.cc b/third-party/astc-codec/src/decoder/test/logical_astc_block_test.cc deleted file mode 100644 index ed85f3fd..00000000 --- a/third-party/astc-codec/src/decoder/test/logical_astc_block_test.cc +++ /dev/null @@ -1,273 +0,0 @@ -// Copyright 2018 Google LLC -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// https://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -#include "src/decoder/logical_astc_block.h" -#include "src/decoder/test/image_utils.h" - -#include <gtest/gtest.h> -#include <gmock/gmock.h> - -#include <fstream> -#include <string> - -namespace astc_codec { - -namespace { - -using ::testing::Eq; -using ::testing::ElementsAre; -using ::testing::TestWithParam; -using ::testing::ValuesIn; - -ImageBuffer LoadGoldenImageWithAlpha(std::string basename) { - const std::string filename = std::string("src/decoder/testdata/") + basename + ".bmp"; - ImageBuffer result; - LoadGoldenBmp(filename, &result); - EXPECT_EQ(result.BytesPerPixel(), 4); - return result; -} - -ImageBuffer LoadGoldenImage(std::string basename) { - const std::string filename = std::string("src/decoder/testdata/") + basename + ".bmp"; - ImageBuffer result; - LoadGoldenBmp(filename, &result); - EXPECT_EQ(result.BytesPerPixel(), 3); - return result; -} - -struct ImageTestParams { - std::string image_name; - bool has_alpha; - Footprint footprint; - int width; - int height; -}; - -static void PrintTo(const ImageTestParams& params, std::ostream* os) { - *os << "ImageTestParams(" << params.image_name << ", " - << params.width << "x" << params.height << ", " - << (params.has_alpha ? "RGBA" : "RGB") << ", " - << "footprint " << params.footprint.Width() << "x" - << params.footprint.Height() << ")"; -} - -class LogicalASTCBlockTest : public TestWithParam<ImageTestParams> { }; - -// Test to make sure that reading out color values from blocks is not -// terribly wrong. To do so, we compress an image and then decompress it -// using our logical blocks and the library. The difference between the -// decoded images should be minimal. -TEST_P(LogicalASTCBlockTest, ImageWithFootprint) { - const auto& params = GetParam(); - const std::string astc = LoadASTCFile(params.image_name); - - ImageBuffer our_decoded_image; - our_decoded_image.Allocate(params.width, params.height, params.has_alpha ? 4 : 3); - - const int block_width = params.footprint.Width(); - const int block_height = params.footprint.Height(); - - base::UInt128 block; - for (int i = 0; i < astc.size(); i += 16) { - const int block_index = i / 16; - const int blocks_wide = - (params.width + block_width - 1) / block_width; - const int block_x = block_index % blocks_wide; - const int block_y = block_index / blocks_wide; - memcpy(&block, astc.data() + i, sizeof(block)); - - PhysicalASTCBlock physical_block(block); - if (physical_block.IsVoidExtent()) { - auto ve = UnpackVoidExtent(physical_block); - ASSERT_TRUE(ve) << "ASTC encoder produced invalid block!"; - } else { - auto ib = UnpackIntermediateBlock(physical_block); - ASSERT_TRUE(ib) << "ASTC encoder produced invalid block!"; - } - - // Make sure that the library doesn't produce incorrect ASTC blocks. - // This is covered in more depth in other tests in - // intermediate_astc_block_test and physical_astc_block_test - auto lb = UnpackLogicalBlock(params.footprint, physical_block); - ASSERT_TRUE(lb) << "ASTC encoder produced invalid block!"; - - LogicalASTCBlock logical_block = lb.value(); - const size_t color_size = params.has_alpha ? 4 : 3; - - for (int y = 0; y < block_height; ++y) { - for (int x = 0; x < block_width; ++x) { - const int px = block_width * block_x + x; - const int py = block_height * block_y + y; - - // Skip out of bounds. - if (px >= params.width || py >= params.height) { - continue; - } - - uint8_t* pixel = our_decoded_image(px, py); - const RgbaColor decoded_color = logical_block.ColorAt(x, y); - ASSERT_LE(color_size, decoded_color.size()); - - for (int c = 0; c < color_size; ++c) { - // All of the pixels should also be 8-bit values. - ASSERT_GE(decoded_color[c], 0); - ASSERT_LT(decoded_color[c], 256); - pixel[c] = decoded_color[c]; - } - } - } - } - - // Check that the decoded image is *very* similar to the library decoding - // of an ASTC texture. They may not be exact due to differences in how we - // convert a 16-bit float to an 8-bit integer. - ImageBuffer decoded_image = params.has_alpha ? LoadGoldenImageWithAlpha(params.image_name) : LoadGoldenImage(params.image_name); - CompareSumOfSquaredDifferences(decoded_image, our_decoded_image, 1.0); -} - -// Test to make sure that a simple gradient image can be compressed and decoded -// by our logical block representation. This should work with every footprint. -std::vector<ImageTestParams> GetSyntheticImageTestParams() { - return { - // image_name alpha astc footprint width height - { "footprint_4x4", false, Footprint::Get4x4(), 32, 32 }, - { "footprint_5x4", false, Footprint::Get5x4(), 32, 32 }, - { "footprint_5x5", false, Footprint::Get5x5(), 32, 32 }, - { "footprint_6x5", false, Footprint::Get6x5(), 32, 32 }, - { "footprint_6x6", false, Footprint::Get6x6(), 32, 32 }, - { "footprint_8x5", false, Footprint::Get8x5(), 32, 32 }, - { "footprint_8x6", false, Footprint::Get8x6(), 32, 32 }, - { "footprint_10x5", false, Footprint::Get10x5(), 32, 32 }, - { "footprint_10x6", false, Footprint::Get10x6(), 32, 32 }, - { "footprint_8x8", false, Footprint::Get8x8(), 32, 32 }, - { "footprint_10x8", false, Footprint::Get10x8(), 32, 32 }, - { "footprint_10x10", false, Footprint::Get10x10(), 32, 32 }, - { "footprint_12x10", false, Footprint::Get12x10(), 32, 32 }, - { "footprint_12x12", false, Footprint::Get12x12(), 32, 32 }, - }; -} - -INSTANTIATE_TEST_CASE_P(Synthetic, LogicalASTCBlockTest, - ValuesIn(GetSyntheticImageTestParams())); - -// Test to make sure that reading out color values from blocks in a real-world -// image isn't terribly wrong, either. -std::vector<ImageTestParams> GetRealWorldImageTestParams() { - return { - // image_name alpha astc footprint width height - { "rgb_4x4", false, Footprint::Get4x4(), 224, 288 }, - { "rgb_6x6", false, Footprint::Get6x6(), 224, 288 }, - { "rgb_8x8", false, Footprint::Get8x8(), 224, 288 }, - { "rgb_12x12", false, Footprint::Get12x12(), 224, 288 }, - { "rgb_5x4", false, Footprint::Get5x4(), 224, 288 } - }; -} - -INSTANTIATE_TEST_CASE_P(RealWorld, LogicalASTCBlockTest, - ValuesIn(GetRealWorldImageTestParams())); - -// Test to make sure that reading out color values from blocks in a real-world -// image isn't terribly wrong, either. -std::vector<ImageTestParams> GetTransparentImageTestParams() { - return { - // image_name alpha astc footprint width height - { "atlas_small_4x4", true, Footprint::Get4x4(), 256, 256 }, - { "atlas_small_5x5", true, Footprint::Get5x5(), 256, 256 }, - { "atlas_small_6x6", true, Footprint::Get6x6(), 256, 256 }, - { "atlas_small_8x8", true, Footprint::Get8x8(), 256, 256 }, - }; -} - -INSTANTIATE_TEST_CASE_P(Transparent, LogicalASTCBlockTest, - ValuesIn(GetTransparentImageTestParams())); - -// Test to make sure that if we set our endpoints then it's reflected in our -// color selection -TEST(LogicalASTCBlockTest, SetEndpoints) { - LogicalASTCBlock logical_block(Footprint::Get8x8()); - - // Setup a weight checkerboard - for (int j = 0; j < 8; ++j) { - for (int i = 0; i < 8; ++i) { - if (((i ^ j) & 1) == 1) { - logical_block.SetWeightAt(i, j, 0); - } else { - logical_block.SetWeightAt(i, j, 64); - } - } - } - - // Now set the colors to something ridiculous - logical_block.SetEndpoints({{ 123, 45, 67, 89 }}, {{ 101, 121, 31, 41 }}, 0); - - // For each pixel, we expect it to mirror the endpoints in a checkerboard - // pattern - for (int j = 0; j < 8; ++j) { - for (int i = 0; i < 8; ++i) { - if (((i ^ j) & 1) == 1) { - EXPECT_THAT(logical_block.ColorAt(i, j), ElementsAre(123, 45, 67, 89)); - } else { - EXPECT_THAT(logical_block.ColorAt(i, j), ElementsAre(101, 121, 31, 41)); - } - } - } -} - -// Test whether or not setting weight values under different circumstances is -// supported and reflected in the query functions. -TEST(LogicalASTCBlockTest, SetWeightVals) { - LogicalASTCBlock logical_block(Footprint::Get4x4()); - - EXPECT_THAT(logical_block.GetFootprint(), Eq(Footprint::Get4x4())); - - // Not a dual plane by default - EXPECT_FALSE(logical_block.IsDualPlane()); - logical_block.SetWeightAt(2, 3, 2); - - // Set the dual plane - logical_block.SetDualPlaneChannel(0); - EXPECT_TRUE(logical_block.IsDualPlane()); - - // This shouldn't have reset our weight - const LogicalASTCBlock other_block = logical_block; - EXPECT_THAT(other_block.WeightAt(2, 3), Eq(2)); - EXPECT_THAT(other_block.DualPlaneWeightAt(0, 2, 3), Eq(2)); - - // If we set the dual plane weight, it shouldn't change the original weight - // value or the other channels - logical_block.SetDualPlaneWeightAt(0, 2, 3, 1); - EXPECT_THAT(logical_block.WeightAt(2, 3), Eq(2)); - EXPECT_THAT(logical_block.DualPlaneWeightAt(0, 2, 3), Eq(1)); - for (int i = 1; i < 4; ++i) { - EXPECT_THAT(logical_block.DualPlaneWeightAt(i, 2, 3), Eq(2)); - } - - // Remove the dual plane - logical_block.SetDualPlaneChannel(-1); - EXPECT_FALSE(logical_block.IsDualPlane()); - - // Now the original dual plane weight should be reset back to the others. Note - // that we have to call DualPlaneWeightAt from a const logical block since - // returning a reference to a weight that doesn't exist is illegal. - const LogicalASTCBlock other_block2 = logical_block; - EXPECT_THAT(logical_block.WeightAt(2, 3), Eq(2)); - for (int i = 0; i < 4; ++i) { - EXPECT_EQ(logical_block.WeightAt(2, 3), - other_block2.DualPlaneWeightAt(i, 2, 3)); - } -} - -} // namespace - -} // namespace astc_codec diff --git a/third-party/astc-codec/src/decoder/test/partition_test.cc b/third-party/astc-codec/src/decoder/test/partition_test.cc deleted file mode 100644 index 63adfb50..00000000 --- a/third-party/astc-codec/src/decoder/test/partition_test.cc +++ /dev/null @@ -1,263 +0,0 @@ -// Copyright 2018 Google LLC -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// https://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -#include "src/decoder/partition.h" - -#include <gmock/gmock.h> -#include <gtest/gtest.h> - -#include <array> -#include <random> -#include <string> -#include <vector> - -namespace { - -using ::testing::ElementsAreArray; -using ::testing::Eq; -using ::testing::Le; -using ::testing::Not; - -using astc_codec::Footprint; -using astc_codec::Partition; -using astc_codec::PartitionMetric; -using astc_codec::GetASTCPartition; -using astc_codec::FindClosestASTCPartition; - -// Test to make sure that a simple difference between two partitions where -// most of the values are the same returns what we expect. -TEST(PartitionTest, TestSimplePartitionMetric) { - Partition a = {Footprint::Get6x6(), /* num_parts = */ 2, - /* partition_id = */ {}, /* assignment = */ {}}; - Partition b = a; - - a.assignment = { - 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 1, - }; - - b.assignment = { - 1, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, - }; - - const int dist = PartitionMetric(a, b); - EXPECT_EQ(dist, 2); -} - -// Test to make sure that if one partition is a subset of another that we still -// return the proper difference against the subset of the larger one. -TEST(PartitionDeathTest, TestPartitionMetric) { - Partition a = {Footprint::Get4x4(), /* num_parts = */ 2, - /* partition_id = */ {}, /* assignment = */ {}}; - Partition b = {Footprint::Get6x6(), /* num_parts = */ 2, - /* partition_id = */ {}, /* assignment = */ {}}; - - a.assignment = {{ - 1, 1, 1, 1, - 0, 0, 0, 0, - 0, 0, 0, 0, - 0, 0, 0, 1, - }}; - - b.assignment = {{ - 1, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 1, - 0, 0, 0, 0, 0, 0, - 0, 1, 0, 0, 1, 0, - 0, 0, 1, 1, 0, 0, - }}; - - EXPECT_DEATH(PartitionMetric(a, b), ""); -} - -// Test to make sure that even if we have different numbers of subsets for each -// partition, that the returned value is what we'd expect. -TEST(PartitionTest, TestDiffPartsPartitionMetric) { - Partition a = {Footprint::Get4x4(), /* num_parts = */ 2, - /* partition_id = */ {}, /* assignment = */ {}}; - Partition b = {Footprint::Get4x4(), /* num_parts = */ 3, - /* partition_id = */ {}, /* assignment = */ {}}; - - a.assignment = {{ - 2, 2, 2, 0, - 0, 0, 0, 0, - 0, 0, 0, 0, - 0, 0, 0, 1, - }}; - - b.assignment = {{ - 1, 0, 0, 0, - 0, 0, 0, 0, - 0, 0, 0, 0, - 0, 0, 0, 0 - }}; - - const int dist = PartitionMetric(a, b); - EXPECT_EQ(dist, 3); -} - -// An additional sanity check test that makes sure that we're not always mapping -// zero to zero in our tests. -TEST(PartitionTest, TestDiffMappingPartitionMetric) { - Partition a = {Footprint::Get4x4(), /* num_parts = */ 2, - /* partition_id = */ {}, /* assignment = */ {}}; - Partition b = {Footprint::Get4x4(), /* num_parts = */ 3, - /* partition_id = */ {}, /* assignment = */ {}}; - - a.assignment = {{ - 0, 1, 2, 2, - 2, 2, 2, 2, - 2, 2, 2, 2, - 2, 2, 2, 2, - }}; - - b.assignment = {{ - 1, 0, 0, 0, - 0, 0, 0, 0, - 0, 0, 0, 0, - 0, 0, 0, 0, - }}; - - const int dist = PartitionMetric(a, b); - EXPECT_EQ(dist, 1); -} - -// Finally, if we grab an ASTC partition and modify it a tad, the closest -// partition should still be the same ASTC partition. -TEST(PartitionTest, TestFindingASTCPartition) { - const Partition astc = GetASTCPartition(Footprint::Get12x12(), 3, 0x3CB); - Partition almost_astc = astc; - almost_astc.assignment[0]++; - - const Partition& closest_astc = FindClosestASTCPartition(almost_astc); - EXPECT_EQ(astc, closest_astc); -} - -// Test a partition that was obtained from the reference ASTC encoder. We should -// be able to match it exactly -TEST(PartitionTest, TestSpecificPartition) { - const Partition astc = GetASTCPartition(Footprint::Get10x6(), 3, 557); - EXPECT_THAT(astc.assignment, ElementsAreArray(std::array<int, 60> {{ - 0, 0, 0, 0, 1, 1, 1, 2, 2, 2, - 0, 0, 0, 0, 1, 1, 1, 2, 2, 2, - 0, 0, 0, 0, 1, 1, 1, 2, 2, 2, - 0, 0, 0, 0, 1, 1, 1, 2, 2, 2, - 0, 0, 0, 0, 1, 1, 1, 2, 2, 2, - 0, 0, 0, 0, 1, 1, 1, 2, 2, 2 }})); -} - -// Make sure that when we match against this specific partition, it'll return a -// partition with the same number of subsets -TEST(PartitionTest, EstimatedPartitionSubsets) { - Partition partition = { - /* footprint = */ Footprint::Get6x6(), - /* num_parts = */ 2, - /* partition_id = */ {}, - /* assignment = */ { - 0, 0, 1, 1, 1, 0, - 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, - 0, 1, 1, 1, 1, 1, - 0, 0, 0, 0, 0, 0, - 1, 1, 1, 1, 1, 1 - }}; - - const Partition astc = FindClosestASTCPartition(partition); - EXPECT_THAT(astc.num_parts, Eq(partition.num_parts)); -} - -// Make sure that regardless of what partition we match against, it'll return a -// partition with at most a fewer number of subsets -TEST(PartitionTest, EstimatedPartitionFewerSubsets) { - std::mt19937 random(0xdeadbeef); - auto randUniform = [&random](int max) { - std::uniform_int_distribution<> dist(0, max - 1); - return dist(random); - }; - - constexpr int kNumFootprints = Footprint::NumValidFootprints(); - const auto kFootprints = std::array<Footprint, kNumFootprints> {{ - Footprint::Get4x4(), - Footprint::Get5x4(), - Footprint::Get5x5(), - Footprint::Get6x5(), - Footprint::Get6x6(), - Footprint::Get8x5(), - Footprint::Get8x6(), - Footprint::Get8x8(), - Footprint::Get10x5(), - Footprint::Get10x6(), - Footprint::Get10x8(), - Footprint::Get10x10(), - Footprint::Get12x10(), - Footprint::Get12x12() - }}; - - constexpr int kNumTests = 200; - for (int i = 0; i < kNumTests; ++i) { - const auto& footprint = kFootprints[randUniform(kNumFootprints)]; - const int num_parts = 2 + randUniform(3); - Partition partition = { - footprint, - num_parts, - /* partition_id = */ {}, - /* assignment = */ std::vector<int>(footprint.NumPixels(), 0)}; - - for (auto& p : partition.assignment) { - p = randUniform(num_parts); - } - - const Partition astc = FindClosestASTCPartition(partition); - EXPECT_THAT(astc.num_parts, Le(partition.num_parts)) - << "Test #" << i << ": " - << "Selected partition with ID " << astc.partition_id.value(); - } -} - -// Make sure that we generate unique partitions that are close to the -// candidates. -TEST(PartitionTest, UniquePartitionResults) { - Partition partition = { - /* footprint = */ Footprint::Get6x6(), - /* num_parts = */ 2, - /* partition_id = */ {}, - /* assignment = */ { - 0, 1, 1, 1, 1, 1, - 0, 1, 1, 1, 1, 1, - 0, 1, 1, 1, 1, 1, - 0, 1, 1, 1, 1, 1, - 0, 1, 1, 1, 1, 1, - 0, 1, 1, 1, 1, 1 - }}; - - const auto parts = FindKClosestASTCPartitions(partition, 2); - EXPECT_THAT(*parts[0], Not(Eq(*parts[1]))); -} - -// TODO(google): Verify somehow that the assignment generated from -// GetASTCPartition actually matches what's in the spec. The selection -// function was more or less copy/pasted though so it's unclear how to -// measure that against e.g. the ASTC encoder. - -} // namespace diff --git a/third-party/astc-codec/src/decoder/test/physical_astc_block_test.cc b/third-party/astc-codec/src/decoder/test/physical_astc_block_test.cc deleted file mode 100644 index 8eafe461..00000000 --- a/third-party/astc-codec/src/decoder/test/physical_astc_block_test.cc +++ /dev/null @@ -1,361 +0,0 @@ -// Copyright 2018 Google LLC -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// https://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -#include "src/decoder/physical_astc_block.h" -#include "src/base/uint128.h" - -#include <gtest/gtest.h> - -#include <string> -#include <vector> - -using astc_codec::PhysicalASTCBlock; -using astc_codec::ColorEndpointMode; -using astc_codec::base::UInt128; - -namespace { - -static const PhysicalASTCBlock kErrorBlock(UInt128(0)); - -// Test to make sure that each of the constructors work and that -// they produce the same block encodings, since the ASTC blocks -// are little-endian -TEST(PhysicalASTCBlockTest, TestConstructors) { - // Little-endian reading of bytes - PhysicalASTCBlock blk1(0x0000000001FE000173ULL); - PhysicalASTCBlock blk2( - std::string("\x73\x01\x00\xFE\x01\x00\x00\x00\x00" - "\x00\x00\x00\x00\x00\x00\x00\x00\x00", 16)); - EXPECT_EQ(blk1.GetBlockBits(), blk2.GetBlockBits()); -} - -// Test to see if we properly decode the maximum value that a weight -// can take in an ASTC block based on the block mode encoding. We test -// against a valid case and various error cases -TEST(PhysicalASTCBlockTest, TestWeightRange) { - PhysicalASTCBlock blk1(0x0000000001FE000173ULL); - auto weight_range = blk1.WeightRange(); - ASSERT_TRUE(weight_range); - EXPECT_EQ(weight_range.value(), 7); - - // If we flip the high bit then we should have a range of 31, - // although then we have too many bits and this should error. - PhysicalASTCBlock blk2(0x0000000001FE000373ULL); - EXPECT_FALSE(blk2.WeightRange()); - - // One bit per weight -- range of 1 - PhysicalASTCBlock non_shared_cem(0x4000000000800D44ULL); - weight_range = non_shared_cem.WeightRange(); - ASSERT_TRUE(weight_range); - EXPECT_EQ(weight_range.value(), 1); - - // Error blocks have no weight range - EXPECT_FALSE(kErrorBlock.WeightRange()); -} - -// Test to see if we properly decode the weight grid width and height -// in an ASTC block based on the block mode encoding. We test against -// a valid case and various error cases -TEST(PhysicalASTCBlockTest, TestWeightDims) { - PhysicalASTCBlock blk1(0x0000000001FE000173ULL); - auto weight_dims = blk1.WeightGridDims(); - EXPECT_TRUE(weight_dims); - EXPECT_EQ(weight_dims.value()[0], 6); - EXPECT_EQ(weight_dims.value()[1], 5); - - // If we flip the high bit then we should have a range of 31, - // although then we have too many bits for the weight grid - // and this should error. - PhysicalASTCBlock blk2(0x0000000001FE000373ULL); - EXPECT_FALSE(blk2.WeightGridDims()); - EXPECT_EQ(blk2.IsIllegalEncoding().value(), - "Too many bits required for weight grid"); - - // Dual plane block with 3x5 weight dims - PhysicalASTCBlock blk3(0x0000000001FE0005FFULL); - weight_dims = blk3.WeightGridDims(); - ASSERT_TRUE(weight_dims); - EXPECT_EQ(weight_dims->at(0), 3); - EXPECT_EQ(weight_dims->at(1), 5); - - // Error blocks shouldn't have any weight dims - EXPECT_FALSE(kErrorBlock.WeightGridDims()); - - PhysicalASTCBlock non_shared_cem(0x4000000000800D44ULL); - weight_dims = non_shared_cem.WeightGridDims(); - ASSERT_TRUE(weight_dims); - EXPECT_EQ(weight_dims->at(0), 8); - EXPECT_EQ(weight_dims->at(1), 8); -} - -// Test to see whether or not the presence of a dual-plane bit -// is decoded properly. Error encodings are tested to *not* return -// that they have dual planes. -TEST(PhysicalASTCBlockTest, TestDualPlane) { - PhysicalASTCBlock blk1(0x0000000001FE000173ULL); - EXPECT_FALSE(blk1.IsDualPlane()); - EXPECT_FALSE(kErrorBlock.IsDualPlane()); - - // If we flip the dual plane bit, we will have too many bits - // for the weight grid and this should error - PhysicalASTCBlock blk2(0x0000000001FE000573ULL); - EXPECT_FALSE(blk2.IsDualPlane()); - EXPECT_FALSE(blk2.WeightGridDims()); - EXPECT_EQ(blk2.IsIllegalEncoding().value(), - "Too many bits required for weight grid"); - - // A dual plane with 3x5 weight grid should be supported - PhysicalASTCBlock blk3(0x0000000001FE0005FFULL); - EXPECT_TRUE(blk3.IsDualPlane()); - - // If we use the wrong block mode, then a valid block - // shouldn't have any dual plane - PhysicalASTCBlock blk4(0x0000000001FE000108ULL); - EXPECT_FALSE(blk4.IsDualPlane()); - EXPECT_FALSE(blk4.IsIllegalEncoding()); -} - -// Make sure that we properly calculate the number of bits used to encode -// the weight grid. Given error encodings or void extent blocks, this number -// should be zero -TEST(PhysicalASTCBlockTest, TestNumWeightBits) { - // 6x5 single-plane weight grid with 3-bit weights - // should have 90 bits for the weights. - PhysicalASTCBlock blk1(0x0000000001FE000173ULL); - EXPECT_EQ(90, blk1.NumWeightBits()); - - // Error block has no weight bits - EXPECT_FALSE(kErrorBlock.NumWeightBits()); - - // Void extent blocks have no weight bits - EXPECT_FALSE(PhysicalASTCBlock(0xFFF8003FFE000DFCULL).NumWeightBits()); - - // If we flip the dual plane bit, we will have too many bits - // for the weight grid and this should error and return no bits - PhysicalASTCBlock blk2(0x0000000001FE000573ULL); - EXPECT_FALSE(blk2.NumWeightBits()); - - // 3x5 dual-plane weight grid with 3-bit weights - // should have 90 bits for the weights. - PhysicalASTCBlock blk3(0x0000000001FE0005FFULL); - EXPECT_EQ(90, blk3.NumWeightBits()); -} - -// Test to make sure that our weight bits start where we expect them to. -// In other words, make sure that the calculation based on the block mode for -// where the weight bits start is accurate. -TEST(PhysicalASTCBlockTest, TestStartWeightBit) { - EXPECT_EQ(PhysicalASTCBlock(0x4000000000800D44ULL).WeightStartBit(), 64); - - // Error blocks have no weight start bit - EXPECT_FALSE(kErrorBlock.WeightStartBit()); - - // Void extent blocks have no weight start bit - EXPECT_FALSE(PhysicalASTCBlock(0xFFF8003FFE000DFCULL).WeightStartBit()); -} - -// Test to make sure that we catch various different reasons for error encoding -// of ASTC blocks, but also that certain encodings aren't errors. -TEST(PhysicalASTCBlockTest, TestErrorBlocks) { - // Various valid block modes - EXPECT_FALSE(PhysicalASTCBlock(0x0000000001FE000173ULL).IsIllegalEncoding()); - EXPECT_FALSE(PhysicalASTCBlock(0x0000000001FE0005FFULL).IsIllegalEncoding()); - EXPECT_FALSE(PhysicalASTCBlock(0x0000000001FE000108ULL).IsIllegalEncoding()); - - // This is an error because it uses an invalid block mode - EXPECT_EQ(kErrorBlock.IsIllegalEncoding().value(), "Reserved block mode"); - - // This is an error because we have too many weight bits - PhysicalASTCBlock err_blk(0x0000000001FE000573ULL); - EXPECT_EQ(err_blk.IsIllegalEncoding().value(), - "Too many bits required for weight grid"); - - // This is an error because we have too many weights - PhysicalASTCBlock err_blk2 = PhysicalASTCBlock(0x0000000001FE0005A8ULL); - EXPECT_EQ(err_blk2.IsIllegalEncoding().value(), "Too many weights specified"); - - PhysicalASTCBlock err_blk3 = PhysicalASTCBlock(0x0000000001FE000588ULL); - EXPECT_EQ(err_blk3.IsIllegalEncoding().value(), "Too many weights specified"); - - // This is an error because we have too few weights - PhysicalASTCBlock err_blk4 = PhysicalASTCBlock(0x0000000001FE00002ULL); - EXPECT_EQ(err_blk4.IsIllegalEncoding().value(), - "Too few bits required for weight grid"); - - // Four partitions, dual plane -- should be error - // 2x2 weight grid, 3 bits per weight - PhysicalASTCBlock dual_plane_four_parts(0x000000000000001D1FULL); - EXPECT_FALSE(dual_plane_four_parts.NumPartitions()); - EXPECT_EQ(dual_plane_four_parts.IsIllegalEncoding().value(), - "Both four partitions and dual plane specified"); -} - -// Test to make sure that we properly identify and can manipulate void-extent -// blocks. These are ASTC blocks that only define a single color for the entire -// block. -TEST(PhysicalASTCBlockTest, TestVoidExtentBlocks) { - // Various valid block modes that aren't void extent blocks - EXPECT_FALSE(PhysicalASTCBlock(0x0000000001FE000173ULL).IsVoidExtent()); - EXPECT_FALSE(PhysicalASTCBlock(0x0000000001FE0005FFULL).IsVoidExtent()); - EXPECT_FALSE(PhysicalASTCBlock(0x0000000001FE000108ULL).IsVoidExtent()); - - // Error block is not a void extent block - EXPECT_FALSE(kErrorBlock.IsVoidExtent()); - - // Void extent block is void extent block... - UInt128 void_extent_encoding(0, 0xFFF8003FFE000DFCULL); - EXPECT_FALSE(PhysicalASTCBlock(void_extent_encoding).IsIllegalEncoding()); - EXPECT_TRUE(PhysicalASTCBlock(void_extent_encoding).IsVoidExtent()); - - // If we modify the high 64 bits it shouldn't change anything - void_extent_encoding |= UInt128(0xdeadbeefdeadbeef, 0); - EXPECT_FALSE(PhysicalASTCBlock(void_extent_encoding).IsIllegalEncoding()); - EXPECT_TRUE(PhysicalASTCBlock(void_extent_encoding).IsVoidExtent()); -} - -TEST(PhysicalASTCBlockTest, TestVoidExtentCoordinates) { - // The void extent block should have texture coordinates from 0-8191 - auto coords = PhysicalASTCBlock(0xFFF8003FFE000DFCULL).VoidExtentCoords(); - EXPECT_EQ(coords->at(0), 0); - EXPECT_EQ(coords->at(1), 8191); - EXPECT_EQ(coords->at(2), 0); - EXPECT_EQ(coords->at(3), 8191); - - // If we set the coords to all 1's then it's still a void extent - // block, but there aren't any void extent coords. - EXPECT_FALSE(PhysicalASTCBlock(0xFFFFFFFFFFFFFDFCULL).IsIllegalEncoding()); - EXPECT_TRUE(PhysicalASTCBlock(0xFFFFFFFFFFFFFDFCULL).IsVoidExtent()); - EXPECT_FALSE(PhysicalASTCBlock(0xFFFFFFFFFFFFFDFCULL).VoidExtentCoords()); - - // If we set the void extent coords to something where the coords are - // >= each other, then the encoding is illegal. - EXPECT_TRUE(PhysicalASTCBlock(0x0008004002001DFCULL).IsIllegalEncoding()); - EXPECT_TRUE(PhysicalASTCBlock(0x0007FFC001FFFDFCULL).IsIllegalEncoding()); -} - -// Test to see if we can properly identify the number of partitions in a block -// In particular -- we need to make sure we properly identify single and -// multi-partition blocks, but also that void extent and error blocks don't -// return valid numbers of partitions -TEST(PhysicalASTCBlockTest, TestNumPartitions) { - // Various valid block modes, but all single partition - EXPECT_EQ(PhysicalASTCBlock(0x0000000001FE000173ULL).NumPartitions(), 1); - EXPECT_EQ(PhysicalASTCBlock(0x0000000001FE0005FFULL).NumPartitions(), 1); - EXPECT_EQ(PhysicalASTCBlock(0x0000000001FE000108ULL).NumPartitions(), 1); - - // Two to four partitions don't have enough bits for color. - EXPECT_FALSE(PhysicalASTCBlock(0x000000000000000973ULL).NumPartitions()); - EXPECT_FALSE(PhysicalASTCBlock(0x000000000000001173ULL).NumPartitions()); - EXPECT_FALSE(PhysicalASTCBlock(0x000000000000001973ULL).NumPartitions()); - - // Test against having more than one partition - PhysicalASTCBlock non_shared_cem(0x4000000000800D44ULL); - EXPECT_EQ(non_shared_cem.NumPartitions(), 2); -} - -// Test the color endpoint modes specified for how the endpoints are encoded. -// In particular, test that shared color endpoint modes work for multi-partition -// blocks and that non-shared color endpoint modes also work. -TEST(PhysicalASTCBlockTest, TestColorEndpointModes) { - // Four partitions -- one shared CEM - const auto blk1 = PhysicalASTCBlock(0x000000000000001961ULL); - for (int i = 0; i < 4; ++i) { - EXPECT_EQ(blk1.GetEndpointMode(i), ColorEndpointMode::kLDRLumaDirect); - } - - // Void extent blocks have no endpoint modes - EXPECT_FALSE(PhysicalASTCBlock(0xFFF8003FFE000DFCULL).GetEndpointMode(0)); - - // Test out of range partitions - EXPECT_FALSE(PhysicalASTCBlock(0x0000000001FE000173ULL).GetEndpointMode(1)); - EXPECT_FALSE(PhysicalASTCBlock(0x0000000001FE000173ULL).GetEndpointMode(-1)); - EXPECT_FALSE(PhysicalASTCBlock(0x0000000001FE000173ULL).GetEndpointMode(100)); - - // Error blocks have no endpoint modes - EXPECT_FALSE(kErrorBlock.GetEndpointMode(0)); - - // Test non-shared CEMs - PhysicalASTCBlock non_shared_cem(0x4000000000800D44ULL); - EXPECT_EQ(non_shared_cem.GetEndpointMode(0), - ColorEndpointMode::kLDRLumaDirect); - EXPECT_EQ(non_shared_cem.GetEndpointMode(1), - ColorEndpointMode::kLDRLumaBaseOffset); -} - -// Make sure that if we have more than one partition then we have proper -// partition IDs (these determine which pixels correspond to which partition) -TEST(PhysicalASTCBlockTest, TestPartitionID) { - // Valid partitions - EXPECT_EQ(PhysicalASTCBlock(0x4000000000FFED44ULL).PartitionID(), 0x3FF); - EXPECT_EQ(PhysicalASTCBlock(0x4000000000AAAD44ULL).PartitionID(), 0x155); - - // Error blocks have no partition IDs - EXPECT_FALSE(kErrorBlock.PartitionID()); - - // Void extent blocks have no endpoint modes - EXPECT_FALSE(PhysicalASTCBlock(0xFFF8003FFE000DFCULL).PartitionID()); -} - -// Make sure that we're properly attributing the number of bits associated with -// the encoded color values. -TEST(PhysicalASTCBlockTest, TestNumColorBits) { - // If we're using a direct luma channel, then the number of color bits is 16 - EXPECT_EQ(PhysicalASTCBlock(0x0000000001FE000173ULL).NumColorValues(), 2); - EXPECT_EQ(PhysicalASTCBlock(0x0000000001FE000173ULL).NumColorBits(), 16); - - // Error blocks have nothing - EXPECT_FALSE(kErrorBlock.NumColorValues()); - EXPECT_FALSE(kErrorBlock.NumColorBits()); - - // Void extent blocks have four color values and 64 bits of color - EXPECT_EQ(PhysicalASTCBlock(0xFFF8003FFE000DFCULL).NumColorValues(), 4); - EXPECT_EQ(PhysicalASTCBlock(0xFFF8003FFE000DFCULL).NumColorBits(), 64); -} - -// Make sure that we're properly decoding the range of values that each of the -// encoded color values can take -TEST(PhysicalASTCBlockTest, TestColorValuesRange) { - // If we're using a direct luma channel, then we use two color values up to - // a full byte each. - EXPECT_EQ(PhysicalASTCBlock(0x0000000001FE000173ULL).ColorValuesRange(), 255); - - // Error blocks have nothing - EXPECT_FALSE(kErrorBlock.ColorValuesRange()); - - // Void extent blocks have four color values and 64 bits of color, so the - // color range for each is sixteen bits. - EXPECT_EQ(PhysicalASTCBlock(0xFFF8003FFE000DFCULL).ColorValuesRange(), - (1 << 16) - 1); -} - -// Test that we know where the color data starts. This is different mostly -// depending on whether or not the block is single-partition or void extent. -TEST(PhysicalASTCBlockTest, TestColorStartBits) { - // Void extent blocks start at bit 64 - EXPECT_EQ(PhysicalASTCBlock(0xFFF8003FFE000DFCULL).ColorStartBit(), 64); - - // Error blocks don't start anywhere - EXPECT_FALSE(kErrorBlock.ColorStartBit()); - - // Single partition blocks start at bit 17 - EXPECT_EQ(PhysicalASTCBlock(0x0000000001FE000173ULL).ColorStartBit(), 17); - EXPECT_EQ(PhysicalASTCBlock(0x0000000001FE0005FFULL).ColorStartBit(), 17); - EXPECT_EQ(PhysicalASTCBlock(0x0000000001FE000108ULL).ColorStartBit(), 17); - - // Multi-partition blocks start at bit 29 - EXPECT_EQ(PhysicalASTCBlock(0x4000000000FFED44ULL).ColorStartBit(), 29); - EXPECT_EQ(PhysicalASTCBlock(0x4000000000AAAD44ULL).ColorStartBit(), 29); -} - -} // namespace diff --git a/third-party/astc-codec/src/decoder/test/quantization_test.cc b/third-party/astc-codec/src/decoder/test/quantization_test.cc deleted file mode 100644 index f882876e..00000000 --- a/third-party/astc-codec/src/decoder/test/quantization_test.cc +++ /dev/null @@ -1,288 +0,0 @@ -// Copyright 2018 Google LLC -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// https://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -#include "src/decoder/quantization.h" -#include "src/decoder/integer_sequence_codec.h" - -#include <gtest/gtest.h> - -#include <functional> -#include <string> -#include <vector> - -namespace astc_codec { - -namespace { - -// Make sure that we never exceed the maximum range that we pass in. -TEST(QuantizationTest, TestQuantizeMaxRange) { - for (int i = kEndpointRangeMinValue; i < 256; ++i) { - EXPECT_LE(QuantizeCEValueToRange(255, i), i); - } - - for (int i = 1; i < kWeightRangeMaxValue; ++i) { - EXPECT_LE(QuantizeWeightToRange(64, i), i); - } -} - -// Make sure that whenever we unquantize and requantize a value we get back -// what we started with. -TEST(QuantizationTest, TestReversibility) { - for (auto itr = ISERangeBegin(); itr != ISERangeEnd(); itr++) { - const int range = *itr; - if (range <= kWeightRangeMaxValue) { - for (int j = 0; j <= range; ++j) { - const int q = UnquantizeWeightFromRange(j, range); - EXPECT_EQ(QuantizeWeightToRange(q, range), j); - } - } - - if (range >= kEndpointRangeMinValue) { - for (int j = 0; j <= range; ++j) { - const int q = UnquantizeCEValueFromRange(j, range); - EXPECT_EQ(QuantizeCEValueToRange(q, range), j); - } - } - } -} - -// Make sure that whenever we quantize a non-maximal value it gets sent to the -// proper range -TEST(QuantizationTest, TestQuantizationRange) { - for (auto itr = ISERangeBegin(); itr != ISERangeEnd(); itr++) { - const int range = *itr; - if (range >= kEndpointRangeMinValue) { - EXPECT_LE(QuantizeCEValueToRange(0, range), range); - EXPECT_LE(QuantizeCEValueToRange(4, range), range); - EXPECT_LE(QuantizeCEValueToRange(15, range), range); - EXPECT_LE(QuantizeCEValueToRange(22, range), range); - EXPECT_LE(QuantizeCEValueToRange(66, range), range); - EXPECT_LE(QuantizeCEValueToRange(91, range), range); - EXPECT_LE(QuantizeCEValueToRange(126, range), range); - } - - if (range <= kWeightRangeMaxValue) { - EXPECT_LE(QuantizeWeightToRange(0, range), range); - EXPECT_LE(QuantizeWeightToRange(4, range), range); - EXPECT_LE(QuantizeWeightToRange(15, range), range); - EXPECT_LE(QuantizeWeightToRange(22, range), range); - } - } -} - -// Make sure that whenever we unquantize a value it remains within [0, 255] -TEST(QuantizationTest, TestUnquantizationRange) { - EXPECT_LT(UnquantizeCEValueFromRange(2, 7), 256); - EXPECT_LT(UnquantizeCEValueFromRange(7, 7), 256); - EXPECT_LT(UnquantizeCEValueFromRange(39, 63), 256); - EXPECT_LT(UnquantizeCEValueFromRange(66, 79), 256); - EXPECT_LT(UnquantizeCEValueFromRange(91, 191), 256); - EXPECT_LT(UnquantizeCEValueFromRange(126, 255), 256); - EXPECT_LT(UnquantizeCEValueFromRange(255, 255), 256); - - EXPECT_LE(UnquantizeWeightFromRange(0, 1), 64); - EXPECT_LE(UnquantizeWeightFromRange(2, 7), 64); - EXPECT_LE(UnquantizeWeightFromRange(7, 7), 64); - EXPECT_LE(UnquantizeWeightFromRange(29, 31), 64); -} - -// When we quantize a value, it should use the largest quantization range that -// does not exceed the desired range. -TEST(QuantizationTest, TestUpperBoundRanges) { - auto expected_range_itr = ISERangeBegin(); - for (int desired_range = 1; desired_range < 256; ++desired_range) { - if (desired_range == *(expected_range_itr + 1)) { - ++expected_range_itr; - } - const int expected_range = *expected_range_itr; - ASSERT_LE(expected_range, desired_range); - - if (desired_range >= kEndpointRangeMinValue) { - EXPECT_EQ(QuantizeCEValueToRange(0, desired_range), - QuantizeCEValueToRange(0, expected_range)); - - EXPECT_EQ(QuantizeCEValueToRange(208, desired_range), - QuantizeCEValueToRange(208, expected_range)); - - EXPECT_EQ(QuantizeCEValueToRange(173, desired_range), - QuantizeCEValueToRange(173, expected_range)); - - EXPECT_EQ(QuantizeCEValueToRange(13, desired_range), - QuantizeCEValueToRange(13, expected_range)); - - EXPECT_EQ(QuantizeCEValueToRange(255, desired_range), - QuantizeCEValueToRange(255, expected_range)); - } - - if (desired_range <= kWeightRangeMaxValue) { - EXPECT_EQ(QuantizeWeightToRange(0, desired_range), - QuantizeWeightToRange(0, expected_range)); - - EXPECT_EQ(QuantizeWeightToRange(63, desired_range), - QuantizeWeightToRange(63, expected_range)); - - EXPECT_EQ(QuantizeWeightToRange(12, desired_range), - QuantizeWeightToRange(12, expected_range)); - - EXPECT_EQ(QuantizeWeightToRange(23, desired_range), - QuantizeWeightToRange(23, expected_range)); - } - } - - // Make sure that we covered all the possible ranges - ASSERT_EQ(std::next(expected_range_itr), ISERangeEnd()); -} - -// Make sure that quantizing to the largest range is the identity function. -TEST(QuantizationTest, TestIdentity) { - for (int i = 0; i < 256; ++i) { - EXPECT_EQ(QuantizeCEValueToRange(i, 255), i); - } - - // Note: This doesn't apply to weights since there's a weird hack to convert - // values from [0, 31] to [0, 64]. -} - -// Make sure that bit quantization is monotonic with respect to the input, -// since quantizing and dequantizing bits is a matter of truncation and bit -// replication -TEST(QuantizationTest, TestMonotonicBitPacking) { - for (int num_bits = 3; num_bits < 8; ++num_bits) { - const int range = (1 << num_bits) - 1; - int last_quant_val = -1; - for (int i = 0; i < 256; ++i) { - const int quant_val = QuantizeCEValueToRange(i, range); - EXPECT_LE(last_quant_val, quant_val); - last_quant_val = quant_val; - } - - // Also expect the last quantization val to be equal to the range - EXPECT_EQ(last_quant_val, range); - - if (range <= kWeightRangeMaxValue) { - last_quant_val = -1; - for (int i = 0; i <= 64; ++i) { - const int quant_val = QuantizeWeightToRange(i, range); - EXPECT_LE(last_quant_val, quant_val); - last_quant_val = quant_val; - } - EXPECT_EQ(last_quant_val, range); - } - } -} - -// Make sure that bit quantization reflects that quantized values below the bit -// replication threshold get mapped to zero -TEST(QuantizationTest, TestSmallBitPacking) { - for (int num_bits = 1; num_bits <= 8; ++num_bits) { - const int range = (1 << num_bits) - 1; - - // The largest number that should map to zero is one less than half of the - // smallest representation w.r.t. range. For example: if we have a range - // of 7, it means that we have 3 total bits abc for quantized values. If we - // unquantize to 8 bits, it means that our resulting value will be abcabcab. - // Hence, we map 000 to 0 and 001 to 0b00100100 = 36. The earliest value - // that should not map to zero with three bits is therefore 0b00001111 = 15. - // This ends up being (1 << (8 - 3 - 1)) - 1. We don't use 0b00011111 = 31 - // because this would "round up" to 1 during quantization. This value is not - // necessarily the largest, but it is the largest that we can *guarantee* - // should map to zero. - - if (range >= kEndpointRangeMinValue) { - constexpr int cev_bits = 8; - const int half_max_quant_bits = std::max(0, cev_bits - num_bits - 1); - const int largest_cev_to_zero = (1 << half_max_quant_bits) - 1; - EXPECT_EQ(QuantizeCEValueToRange(largest_cev_to_zero, range), 0) - << " Largest CEV to zero: " << largest_cev_to_zero - << " Range: " << range; - } - - if (range <= kWeightRangeMaxValue) { - constexpr int weight_bits = 6; - const int half_max_quant_bits = std::max(0, weight_bits - num_bits - 1); - const int largest_weight_to_zero = (1 << half_max_quant_bits) - 1; - EXPECT_EQ(QuantizeWeightToRange(largest_weight_to_zero, range), 0) - << " Largest weight to zero: " << largest_weight_to_zero - << " Range: " << range; - } - } -} - -// Test specific quint and trit weight encodings with values that were obtained -// using the reference ASTC codec. -TEST(QuantizationTest, TestSpecificQuintTritPackings) { - std::vector<int> vals = { 4, 6, 4, 6, 7, 5, 7, 5 }; - std::vector<int> quantized; - - // Test a quint packing - std::transform( - vals.begin(), vals.end(), std::back_inserter(quantized), - std::bind(UnquantizeWeightFromRange, std::placeholders::_1, 9)); - const std::vector<int> quintExpected = {14, 21, 14, 21, 43, 50, 43, 50 }; - EXPECT_EQ(quantized, quintExpected); - - // Test a trit packing - std::transform( - vals.begin(), vals.end(), quantized.begin(), - std::bind(UnquantizeWeightFromRange, std::placeholders::_1, 11)); - const std::vector<int> tritExpected = { 5, 23, 5, 23, 41, 59, 41, 59 }; - EXPECT_EQ(quantized, tritExpected); -} - -// Make sure that we properly die when we pass in values below the minimum -// allowed ranges for our quantization intervals. -TEST(QuantizationDeathTest, TestInvalidMinRange) { - for (int i = 0; i < kEndpointRangeMinValue; ++i) { - EXPECT_DEBUG_DEATH(QuantizeCEValueToRange(0, i), ""); - EXPECT_DEBUG_DEATH(UnquantizeCEValueFromRange(0, i), ""); - } - - EXPECT_DEBUG_DEATH(QuantizeWeightToRange(0, 0), ""); - EXPECT_DEBUG_DEATH(UnquantizeWeightFromRange(0, 0), ""); -} - -// Make sure that we properly die when we pass in bogus values. -TEST(QuantizationDeathTest, TestOutOfRange) { - EXPECT_DEBUG_DEATH(QuantizeCEValueToRange(-1, 10), ""); - EXPECT_DEBUG_DEATH(QuantizeCEValueToRange(256, 7), ""); - EXPECT_DEBUG_DEATH(QuantizeCEValueToRange(10000, 17), ""); - - EXPECT_DEBUG_DEATH(UnquantizeCEValueFromRange(-1, 10), ""); - EXPECT_DEBUG_DEATH(UnquantizeCEValueFromRange(8, 7), ""); - EXPECT_DEBUG_DEATH(UnquantizeCEValueFromRange(-1000, 17), ""); - - EXPECT_DEBUG_DEATH(QuantizeCEValueToRange(0, -7), ""); - EXPECT_DEBUG_DEATH(UnquantizeCEValueFromRange(0, -17), ""); - - EXPECT_DEBUG_DEATH(QuantizeCEValueToRange(0, 257), ""); - EXPECT_DEBUG_DEATH(UnquantizeCEValueFromRange(0, 256), ""); - - EXPECT_DEBUG_DEATH(QuantizeWeightToRange(-1, 10), ""); - EXPECT_DEBUG_DEATH(QuantizeWeightToRange(256, 7), ""); - EXPECT_DEBUG_DEATH(QuantizeWeightToRange(10000, 17), ""); - - EXPECT_DEBUG_DEATH(UnquantizeWeightFromRange(-1, 10), ""); - EXPECT_DEBUG_DEATH(UnquantizeWeightFromRange(8, 7), ""); - EXPECT_DEBUG_DEATH(UnquantizeWeightFromRange(-1000, 17), ""); - - EXPECT_DEBUG_DEATH(QuantizeWeightToRange(0, -7), ""); - EXPECT_DEBUG_DEATH(UnquantizeWeightFromRange(0, -17), ""); - - EXPECT_DEBUG_DEATH(QuantizeWeightToRange(0, 32), ""); - EXPECT_DEBUG_DEATH(UnquantizeWeightFromRange(0, 64), ""); -} - -} // namespace - -} // namespace astc_codec diff --git a/third-party/astc-codec/src/decoder/test/weight_infill_test.cc b/third-party/astc-codec/src/decoder/test/weight_infill_test.cc deleted file mode 100644 index 79c77455..00000000 --- a/third-party/astc-codec/src/decoder/test/weight_infill_test.cc +++ /dev/null @@ -1,69 +0,0 @@ -// Copyright 2018 Google LLC -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// https://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -#include "src/decoder/weight_infill.h" -#include "src/decoder/footprint.h" - -#include <gtest/gtest.h> - -#include <vector> - -namespace astc_codec { - -namespace { - -// Make sure that the physical size of the bit representations for certain -// dimensions of weight grids matches our expectations -TEST(ASTCWeightInfillTest, TestGetBitCount) { - // Bit encodings - EXPECT_EQ(32, CountBitsForWeights(4, 4, 3)); - EXPECT_EQ(48, CountBitsForWeights(4, 4, 7)); - EXPECT_EQ(24, CountBitsForWeights(2, 4, 7)); - EXPECT_EQ(8, CountBitsForWeights(2, 4, 1)); - - // Trit encodings - EXPECT_EQ(32, CountBitsForWeights(4, 5, 2)); - EXPECT_EQ(26, CountBitsForWeights(4, 4, 2)); - EXPECT_EQ(52, CountBitsForWeights(4, 5, 5)); - EXPECT_EQ(42, CountBitsForWeights(4, 4, 5)); - - // Quint encodings - EXPECT_EQ(21, CountBitsForWeights(3, 3, 4)); - EXPECT_EQ(38, CountBitsForWeights(4, 4, 4)); - EXPECT_EQ(49, CountBitsForWeights(3, 7, 4)); - EXPECT_EQ(52, CountBitsForWeights(4, 3, 19)); - EXPECT_EQ(70, CountBitsForWeights(4, 4, 19)); -} - -// Make sure that we bilerp our weights properly -TEST(ASTCWeightInfillTest, TestInfillBilerp) { - std::vector<int> weights = InfillWeights( - {{ 1, 3, 5, 3, 5, 7, 5, 7, 9 }}, Footprint::Get5x5(), 3, 3); - - std::vector<int> expected_weights = { - 1, 2, 3, 4, 5, - 2, 3, 4, 5, 6, - 3, 4, 5, 6, 7, - 4, 5, 6, 7, 8, - 5, 6, 7, 8, 9 }; - - ASSERT_EQ(weights.size(), expected_weights.size()); - for (int i = 0; i < weights.size(); ++i) { - EXPECT_EQ(weights[i], expected_weights[i]); - } -} - -} // namespace - -} // namespace astc_codec diff --git a/third-party/astc-codec/src/decoder/testdata/atlas_small_4x4.astc b/third-party/astc-codec/src/decoder/testdata/atlas_small_4x4.astc Binary files differdeleted file mode 100644 index 0dd080b1..00000000 --- a/third-party/astc-codec/src/decoder/testdata/atlas_small_4x4.astc +++ /dev/null diff --git a/third-party/astc-codec/src/decoder/testdata/atlas_small_4x4.bmp b/third-party/astc-codec/src/decoder/testdata/atlas_small_4x4.bmp Binary files differdeleted file mode 100644 index 32412b3e..00000000 --- a/third-party/astc-codec/src/decoder/testdata/atlas_small_4x4.bmp +++ /dev/null diff --git a/third-party/astc-codec/src/decoder/testdata/atlas_small_5x5.astc b/third-party/astc-codec/src/decoder/testdata/atlas_small_5x5.astc Binary files differdeleted file mode 100644 index 2831c90e..00000000 --- a/third-party/astc-codec/src/decoder/testdata/atlas_small_5x5.astc +++ /dev/null diff --git a/third-party/astc-codec/src/decoder/testdata/atlas_small_5x5.bmp b/third-party/astc-codec/src/decoder/testdata/atlas_small_5x5.bmp Binary files differdeleted file mode 100644 index 95b0186a..00000000 --- a/third-party/astc-codec/src/decoder/testdata/atlas_small_5x5.bmp +++ /dev/null diff --git a/third-party/astc-codec/src/decoder/testdata/atlas_small_6x6.astc b/third-party/astc-codec/src/decoder/testdata/atlas_small_6x6.astc Binary files differdeleted file mode 100644 index b2cc9c2d..00000000 --- a/third-party/astc-codec/src/decoder/testdata/atlas_small_6x6.astc +++ /dev/null diff --git a/third-party/astc-codec/src/decoder/testdata/atlas_small_6x6.bmp b/third-party/astc-codec/src/decoder/testdata/atlas_small_6x6.bmp Binary files differdeleted file mode 100644 index 796812e2..00000000 --- a/third-party/astc-codec/src/decoder/testdata/atlas_small_6x6.bmp +++ /dev/null diff --git a/third-party/astc-codec/src/decoder/testdata/atlas_small_8x8.astc b/third-party/astc-codec/src/decoder/testdata/atlas_small_8x8.astc Binary files differdeleted file mode 100644 index a8805f28..00000000 --- a/third-party/astc-codec/src/decoder/testdata/atlas_small_8x8.astc +++ /dev/null diff --git a/third-party/astc-codec/src/decoder/testdata/atlas_small_8x8.bmp b/third-party/astc-codec/src/decoder/testdata/atlas_small_8x8.bmp Binary files differdeleted file mode 100644 index 8f92698c..00000000 --- a/third-party/astc-codec/src/decoder/testdata/atlas_small_8x8.bmp +++ /dev/null diff --git a/third-party/astc-codec/src/decoder/testdata/checkerboard.astc b/third-party/astc-codec/src/decoder/testdata/checkerboard.astc Binary files differdeleted file mode 100644 index 79acdca3..00000000 --- a/third-party/astc-codec/src/decoder/testdata/checkerboard.astc +++ /dev/null diff --git a/third-party/astc-codec/src/decoder/testdata/checkered_10.astc b/third-party/astc-codec/src/decoder/testdata/checkered_10.astc Binary files differdeleted file mode 100644 index e3b19657..00000000 --- a/third-party/astc-codec/src/decoder/testdata/checkered_10.astc +++ /dev/null diff --git a/third-party/astc-codec/src/decoder/testdata/checkered_11.astc b/third-party/astc-codec/src/decoder/testdata/checkered_11.astc Binary files differdeleted file mode 100644 index c80c6a46..00000000 --- a/third-party/astc-codec/src/decoder/testdata/checkered_11.astc +++ /dev/null diff --git a/third-party/astc-codec/src/decoder/testdata/checkered_12.astc b/third-party/astc-codec/src/decoder/testdata/checkered_12.astc Binary files differdeleted file mode 100644 index a82583a9..00000000 --- a/third-party/astc-codec/src/decoder/testdata/checkered_12.astc +++ /dev/null diff --git a/third-party/astc-codec/src/decoder/testdata/checkered_4.astc b/third-party/astc-codec/src/decoder/testdata/checkered_4.astc Binary files differdeleted file mode 100644 index ac607164..00000000 --- a/third-party/astc-codec/src/decoder/testdata/checkered_4.astc +++ /dev/null diff --git a/third-party/astc-codec/src/decoder/testdata/checkered_5.astc b/third-party/astc-codec/src/decoder/testdata/checkered_5.astc Binary files differdeleted file mode 100644 index 0389c53d..00000000 --- a/third-party/astc-codec/src/decoder/testdata/checkered_5.astc +++ /dev/null diff --git a/third-party/astc-codec/src/decoder/testdata/checkered_6.astc b/third-party/astc-codec/src/decoder/testdata/checkered_6.astc Binary files differdeleted file mode 100644 index 210dd340..00000000 --- a/third-party/astc-codec/src/decoder/testdata/checkered_6.astc +++ /dev/null diff --git a/third-party/astc-codec/src/decoder/testdata/checkered_7.astc b/third-party/astc-codec/src/decoder/testdata/checkered_7.astc Binary files differdeleted file mode 100644 index 8ea10f84..00000000 --- a/third-party/astc-codec/src/decoder/testdata/checkered_7.astc +++ /dev/null diff --git a/third-party/astc-codec/src/decoder/testdata/checkered_8.astc b/third-party/astc-codec/src/decoder/testdata/checkered_8.astc Binary files differdeleted file mode 100644 index 3708882d..00000000 --- a/third-party/astc-codec/src/decoder/testdata/checkered_8.astc +++ /dev/null diff --git a/third-party/astc-codec/src/decoder/testdata/checkered_9.astc b/third-party/astc-codec/src/decoder/testdata/checkered_9.astc Binary files differdeleted file mode 100644 index b5c962a1..00000000 --- a/third-party/astc-codec/src/decoder/testdata/checkered_9.astc +++ /dev/null diff --git a/third-party/astc-codec/src/decoder/testdata/footprint_10x10.astc b/third-party/astc-codec/src/decoder/testdata/footprint_10x10.astc Binary files differdeleted file mode 100644 index 6799cd08..00000000 --- a/third-party/astc-codec/src/decoder/testdata/footprint_10x10.astc +++ /dev/null diff --git a/third-party/astc-codec/src/decoder/testdata/footprint_10x10.bmp b/third-party/astc-codec/src/decoder/testdata/footprint_10x10.bmp Binary files differdeleted file mode 100644 index 7ded6adf..00000000 --- a/third-party/astc-codec/src/decoder/testdata/footprint_10x10.bmp +++ /dev/null diff --git a/third-party/astc-codec/src/decoder/testdata/footprint_10x5.astc b/third-party/astc-codec/src/decoder/testdata/footprint_10x5.astc Binary files differdeleted file mode 100644 index cbfe4f26..00000000 --- a/third-party/astc-codec/src/decoder/testdata/footprint_10x5.astc +++ /dev/null diff --git a/third-party/astc-codec/src/decoder/testdata/footprint_10x5.bmp b/third-party/astc-codec/src/decoder/testdata/footprint_10x5.bmp Binary files differdeleted file mode 100644 index 68202f85..00000000 --- a/third-party/astc-codec/src/decoder/testdata/footprint_10x5.bmp +++ /dev/null diff --git a/third-party/astc-codec/src/decoder/testdata/footprint_10x6.astc b/third-party/astc-codec/src/decoder/testdata/footprint_10x6.astc Binary files differdeleted file mode 100644 index 53e37b4a..00000000 --- a/third-party/astc-codec/src/decoder/testdata/footprint_10x6.astc +++ /dev/null diff --git a/third-party/astc-codec/src/decoder/testdata/footprint_10x6.bmp b/third-party/astc-codec/src/decoder/testdata/footprint_10x6.bmp Binary files differdeleted file mode 100644 index 3dffe72e..00000000 --- a/third-party/astc-codec/src/decoder/testdata/footprint_10x6.bmp +++ /dev/null diff --git a/third-party/astc-codec/src/decoder/testdata/footprint_10x8.astc b/third-party/astc-codec/src/decoder/testdata/footprint_10x8.astc Binary files differdeleted file mode 100644 index b9613e58..00000000 --- a/third-party/astc-codec/src/decoder/testdata/footprint_10x8.astc +++ /dev/null diff --git a/third-party/astc-codec/src/decoder/testdata/footprint_10x8.bmp b/third-party/astc-codec/src/decoder/testdata/footprint_10x8.bmp Binary files differdeleted file mode 100644 index b7d75f73..00000000 --- a/third-party/astc-codec/src/decoder/testdata/footprint_10x8.bmp +++ /dev/null diff --git a/third-party/astc-codec/src/decoder/testdata/footprint_12x10.astc b/third-party/astc-codec/src/decoder/testdata/footprint_12x10.astc Binary files differdeleted file mode 100644 index 54f59193..00000000 --- a/third-party/astc-codec/src/decoder/testdata/footprint_12x10.astc +++ /dev/null diff --git a/third-party/astc-codec/src/decoder/testdata/footprint_12x10.bmp b/third-party/astc-codec/src/decoder/testdata/footprint_12x10.bmp Binary files differdeleted file mode 100644 index 2007a3dc..00000000 --- a/third-party/astc-codec/src/decoder/testdata/footprint_12x10.bmp +++ /dev/null diff --git a/third-party/astc-codec/src/decoder/testdata/footprint_12x12.astc b/third-party/astc-codec/src/decoder/testdata/footprint_12x12.astc Binary files differdeleted file mode 100644 index d94d0a6c..00000000 --- a/third-party/astc-codec/src/decoder/testdata/footprint_12x12.astc +++ /dev/null diff --git a/third-party/astc-codec/src/decoder/testdata/footprint_12x12.bmp b/third-party/astc-codec/src/decoder/testdata/footprint_12x12.bmp Binary files differdeleted file mode 100644 index 57e24a22..00000000 --- a/third-party/astc-codec/src/decoder/testdata/footprint_12x12.bmp +++ /dev/null diff --git a/third-party/astc-codec/src/decoder/testdata/footprint_4x4.astc b/third-party/astc-codec/src/decoder/testdata/footprint_4x4.astc Binary files differdeleted file mode 100644 index fdf3cd6b..00000000 --- a/third-party/astc-codec/src/decoder/testdata/footprint_4x4.astc +++ /dev/null diff --git a/third-party/astc-codec/src/decoder/testdata/footprint_4x4.bmp b/third-party/astc-codec/src/decoder/testdata/footprint_4x4.bmp Binary files differdeleted file mode 100644 index fcb4e077..00000000 --- a/third-party/astc-codec/src/decoder/testdata/footprint_4x4.bmp +++ /dev/null diff --git a/third-party/astc-codec/src/decoder/testdata/footprint_5x4.astc b/third-party/astc-codec/src/decoder/testdata/footprint_5x4.astc Binary files differdeleted file mode 100644 index 06830594..00000000 --- a/third-party/astc-codec/src/decoder/testdata/footprint_5x4.astc +++ /dev/null diff --git a/third-party/astc-codec/src/decoder/testdata/footprint_5x4.bmp b/third-party/astc-codec/src/decoder/testdata/footprint_5x4.bmp Binary files differdeleted file mode 100644 index 9cae5f93..00000000 --- a/third-party/astc-codec/src/decoder/testdata/footprint_5x4.bmp +++ /dev/null diff --git a/third-party/astc-codec/src/decoder/testdata/footprint_5x5.astc b/third-party/astc-codec/src/decoder/testdata/footprint_5x5.astc Binary files differdeleted file mode 100644 index 03c3395a..00000000 --- a/third-party/astc-codec/src/decoder/testdata/footprint_5x5.astc +++ /dev/null diff --git a/third-party/astc-codec/src/decoder/testdata/footprint_5x5.bmp b/third-party/astc-codec/src/decoder/testdata/footprint_5x5.bmp Binary files differdeleted file mode 100644 index c5ddeec4..00000000 --- a/third-party/astc-codec/src/decoder/testdata/footprint_5x5.bmp +++ /dev/null diff --git a/third-party/astc-codec/src/decoder/testdata/footprint_6x5.astc b/third-party/astc-codec/src/decoder/testdata/footprint_6x5.astc Binary files differdeleted file mode 100644 index d0d455d0..00000000 --- a/third-party/astc-codec/src/decoder/testdata/footprint_6x5.astc +++ /dev/null diff --git a/third-party/astc-codec/src/decoder/testdata/footprint_6x5.bmp b/third-party/astc-codec/src/decoder/testdata/footprint_6x5.bmp Binary files differdeleted file mode 100644 index 94a005dc..00000000 --- a/third-party/astc-codec/src/decoder/testdata/footprint_6x5.bmp +++ /dev/null diff --git a/third-party/astc-codec/src/decoder/testdata/footprint_6x6.astc b/third-party/astc-codec/src/decoder/testdata/footprint_6x6.astc Binary files differdeleted file mode 100644 index 47e038ef..00000000 --- a/third-party/astc-codec/src/decoder/testdata/footprint_6x6.astc +++ /dev/null diff --git a/third-party/astc-codec/src/decoder/testdata/footprint_6x6.bmp b/third-party/astc-codec/src/decoder/testdata/footprint_6x6.bmp Binary files differdeleted file mode 100644 index fb1f41c4..00000000 --- a/third-party/astc-codec/src/decoder/testdata/footprint_6x6.bmp +++ /dev/null diff --git a/third-party/astc-codec/src/decoder/testdata/footprint_8x5.astc b/third-party/astc-codec/src/decoder/testdata/footprint_8x5.astc Binary files differdeleted file mode 100644 index 4ef49d65..00000000 --- a/third-party/astc-codec/src/decoder/testdata/footprint_8x5.astc +++ /dev/null diff --git a/third-party/astc-codec/src/decoder/testdata/footprint_8x5.bmp b/third-party/astc-codec/src/decoder/testdata/footprint_8x5.bmp Binary files differdeleted file mode 100644 index 6d4f6093..00000000 --- a/third-party/astc-codec/src/decoder/testdata/footprint_8x5.bmp +++ /dev/null diff --git a/third-party/astc-codec/src/decoder/testdata/footprint_8x6.astc b/third-party/astc-codec/src/decoder/testdata/footprint_8x6.astc Binary files differdeleted file mode 100644 index 11355095..00000000 --- a/third-party/astc-codec/src/decoder/testdata/footprint_8x6.astc +++ /dev/null diff --git a/third-party/astc-codec/src/decoder/testdata/footprint_8x6.bmp b/third-party/astc-codec/src/decoder/testdata/footprint_8x6.bmp Binary files differdeleted file mode 100644 index 35e71219..00000000 --- a/third-party/astc-codec/src/decoder/testdata/footprint_8x6.bmp +++ /dev/null diff --git a/third-party/astc-codec/src/decoder/testdata/footprint_8x8.astc b/third-party/astc-codec/src/decoder/testdata/footprint_8x8.astc Binary files differdeleted file mode 100644 index bdeb9c9b..00000000 --- a/third-party/astc-codec/src/decoder/testdata/footprint_8x8.astc +++ /dev/null diff --git a/third-party/astc-codec/src/decoder/testdata/footprint_8x8.bmp b/third-party/astc-codec/src/decoder/testdata/footprint_8x8.bmp Binary files differdeleted file mode 100644 index 3b3a1c89..00000000 --- a/third-party/astc-codec/src/decoder/testdata/footprint_8x8.bmp +++ /dev/null diff --git a/third-party/astc-codec/src/decoder/testdata/rgb_12x12.astc b/third-party/astc-codec/src/decoder/testdata/rgb_12x12.astc Binary files differdeleted file mode 100644 index cc0fc3d3..00000000 --- a/third-party/astc-codec/src/decoder/testdata/rgb_12x12.astc +++ /dev/null diff --git a/third-party/astc-codec/src/decoder/testdata/rgb_12x12.bmp b/third-party/astc-codec/src/decoder/testdata/rgb_12x12.bmp Binary files differdeleted file mode 100644 index 50538ded..00000000 --- a/third-party/astc-codec/src/decoder/testdata/rgb_12x12.bmp +++ /dev/null diff --git a/third-party/astc-codec/src/decoder/testdata/rgb_4x4.astc b/third-party/astc-codec/src/decoder/testdata/rgb_4x4.astc Binary files differdeleted file mode 100644 index 84527d3a..00000000 --- a/third-party/astc-codec/src/decoder/testdata/rgb_4x4.astc +++ /dev/null diff --git a/third-party/astc-codec/src/decoder/testdata/rgb_4x4.bmp b/third-party/astc-codec/src/decoder/testdata/rgb_4x4.bmp Binary files differdeleted file mode 100644 index fae4f919..00000000 --- a/third-party/astc-codec/src/decoder/testdata/rgb_4x4.bmp +++ /dev/null diff --git a/third-party/astc-codec/src/decoder/testdata/rgb_5x4.astc b/third-party/astc-codec/src/decoder/testdata/rgb_5x4.astc Binary files differdeleted file mode 100644 index 377938de..00000000 --- a/third-party/astc-codec/src/decoder/testdata/rgb_5x4.astc +++ /dev/null diff --git a/third-party/astc-codec/src/decoder/testdata/rgb_5x4.bmp b/third-party/astc-codec/src/decoder/testdata/rgb_5x4.bmp Binary files differdeleted file mode 100644 index a0c1fdbb..00000000 --- a/third-party/astc-codec/src/decoder/testdata/rgb_5x4.bmp +++ /dev/null diff --git a/third-party/astc-codec/src/decoder/testdata/rgb_6x6.astc b/third-party/astc-codec/src/decoder/testdata/rgb_6x6.astc Binary files differdeleted file mode 100644 index 8a70c0fd..00000000 --- a/third-party/astc-codec/src/decoder/testdata/rgb_6x6.astc +++ /dev/null diff --git a/third-party/astc-codec/src/decoder/testdata/rgb_6x6.bmp b/third-party/astc-codec/src/decoder/testdata/rgb_6x6.bmp Binary files differdeleted file mode 100644 index e1a5dcd8..00000000 --- a/third-party/astc-codec/src/decoder/testdata/rgb_6x6.bmp +++ /dev/null diff --git a/third-party/astc-codec/src/decoder/testdata/rgb_8x8.astc b/third-party/astc-codec/src/decoder/testdata/rgb_8x8.astc Binary files differdeleted file mode 100644 index 1bca381d..00000000 --- a/third-party/astc-codec/src/decoder/testdata/rgb_8x8.astc +++ /dev/null diff --git a/third-party/astc-codec/src/decoder/testdata/rgb_8x8.bmp b/third-party/astc-codec/src/decoder/testdata/rgb_8x8.bmp Binary files differdeleted file mode 100644 index 12b6eb24..00000000 --- a/third-party/astc-codec/src/decoder/testdata/rgb_8x8.bmp +++ /dev/null diff --git a/third-party/astc-codec/src/decoder/tools/astc_inspector_cli.cc b/third-party/astc-codec/src/decoder/tools/astc_inspector_cli.cc deleted file mode 100644 index 105f5749..00000000 --- a/third-party/astc-codec/src/decoder/tools/astc_inspector_cli.cc +++ /dev/null @@ -1,785 +0,0 @@ -// Copyright 2018 Google LLC -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// https://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -// astc_inspector_cli collects the various statistics of a stream of ASTC data -// stored in an ASTC file. -// -// Example usage: -// To dump statistics about an ASTC file, use: -// astc_inspector_cli <filename> -// -// To dump statistics on a specific block in an ASTC file, use: -// astc_inspector_cli <filename> <number> - -#include <algorithm> -#include <array> -#include <fstream> -#include <functional> -#include <iomanip> -#include <iostream> -#include <memory> -#include <numeric> -#include <sstream> -#include <string> -#include <unordered_map> -#include <unordered_set> -#include <vector> - -#include "src/base/string_utils.h" -#include "src/decoder/astc_file.h" -#include "src/decoder/endpoint_codec.h" -#include "src/decoder/intermediate_astc_block.h" -#include "src/decoder/partition.h" -#include "src/decoder/quantization.h" -#include "src/decoder/weight_infill.h" - -using astc_codec::ASTCFile; -using astc_codec::ColorEndpointMode; -using astc_codec::IntermediateBlockData; -using astc_codec::PhysicalASTCBlock; -using astc_codec::RgbaColor; -using astc_codec::VoidExtentData; -using astc_codec::base::Optional; - -namespace { - -constexpr int kNumEndpointModes = - static_cast<int>(ColorEndpointMode::kNumColorEndpointModes); -constexpr std::array<const char*, kNumEndpointModes> kModeStrings {{ - "kLDRLumaDirect", "kLDRLumaBaseOffset", "kHDRLumaLargeRange", - "kHDRLumaSmallRange", "kLDRLumaAlphaDirect", "kLDRLumaAlphaBaseOffset", - "kLDRRGBBaseScale", "kHDRRGBBaseScale", "kLDRRGBDirect", - "kLDRRGBBaseOffset", "kLDRRGBBaseScaleTwoA", "kHDRRGBDirect", - "kLDRRGBADirect", "kLDRRGBABaseOffset", "kHDRRGBDirectLDRAlpha", - "kHDRRGBDirectHDRAlpha" }}; - -//////////////////////////////////////////////////////////////////////////////// -// -// A generic stat that should be tracked via an instance of ASTCFileStats. -class Stat { - public: - explicit Stat(const std::vector<IntermediateBlockData>* blocks, size_t total) - : blocks_(blocks), total_(total) { } - virtual ~Stat() { } - - virtual std::ostream& PrintToStream(std::ostream& out) const = 0; - - protected: - // Utility function to iterate over all of the blocks that are not void-extent - // blocks. FoldFn optionally allows a value to accumulate. It should be of the - // type: - // (const IntermediateBlockData&, T x) -> T - template<typename T, typename FoldFn> - T IterateBlocks(T initial, FoldFn f) const { - T result = initial; - for (const auto& block : *blocks_) { - result = f(block, std::move(result)); - } - return result; - } - - size_t NumBlocks() const { return total_; } - - private: - const std::vector<IntermediateBlockData>* const blocks_; - const size_t total_; -}; - -//////////////////////////////////////////////////////////////////////////////// -// -// Computes the number of void extent blocks. -class VoidExtentCount : public Stat { - public: - VoidExtentCount(const std::vector<IntermediateBlockData>* blocks, - size_t total, std::string description) - : Stat(blocks, total), description_(std::move(description)), - count_(total - blocks->size()) { } - - std::ostream& PrintToStream(std::ostream& out) const override { - return out << description_ << ": " << count_ - << " (" << (count_ * 100 / NumBlocks()) << "%)" << std::endl; - }; - - private: - const std::string description_; - const size_t count_; -}; - -////////////////////////////////////////////////////////////////////////////// -// -// Computes a per-block stat and reports it as an average over all blocks. -class PerBlockAverage : public Stat { - public: - PerBlockAverage(const std::vector<IntermediateBlockData>* blocks, - size_t total, std::string description, - const std::function<int(const IntermediateBlockData&)> &fn) - : Stat(blocks, total), - description_(std::move(description)) { - int sum = 0; - size_t count = 0; - for (const auto& block : *blocks) { - sum += fn(block); - ++count; - } - average_ = sum / count; - } - - std::ostream& PrintToStream(std::ostream& out) const override { - return out << description_ << ": " << average_ << std::endl; - } - - private: - size_t average_; - std::string description_; -}; - -////////////////////////////////////////////////////////////////////////////// -// -// Computes a per-block true or false value and reports how many blocks return -// true with a percentage of total blocks. -class PerBlockPredicate : public Stat { - public: - PerBlockPredicate(const std::vector<IntermediateBlockData>* blocks, - size_t total, std::string description, - const std::function<bool(const IntermediateBlockData&)> &fn) - : Stat(blocks, total), - description_(std::move(description)), - count_(std::count_if(blocks->begin(), blocks->end(), fn)) { } - - std::ostream& PrintToStream(std::ostream& out) const override { - return out << description_ << ": " << count_ - << " (" << (count_ * 100 / NumBlocks()) << "%)" << std::endl; - }; - - private: - const std::string description_; - const size_t count_; -}; - -////////////////////////////////////////////////////////////////////////////// -// -// Returns a histogram of the number of occurrences of each endpoint mode in -// the list of blocks. Note, due to multi-subset blocks, the sum of these -// values will not match the total number of blocks. -class ModeCountsStat : public Stat { - public: - explicit ModeCountsStat(const std::vector<IntermediateBlockData>* blocks, - size_t total) - : Stat(blocks, total), - mode_counts_(IterateBlocks<ModeArray>( - {}, [](const IntermediateBlockData& data, ModeArray&& m) { - auto result = m; - for (const auto& ep : data.endpoints) { - result[static_cast<int>(ep.mode)]++; - } - return result; - })) { } - - std::ostream& PrintToStream(std::ostream& out) const override { - const size_t total_modes_used = - std::accumulate(mode_counts_.begin(), mode_counts_.end(), 0); - - out << "Endpoint modes used: " << std::endl; - for (size_t i = 0; i < kNumEndpointModes; ++i) { - out << " "; - out << std::setw(30) << std::left << std::setfill('.') << kModeStrings[i]; - out << std::setw(8) << std::right << std::setfill('.') << mode_counts_[i]; - - std::stringstream pct; - pct << " (" << (mode_counts_[i] * 100 / total_modes_used) << "%)"; - - out << std::setw(6) << std::right << std::setfill(' ') << pct.str(); - out << std::endl; - } - - return out; - } - - private: - using ModeArray = std::array<int, kNumEndpointModes>; - const ModeArray mode_counts_; -}; - -////////////////////////////////////////////////////////////////////////////// -// -// Counts the number of unique endpoints used across all blocks. -class UniqueEndpointsCount : public Stat { - public: - explicit UniqueEndpointsCount( - const std::vector<IntermediateBlockData>* blocks, size_t total) - : Stat(blocks, total), - unique_endpoints_(IterateBlocks<UniqueEndpointSet>( - UniqueEndpointSet(), - [](const IntermediateBlockData& data, UniqueEndpointSet&& eps) { - UniqueEndpointSet result(eps); - for (const auto& ep : data.endpoints) { - RgbaColor ep_one, ep_two; - DecodeColorsForMode(ep.colors, data.endpoint_range.value(), - ep.mode, &ep_one, &ep_two); - result.insert(PackEndpoint(ep_one)); - result.insert(PackEndpoint(ep_two)); - } - return result; - })) { } - - std::ostream& PrintToStream(std::ostream& out) const override { - out << "Num unique endpoints: " << unique_endpoints_.size() << std::endl; - return out; - } - - private: - static uint32_t PackEndpoint(const RgbaColor& color) { - uint32_t result = 0; - for (const int& c : color) { - constexpr int kSaturatedChannelValue = 0xFF; - assert(c >= 0); - assert(c <= kSaturatedChannelValue); - result <<= 8; - result |= c; - } - return result; - } - - using UniqueEndpointSet = std::unordered_set<uint32_t>; - const UniqueEndpointSet unique_endpoints_; -}; - -////////////////////////////////////////////////////////////////////////////// -// -// Computes a histogram of the number of occurrences of 1-4 subset partitions. -class PartitionCountStat : public Stat { - public: - explicit PartitionCountStat(const std::vector<IntermediateBlockData>* blocks, - size_t total) - : Stat(blocks, total) - , part_counts_(IterateBlocks<PartCount>( - {}, [](const IntermediateBlockData& data, PartCount&& m) { - PartCount result = m; - result[data.endpoints.size() - 1]++; - return result; - })) { } - - std::ostream& PrintToStream(std::ostream& out) const override { - out << "Num partitions used: " << std::endl; - for (size_t i = 0; i < part_counts_.size(); ++i) { - out << " " << i + 1 << ": " << part_counts_[i] << std::endl; - } - return out; - } - - private: - using PartCount = std::array<int, 4>; - const PartCount part_counts_; -}; - -////////////////////////////////////////////////////////////////////////////// -// -// For each block that uses dual-plane mode, computes and stores the dual-plane -// channels in a vector. Outputs the number of each channel used across all -// blocks -class DualChannelStat : public Stat { - private: - static constexpr auto kNumDualPlaneChannels = - std::tuple_size<astc_codec::Endpoint>::value; - using CountsArray = std::array<int, kNumDualPlaneChannels>; - - public: - explicit DualChannelStat(const std::vector<IntermediateBlockData>* blocks, - size_t total) - : Stat(blocks, total), - dual_channels_(IterateBlocks( - std::vector<int>(), - [](const IntermediateBlockData& data, std::vector<int>&& input) { - auto result = input; - if (data.dual_plane_channel) { - result.push_back(data.dual_plane_channel.value()); - } - return result; - })) { } - - std::ostream& PrintToStream(std::ostream& out) const override { - // Similar to the number of partitions, the number of dual plane blocks - // can be determined by parsing the next four fields and summing them. - const int num_dual_plane_blocks = dual_channels_.size(); - out << "Number of dual-plane blocks: " << num_dual_plane_blocks - << " (" << (num_dual_plane_blocks * 100) / NumBlocks() << "%)" - << std::endl; - - CountsArray counts = GetCounts(); - assert(counts.size() == kNumDualPlaneChannels); - - for (size_t i = 0; i < counts.size(); ++i) { - out << " " << i << ": " << counts[i] << std::endl; - } - return out; - } - - private: - CountsArray GetCounts() const { - CountsArray counts; - for (size_t i = 0; i < kNumDualPlaneChannels; ++i) { - counts[i] = - std::count_if(dual_channels_.begin(), dual_channels_.end(), - [i](int channel) { return i == channel; }); - } - return counts; - } - - const std::vector<int> dual_channels_; -}; - - -// Stores the intermediate block representations of the blocks associated with -// an ASTCFile. Also provides various facilities for extracting aggregate data -// from these blocks. -class ASTCFileStats { - public: - explicit ASTCFileStats(const std::unique_ptr<ASTCFile>& astc_file) { - const size_t total = astc_file->NumBlocks(); - - for (size_t block_idx = 0; block_idx < astc_file->NumBlocks(); ++block_idx) { - const PhysicalASTCBlock pb = astc_file->GetBlock(block_idx); - assert(!pb.IsIllegalEncoding()); - if (pb.IsIllegalEncoding()) { - std::cerr << "WARNING: Block " << block_idx << " has illegal encoding." << std::endl; - continue; - } - - if (!pb.IsVoidExtent()) { - Optional<IntermediateBlockData> block = UnpackIntermediateBlock(pb); - if (!block) { - std::cerr << "WARNING: Block " << block_idx << " failed to unpack." << std::endl; - continue; - } - - blocks_.push_back(block.value()); - } - } - - stats_.emplace_back(new UniqueEndpointsCount(&blocks_, total)); - stats_.emplace_back(new VoidExtentCount( - &blocks_, total, "Num void extent blocks")); - - stats_.emplace_back(new PerBlockAverage( - &blocks_, total, "Average weight range", - [](const IntermediateBlockData& b) { return b.weight_range; })); - - stats_.emplace_back(new PerBlockAverage( - &blocks_, total, "Average number of weights", - [](const IntermediateBlockData& b) { return b.weights.size(); })); - - stats_.emplace_back(new PerBlockPredicate( - &blocks_, total, "Num blocks that use blue contract mode", - [](const IntermediateBlockData& block) { - for (const auto& ep : block.endpoints) { - if (UsesBlueContract( - block.endpoint_range.valueOr(255), ep.mode, ep.colors)) { - return true; - } - } - - return false; - })); - - stats_.emplace_back(new ModeCountsStat(&blocks_, total)); - - stats_.emplace_back(new PerBlockPredicate( - &blocks_, total, "Num multi-part blocks", - [](const IntermediateBlockData& block) { - return block.endpoints.size() > 1; - })); - stats_.emplace_back(new PartitionCountStat(&blocks_, total)); - - stats_.emplace_back(new DualChannelStat(&blocks_, total)); - } - - // Returns a sorted list of pairs of the form (part_id, count) where the - // |part_id| is the partition ID used for 2-subset blocks, and |count| is the - // number of times that particular ID was used. - std::vector<std::pair<int, int>> ComputePartIDHistogram() const { - std::vector<int> part_ids(1 << 11, 0); - std::iota(part_ids.begin(), part_ids.end(), 0); - - // The histogram will then pair IDs with counts so that we can sort by - // the number of instances later on. - std::vector<std::pair<int, int>> part_id_histogram; - std::transform(part_ids.begin(), part_ids.end(), - std::back_inserter(part_id_histogram), - [](const int& x) { return std::make_pair(x, 0); }); - - // Actually count the IDs in the list of blocks. - for (const auto& block : blocks_) { - if (block.endpoints.size() == 2) { - const int id = block.partition_id.value(); - assert(part_id_histogram[id].first == id); - part_id_histogram[id].second++; - } - } - - struct OrderBySecondGreater { - typedef std::pair<int, int> PairType; - bool operator()(const PairType& lhs, const PairType& rhs) { - return lhs.second > rhs.second; - } - }; - - // Sort by descending numbers of occurrence for each partition ID - std::sort(part_id_histogram.begin(), part_id_histogram.end(), - OrderBySecondGreater()); - - return part_id_histogram; - } - - // Weights range from 2x2 - 12x12. For simplicity define buckets for every - // pair in [0, 12]^2. - constexpr static int kResolutionBuckets = 13; - // Returns a linear array of buckets over all pairs of grid resolutions, - // x-major in memory. - std::vector<int> ComputeWeightResolutionHistogram() const { - // Allocate one bucket for every grid resolution. - std::vector<int> resolution_histogram( - kResolutionBuckets * kResolutionBuckets, 0); - - // Count the weight resolutions in the list of blocks. - for (const auto& block : blocks_) { - const int dim_x = block.weight_grid_dim_x; - const int dim_y = block.weight_grid_dim_y; - assert(dim_x > 0); - assert(dim_x < kResolutionBuckets); - assert(dim_y > 0); - assert(dim_y < kResolutionBuckets); - ++resolution_histogram[dim_x + dim_y * kResolutionBuckets]; - } - - return resolution_histogram; - } - - // Runs through each defined statistic and prints it out to stdout. Also - // prints a histogram of partition ids used for the given blocks. - void PrintStats() const { - for (const auto& stat : stats_) { - stat->PrintToStream(std::cout); - } - - // We also want to find if there are any 2-subset partition IDs that are - // used disproportionately often. Since partition IDs are 11 bits long, we - // can have as many as (1 << 11) used IDs in a given sequence of blocks. - const auto part_id_histogram = ComputePartIDHistogram(); - const int total_part_ids = std::accumulate( - part_id_histogram.begin(), part_id_histogram.end(), 0, - [](const int& x, const std::pair<int, int>& hist) { - return x + hist.second; - }); - - if (total_part_ids > 0) { - // Display numbers until we either: - // A. Display the top 90% of used partitions - // B. Reach a point where the remaining partition IDs constitute < 1% of - // the total number of IDs used. - const auto prepare_part_entry = []() -> std::ostream& { - return std::cout << std::setw(6) << std::left << std::setfill('.'); - }; - int part_accum = 0; - std::cout << "Two subset partition ID histogram: " << std::endl; - std::cout << " "; - prepare_part_entry() << "ID" << "Count" << std::endl; - for (const auto& hist : part_id_histogram) { - part_accum += hist.second; - if ((hist.second * 100 / total_part_ids) < 1 || - (100 * (total_part_ids - part_accum)) / total_part_ids < 10) { - const int num_to_display = (total_part_ids - part_accum); - std::cout << " rest: " << num_to_display - << " (" << (num_to_display * 100 / total_part_ids) - << "%)" << std::endl; - break; - } else { - std::cout << " "; - prepare_part_entry() << hist.first << hist.second - << " (" << (hist.second * 100 / total_part_ids) - << "%)" << std::endl; - } - } - } - - // Build the 2D histogram of resolutions. - std::vector<int> weight_histogram = ComputeWeightResolutionHistogram(); - // Labels the weight resolution table. - std::cout << "Weight resolutions:" << std::endl; - const auto prepare_weight_entry = []() -> std::ostream& { - return std::cout << std::setw(6) << std::left << std::setfill(' '); - }; - prepare_weight_entry() << "H W"; - for (int resolution_x = 2; resolution_x < kResolutionBuckets; - ++resolution_x) { - prepare_weight_entry() << resolution_x; - } - std::cout << std::endl; - - // Displays table; skips rows/cols {0, 1} since they will always be empty. - for (int resolution_y = 2; resolution_y < kResolutionBuckets; - ++resolution_y) { - prepare_weight_entry() << resolution_y; - for (int resolution_x = 2; resolution_x < kResolutionBuckets; - ++resolution_x) { - const int count = - weight_histogram[resolution_x + resolution_y * kResolutionBuckets]; - prepare_weight_entry(); - if (!count) { - std::cout << "*"; - } else { - std::cout << count; - } - } - std::cout << std::endl; - } - } - - size_t NumBlocks() const { return blocks_.size(); } - - private: - std::vector<std::unique_ptr<Stat>> stats_; - std::vector<IntermediateBlockData> blocks_; -}; - -std::ostream& operator<<(std::ostream& stream, const RgbaColor& color) { - stream << "{"; - constexpr int kNumChannels = std::tuple_size<RgbaColor>::value; - for (int i = 0; i < kNumChannels; ++i) { - stream << color[i]; - if (i < (kNumChannels - 1)) { - stream << ", "; - } - } - return stream << "}"; -} - -void PrintStatsForBlock(const PhysicalASTCBlock& pb, - astc_codec::Footprint footprint) { - const auto print_void_extent = [&pb](const VoidExtentData& void_extent_data) { - std::cout << "Void extent block:" << std::endl; - std::cout << " 16-bit RGBA: {" - << void_extent_data.r << ", " - << void_extent_data.g << ", " - << void_extent_data.b << ", " - << void_extent_data.a << "}" << std::endl; - if (pb.VoidExtentCoords()) { - std::cout << " Extent (S): {" - << void_extent_data.coords[0] << ", " - << void_extent_data.coords[1] << "}" << std::endl; - std::cout << " Extent (T): {" - << void_extent_data.coords[2] << ", " - << void_extent_data.coords[3] << "}" << std::endl; - } else { - std::cout << " No valid extent data" << std::endl; - } - }; - - const auto print_endpoint_data = - [](ColorEndpointMode mode, int endpoint_range, - const std::vector<int>& encoded_vals) { - std::cout << " Endpoint mode: " - << kModeStrings[static_cast<int>(mode)] << std::endl; - std::cout << " Uses blue-contract mode: " - << (UsesBlueContract(endpoint_range, mode, encoded_vals) - ? "true" : "false") - << std::endl; - - RgbaColor endpoint_low, endpoint_high; - DecodeColorsForMode(encoded_vals, endpoint_range, mode, - &endpoint_low, &endpoint_high); - - std::cout << " Low endpoint: " << endpoint_low << std::endl; - std::cout << " High endpoint: " << endpoint_high << std::endl; - }; - - const auto print_color_data = - [&print_endpoint_data, &footprint](const IntermediateBlockData& ib_data) { - const int endpoint_range = ib_data.endpoint_range.value(); - std::cout << "Endpoint range: " << endpoint_range << std::endl; - - const int num_parts = ib_data.endpoints.size(); - if (ib_data.partition_id.hasValue()) { - const int part_id = ib_data.partition_id.value(); - std::cout << "Parititon ID: " << part_id << std::endl; - - const auto part = GetASTCPartition(footprint, num_parts, part_id); - assert(part.assignment.size() == footprint.Height() * footprint.Width()); - - std::cout << "Assignment:" << std::endl; - for (int y = 0; y < footprint.Height(); ++y) { - std::cout << " "; - for (int x = 0; x < footprint.Width(); ++x) { - const int texel_index = y * footprint.Width() + x; - std::cout << " " << part.assignment[texel_index]; - } - std::cout << std::endl; - } - } else { - std::cout << "Single partition" << std::endl; - } - - int endpoint_index = 0; - for (const auto& ep_data : ib_data.endpoints) { - if (num_parts == 1) { - std::cout << "Endpoints:" << std::endl; - } else { - std::cout << "Endpoint " << (endpoint_index++) << ": " << std::endl; - } - print_endpoint_data(ep_data.mode, endpoint_range, ep_data.colors); - } - - if (ib_data.dual_plane_channel) { - std::cout << "Dual plane channel: " - << ib_data.dual_plane_channel.value() << std::endl; - } else { - std::cout << "Single plane" << std::endl; - } - }; - - const auto print_weight_data = - [&footprint](const IntermediateBlockData& ib_data) { - std::cout << "Weight grid dimensions: " - << ib_data.weight_grid_dim_x << "x" << ib_data.weight_grid_dim_y - << std::endl; - std::cout << "Weight range: " << ib_data.weight_range << std::endl; - - std::cout << "Encoded weight grid: " << std::endl; - int weight_idx = 0; - for (int j = 0; j < ib_data.weight_grid_dim_y; ++j) { - std::cout << " "; - for (int i = 0; i < ib_data.weight_grid_dim_x; ++i) { - std::cout << std::setw(3) << std::left << std::setfill(' ') - << ib_data.weights[weight_idx++]; - } - std::cout << std::endl; - } - - std::cout << "Actual weight grid: " << std::endl; - std::vector<int> actual_weights = ib_data.weights; - for (auto& weight : actual_weights) { - weight = astc_codec::UnquantizeWeightFromRange( - weight, ib_data.weight_range); - } - - actual_weights = astc_codec::InfillWeights( - actual_weights, footprint, ib_data.weight_grid_dim_x, - ib_data.weight_grid_dim_y); - - weight_idx = 0; - for (int j = 0; j < footprint.Height(); ++j) { - std::cout << " "; - for (int i = 0; i < footprint.Width(); ++i) { - std::cout << std::setw(3) << std::left << std::setfill(' ') - << actual_weights[weight_idx++]; - } - std::cout << std::endl; - } - }; - - if (pb.IsVoidExtent()) { - Optional<VoidExtentData> ve = astc_codec::UnpackVoidExtent(pb); - if (!ve) { - std::cerr << "ERROR: Failed to unpack void extent block." << std::endl; - } else { - print_void_extent(ve.value()); - } - } else { - Optional<IntermediateBlockData> ib = - astc_codec::UnpackIntermediateBlock(pb); - if (!ib) { - std::cerr << "ERROR: Failed to unpack intermediate block." << std::endl; - } else { - const auto& ib_data = ib.value(); - print_color_data(ib_data); - print_weight_data(ib_data); - } - } -} - -} // namespace - -int main(int argc, char* argv[]) { - bool error = false; - - std::string filename; - size_t block_index = 0; - bool has_block_index = false; - - if (argc >= 2) { - filename = argv[1]; - - if (argc == 3) { - int32_t param = astc_codec::base::ParseInt32(argv[2], -1); - if (param < 0) { - std::cerr << "ERROR: Invalid block index." << std::endl; - error = true; - } else { - block_index = static_cast<size_t>(param); - has_block_index = true; - } - } else if (argc != 2) { - std::cerr << "ERROR: Too many parameters." << std::endl; - error = true; - } - } else { - error = true; - } - - if (error) { - std::cout << ((argc >= 0) ? argv[0] : "astc_inspector_cli") - << " <filename> [<block index>]" << std::endl - << std::endl - << "Collects the various statistics of a stream of ASTC data " - << "stored in an ASTC file." << std::endl - << std::endl - << " filename ASTC file path." << std::endl - << " block index If specified, show detailed information about a block" - << std::endl; - return 1; - } - - std::string error_string; - std::unique_ptr<ASTCFile> astc_file = ASTCFile::LoadFile(argv[1], &error_string); - if (!astc_file) { - std::cerr << "ERROR: " << error_string << std::endl; - return 2; - } - - if (has_block_index) { - Optional<astc_codec::Footprint> footprint = - astc_codec::Footprint::Parse(astc_file->GetFootprintString().c_str()); - if (!footprint) { - std::cerr << "ERROR: Invalid footprint \"" << astc_file->GetFootprintString() << "\"" << std::endl; - return 3; - } - - PrintStatsForBlock(astc_file->GetBlock(block_index), footprint.value()); - } else { - std::cout << "Dimensions: " << astc_file->GetWidth() << "x" - << astc_file->GetHeight() << ", depth " << astc_file->GetDepth() - << std::endl; - - ASTCFileStats stats(astc_file); - - std::cout << std::endl - << "Total bits used: " << 128 * astc_file->NumBlocks() - << " (" << astc_file->NumBlocks() << " blocks, " - << (astc_file->NumBlocks() * 16) << " bytes)" - << std::endl << std::endl; - - stats.PrintStats(); - } - - return 0; -} diff --git a/third-party/astc-codec/src/decoder/types.h b/third-party/astc-codec/src/decoder/types.h deleted file mode 100644 index 728d5adf..00000000 --- a/third-party/astc-codec/src/decoder/types.h +++ /dev/null @@ -1,74 +0,0 @@ -// Copyright 2018 Google LLC -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// https://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -#ifndef ASTC_CODEC_DECODER_ASTC_TYPES_H_ -#define ASTC_CODEC_DECODER_ASTC_TYPES_H_ - -#include <array> -#include <string> -#include <utility> - -namespace astc_codec { - -// The color endpoint mode determines how the values encoded in the ASTC block -// are interpreted in order to create the RGBA values for the given endpoint -// pair. The order of this enum is required to match the ASTC specification in -// Section C.2.14. -enum class ColorEndpointMode { - kLDRLumaDirect = 0, - kLDRLumaBaseOffset, - kHDRLumaLargeRange, - kHDRLumaSmallRange, - kLDRLumaAlphaDirect, - kLDRLumaAlphaBaseOffset, - kLDRRGBBaseScale, - kHDRRGBBaseScale, - kLDRRGBDirect, - kLDRRGBBaseOffset, - kLDRRGBBaseScaleTwoA, - kHDRRGBDirect, - kLDRRGBADirect, - kLDRRGBABaseOffset, - kHDRRGBDirectLDRAlpha, - kHDRRGBDirectHDRAlpha, - - // The total number of color endpoints defined by the ASTC specification. - // This isn't a specific endpoint mode and its sole purpose is to be used - // as a constant number. - kNumColorEndpointModes -}; - -// Returns the class for the given mode as defined in Section C.2.11. -constexpr int EndpointModeClass(ColorEndpointMode mode) { - return static_cast<int>(mode) / 4; -} - -// Returns the number of encoded color values for the given endpoint mode. The -// number of encoded color values and their range determines the size of the -// color data in a physical ASTC block. This information is taken from -// Section C.2.17 of the ASTC specification. -constexpr int NumColorValuesForEndpointMode(ColorEndpointMode mode) { - return (EndpointModeClass(mode) + 1) * 2; -} - -// We define a number of convenience types here that give more logical meaning -// throughout the ASTC utilities. -using RgbColor = std::array<int, 3>; -using RgbaColor = std::array<int, 4>; -using Endpoint = RgbaColor; -using EndpointPair = std::pair<Endpoint, Endpoint>; - -} // namespace astc_codec - -#endif // ASTC_CODEC_DECODER_ASTC_TYPES_H_ diff --git a/third-party/astc-codec/src/decoder/weight_infill.cc b/third-party/astc-codec/src/decoder/weight_infill.cc deleted file mode 100644 index 62909aa6..00000000 --- a/third-party/astc-codec/src/decoder/weight_infill.cc +++ /dev/null @@ -1,122 +0,0 @@ -// Copyright 2018 Google LLC -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// https://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -#include "src/decoder/weight_infill.h" -#include "src/decoder/integer_sequence_codec.h" - -#include <array> -#include <cmath> -#include <utility> - -namespace astc_codec { - -namespace { - -// The following functions are based on Section C.2.18 of the ASTC specification -int GetScaleFactorD(int block_dim) { - return static_cast<int>((1024.f + static_cast<float>(block_dim >> 1)) / - static_cast<float>(block_dim - 1)); -} - -std::pair<int, int> GetGridSpaceCoordinates( - Footprint footprint, int s, int t, int weight_dim_x, int weight_dim_y) { - const int ds = GetScaleFactorD(footprint.Width()); - const int dt = GetScaleFactorD(footprint.Height()); - - const int cs = ds * s; - const int ct = dt * t; - - const int gs = (cs * (weight_dim_x - 1) + 32) >> 6; - const int gt = (ct * (weight_dim_y - 1) + 32) >> 6; - - assert(gt < 1 << 8); - assert(gs < 1 << 8); - - return std::make_pair(gs, gt); -} - -// Returns the weight-grid values that are to be used for bilinearly -// interpolating the weight to its final value. If the returned value -// is equal to weight_dim_x * weight_dim_y, it may be ignored. -std::array<int, 4> BilerpGridPointsForWeight( - const std::pair<int, int>& grid_space_coords, int weight_dim_x) { - const int js = grid_space_coords.first >> 4; - const int jt = grid_space_coords.second >> 4; - - std::array<int, 4> result; - result[0] = js + weight_dim_x * jt; - result[1] = js + weight_dim_x * jt + 1; - result[2] = js + weight_dim_x * (jt + 1); - result[3] = js + weight_dim_x * (jt + 1) + 1; - - return result; -} - -std::array<int, 4> BilerpGridPointFactorsForWeight( - const std::pair<int, int>& grid_space_coords) { - const int fs = grid_space_coords.first & 0xF; - const int ft = grid_space_coords.second & 0xF; - - std::array<int, 4> result; - result[3] = (fs * ft + 8) >> 4; - result[2] = ft - result[3]; - result[1] = fs - result[3]; - result[0] = 16 - fs - ft + result[3]; - - assert(result[0] <= 16); - assert(result[1] <= 16); - assert(result[2] <= 16); - assert(result[3] <= 16); - - return result; -} - -} // namespace - -//////////////////////////////////////////////////////////////////////////////// - -int CountBitsForWeights(int weight_dim_x, int weight_dim_y, - int target_weight_range) { - int num_weights = weight_dim_x * weight_dim_y; - return IntegerSequenceCodec:: - GetBitCountForRange(num_weights, target_weight_range); -} - -std::vector<int> InfillWeights(const std::vector<int>& weights, - Footprint footprint, int dim_x, int dim_y) { - std::vector<int> result; - result.reserve(footprint.NumPixels()); - for (int t = 0; t < footprint.Height(); ++t) { - for (int s = 0; s < footprint.Width(); ++s) { - const auto grid_space_coords = - GetGridSpaceCoordinates(footprint, s, t, dim_x, dim_y); - const auto grid_pts = - BilerpGridPointsForWeight(grid_space_coords, dim_x); - const auto grid_factors = - BilerpGridPointFactorsForWeight(grid_space_coords); - - int weight = 0; - for (int i = 0; i < 4; ++i) { - if (grid_pts[i] < dim_x * dim_y) { - weight += weights.at(grid_pts[i]) * grid_factors[i]; - } - } - result.push_back((weight + 8) >> 4); - } - } - - return result; -} - -} // namespace astc_codec diff --git a/third-party/astc-codec/src/decoder/weight_infill.h b/third-party/astc-codec/src/decoder/weight_infill.h deleted file mode 100644 index 4a09d358..00000000 --- a/third-party/astc-codec/src/decoder/weight_infill.h +++ /dev/null @@ -1,38 +0,0 @@ -// Copyright 2018 Google LLC -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// https://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -#ifndef ASTC_CODEC_DECODER_WEIGHT_INFILL_H_ -#define ASTC_CODEC_DECODER_WEIGHT_INFILL_H_ - -#include "src/decoder/footprint.h" - -#include <vector> - -namespace astc_codec { - -// Returns the number of bits used to represent the weight grid at the target -// dimensions and weight range. -int CountBitsForWeights(int weight_dim_x, int weight_dim_y, - int target_weight_range); - -// Performs weight infill of a grid of weights of size |dim_x * dim_y|. The -// weights are fit using the algorithm laid out in Section C.2.18 of the ASTC -// specification. Weights are expected to be passed unquantized and the returned -// grid will be unquantized as well (i.e. each weight within the range [0, 64]). -std::vector<int> InfillWeights(const std::vector<int>& weights, - Footprint footprint, int dim_x, int dim_y); - -} // namespace astc_codec - -#endif // ASTC_CODEC_DECODER_WEIGHT_INFILL_H_ diff --git a/third-party/astc-codec/third_party/honggfuzz.BUILD b/third-party/astc-codec/third_party/honggfuzz.BUILD deleted file mode 100644 index 67a44bee..00000000 --- a/third-party/astc-codec/third_party/honggfuzz.BUILD +++ /dev/null @@ -1,34 +0,0 @@ -config_setting( - name = "opt", - values = {"compilation_mode": "opt"} -) - -cc_library( - name = "honggfuzz", - srcs = glob([ - "libhfuzz/*.c", - "libhfcommon/*.c", - ], - exclude = ["libhfuzz/linux.c"], - ) + select({ - "@bazel_tools//src/conditions:darwin_x86_64": [], - "@bazel_tools//src/conditions:darwin": [], - "//conditions:default": ["libhfuzz/linux.c"], - }), - hdrs = glob([ - "libhfuzz/*.h", - "libhfcommon/*.h", - "honggfuzz.h", - ]), - defines = select({ - "@bazel_tools//src/conditions:darwin_x86_64": ["_HF_ARCH_DARWIN"], - "@bazel_tools//src/conditions:darwin": ["_HF_ARCH_DARWIN"], - "//conditions:default": ["_HF_ARCH_LINUX", "linux=linux"], - }) + select({ - ":opt": [], - "//conditions:default": ["DEBUG=DEBUG"], - }), - includes = ["."], - visibility = ["//visibility:public"], - linkstatic = 1 -) diff --git a/third-party/astc-codec/tools/bazel.rc b/third-party/astc-codec/tools/bazel.rc deleted file mode 100644 index e47b0069..00000000 --- a/third-party/astc-codec/tools/bazel.rc +++ /dev/null @@ -1,6 +0,0 @@ -# For building with the clang-specific flavor of ASAN. -build:clang-asan --client_env=CC=clang-5.0 -build:clang-asan --copt -g3 -build:clang-asan --copt -fsanitize=address -build:clang-asan --linkopt -fsanitize=address -build:clang-asan --copt -fno-omit-frame-pointer |