/* -*- tab-width: 4; -*- */ /* vi: set sw=2 ts=4 expandtab: */ /* * Copyright 2010-2020 Mark Callow. * SPDX-License-Identifier: Apache-2.0 */ /** * @internal * @file * @~English * * @brief Tests of internal API functions. * * @author Mark Callow, github.com/MarkCallow */ #if defined(_WIN32) #define _CRT_SECURE_NO_WARNINGS #if _MSC_VER < 1900 #define snprintf _snprintf #endif #endif #include #include "GL/glcorearb.h" #include "gl_format.h" #include "ktx.h" extern "C" { #include "ktxint.h" #include "filestream.h" #include "memstream.h" } #include "gtest/gtest.h" #include "wthelper.h" #include "ltexceptions.h" // These are so we can test swizzle_to_rgba. Do not put inside "namespace {" // as there is no "namespace {" in basis_encode.cpp where the function is // defined. enum swizzle_e { R = 1, G = 2, B = 3, A = 4, ZERO = 5, ONE = 6, }; extern void swizzle_to_rgba(uint8_t* rgbadst, uint8_t* rgbasrc, uint32_t src_len, ktx_size_t image_size, swizzle_e swizzle[4]); namespace { /////////////////////////////////////////////////////////// // Test fixtures /////////////////////////////////////////////////////////// //-------------------------------------------- // Fixture for CheckHeaderTest //-------------------------------------------- class CheckHeader1Test : public ::testing::Test { protected: CheckHeader1Test() { // Done this way rather than by using an initializer here // so it will compile on VS 2008. memcpy(testHeader.identifier, ktxId, sizeof(ktxId)); testHeader.endianness = 0x04030201; testHeader.glType = GL_UNSIGNED_BYTE; testHeader.glTypeSize = 1; testHeader.glFormat = GL_RGBA; testHeader.glInternalformat = GL_RGBA8; testHeader.glBaseInternalformat = GL_RGBA8; testHeader.pixelWidth = 16; testHeader.pixelHeight = 16; testHeader.pixelDepth = 16; testHeader.numberOfArrayElements = 0; testHeader.numberOfFaces = 1; testHeader.numberOfMipLevels = 5; testHeader.bytesOfKeyValueData = 0; } KTX_header testHeader; public: static ktx_uint8_t ktxId[12]; }; ktx_uint8_t CheckHeader1Test::ktxId[12] = { 0xAB, 0x4B, 0x54, 0x58, 0x20, 0x31, 0x31, 0xBB, 0x0D, 0x0A, 0x1A, 0x0A }; //-------------------------------------------- // Base fixture for WriterTestHelper tests. //-------------------------------------------- template class WriterTestHelperTestBase : public ::testing::Test { public: WriterTestHelperTestBase() { } WriterTestHelper helper; ktx_uint32_t numComponents() { return num_components; } }; class WriterTestHelperRGBA8Test : public WriterTestHelperTestBase { }; class WriterTestHelperRGB8Test : public WriterTestHelperTestBase { }; typedef WriterTestHelper::createFlagBits createFlagBits; ////////////////////////////// // CheckHeaderTest ////////////////////////////// #if defined(DEBUG) TEST_F(CheckHeader1Test, AssertsOnNullArguments) { ASSERT_DEATH_IF_SUPPORTED(ktxCheckHeader1_(0, 0), "Assert*"); } #endif TEST_F(CheckHeader1Test, ValidatesIdentifier) { KTX_supplemental_info suppInfo; EXPECT_EQ(ktxCheckHeader1_(&testHeader, &suppInfo), KTX_SUCCESS); testHeader.identifier[9] = 0; EXPECT_EQ(ktxCheckHeader1_(&testHeader, &suppInfo), KTX_UNKNOWN_FILE_FORMAT); } TEST_F(CheckHeader1Test, DisallowsInvalidEndianness) { KTX_supplemental_info suppInfo; testHeader.endianness = 0; EXPECT_EQ(ktxCheckHeader1_(&testHeader, &suppInfo), KTX_FILE_DATA_ERROR); } ////////////////////////////// // MemStreamTest ////////////////////////////// TEST(MemStreamTest, Read) { ktxStream stream; const ktx_uint8_t* data = (ktx_uint8_t*)"28 bytes of rubbish to read."; const size_t size = 28; char readBuf[size]; ktxMemStream_construct_ro(&stream, data, size); stream.read(&stream, readBuf, size); EXPECT_EQ(memcmp(data, readBuf, size), 0); ktxMemStream_destruct(&stream); } TEST(MemStreamTest, Write) { ktxStream stream; const ktx_uint8_t* data = (ktx_uint8_t*)"29 bytes of rubbish to write."; const size_t count = 29; size_t returnedCount; ktx_uint8_t* returnedData; ktxMemStream_construct(&stream, KTX_TRUE); stream.write(&stream, data, 1, count); stream.getsize(&stream, &returnedCount); ktxMemStream_getdata(&stream, &returnedData); EXPECT_EQ(returnedCount, count); EXPECT_EQ(memcmp(data, returnedData, count), 0); ktxMemStream_destruct(&stream); } TEST(MemStreamTest, WriteExpand) { ktxStream stream; const ktx_uint8_t* data = (ktx_uint8_t*)"29 bytes of rubbish to write."; const ktx_uint8_t* data2 = (ktx_uint8_t*)" 26 more bytes of rubbish."; const size_t count = 29; const size_t count2 = 26; size_t returnedCount; ktx_uint8_t* returnedData; ktxMemStream_construct(&stream, KTX_TRUE); stream.write(&stream, data, 1, count); stream.write(&stream, data2, 1, count2); stream.getsize(&stream, &returnedCount); EXPECT_EQ(returnedCount, count + count2); ktxMemStream_getdata(&stream, &returnedData); EXPECT_EQ(memcmp(data, returnedData, count), 0); EXPECT_EQ(memcmp(data2, &returnedData[count], count2), 0); ktxMemStream_destruct(&stream); } ////////////////////////////// // WriterTestHelper tests. ////////////////////////////// TEST_F(WriterTestHelperRGB8Test, Construct2D) { helper.resize(createFlagBits::eNone, 1, 1, 2, 32, 32, 1); EXPECT_EQ(helper.images.size(), 1U); EXPECT_EQ(helper.images[0].size(), 1U); EXPECT_EQ(helper.images[0][0].size(), 1U); EXPECT_EQ(helper.images[0][0][0].size(), 32 * 32 * 3U); EXPECT_EQ(numComponents(), 3U); } TEST_F(WriterTestHelperRGB8Test, Construct3D) { helper.resize(createFlagBits::eNone, 1, 1, 3, 32, 32, 32); EXPECT_EQ(helper.images.size(), 1U); EXPECT_EQ(helper.images[0].size(), 1U); EXPECT_EQ(helper.images[0][0].size(), 32U); EXPECT_EQ(helper.images[0][0][0].size(), (size_t)(32 * 32 * 3)); EXPECT_EQ(numComponents(), 3U); } ///////////////////////////////////// // Base fixture for createDFD tests. ///////////////////////////////////// // TODO: Move DFD tests to dfdutils when build is redone with CMake. #include #define LIBKTX // To make dfd.h not include vulkan/vulkan_core.h. #include "dfdutils/dfd.h" // Template for single plane formats. template class createDFDTestBase : public ::testing::Test { public: struct sampleType { uint32_t bitOffset: 16; uint32_t bitLength: 8; uint32_t channelType: 8; // Includes qualifiers uint32_t samplePosition0: 8; uint32_t samplePosition1: 8; uint32_t samplePosition2: 8; uint32_t samplePosition3: 8; uint32_t lower; uint32_t upper; }; createDFDTestBase() { expected.vendorId = KHR_DF_VENDORID_KHRONOS; expected.descriptorType = KHR_DF_KHR_DESCRIPTORTYPE_BASICFORMAT; expected.versionNumber = KHR_DF_VERSIONNUMBER_1_3; // sizeof is after template instantiation so BDFD already includes // numComponents samples. expected.descriptorBlockSize = sizeof(BDFD); expected.bytesPlane0 = bytesPlane; expected.bytesPlane1 = 0; expected.bytesPlane2 = 0; expected.bytesPlane3 = 0; expected.bytesPlane4 = 0; expected.bytesPlane5 = 0; expected.bytesPlane6 = 0; expected.bytesPlane7 = 0; } protected: struct BDFD { uint32_t vendorId: 17; uint32_t descriptorType: 15; uint32_t versionNumber: 16; uint32_t descriptorBlockSize: 16; uint32_t model: 8; uint32_t primaries: 8; uint32_t transfer: 8; uint32_t flags: 8; uint32_t texelBlockDimension0: 8; uint32_t texelBlockDimension1: 8; uint32_t texelBlockDimension2: 8; uint32_t texelBlockDimension3: 8; uint32_t bytesPlane0: 8; uint32_t bytesPlane1: 8; uint32_t bytesPlane2: 8; uint32_t bytesPlane3: 8; uint32_t bytesPlane4: 8; uint32_t bytesPlane5: 8; uint32_t bytesPlane6: 8; uint32_t bytesPlane7: 8; sampleType samples[numComponents]; } expected; }; template class createDFDTestBaseUncomp : public createDFDTestBase { using typename createDFDTestBase::sampleType; public: createDFDTestBaseUncomp() : createDFDTestBase() { expected.texelBlockDimension0 = 0; expected.texelBlockDimension1 = 0; expected.texelBlockDimension2 = 0; expected.texelBlockDimension3 = 0; } void customize(ktx_uint8_t model, ktx_uint8_t primaries, ktx_uint8_t transfer, ktx_uint8_t flags, std::initializer_list samples) { expected.model = model; expected.primaries = primaries; expected.transfer = transfer; expected.flags = flags; uint32_t i = 0; // There's got to be some syntax for declaring this in the for for (auto sample : samples ) { expected.samples[i] = sample; if (++i == numComponents) break; } } protected: using createDFDTestBase::expected; }; template class createDFDTestBaseComp : public createDFDTestBase { using typename createDFDTestBase::sampleType; public: createDFDTestBaseComp() : createDFDTestBase() { expected.texelBlockDimension3 = 0; } void customize(ktx_uint8_t model, ktx_uint8_t primaries, ktx_uint8_t transfer, ktx_uint8_t flags, ktx_uint32_t dim0, ktx_uint32_t dim1, ktx_uint32_t dim2, std::initializer_list samples) { expected.model = model; expected.primaries = primaries; expected.transfer = transfer; expected.flags = flags; expected.texelBlockDimension0 = dim0; expected.texelBlockDimension1 = dim1; expected.texelBlockDimension2 = dim2; uint32_t i = 0; // There's got to be some syntax for declaring this in the for for (auto sample : samples ) { expected.samples[i] = sample; if (++i == numComponents) break; } } void customize(ktx_uint8_t model, ktx_uint8_t primaries, ktx_uint8_t transfer, ktx_uint8_t flags, ktx_uint32_t dim0, ktx_uint32_t dim1, std::initializer_list samples) { customize(model, primaries, transfer, flags, dim0, dim1, 0, samples); } protected: using createDFDTestBase::expected; }; class createDFDUnpackedTest4 : public createDFDTestBaseUncomp<4, 4> { }; class createDFDUnpackedTest3 : public createDFDTestBaseUncomp<3, 3> { }; class createDFDPackedTest3 : public createDFDTestBaseUncomp<3, 2> { }; class createDFDCompressedTest1 : public createDFDTestBaseComp<1, 8> { }; class createDFDCompressedTest2 : public createDFDTestBaseComp<2, 16> { }; class createDFDCompressedTest1x16 : public createDFDTestBaseComp<1, 16> { }; ////////////////////////////// // createDFD tests. ////////////////////////////// TEST_F(createDFDUnpackedTest4, FormatSRGBA8) { customize(KHR_DF_MODEL_RGBSDA, KHR_DF_PRIMARIES_BT709, KHR_DF_TRANSFER_SRGB, KHR_DF_FLAG_ALPHA_STRAIGHT, { {0, 7, KHR_DF_CHANNEL_RGBSDA_RED, 0, 0, 0, 0, 0, 255}, {8, 7, KHR_DF_CHANNEL_RGBSDA_GREEN, 0, 0, 0, 0, 0, 255}, {16, 7, KHR_DF_CHANNEL_RGBSDA_BLUE, 0, 0, 0, 0, 0, 255}, {24, 7, KHR_DF_CHANNEL_RGBSDA_ALPHA | KHR_DF_SAMPLE_DATATYPE_LINEAR, 0, 0, 0, 0, 0, 255} } ); uint32_t* dfd = createDFDUnpacked(KTX_FALSE, 4, 1, KTX_FALSE, s_SRGB); EXPECT_EQ(*dfd, sizeof(expected) + 4U); EXPECT_EQ(memcmp(&expected, dfd+1, sizeof(expected)), 0); free(dfd); } TEST_F(createDFDUnpackedTest4, FormatSBGRA8) { customize(KHR_DF_MODEL_RGBSDA, KHR_DF_PRIMARIES_BT709, KHR_DF_TRANSFER_SRGB, KHR_DF_FLAG_ALPHA_STRAIGHT, { {0, 7, KHR_DF_CHANNEL_RGBSDA_BLUE, 0, 0, 0, 0, 0, 255}, {8, 7, KHR_DF_CHANNEL_RGBSDA_GREEN, 0, 0, 0, 0, 0, 255}, {16, 7, KHR_DF_CHANNEL_RGBSDA_RED, 0, 0, 0, 0, 0, 255}, {24, 7, KHR_DF_CHANNEL_RGBSDA_ALPHA | KHR_DF_SAMPLE_DATATYPE_LINEAR, 0, 0, 0, 0, 0, 255} } ); uint32_t* dfd = createDFDUnpacked(KTX_FALSE, 4, 1, KTX_TRUE, s_SRGB); EXPECT_EQ(*dfd, sizeof(expected) + 4U); EXPECT_EQ(memcmp(&expected, dfd+1, sizeof(expected)), 0); free(dfd); } TEST_F(createDFDUnpackedTest4, FormatRGBA8) { customize(KHR_DF_MODEL_RGBSDA, KHR_DF_PRIMARIES_BT709, KHR_DF_TRANSFER_LINEAR, KHR_DF_FLAG_ALPHA_STRAIGHT, { {0, 7, KHR_DF_CHANNEL_RGBSDA_RED, 0, 0, 0, 0, 0, 255}, {8, 7, KHR_DF_CHANNEL_RGBSDA_GREEN, 0, 0, 0, 0, 0, 255}, {16, 7, KHR_DF_CHANNEL_RGBSDA_BLUE, 0, 0, 0, 0, 0, 255}, {24, 7, KHR_DF_CHANNEL_RGBSDA_ALPHA, 0, 0, 0, 0, 0, 255} } ); uint32_t* dfd = createDFDUnpacked(KTX_FALSE, 4, 1, KTX_FALSE, s_UNORM); EXPECT_EQ(*dfd, sizeof(expected) + 4U); EXPECT_EQ(memcmp(&expected, dfd+1, sizeof(expected)), 0); free(dfd); } TEST_F(createDFDUnpackedTest3, FormatSRGB8) { customize(KHR_DF_MODEL_RGBSDA, KHR_DF_PRIMARIES_BT709, KHR_DF_TRANSFER_SRGB, KHR_DF_FLAG_ALPHA_STRAIGHT, { {0, 7, KHR_DF_CHANNEL_RGBSDA_RED, 0, 0, 0, 0, 0, 255}, {8, 7, KHR_DF_CHANNEL_RGBSDA_GREEN, 0, 0, 0, 0, 0, 255}, {16, 7, KHR_DF_CHANNEL_RGBSDA_BLUE, 0, 0, 0, 0, 0, 255}, } ); uint32_t* dfd = createDFDUnpacked(KTX_FALSE, 3, 1, KTX_FALSE, s_SRGB); EXPECT_EQ(*dfd, sizeof(expected) + 4U); EXPECT_EQ(memcmp(&expected, dfd+1, sizeof(expected)), 0); free(dfd); } TEST_F(createDFDPackedTest3, FormatRGB565) { customize(KHR_DF_MODEL_RGBSDA, KHR_DF_PRIMARIES_BT709, KHR_DF_TRANSFER_LINEAR, KHR_DF_FLAG_ALPHA_STRAIGHT, { {0, 4, KHR_DF_CHANNEL_RGBSDA_BLUE, 0, 0, 0, 0, 0, 31}, {5, 5, KHR_DF_CHANNEL_RGBSDA_GREEN, 0, 0, 0, 0, 0, 63}, {11, 4, KHR_DF_CHANNEL_RGBSDA_RED, 0, 0, 0, 0, 0, 31}, } ); // In order from LSB. int bits[] = {5, 6, 5, 0}; int channels[] = { KHR_DF_CHANNEL_RGBSDA_BLUE, KHR_DF_CHANNEL_RGBSDA_GREEN, KHR_DF_CHANNEL_RGBSDA_RED, 0 }; uint32_t* dfd = createDFDPacked(KTX_FALSE, 3, bits, channels, s_UNORM); EXPECT_EQ(*dfd, sizeof(expected) + 4U); EXPECT_EQ(memcmp(&expected, dfd+1, sizeof(expected)), 0); free(dfd); } TEST_F(createDFDCompressedTest1, FormatETC1S_R8B8G8) { customize(KHR_DF_MODEL_ETC1S, KHR_DF_PRIMARIES_BT709, KHR_DF_TRANSFER_LINEAR, KHR_DF_FLAG_ALPHA_STRAIGHT, 3, 3, { {0, 63, KHR_DF_CHANNEL_ETC1S_RGB , 0, 0, 0, 0, 0, 0xFFFFFFFF}, } ); uint32_t* dfd = createDFDCompressed(c_ETC1S, 4, 4, 1, s_UNORM); EXPECT_EQ(*dfd, sizeof(expected) + 4U); EXPECT_EQ(memcmp(&expected, dfd+1, sizeof(expected)), 0); free(dfd); } TEST_F(createDFDCompressedTest1, FormatETC1S_SR8B8G8) { customize(KHR_DF_MODEL_ETC1S, KHR_DF_PRIMARIES_BT709, KHR_DF_TRANSFER_SRGB, KHR_DF_FLAG_ALPHA_STRAIGHT, 3, 3, { {0, 63, KHR_DF_CHANNEL_ETC1S_RGB, 0, 0, 0, 0, 0, 0xFFFFFFFF}, } ); uint32_t* dfd = createDFDCompressed(c_ETC1S, 4, 4, 1, s_SRGB); EXPECT_EQ(*dfd, sizeof(expected) + 4U); EXPECT_EQ(memcmp(&expected, dfd+1, sizeof(expected)), 0); free(dfd); } TEST_F(createDFDCompressedTest1, FormatETC2_R8B8G8) { customize(KHR_DF_MODEL_ETC2, KHR_DF_PRIMARIES_BT709, KHR_DF_TRANSFER_LINEAR, KHR_DF_FLAG_ALPHA_STRAIGHT, 3, 3, { {0, 63, KHR_DF_CHANNEL_ETC2_COLOR, 0, 0, 0, 0, 0, 0xFFFFFFFF}, } ); uint32_t* dfd = createDFDCompressed(c_ETC2_R8G8B8, 4, 4, 1, s_UNORM); EXPECT_EQ(*dfd, sizeof(expected) + 4U); EXPECT_EQ(memcmp(&expected, dfd+1, sizeof(expected)), 0); free(dfd); } TEST_F(createDFDCompressedTest2, FormatETC2_R8G8B8A8) { customize(KHR_DF_MODEL_ETC2, KHR_DF_PRIMARIES_BT709, KHR_DF_TRANSFER_LINEAR, KHR_DF_FLAG_ALPHA_STRAIGHT, 3, 3, { {0, 63, KHR_DF_CHANNEL_ETC2_ALPHA, 0, 0, 0, 0, 0, 0xFFFFFFFF}, {64, 63, KHR_DF_CHANNEL_ETC2_COLOR, 0, 0, 0, 0, 0, 0xFFFFFFFF}, } ); uint32_t* dfd = createDFDCompressed(c_ETC2_R8G8B8A8, 4, 4, 1, s_UNORM); EXPECT_EQ(*dfd, sizeof(expected) + 4U); EXPECT_EQ(memcmp(&expected, dfd+1, sizeof(expected)), 0); free(dfd); } TEST_F(createDFDCompressedTest1, FormatETC2_SR8B8G8) { customize(KHR_DF_MODEL_ETC2, KHR_DF_PRIMARIES_BT709, KHR_DF_TRANSFER_SRGB, KHR_DF_FLAG_ALPHA_STRAIGHT, 3, 3, { {0, 63, KHR_DF_CHANNEL_ETC2_COLOR, 0, 0, 0, 0, 0, 0xFFFFFFFF}, } ); uint32_t* dfd = createDFDCompressed(c_ETC2_R8G8B8, 4, 4, 1, s_SRGB); EXPECT_EQ(*dfd, sizeof(expected) + 4U); EXPECT_EQ(memcmp(&expected, dfd+1, sizeof(expected)), 0); free(dfd); } TEST_F(createDFDCompressedTest2, FormatETC2_SR8G8B8A8) { customize(KHR_DF_MODEL_ETC2, KHR_DF_PRIMARIES_BT709, KHR_DF_TRANSFER_SRGB, KHR_DF_FLAG_ALPHA_STRAIGHT, 3, 3, { {0, 63, KHR_DF_CHANNEL_ETC2_ALPHA | KHR_DF_SAMPLE_DATATYPE_LINEAR, 0, 0, 0, 0, 0, 0xFFFFFFFF}, {64, 63, KHR_DF_CHANNEL_ETC2_COLOR, 0, 0, 0, 0, 0, 0xFFFFFFFF}, } ); uint32_t* dfd = createDFDCompressed(c_ETC2_R8G8B8A8, 4, 4, 1, s_SRGB); EXPECT_EQ(*dfd, sizeof(expected) + 4U); EXPECT_EQ(memcmp(&expected, dfd+1, sizeof(expected)), 0); free(dfd); } TEST_F(createDFDCompressedTest1x16, FormatASTC_12x12_SRGB) { customize(KHR_DF_MODEL_ASTC, KHR_DF_PRIMARIES_BT709, KHR_DF_TRANSFER_SRGB, KHR_DF_FLAG_ALPHA_STRAIGHT, 11, 11, { {0, 127, KHR_DF_CHANNEL_ASTC_DATA, 0, 0, 0, 0, 0, 0xFFFFFFFF}, } ); uint32_t* dfd = createDFDCompressed(c_ASTC, 12, 12, 1, s_SRGB); EXPECT_EQ(*dfd, sizeof(expected) + 4U); EXPECT_EQ(memcmp(&expected, dfd+1, sizeof(expected)), 0); free(dfd); } TEST_F(createDFDCompressedTest1x16, FormatASTC_10x5_SRGB) { customize(KHR_DF_MODEL_ASTC, KHR_DF_PRIMARIES_BT709, KHR_DF_TRANSFER_SRGB, KHR_DF_FLAG_ALPHA_STRAIGHT, 9, 4, { {0, 127, KHR_DF_CHANNEL_ASTC_DATA, 0, 0, 0, 0, 0, 0xFFFFFFFF}, } ); uint32_t* dfd = createDFDCompressed(c_ASTC, 10, 5, 1, s_SRGB); EXPECT_EQ(*dfd, sizeof(expected) + 4U); EXPECT_EQ(memcmp(&expected, dfd+1, sizeof(expected)), 0); free(dfd); } TEST_F(createDFDCompressedTest1x16, FormatASTC_5x4) { customize(KHR_DF_MODEL_ASTC, KHR_DF_PRIMARIES_BT709, KHR_DF_TRANSFER_LINEAR, KHR_DF_FLAG_ALPHA_STRAIGHT, 4, 3, { {0, 127, KHR_DF_CHANNEL_ASTC_DATA, 0, 0, 0, 0, 0, 0xFFFFFFFF}, } ); uint32_t* dfd = createDFDCompressed(c_ASTC, 5, 4, 1, s_UNORM); EXPECT_EQ(*dfd, sizeof(expected) + 4U); EXPECT_EQ(memcmp(&expected, dfd+1, sizeof(expected)), 0); free(dfd); } TEST_F(createDFDCompressedTest1x16, FormatASTC_10x8) { customize(KHR_DF_MODEL_ASTC, KHR_DF_PRIMARIES_BT709, KHR_DF_TRANSFER_LINEAR, KHR_DF_FLAG_ALPHA_STRAIGHT, 9, 7, { {0, 127, KHR_DF_CHANNEL_ASTC_DATA, 0, 0, 0, 0, 0, 0xFFFFFFFF}, } ); uint32_t* dfd = createDFDCompressed(c_ASTC, 10, 8, 1, s_UNORM); EXPECT_EQ(*dfd, sizeof(expected) + 4U); EXPECT_EQ(memcmp(&expected, dfd+1, sizeof(expected)), 0); free(dfd); } TEST_F(createDFDCompressedTest1x16, FormatASTC_3x3x3) { customize(KHR_DF_MODEL_ASTC, KHR_DF_PRIMARIES_BT709, KHR_DF_TRANSFER_LINEAR, KHR_DF_FLAG_ALPHA_STRAIGHT, 2, 2, 2, { {0, 127, KHR_DF_CHANNEL_ASTC_DATA, 0, 0, 0, 0, 0, 0xFFFFFFFF}, } ); uint32_t* dfd = createDFDCompressed(c_ASTC, 3, 3, 3, s_UNORM); EXPECT_EQ(*dfd, sizeof(expected) + 4U); EXPECT_EQ(memcmp(&expected, dfd+1, sizeof(expected)), 0); free(dfd); } TEST_F(createDFDCompressedTest1, FormatBC1) { customize(KHR_DF_MODEL_BC1A, KHR_DF_PRIMARIES_BT709, KHR_DF_TRANSFER_LINEAR, KHR_DF_FLAG_ALPHA_STRAIGHT, 3, 3, { {0, 63, KHR_DF_CHANNEL_BC1A_COLOR, 0, 0, 0, 0, 0, 0xFFFFFFFF}, } ); uint32_t* dfd = createDFDCompressed(c_BC1_RGB, 4, 4, 1, s_UNORM); EXPECT_EQ(*dfd, sizeof(expected) + 4U); EXPECT_EQ(memcmp(&expected, dfd+1, sizeof(expected)), 0); free(dfd); } class DFDVkFormatListTest : public ::testing::Test { protected: DFDVkFormatListTest() {} static constexpr VkFormat formats[] = { #include "vkformat_list.inl" }; }; extern "C" const char* vkFormatString(VkFormat format); TEST_F(DFDVkFormatListTest, ReconstructDFDBytesPlanes) { uint32_t* dfd; uint32_t* bdb; uint32_t origBytesPlane03, origBytesPlane47; for (uint32_t i = 0; i < sizeof(formats) / sizeof(VkFormat); i++) { dfd = vk2dfd(formats[i]); ASSERT_TRUE(dfd != NULL) << "vk2dfd failed to produce DFD for " << vkFormatString(formats[i]); bdb = dfd + 1; // There are 4 bytesPlane values in one word. Capture all at once. origBytesPlane03 = bdb[KHR_DF_WORD_BYTESPLANE0]; origBytesPlane47 = bdb[KHR_DF_WORD_BYTESPLANE4]; bdb[KHR_DF_WORD_BYTESPLANE0] = 0U; bdb[KHR_DF_WORD_BYTESPLANE1] = 0U; reconstructDFDBytesPlanesFromSamples(dfd); EXPECT_EQ(origBytesPlane03, bdb[KHR_DF_WORD_BYTESPLANE0]); EXPECT_EQ(origBytesPlane47, bdb[KHR_DF_WORD_BYTESPLANE4]); free(dfd); } // No need to test reconstruction for UASTC as, colorModel aside, the DFD // is identical to that for VK_FORMAT_ASTC_4x4_BLOCK_UNORM which has been // tested above. // Make ETC1S DFDs and test reconstruction. for (uint32_t sampleCount = 1; sampleCount < 3; sampleCount++) { uint32_t bdbSize = KHR_DF_WORD_SAMPLESTART + sampleCount * KHR_DF_WORD_SAMPLEWORDS; bdbSize *= sizeof(uint32_t); uint32_t dfdSize = bdbSize + 1 * sizeof(uint32_t); dfd = new uint32_t[dfdSize]; bdb = dfd + 1; KHR_DFDSETVAL(bdb, VENDORID, KHR_DF_VENDORID_KHRONOS); KHR_DFDSETVAL(bdb, DESCRIPTORTYPE, KHR_DF_KHR_DESCRIPTORTYPE_BASICFORMAT); KHR_DFDSETVAL(bdb, VERSIONNUMBER, KHR_DF_VERSIONNUMBER_LATEST); KHR_DFDSETVAL(bdb, DESCRIPTORBLOCKSIZE, bdbSize); KHR_DFDSETVAL(bdb, MODEL, KHR_DF_MODEL_ETC1S); KHR_DFDSETVAL(bdb, PRIMARIES, KHR_DF_PRIMARIES_BT709); KHR_DFDSETVAL(bdb, TRANSFER, KHR_DF_TRANSFER_SRGB); KHR_DFDSETVAL(bdb, FLAGS, 0); bdb[KHR_DF_WORD_TEXELBLOCKDIMENSION0] = 3 | (3 << KHR_DF_SHIFT_TEXELBLOCKDIMENSION1); bdb[KHR_DF_WORD_BYTESPLANE0] = 0; /* bytesPlane3..0 = 0 */ //KHR_DFDSETVAL(nbdb, BYTESPLANE0, 8); //if (sampleCoount == 2) // KHR_DFDSETVAL(nbdb, BYTESPLANE1, 8); bdb[KHR_DF_WORD_BYTESPLANE4] = 0; /* bytesPlane7..5 = 0 */ for (uint32_t sample = 0; sample < sampleCount; sample++) { uint16_t channelId, bitOffset; if (sample == 0) { bitOffset = 0; channelId = KHR_DF_CHANNEL_ETC1S_RGB; } else { bitOffset = 64; channelId = KHR_DF_CHANNEL_ETC1S_AAA; } KHR_DFDSETSVAL(bdb, sample, CHANNELID, channelId); KHR_DFDSETSVAL(bdb, sample, QUALIFIERS, 0); KHR_DFDSETSVAL(bdb, sample, SAMPLEPOSITION_ALL, 0); KHR_DFDSETSVAL(bdb, sample, BITOFFSET, bitOffset); KHR_DFDSETSVAL(bdb, sample, BITLENGTH, 63); KHR_DFDSETSVAL(bdb, sample, SAMPLELOWER, 0); KHR_DFDSETSVAL(bdb, sample, SAMPLEUPPER, UINT32_MAX); } reconstructDFDBytesPlanesFromSamples(dfd); EXPECT_EQ(8U, KHR_DFDVAL(bdb, BYTESPLANE0)); if (sampleCount == 2) EXPECT_EQ(8U, KHR_DFDVAL(bdb, BYTESPLANE1)); else EXPECT_EQ(0U, KHR_DFDVAL(bdb, BYTESPLANE1)); EXPECT_EQ(0U, KHR_DFDVAL(bdb, BYTESPLANE2)); EXPECT_EQ(0U, KHR_DFDVAL(bdb, BYTESPLANE3)); EXPECT_EQ(0U, bdb[KHR_DF_WORD_BYTESPLANE4]); delete[] dfd; } } TEST_F(DFDVkFormatListTest, BidirectionalVk2DfDTest) { for (uint32_t i = 0; i < sizeof(formats) / sizeof(VkFormat); i++) { uint32_t* dfd = vk2dfd(formats[i]); ASSERT_TRUE(dfd != NULL) << "vk2dfd failed to produce DFD for " << vkFormatString(formats[i]); VkFormat formatOut = dfd2vk(dfd); // The SCALED formats are indistinguishable from the INT formats // and dfd2vk resolves the ambiguity in favor of the format more // likely to be used as a texture. // // The A8B8G8R8_*_PACK32 formats are indistinguishable from the // R8G8B8A8* formats and dfd2vk returns the more common format. switch (formats[i]) { case VK_FORMAT_R8_USCALED: EXPECT_EQ(formatOut, VK_FORMAT_R8_UINT); break; case VK_FORMAT_R8_SSCALED: EXPECT_EQ(formatOut, VK_FORMAT_R8_SINT); break; case VK_FORMAT_R8G8_USCALED: EXPECT_EQ(formatOut, VK_FORMAT_R8G8_UINT); break; case VK_FORMAT_R8G8_SSCALED: EXPECT_EQ(formatOut, VK_FORMAT_R8G8_SINT); break; case VK_FORMAT_B8G8R8_USCALED: EXPECT_EQ(formatOut, VK_FORMAT_B8G8R8_UINT); break; case VK_FORMAT_B8G8R8_SSCALED: EXPECT_EQ(formatOut, VK_FORMAT_B8G8R8_SINT); break; case VK_FORMAT_R8G8B8_USCALED: EXPECT_EQ(formatOut, VK_FORMAT_R8G8B8_UINT); break; case VK_FORMAT_R8G8B8_SSCALED: EXPECT_EQ(formatOut, VK_FORMAT_R8G8B8_SINT); break; case VK_FORMAT_R8G8B8A8_USCALED: EXPECT_EQ(formatOut, VK_FORMAT_R8G8B8A8_UINT); break; case VK_FORMAT_R8G8B8A8_SSCALED: EXPECT_EQ(formatOut, VK_FORMAT_R8G8B8A8_SINT); break; case VK_FORMAT_B8G8R8A8_USCALED: EXPECT_EQ(formatOut, VK_FORMAT_B8G8R8A8_UINT); break; case VK_FORMAT_B8G8R8A8_SSCALED: EXPECT_EQ(formatOut, VK_FORMAT_B8G8R8A8_SINT); break; case VK_FORMAT_A8B8G8R8_USCALED_PACK32: EXPECT_EQ(formatOut, VK_FORMAT_R8G8B8A8_UINT); break; case VK_FORMAT_A8B8G8R8_SSCALED_PACK32: EXPECT_EQ(formatOut, VK_FORMAT_R8G8B8A8_SINT); break; case VK_FORMAT_A8B8G8R8_UINT_PACK32: EXPECT_EQ(formatOut, VK_FORMAT_R8G8B8A8_UINT); break; case VK_FORMAT_A8B8G8R8_SINT_PACK32: EXPECT_EQ(formatOut, VK_FORMAT_R8G8B8A8_SINT); break; case VK_FORMAT_A8B8G8R8_SRGB_PACK32: EXPECT_EQ(formatOut, VK_FORMAT_R8G8B8A8_SRGB); break; case VK_FORMAT_A2R10G10B10_USCALED_PACK32: EXPECT_EQ(formatOut, VK_FORMAT_A2R10G10B10_UINT_PACK32); break; case VK_FORMAT_A2R10G10B10_SSCALED_PACK32: EXPECT_EQ(formatOut, VK_FORMAT_A2R10G10B10_SINT_PACK32); break; case VK_FORMAT_A2B10G10R10_USCALED_PACK32: EXPECT_EQ(formatOut, VK_FORMAT_A2B10G10R10_UINT_PACK32); break; case VK_FORMAT_A2B10G10R10_SSCALED_PACK32: EXPECT_EQ(formatOut, VK_FORMAT_A2B10G10R10_SINT_PACK32); break; case VK_FORMAT_R16_USCALED: EXPECT_EQ(formatOut, VK_FORMAT_R16_UINT); break; case VK_FORMAT_R16_SSCALED: EXPECT_EQ(formatOut, VK_FORMAT_R16_SINT); break; case VK_FORMAT_R16G16_USCALED: EXPECT_EQ(formatOut, VK_FORMAT_R16G16_UINT); break; case VK_FORMAT_R16G16_SSCALED: EXPECT_EQ(formatOut, VK_FORMAT_R16G16_SINT); break; case VK_FORMAT_R16G16B16_USCALED: EXPECT_EQ(formatOut, VK_FORMAT_R16G16B16_UINT); break; case VK_FORMAT_R16G16B16_SSCALED: EXPECT_EQ(formatOut, VK_FORMAT_R16G16B16_SINT); break; case VK_FORMAT_R16G16B16A16_USCALED: EXPECT_EQ(formatOut, VK_FORMAT_R16G16B16A16_UINT); break; case VK_FORMAT_R16G16B16A16_SSCALED: EXPECT_EQ(formatOut, VK_FORMAT_R16G16B16A16_SINT); break; case VK_FORMAT_A8B8G8R8_UNORM_PACK32: EXPECT_EQ(formatOut, VK_FORMAT_R8G8B8A8_UNORM); break; case VK_FORMAT_A8B8G8R8_SNORM_PACK32: EXPECT_EQ(formatOut, VK_FORMAT_R8G8B8A8_SNORM); break; default: EXPECT_EQ(formatOut, formats[i]); } free(dfd); } } ////////////////////////////// // HashListTest Fixture ////////////////////////////// class HashListTest : public ::testing::Test { protected: HashListTest() : writerVal("HashListTest"), orientationVal("ruo") { } void constructList(bool sort) { KTX_error_code result; ktxHashList_Construct(&head); result = ktxHashList_AddKVPair(&head, KTX_WRITER_KEY, (ktx_uint32_t)writerVal.length() + 1, writerVal.c_str()); EXPECT_EQ(result, KTX_SUCCESS); result = ktxHashList_AddKVPair(&head, KTX_ORIENTATION_KEY, (ktx_uint32_t)orientationVal.length() + 1, orientationVal.c_str()); EXPECT_EQ(result, KTX_SUCCESS); if (sort) { ktxHashList_Sort(&head); sorted = true; } } void checkList() { compareList(head, sorted); } void compareList(ktxHashList list, bool isSorted) { ktxHashListEntry* entry = list; ktx_uint32_t entryCount = 0; for (; entry != NULL; entry = ktxHashList_Next(entry)) { char* key; ktx_uint8_t* value; ktx_uint32_t keyLen, valueLen; entryCount++; ktxHashListEntry_GetKey(entry, &keyLen, &key); ktxHashListEntry_GetValue(entry, &valueLen, (void**)&value); if (isSorted) { switch (entryCount) { case 1: EXPECT_STREQ(key, KTX_ORIENTATION_KEY); break; case 2: EXPECT_STREQ(key, KTX_WRITER_KEY); break; default: break; } } if (strcmp(key, KTX_ORIENTATION_KEY) == 0) EXPECT_EQ(orientationVal.compare((char*)value), 0); else if (strcmp(key, KTX_WRITER_KEY) == 0) EXPECT_EQ(writerVal.compare((char*)value), 0); else EXPECT_TRUE(false); } EXPECT_EQ(entryCount, 2U); } ktxHashList head; std::string writerVal; std::string orientationVal; bool sorted; }; ////////////////////////////// // HashListTests ////////////////////////////// TEST_F(HashListTest, ConstructSorted) { constructList(true); checkList(); } TEST_F(HashListTest, ConstructCopy) { ktxHashList copyHead; constructList(true); ktxHashList_ConstructCopy(©Head, head); compareList(copyHead, true); } /////////////////////// // Swizzle test fixture /////////////////////// template class SwizzleTestBase : public ::testing::Test { public: SwizzleTestBase() { std::vector color; // Use swizzle enumerator values for easy checking of result. std::vector defaultColor = { R, G, B, A }; color.resize(num_components); for (uint32_t i = 0; i < num_components; i++) { color[i] = defaultColor[i]; } helper.resize(createFlagBits::eNone, 1, 1, 2, width, height, 1, &color); } void runTest(swizzle_e swizzle[4]) { ktxTexture2* texture; ktx_error_code_e result; helper.texinfo.vkFormat = vkGetFormatFromOpenGLInternalFormat(helper.texinfo.glInternalformat); result = ktxTexture2_Create(&helper.texinfo, KTX_TEXTURE_CREATE_ALLOC_STORAGE, &texture); ASSERT_TRUE(result == KTX_SUCCESS); ASSERT_TRUE(texture != NULL) << "ktxTexture_Create failed: " << ktxErrorString(result); ASSERT_TRUE(texture->pData != NULL) << "Image storage not allocated"; result = helper.copyImagesToTexture(ktxTexture(texture)); ASSERT_TRUE(result == KTX_SUCCESS); size_t destByteLen = width * height * 4 * sizeof(GLubyte); size_t srcByteLen = width * height * num_components * sizeof(GLubyte); typedef GLubyte color[4]; color* dest = (color*)malloc(destByteLen); memset(dest, 0x7f, destByteLen); swizzle_to_rgba((uint8_t*)dest, texture->pData, num_components, srcByteLen, swizzle); for (uint32_t i = 0; i < width * height; i++) { for (uint32_t c = 0; c < 4; c++) { if (swizzle[c] == ZERO) EXPECT_EQ(dest[i][c], 0); else if (swizzle[c] == ONE) EXPECT_EQ(dest[i][c], 255); else EXPECT_EQ(swizzle[c], dest[i][c]) << "c = " << c << ", i = " << i; } } } protected: WriterTestHelper helper; const unsigned int width = 16; const unsigned int height = 16; }; class SwizzleToRGBATestR8 : public SwizzleTestBase<1, GL_R8> { }; class SwizzleToRGBATestRG8 : public SwizzleTestBase<2, GL_RG8> { }; class SwizzleToRGBATestRGB8 : public SwizzleTestBase<3, GL_RGB8> { }; class SwizzleToRGBATestRGBA8 : public SwizzleTestBase<4, GL_RGBA8> { }; //////////////////////// // swizzle_to_rgba tests //////////////////////// TEST_F(SwizzleToRGBATestR8, RRRONE) { swizzle_e r_to_rgba_mapping[4] = { R, R, R, ONE }; runTest(r_to_rgba_mapping); } TEST_F(SwizzleToRGBATestRG8, RRRG) { swizzle_e r_to_rgba_mapping[4] = { R, R, R, G }; runTest(r_to_rgba_mapping); } TEST_F(SwizzleToRGBATestRGB8, RGBONE) { swizzle_e r_to_rgba_mapping[4] = { R, G, B, ONE }; runTest(r_to_rgba_mapping); } TEST_F(SwizzleToRGBATestRGB8, RRRG) { swizzle_e r_to_rgba_mapping[4] = { R, R, R, G }; runTest(r_to_rgba_mapping); } TEST_F(SwizzleToRGBATestRGBA8, RGBA) { swizzle_e r_to_rgba_mapping[4] = { R, G, B, A }; runTest(r_to_rgba_mapping); } TEST_F(SwizzleToRGBATestRGBA8, RRRG) { swizzle_e r_to_rgba_mapping[4] = { R, R, R, G }; runTest(r_to_rgba_mapping); } TEST_F(SwizzleToRGBATestRGBA8, BGRA) { swizzle_e r_to_rgba_mapping[4] = { B, G, R, A }; runTest(r_to_rgba_mapping); } TEST_F(SwizzleToRGBATestRGBA8, BGRZERO) { swizzle_e r_to_rgba_mapping[4] = { B, G, R, ZERO }; runTest(r_to_rgba_mapping); } TEST_F(SwizzleToRGBATestRGBA8, ARGB) { swizzle_e r_to_rgba_mapping[4] = { A, R, G, B }; runTest(r_to_rgba_mapping); } ////////////////////////////// // LoadTest exceptions tests ////////////////////////////// #define OUT_OF_HOST_MEMORY -1 #define OUT_OF_DEVICE_MEMORY -2 #define FRAGMENTED_POOL -12 #define OUT_OF_POOL_MEMORY -1000069000 TEST(BadVulkanAllocExceptionTest, NoDeviceMemory) { try { throw bad_vulkan_alloc(OUT_OF_DEVICE_MEMORY, "no device memory test"); } catch (bad_vulkan_alloc& e) { EXPECT_EQ(strcmp(e.what(), "Out of device memory for no device memory test."), 0); } } TEST(BadVulkanAllocExceptionTest, NoHostMemory) { try { throw bad_vulkan_alloc(OUT_OF_HOST_MEMORY, "no host memory test"); } catch (bad_vulkan_alloc& e) { EXPECT_EQ(strcmp(e.what(), "Out of host memory for no host memory test."), 0); } } TEST(BadVulkanAllocExceptionTest, NoPoolMemory) { try { throw bad_vulkan_alloc(OUT_OF_POOL_MEMORY, "no pool memory test"); } catch (bad_vulkan_alloc& e) { EXPECT_EQ(strcmp(e.what(), "Out of pool memory for no pool memory test."), 0); } } TEST(BadVulkanAllocExceptionTest, PoolFragmented) { try { throw bad_vulkan_alloc(FRAGMENTED_POOL, "fragmented pool memory test"); } catch (bad_vulkan_alloc& e) { EXPECT_EQ(strcmp(e.what(), "Pool fragmented when allocating for fragmented pool memory test."), 0); } } } // namespace