aboutsummaryrefslogtreecommitdiff
path: root/src/decoder/codec.cc
diff options
context:
space:
mode:
Diffstat (limited to 'src/decoder/codec.cc')
-rw-r--r--src/decoder/codec.cc132
1 files changed, 132 insertions, 0 deletions
diff --git a/src/decoder/codec.cc b/src/decoder/codec.cc
new file mode 100644
index 0000000..c0f8c07
--- /dev/null
+++ b/src/decoder/codec.cc
@@ -0,0 +1,132 @@
+// 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