// 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 #include #include 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