Implement ASTC support This cl adds both LDR and HDR support for ASTC compressed textures. Only LDR formats are exposed in the PhysicalDevice's properties, but HDR support can be added trivially later by adding the HDR formats and exposing "VK_EXT_texture_compression_astc_hdr". Pulled from: https://github.com/ARM-software/astc-encoder Git hash: 81a5e50741b4c8302cf7d78f314a53e44ee68e1f The astc-encode git repo was added to third-party, with a few minor modifications: 1) All encoding related code has been ripped out, only decoding related code remains 2) Replaced ASTC_CODEC_INTERNAL_ERROR() with UNREACHABLE() in a switch statement in astc_color_unquantize.cpp 3) Some functions were using a lot of stack memory, so I added a unique_ptr to allocate the same objects on the heap, to avoid potential issues. LDR ASTC is decoded to 8bit unsigned RGBA. HDR ASTC is decoded to 32b floating point. Tests: dEQP-VK.*astc* Bug: b/150130101 Change-Id: I6b03fed6e1f326a95c7aefe9f9a9d0a89cf24428 Reviewed-on: https://swiftshader-review.googlesource.com/c/SwiftShader/+/41568 Reviewed-by: Nicolas Capens <nicolascapens@google.com> Tested-by: Nicolas Capens <nicolascapens@google.com> Kokoro-Presubmit: kokoro <noreply+kokoro@google.com>
diff --git a/src/Device/ASTC_Decoder.cpp b/src/Device/ASTC_Decoder.cpp new file mode 100644 index 0000000..344988d --- /dev/null +++ b/src/Device/ASTC_Decoder.cpp
@@ -0,0 +1,127 @@ +// Copyright 2020 The SwiftShader Authors. All Rights Reserved. +// +// 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. + +#include "ASTC_Decoder.hpp" +#include "../third_party/astc-encoder/Source/astc_codec_internals.h" +#include "System/Math.hpp" + +#include <memory> +#include <unordered_map> + +namespace { + +void write_imageblock(unsigned char *img, + // picture-block to initialize with image data. We assume that orig_data is valid + const imageblock *pb, + // output dimensions + int xsize, int ysize, int zsize, + // output format + int bytes, int destPitchB, int destSliceB, bool isUnsignedByte, + // block dimensions + int xdim, int ydim, int zdim, + // position to write the block to + int xpos, int ypos, int zpos) +{ + const float *fptr = pb->orig_data; + const uint8_t *nptr = pb->nan_texel; + + for(int z = 0; z < zdim; z++) + { + for(int y = 0; y < ydim; y++) + { + for(int x = 0; x < xdim; x++) + { + int xi = xpos + x; + int yi = ypos + y; + int zi = zpos + z; + + if(xi >= 0 && yi >= 0 && zi >= 0 && xi < xsize && yi < ysize && zi < zsize) + { + unsigned char *pix = &img[zi * destSliceB + yi * destPitchB + xi * bytes]; + + if(isUnsignedByte) + { + if(*nptr) + { + // NaN-pixel, but we can't display it. Display purple instead. + pix[0] = 0xFF; + pix[1] = 0x00; + pix[2] = 0xFF; + pix[3] = 0xFF; + } + else + { + pix[0] = static_cast<unsigned char>(sw::clamp(fptr[0], 0.0f, 1.0f) * 255.0f + 0.5f); + pix[1] = static_cast<unsigned char>(sw::clamp(fptr[1], 0.0f, 1.0f) * 255.0f + 0.5f); + pix[2] = static_cast<unsigned char>(sw::clamp(fptr[2], 0.0f, 1.0f) * 255.0f + 0.5f); + pix[3] = static_cast<unsigned char>(sw::clamp(fptr[3], 0.0f, 1.0f) * 255.0f + 0.5f); + } + } + else + { + if(*nptr) + { + unsigned int *pixu = reinterpret_cast<unsigned int *>(pix); + pixu[0] = pixu[1] = pixu[2] = pixu[3] = 0x7FFFFFFF; // QNaN + } + else + { + float *pixf = reinterpret_cast<float *>(pix); + pixf[0] = fptr[0]; + pixf[1] = fptr[1]; + pixf[2] = fptr[2]; + pixf[3] = fptr[3]; + } + } + } + fptr += 4; + nptr++; + } + } + } +} + +} // namespace + +void ASTC_Decoder::Decode(const unsigned char *source, unsigned char *dest, + int destWidth, int destHeight, int destDepth, + int bytes, int destPitchB, int destSliceB, + int xBlockSize, int yBlockSize, int zBlockSize, + int xblocks, int yblocks, int zblocks, bool isUnsignedByte) +{ + build_quantization_mode_table(); + + astc_decode_mode decode_mode = isUnsignedByte ? DECODE_LDR : DECODE_HDR; + + std::unique_ptr<block_size_descriptor> bsd(new block_size_descriptor); + init_block_size_descriptor(xBlockSize, yBlockSize, zBlockSize, bsd.get()); + + std::unique_ptr<imageblock> ib(new imageblock); + std::unique_ptr<symbolic_compressed_block> scb(new symbolic_compressed_block); + for(int z = 0; z < zblocks; z++) + { + for(int y = 0; y < yblocks; y++) + { + for(int x = 0; x < xblocks; x++, source += 16) + { + physical_to_symbolic(bsd.get(), *(physical_compressed_block *)source, scb.get()); + decompress_symbolic_block(decode_mode, bsd.get(), x * xBlockSize, y * yBlockSize, z * zBlockSize, scb.get(), ib.get()); + write_imageblock(dest, ib.get(), destWidth, destHeight, destDepth, bytes, destPitchB, destSliceB, isUnsignedByte, + xBlockSize, yBlockSize, zBlockSize, x * xBlockSize, y * yBlockSize, z * zBlockSize); + } + } + } + + term_block_size_descriptor(bsd.get()); +}
diff --git a/src/Device/ASTC_Decoder.hpp b/src/Device/ASTC_Decoder.hpp new file mode 100644 index 0000000..c1a05e5 --- /dev/null +++ b/src/Device/ASTC_Decoder.hpp
@@ -0,0 +1,22 @@ +// Copyright 2020 The SwiftShader Authors. All Rights Reserved. +// +// 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. + +struct ASTC_Decoder +{ + static void Decode(const unsigned char *source, unsigned char *dest, + int destWidth, int destHeight, int destDepth, + int bytes, int destPitchB, int destSliceB, + int xBlockSize, int yBlockSize, int zBlockSize, + int xblocks, int yblocks, int zblocks, bool isUnsignedByte); +}; \ No newline at end of file
diff --git a/src/Device/BUILD.gn b/src/Device/BUILD.gn index 7a874d7..23193f6 100644 --- a/src/Device/BUILD.gn +++ b/src/Device/BUILD.gn
@@ -16,6 +16,7 @@ swiftshader_source_set("Device_headers") { sources = [ + "ASTC_Decoder.hpp", "BC_Decoder.hpp", "Blitter.hpp", "Clipper.hpp", @@ -30,11 +31,14 @@ "Renderer.hpp", "SetupProcessor.hpp", "VertexProcessor.hpp", + "../../third_party/astc-encoder/Source/astc_codec_internals.h", + "../../third_party/astc-encoder/Source/astc_mathlib.h", ] } swiftshader_source_set("Device") { sources = [ + "ASTC_Decoder.cpp", "BC_Decoder.cpp", "Blitter.cpp", "Clipper.cpp", @@ -48,6 +52,18 @@ "Renderer.cpp", "SetupProcessor.cpp", "VertexProcessor.cpp", + "../../third_party/astc-encoder/Source/astc_block_sizes2.cpp", + "../../third_party/astc-encoder/Source/astc_color_unquantize.cpp", + "../../third_party/astc-encoder/Source/astc_decompress_symbolic.cpp", + "../../third_party/astc-encoder/Source/astc_image_load_store.cpp", + "../../third_party/astc-encoder/Source/astc_integer_sequence.cpp", + "../../third_party/astc-encoder/Source/astc_mathlib.cpp", + "../../third_party/astc-encoder/Source/astc_mathlib_softfloat.cpp", + "../../third_party/astc-encoder/Source/astc_partition_tables.cpp", + "../../third_party/astc-encoder/Source/astc_percentile_tables.cpp", + "../../third_party/astc-encoder/Source/astc_quantization.cpp", + "../../third_party/astc-encoder/Source/astc_symbolic_physical.cpp", + "../../third_party/astc-encoder/Source/astc_weight_quant_xfer_tables.cpp", ] include_dirs = [