3212 lines
128 KiB
C++
3212 lines
128 KiB
C++
/* -*- tab-width: 4; -*- */
|
|
/* vi: set sw=2 ts=4 expandtab: */
|
|
|
|
/**
|
|
* @internal
|
|
* @file
|
|
* @~English
|
|
*
|
|
* @brief Test ktxTexture API functions.
|
|
*
|
|
* @author Mark Callow, github.com/MarkCallow
|
|
*/
|
|
|
|
/*
|
|
* Copyright 2010-2020 Mark Callow, <khronos at callow dot im>.
|
|
* SPDX-License-Identifier: Apache-2.0
|
|
*/
|
|
|
|
#if defined(_WIN32)
|
|
#define _CRT_SECURE_NO_WARNINGS
|
|
#if _MSC_VER < 1900
|
|
#define snprintf _snprintf
|
|
#endif
|
|
#endif
|
|
|
|
#include <filesystem>
|
|
#include <fstream>
|
|
#include <iostream>
|
|
#include <string>
|
|
//#include <sys/types.h>
|
|
#include <sys/stat.h>
|
|
#include <limits.h>
|
|
#include <stdint.h>
|
|
#include <string.h>
|
|
#include "GL/glcorearb.h"
|
|
#include "ktx.h"
|
|
#include "ktxint.h"
|
|
#include "texture.h"
|
|
#include "texture1.h"
|
|
#include "texture2.h"
|
|
#include "gtest/gtest.h"
|
|
#include "wthelper.h"
|
|
#include "vk_format.h"
|
|
|
|
#define ROUNDING(x) \
|
|
(3 - ((x + KTX_GL_UNPACK_ALIGNMENT-1) % KTX_GL_UNPACK_ALIGNMENT));
|
|
|
|
#if defined(TestNoMetadata)
|
|
extern ktx_bool_t __disableWriterMetadata__;
|
|
#endif
|
|
|
|
namespace {
|
|
|
|
namespace fs = std::filesystem;
|
|
|
|
// Recursive function to return the greatest common divisor of a and b.
|
|
static uint32_t
|
|
gcd(uint32_t a, uint32_t b) {
|
|
if (a == 0)
|
|
return b;
|
|
return gcd(b % a, a);
|
|
}
|
|
|
|
// Function to return the least common multiple of a & 4.
|
|
uint32_t
|
|
lcm4(uint32_t a)
|
|
{
|
|
if (!(a & 0x03))
|
|
return a; // a is a multiple of 4.
|
|
return (a*4) / gcd(a, 4);
|
|
}
|
|
|
|
//-------------------------------------------------------
|
|
// Helper for base fixture & ktxTexture_WriterTest cases.
|
|
//-------------------------------------------------------
|
|
|
|
template<typename component_type, ktx_uint32_t numComponents,
|
|
GLenum internalformat>
|
|
class TextureWriterTestHelper
|
|
: public WriterTestHelper<component_type, numComponents, internalformat> {
|
|
public:
|
|
using typename WriterTestHelper<component_type, numComponents, internalformat>::createFlags;
|
|
using typename WriterTestHelper<component_type, numComponents, internalformat>::createFlagBits;
|
|
using WriterTestHelper<component_type, numComponents, internalformat>::images;
|
|
using WriterTestHelper<component_type, numComponents, internalformat>::imageList;
|
|
using WriterTestHelper<component_type, numComponents, internalformat>::width;
|
|
using WriterTestHelper<component_type, numComponents, internalformat>::height;
|
|
using WriterTestHelper<component_type, numComponents, internalformat>::levelsFromSize;
|
|
|
|
TextureWriterTestHelper() {}
|
|
|
|
void
|
|
resize(createFlags flags, ktx_uint32_t layers, ktx_uint32_t faces,
|
|
ktx_uint32_t dimensions,
|
|
ktx_uint32_t w, ktx_uint32_t h, ktx_uint32_t d)
|
|
{
|
|
WriterTestHelper<component_type, numComponents, internalformat>::resize(
|
|
flags, layers, faces,
|
|
dimensions,
|
|
w, h, d);
|
|
createInfo.resize(flags, layers, faces,
|
|
dimensions, w, h, d);
|
|
}
|
|
|
|
// Compare images as loaded into a ktxTexture1 object with our image.
|
|
bool
|
|
compareTexture1Images(ktx_uint8_t* pData)
|
|
{
|
|
for (ktx_uint32_t level = 0; level < images.size(); level++) {
|
|
ktx_uint32_t levelWidth = MAX(1, width >> level);
|
|
ktx_uint32_t levelHeight = MAX(1, height >> level);
|
|
ktx_size_t rowBytes = levelWidth * sizeof(component_type) * numComponents;
|
|
ktx_uint32_t rowPadding = ROUNDING(rowBytes);
|
|
ktx_size_t paddedImageBytes = (rowBytes + rowPadding) * levelHeight;
|
|
for (ktx_uint32_t layer = 0; layer < images[0].size(); layer++) {
|
|
for (ktx_uint32_t faceSlice = 0; faceSlice < images[level][layer].size(); faceSlice++) {
|
|
if (rowPadding == 0) {
|
|
if (memcmp(images[level][layer][faceSlice].data(), pData,
|
|
images[level][layer][faceSlice].size() * sizeof(component_type)))
|
|
return false;
|
|
pData += paddedImageBytes;
|
|
} else {
|
|
ktx_uint8_t* pImage = (ktx_uint8_t*)images[level][layer][faceSlice].data();
|
|
for (ktx_uint32_t row = 0; row < levelHeight; row++) {
|
|
if (memcmp(pImage, pData, rowBytes))
|
|
return false;
|
|
pImage += rowBytes;
|
|
pData += rowBytes + rowPadding;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
return true;
|
|
}
|
|
|
|
// Compare images as loaded into a ktxTexture2 object with our image.
|
|
bool
|
|
compareTexture2Images(ktx_uint8_t* pData)
|
|
{
|
|
for (ktx_int32_t level = (ktx_int32_t)images.size() - 1; level >= 0; level--) {
|
|
ktx_uint32_t levelWidth = MAX(1, width >> level);
|
|
ktx_uint32_t levelHeight = MAX(1, height >> level);
|
|
ktx_uint32_t texelBlockSize = sizeof(component_type) * numComponents;
|
|
ktx_uint32_t requiredLevelAlignment = lcm4(texelBlockSize);
|
|
ktx_size_t rowBytes = levelWidth * texelBlockSize;
|
|
ktx_size_t imageBytes = rowBytes * levelHeight;
|
|
for (ktx_uint32_t layer = 0; layer < images[0].size(); layer++) {
|
|
for (ktx_uint32_t faceSlice = 0; faceSlice < images[level][layer].size(); faceSlice++) {
|
|
if (memcmp(images[level][layer][faceSlice].data(), pData,
|
|
images[level][layer][faceSlice].size() * sizeof(component_type)))
|
|
return false;
|
|
pData += imageBytes;
|
|
}
|
|
}
|
|
pData += _KTX_PADN_LEN(requiredLevelAlignment, imageBytes);
|
|
}
|
|
return true;
|
|
}
|
|
|
|
KTX_error_code
|
|
copyImagesToTexture(ktxTexture1* texture) {
|
|
KTX_error_code result = KTX_SUCCESS;
|
|
|
|
for (ktx_uint32_t level = 0; level < images.size(); level++) {
|
|
for (ktx_uint32_t layer = 0; layer < images[level].size(); layer++) {
|
|
for (ktx_uint32_t faceSlice = 0; faceSlice < images[level][layer].size(); faceSlice++) {
|
|
ktx_size_t imageBytes = images[level][layer][faceSlice].size() * sizeof(component_type);
|
|
ktx_uint8_t* imageDataPtr = (ktx_uint8_t*)(images[level][layer][faceSlice].data());
|
|
result = ktxTexture1_SetImageFromMemory(texture,
|
|
level, layer,
|
|
faceSlice,
|
|
imageDataPtr,
|
|
imageBytes);
|
|
if (result != KTX_SUCCESS)
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
return result;
|
|
}
|
|
|
|
class createInfo : public ktxTextureCreateInfo {
|
|
public:
|
|
createInfo() {
|
|
glInternalformat = internalformat;
|
|
}
|
|
|
|
void resize(createFlags flags,
|
|
ktx_uint32_t layers, ktx_uint32_t faces,
|
|
ktx_uint32_t dimensions, ktx_uint32_t w,
|
|
ktx_uint32_t h, ktx_uint32_t d)
|
|
{
|
|
baseWidth = w;
|
|
baseHeight = h;
|
|
baseDepth = d;
|
|
this->numDimensions = dimensions;
|
|
generateMipmaps = flags & createFlagBits::eGenerateMipmaps
|
|
? KTX_TRUE : KTX_FALSE;
|
|
isArray = flags & createFlagBits::eArray ? KTX_TRUE : KTX_FALSE;
|
|
this->numFaces = faces;
|
|
this->numLayers = layers;
|
|
numLevels = flags & createFlagBits::eMipmapped
|
|
? levelsFromSize(w, h, d) : 1;
|
|
};
|
|
} createInfo;
|
|
|
|
};
|
|
|
|
const ktx_uint8_t ktxId[12] = KTX_IDENTIFIER_REF;
|
|
const ktx_uint8_t ktxId2[12] = KTX2_IDENTIFIER_REF;
|
|
|
|
///////////////////////////////////////////////////////////
|
|
// Test fixtures
|
|
///////////////////////////////////////////////////////////
|
|
|
|
//----------------------------------------------------
|
|
// Base fixture for ktxTexture and related test cases.
|
|
//----------------------------------------------------
|
|
|
|
typedef TextureWriterTestHelper<GLubyte, 4, GL_RGBA8>::createFlagBits createFlagBits;
|
|
|
|
template<typename component_type, ktx_uint32_t numComponents,
|
|
GLenum internalformat>
|
|
class ktxTextureTestBase : public ::testing::Test {
|
|
protected:
|
|
ktxTextureTestBase(ktxFormatVersionEnum fv) : pixelSize(16)
|
|
{
|
|
helper.resize(createFlagBits::eMipmapped, 1, 1, 2, 16, 16, 1);
|
|
// Create a KTX file in memory for testing.
|
|
|
|
KTX_error_code errorCode;
|
|
|
|
ktxMemFile = 0;
|
|
iterCbCalls = 0;
|
|
|
|
mipLevels = helper.numLevels;
|
|
|
|
// Create the in-memory KTX file
|
|
|
|
ktxTexture* texture = 0;
|
|
if (fv == KTX_FORMAT_VERSION_ONE) {
|
|
kvDataLen = helper.kvDataLen;
|
|
kvData = helper.kvData;
|
|
errorCode = ktxTexture1_Create(&texinfo,
|
|
KTX_TEXTURE_CREATE_ALLOC_STORAGE,
|
|
(ktxTexture1**)&texture);
|
|
} else {
|
|
kvDataLen = helper.kvDataLenWriter_ktx2;
|
|
kvData = helper.kvDataWriter_ktx2;
|
|
texinfo.vkFormat
|
|
= vkGetFormatFromOpenGLInternalFormat(texinfo.glInternalformat);
|
|
errorCode = ktxTexture2_Create(&texinfo,
|
|
KTX_TEXTURE_CREATE_ALLOC_STORAGE,
|
|
(ktxTexture2**)&texture);
|
|
texture->kvDataHead = helper.kvHash_ktx2;
|
|
}
|
|
if (KTX_SUCCESS != errorCode) {
|
|
ADD_FAILURE() << "ktxTexture"
|
|
<< (fv == KTX_FORMAT_VERSION_ONE ? "1" : "2")
|
|
<< "_Create failed: "
|
|
<< ktxErrorString(errorCode);
|
|
return;
|
|
}
|
|
|
|
// Don't use the above helper.copyImagesToTexture because that is used
|
|
// by various test cases which will compare their results against this.
|
|
// A different code path here provides a small extra correctness check.
|
|
std::vector<wthImageInfo>::const_iterator it = images.begin();
|
|
for (ktx_uint32_t level = 0; level < texinfo.numLevels; level++) {
|
|
ktx_uint32_t levelDepth = MAX(1, texinfo.baseDepth >> level);
|
|
for (ktx_uint32_t layer = 0; layer < texinfo.numLayers; layer++) {
|
|
ktx_uint32_t numImages = texinfo.numFaces == 6
|
|
? texinfo.numFaces : levelDepth;
|
|
for (ktx_uint32_t faceSlice = 0; faceSlice < numImages; faceSlice++) {
|
|
ktxTexture_SetImageFromMemory(texture,
|
|
level, layer, faceSlice,
|
|
it->data, it->size);
|
|
}
|
|
}
|
|
it++;
|
|
}
|
|
|
|
paddedImageDataSize = texture->dataSize;
|
|
texture->kvData = kvData;
|
|
texture->kvDataLen = kvDataLen;
|
|
errorCode = ktxTexture_WriteToMemory(texture, &ktxMemFile,
|
|
&ktxMemFileLen);
|
|
if (KTX_SUCCESS != errorCode) {
|
|
ADD_FAILURE() << "ktxTexture_WriteToMemory failed: "
|
|
<< ktxErrorString(errorCode);
|
|
}
|
|
}
|
|
|
|
~ktxTextureTestBase() {
|
|
delete ktxMemFile;
|
|
}
|
|
|
|
KTX_error_code
|
|
iterCallback(int miplevel, int /*face*/,
|
|
int width, int /*height*/, int /*depth*/,
|
|
ktx_uint64_t faceLodSize,
|
|
void* pixels)
|
|
{
|
|
int expectedWidth = pixelSize >> miplevel;
|
|
EXPECT_EQ(width, expectedWidth);
|
|
EXPECT_EQ(faceLodSize, (uint64_t)(expectedWidth * expectedWidth * 4));
|
|
EXPECT_EQ(memcmp(pixels, images[miplevel].data, images[miplevel].size),
|
|
0);
|
|
iterCbCalls++;
|
|
return KTX_SUCCESS;
|
|
}
|
|
|
|
static KTX_error_code
|
|
iterCallback(int miplevel, int face,
|
|
int width, int height, int depth,
|
|
ktx_uint64_t faceLodSize,
|
|
void* pixels, void* userdata)
|
|
{
|
|
ktxTextureTestBase* fixture = (ktxTextureTestBase*)userdata;
|
|
return fixture->iterCallback(miplevel, face, width, height, depth,
|
|
faceLodSize, pixels);
|
|
}
|
|
|
|
TextureWriterTestHelper<component_type, numComponents, internalformat> helper;
|
|
wthTexInfo& texinfo = helper.texinfo;
|
|
ktxTextureCreateInfo& createInfo = helper.createInfo;
|
|
unsigned char* kvData;
|
|
unsigned int kvDataLen;
|
|
|
|
ktx_uint8_t* ktxMemFile;
|
|
ktx_size_t ktxMemFileLen;
|
|
const int pixelSize;
|
|
unsigned int mipLevels;
|
|
unsigned int iterCbCalls;
|
|
|
|
ktx_size_t paddedImageDataSize;
|
|
ktx_size_t& imageDataSize = helper.imageDataSize;
|
|
std::vector< std::vector < std::vector < std::vector<GLubyte> > > >& imageData = helper.images;
|
|
|
|
std::vector<wthImageInfo>& images = helper.imageList;
|
|
};
|
|
|
|
class ktxTexture1TestBase : public ktxTextureTestBase<GLubyte, 4, GL_RGBA8> {
|
|
protected:
|
|
ktxTexture1TestBase() : ktxTextureTestBase(KTX_FORMAT_VERSION_ONE) { }
|
|
|
|
bool
|
|
compareTexture(ktxTexture1* texture)
|
|
{
|
|
if (texture->glInternalformat != texinfo.glInternalformat)
|
|
return false;
|
|
if (texture->glBaseInternalformat != texinfo.glBaseInternalformat)
|
|
return false;
|
|
if (texture->glFormat != texinfo.glFormat)
|
|
return false;
|
|
if (texture->glType != texinfo.glType)
|
|
return false;
|
|
if (ktxTexture1_glTypeSize(texture) != texinfo.glTypeSize)
|
|
return false;
|
|
if (texture->baseWidth != texinfo.baseWidth)
|
|
return false;
|
|
if (texinfo.baseHeight == 0) {
|
|
if (texture->baseHeight != 1)
|
|
return false;
|
|
} else if (texture->baseHeight != texinfo.baseHeight)
|
|
return false;
|
|
if (texinfo.baseDepth == 0) {
|
|
if (texture->baseDepth != 1)
|
|
return false;
|
|
} else if (texture->baseDepth != texinfo.baseDepth)
|
|
return false;
|
|
if (texture->numFaces != texinfo.numFaces)
|
|
return false;
|
|
if (texture->numLevels != texinfo.numLevels)
|
|
return false;
|
|
return true;
|
|
}
|
|
};
|
|
|
|
|
|
template<typename component_type,
|
|
ktx_uint32_t numComponents,
|
|
GLenum internalformat>
|
|
class ktxTexture2TestBase : public ktxTextureTestBase<component_type,
|
|
numComponents,
|
|
internalformat>
|
|
{
|
|
protected:
|
|
using ktxTextureTestBase<component_type, numComponents, internalformat>::helper;
|
|
using ktxTextureTestBase<component_type, numComponents, internalformat>::texinfo;
|
|
|
|
ktxTexture2TestBase() : ktxTextureTestBase<component_type, numComponents, internalformat>(KTX_FORMAT_VERSION_TWO) { }
|
|
|
|
bool
|
|
compareTexture(ktxTexture2* texture)
|
|
{
|
|
if (texture->vkFormat != (uint32_t)vkGetFormatFromOpenGLInternalFormat(helper.texinfo.glInternalformat))
|
|
return false;
|
|
if (texture->baseWidth != texinfo.baseWidth)
|
|
return false;
|
|
if (texinfo.baseHeight == 0) {
|
|
if (texture->baseHeight != 1)
|
|
return false;
|
|
} else if (texture->baseHeight != texinfo.baseHeight)
|
|
return false;
|
|
if (texinfo.baseDepth == 0) {
|
|
if (texture->baseDepth != 1)
|
|
return false;
|
|
} else if (texture->baseDepth != texinfo.baseDepth)
|
|
return false;
|
|
if (texture->numFaces != texinfo.numFaces)
|
|
return false;
|
|
if (texture->numLevels != texinfo.numLevels)
|
|
return false;
|
|
return true;
|
|
}
|
|
};
|
|
|
|
class ktxTexture2_CreateTest : public ::testing::Test {
|
|
protected:
|
|
ktx_error_code_e create(VkFormat format,
|
|
ktx_uint32_t width = 16u,
|
|
ktx_uint32_t height = 16u,
|
|
ktx_uint32_t depth = 1u,
|
|
ktx_uint32_t dimensions = 2u,
|
|
ktx_uint32_t levels = 1u,
|
|
ktx_uint32_t layers = 1u,
|
|
ktx_uint32_t faces = 1u,
|
|
bool isArray = false,
|
|
bool generateMipmaps = false)
|
|
{
|
|
ktxTextureCreateInfo createInfo;
|
|
createInfo.vkFormat = format;
|
|
createInfo.baseWidth = width;
|
|
createInfo.baseHeight = height;
|
|
createInfo.baseDepth = depth;
|
|
createInfo.numDimensions = dimensions;
|
|
createInfo.numLevels = levels;
|
|
createInfo.numLayers = layers;
|
|
createInfo.numFaces = faces;
|
|
createInfo.isArray = isArray;
|
|
createInfo.generateMipmaps = generateMipmaps;
|
|
|
|
return ktxTexture2_Create(&createInfo,
|
|
KTX_TEXTURE_CREATE_ALLOC_STORAGE,
|
|
&texture);
|
|
}
|
|
|
|
~ktxTexture2_CreateTest() {
|
|
ktxTexture_Destroy(ktxTexture(texture));
|
|
}
|
|
|
|
ktxTexture2* texture;
|
|
};
|
|
|
|
//----------------------------------------------------
|
|
// Template for base fixture for ktxTextureWrite tests.
|
|
//----------------------------------------------------
|
|
|
|
template<typename component_type, ktx_uint32_t numComponents,
|
|
GLenum internalformat>
|
|
class ktxTexture1WriteTestBase : public ::testing::Test {
|
|
public:
|
|
using createFlags = typename WriterTestHelper<component_type, numComponents, internalformat>::createFlags;
|
|
ktxTexture1WriteTestBase() { }
|
|
|
|
void runTest(bool writeMetadata) {
|
|
ktxTexture1* texture = 0;
|
|
KTX_error_code result;
|
|
ktx_uint8_t* ktxMemFile;
|
|
ktx_size_t ktxMemFileLen;
|
|
ktx_uint8_t* filePtr;
|
|
|
|
result = ktxTexture1_Create(&helper.createInfo,
|
|
KTX_TEXTURE_CREATE_ALLOC_STORAGE,
|
|
&texture);
|
|
EXPECT_EQ(result, KTX_SUCCESS);
|
|
ASSERT_TRUE(texture != NULL) << "ktxTexture1_Create failed: "
|
|
<< ktxErrorString(result);
|
|
|
|
if (writeMetadata)
|
|
ktxHashList_AddKVPair(&texture->kvDataHead, KTX_ORIENTATION_KEY,
|
|
(unsigned int)strlen(helper.orientation) + 1,
|
|
helper.orientation);
|
|
|
|
result = helper.copyImagesToTexture(texture);
|
|
ASSERT_TRUE(result == KTX_SUCCESS);
|
|
|
|
EXPECT_EQ(helper.compareTexture1Images(texture->pData), true);
|
|
result = ktxTexture1_WriteToMemory(texture, &ktxMemFile, &ktxMemFileLen);
|
|
|
|
ASSERT_TRUE(result == KTX_SUCCESS) << "ktxTexture_WriteToMemory failed: "
|
|
<< ktxErrorString(result);
|
|
EXPECT_EQ(memcmp(ktxMemFile, ktxId, sizeof(ktxId)), 0);
|
|
EXPECT_EQ(helper.texinfo.compare((KTX_header*)ktxMemFile), true);
|
|
|
|
// Check the metadata.
|
|
filePtr = ktxMemFile + sizeof(KTX_header);
|
|
if (writeMetadata) {
|
|
EXPECT_EQ(memcmp(filePtr, helper.kvData, helper.kvDataLen), 0);
|
|
filePtr += helper.kvDataLen;
|
|
}
|
|
// Check data pointer is properly aligned.
|
|
EXPECT_EQ((intptr_t)filePtr & 0x3, 0);
|
|
|
|
EXPECT_EQ(helper.compareRawImages(filePtr), true);
|
|
|
|
delete ktxMemFile;
|
|
ktxTexture1_Destroy(texture);
|
|
}
|
|
|
|
TextureWriterTestHelper<component_type, numComponents, internalformat> helper;
|
|
};
|
|
|
|
//---------------------------
|
|
// Actual test fixtures
|
|
//---------------------------
|
|
|
|
class ktxTexture_CreateTest : public ktxTexture1TestBase { };
|
|
class ktxTexture1_CreateTest : public ktxTexture1TestBase { };
|
|
class ktxTexture_KVDataTest : public ktxTexture1TestBase { };
|
|
class ktxTexture1_IterateLoadLevelFacesTest : public ktxTexture1TestBase { };
|
|
class ktxTexture1_IterateLevelFacesTest : public ktxTexture1TestBase { };
|
|
class ktxTexture1_LoadImageDataTest : public ktxTexture1TestBase { };
|
|
|
|
class ktxTexture1WriteTestRGBA8 : public ktxTexture1WriteTestBase<GLubyte, 4, GL_RGBA8> { };
|
|
class ktxTexture1WriteTestRGB8 : public ktxTexture1WriteTestBase<GLubyte, 3, GL_RGB8> { };
|
|
class ktxTexture1WriteTestRG16 : public ktxTexture1WriteTestBase<GLushort, 2, GL_RG16> { };
|
|
|
|
class ktxTexture2_IterateLoadLevelFacesTest : public ktxTexture2TestBase<GLubyte, 4, GL_RGBA8> { };
|
|
class ktxTexture2_IterateLevelFacesTest : public ktxTexture2TestBase<GLubyte, 4, GL_RGBA8> { };
|
|
class ktxTexture2_IterateLevelsTest : public ktxTexture2TestBase<GLubyte, 4, GL_RGBA8> { };
|
|
class ktxTexture2_LoadImageDataTest : public ktxTexture2TestBase<GLubyte, 4, GL_RGBA8> { };
|
|
class ktxTexture2_CreateCopyTest: public ktxTexture2TestBase<GLubyte, 4, GL_RGBA8> { };
|
|
|
|
/////////////////////////////////////////
|
|
// ktxTexture_Create tests
|
|
////////////////////////////////////////
|
|
|
|
TEST_F(ktxTexture1_CreateTest, InvalidValueOnNullParams) {
|
|
ktxTexture* texture = 0;
|
|
|
|
EXPECT_EQ(ktxTexture_CreateFromStdioStream(0, 0, &texture),
|
|
KTX_INVALID_VALUE);
|
|
EXPECT_EQ(ktxTexture_CreateFromNamedFile(0, 0, &texture),
|
|
KTX_INVALID_VALUE);
|
|
EXPECT_EQ(ktxTexture_CreateFromMemory(0, 0, 0, &texture),
|
|
KTX_INVALID_VALUE);
|
|
//EXPECT_EQ(ktxTexture_CreateFromStdioStream(0, 0, 0),
|
|
// KTX_INVALID_VALUE);
|
|
EXPECT_EQ(ktxTexture_CreateFromNamedFile("foo", 0, 0),
|
|
KTX_INVALID_VALUE);
|
|
EXPECT_EQ(ktxTexture_CreateFromMemory(ktxMemFile, ktxMemFileLen, 0, 0),
|
|
KTX_INVALID_VALUE);
|
|
}
|
|
|
|
TEST_F(ktxTexture_CreateTest, ConstructFromMemory) {
|
|
ktxTexture* texture = 0;
|
|
KTX_error_code result;
|
|
|
|
if (ktxMemFile != NULL) {
|
|
result = ktxTexture_CreateFromMemory(ktxMemFile, ktxMemFileLen,
|
|
0, &texture);
|
|
EXPECT_EQ(result, KTX_SUCCESS);
|
|
ASSERT_TRUE(texture != NULL) << "ktxTexture_CreateFromMemory failed: "
|
|
<< ktxErrorString(result);
|
|
EXPECT_EQ(texture->classId, ktxTexture1_c);
|
|
EXPECT_EQ(compareTexture((ktxTexture1*)texture), true);
|
|
EXPECT_EQ(texture->isCompressed, KTX_FALSE);
|
|
EXPECT_EQ(texture->generateMipmaps, KTX_FALSE);
|
|
EXPECT_EQ(texture->numDimensions, 2U);
|
|
EXPECT_EQ(texture->numLayers, 1U);
|
|
EXPECT_EQ(texture->isArray, KTX_FALSE);
|
|
if (texture)
|
|
ktxTexture_Destroy(texture);
|
|
}
|
|
}
|
|
|
|
TEST_F(ktxTexture1_CreateTest, ConstructFromMemory) {
|
|
ktxTexture1* texture = 0;
|
|
KTX_error_code result;
|
|
|
|
if (ktxMemFile != NULL) {
|
|
result = ktxTexture1_CreateFromMemory(ktxMemFile, ktxMemFileLen,
|
|
0, &texture);
|
|
EXPECT_EQ(result, KTX_SUCCESS);
|
|
ASSERT_TRUE(texture != NULL) << "ktxTexture_CreateFromMemory failed: "
|
|
<< ktxErrorString(result);
|
|
EXPECT_EQ(compareTexture(texture), true);
|
|
EXPECT_EQ(texture->isCompressed, KTX_FALSE);
|
|
EXPECT_EQ(texture->generateMipmaps, KTX_FALSE);
|
|
EXPECT_EQ(texture->numDimensions, 2U);
|
|
EXPECT_EQ(texture->numLayers, 1U);
|
|
EXPECT_EQ(texture->isArray, KTX_FALSE);
|
|
if (texture)
|
|
ktxTexture1_Destroy(texture);
|
|
}
|
|
}
|
|
|
|
TEST_F(ktxTexture1_CreateTest, CreateEmpty) {
|
|
ktxTexture1* texture = 0;
|
|
KTX_error_code result;
|
|
|
|
result = ktxTexture1_Create(&createInfo, KTX_TEXTURE_CREATE_NO_STORAGE,
|
|
&texture);
|
|
EXPECT_EQ(result, KTX_SUCCESS);
|
|
ASSERT_TRUE(texture != NULL) << "ktxTexture1_Create failed: "
|
|
<< ktxErrorString(result);
|
|
if (texture)
|
|
ktxTexture1_Destroy(texture);
|
|
}
|
|
|
|
TEST_F(ktxTexture1_CreateTest, InvalidValueTooManyMipLevels) {
|
|
ktxTexture1* texture = 0;
|
|
|
|
createInfo.numLevels += 1;
|
|
|
|
EXPECT_EQ(ktxTexture1_Create(&createInfo, KTX_TEXTURE_CREATE_NO_STORAGE, &texture),
|
|
KTX_INVALID_OPERATION);
|
|
}
|
|
|
|
TEST_F(ktxTexture1_CreateTest, InvalidOpOnSetImagesNoStorage) {
|
|
ktxTexture1* texture = 0;
|
|
KTX_error_code result;
|
|
|
|
result = ktxTexture1_Create(&createInfo, KTX_TEXTURE_CREATE_NO_STORAGE,
|
|
&texture);
|
|
EXPECT_EQ(result, KTX_SUCCESS);
|
|
ASSERT_TRUE(texture != NULL) << "ktxTexture1_Create failed: "
|
|
<< ktxErrorString(result);
|
|
|
|
// Type RGBA UNSIGNED_BYTE -> *4
|
|
ktx_size_t imageBytes = imageData[0].size() * 4;
|
|
ktx_uint8_t* imageDataPtr = (ktx_uint8_t*)(&imageData[0].front());
|
|
// Allocate the image data and initialize it to a color.
|
|
EXPECT_EQ(ktxTexture1_SetImageFromMemory(texture, 0, 0, 0,
|
|
imageDataPtr,
|
|
imageBytes),
|
|
KTX_INVALID_OPERATION);
|
|
ASSERT_TRUE(result == KTX_SUCCESS);
|
|
|
|
if (texture)
|
|
ktxTexture1_Destroy(texture);
|
|
}
|
|
|
|
TEST_F(ktxTexture1_CreateTest, CreateEmptyAndSetImages) {
|
|
ktxTexture1* texture = 0;
|
|
KTX_error_code result;
|
|
|
|
result = ktxTexture1_Create(&createInfo, KTX_TEXTURE_CREATE_ALLOC_STORAGE,
|
|
&texture);
|
|
EXPECT_EQ(result, KTX_SUCCESS);
|
|
ASSERT_TRUE(texture != NULL) << "ktxTexture1_Create failed: "
|
|
<< ktxErrorString(result);
|
|
|
|
result = helper.copyImagesToTexture(texture);
|
|
ASSERT_TRUE(result == KTX_SUCCESS);
|
|
// imageData is an RGBA texture so no rounding is necessary and we can
|
|
// use this simple comparison.
|
|
EXPECT_EQ(helper.compareTexture1Images(texture->pData), true);
|
|
|
|
if (texture)
|
|
ktxTexture1_Destroy(texture);
|
|
}
|
|
|
|
TEST_F(ktxTexture1_CreateTest, CreateEmptySetImagesWriteToMemory) {
|
|
ktxTexture1* texture = 0;
|
|
KTX_error_code result;
|
|
ktx_uint8_t* testMemFile;
|
|
ktx_size_t testMemFileLen;
|
|
char orientation[10];
|
|
|
|
result = ktxTexture1_Create(&createInfo, KTX_TEXTURE_CREATE_ALLOC_STORAGE,
|
|
&texture);
|
|
EXPECT_EQ(result, KTX_SUCCESS);
|
|
ASSERT_TRUE(texture != NULL) << "ktxTexture1_Create failed: "
|
|
<< ktxErrorString(result);
|
|
|
|
snprintf(orientation, sizeof(orientation), KTX_ORIENTATION2_FMT,
|
|
'r', 'd');
|
|
ktxHashList_AddKVPair(&texture->kvDataHead, KTX_ORIENTATION_KEY,
|
|
(unsigned int)strlen(orientation) + 1,
|
|
orientation);
|
|
result = helper.copyImagesToTexture(texture);
|
|
ASSERT_TRUE(result == KTX_SUCCESS);
|
|
EXPECT_EQ(helper.compareTexture1Images(texture->pData), true);
|
|
EXPECT_EQ(ktxTexture1_WriteToMemory(texture, &testMemFile, &testMemFileLen),
|
|
KTX_SUCCESS);
|
|
EXPECT_EQ(testMemFileLen, ktxMemFileLen);
|
|
EXPECT_EQ(memcmp(testMemFile, ktxMemFile, ktxMemFileLen), 0);
|
|
|
|
if (texture)
|
|
ktxTexture1_Destroy(texture);
|
|
}
|
|
|
|
/////////////////////////////////////////
|
|
// ktxTexture2_Create tests
|
|
////////////////////////////////////////
|
|
|
|
TEST_F(ktxTexture2_CreateTest, E5B9G9R9) {
|
|
ktx_error_code_e result = create(VK_FORMAT_E5B9G9R9_UFLOAT_PACK32);
|
|
EXPECT_EQ(result, KTX_SUCCESS);
|
|
}
|
|
|
|
/////////////////////////////////////////
|
|
// ktxTexture_KVData tests
|
|
////////////////////////////////////////
|
|
|
|
TEST_F(ktxTexture_KVDataTest, KVDataDeserialized) {
|
|
ktxTexture* texture = 0;
|
|
KTX_error_code result;
|
|
|
|
if (ktxMemFile != NULL) {
|
|
result = ktxTexture_CreateFromMemory(ktxMemFile, ktxMemFileLen,
|
|
0,
|
|
&texture);
|
|
EXPECT_EQ(result, KTX_SUCCESS);
|
|
ASSERT_TRUE(texture != NULL) << "ktxTexture_CreateFromMemory failed: "
|
|
<< ktxErrorString(result);
|
|
ASSERT_TRUE(texture->kvData == NULL) << "Raw KVData should not be loaded";
|
|
ASSERT_TRUE(texture->kvDataHead != NULL) << "KVData not deserialized";
|
|
|
|
char* pValue;
|
|
ktx_uint32_t valueLen;
|
|
char s, t;
|
|
result = ktxHashList_FindValue(&texture->kvDataHead,
|
|
KTX_ORIENTATION_KEY,
|
|
&valueLen, (void**)&pValue);
|
|
EXPECT_EQ(result, KTX_SUCCESS);
|
|
EXPECT_EQ(sscanf(pValue, /*valueLen,*/ KTX_ORIENTATION2_FMT, &s, &t), 2);
|
|
EXPECT_EQ(s,'r');
|
|
EXPECT_EQ(t, 'd');
|
|
if (texture)
|
|
ktxTexture_Destroy(texture);
|
|
}
|
|
}
|
|
|
|
TEST_F(ktxTexture_KVDataTest, LoadRawKVData) {
|
|
ktxTexture* texture = 0;
|
|
KTX_error_code result;
|
|
|
|
if (ktxMemFile != NULL) {
|
|
result = ktxTexture_CreateFromMemory(ktxMemFile, ktxMemFileLen,
|
|
KTX_TEXTURE_CREATE_RAW_KVDATA_BIT,
|
|
&texture);
|
|
EXPECT_EQ(result, KTX_SUCCESS);
|
|
ASSERT_TRUE(texture != NULL) << "ktxTexture_CreateFromMemory failed: "
|
|
<< ktxErrorString(result);
|
|
ASSERT_TRUE(texture->kvData != NULL) << "Raw KVData not loaded";
|
|
ASSERT_TRUE(texture->kvDataHead == NULL) << "KVData should not be deserialized";
|
|
EXPECT_EQ(texture->kvDataLen, kvDataLen) << "Length of KV data incorrect";
|
|
EXPECT_EQ(memcmp(texture->kvData, kvData, kvDataLen), 0);
|
|
if (texture)
|
|
ktxTexture_Destroy(texture);
|
|
}
|
|
}
|
|
|
|
TEST_F(ktxTexture_KVDataTest, SkipKVData) {
|
|
ktxTexture* texture = 0;
|
|
KTX_error_code result;
|
|
|
|
if (ktxMemFile != NULL) {
|
|
result = ktxTexture_CreateFromMemory(ktxMemFile, ktxMemFileLen,
|
|
KTX_TEXTURE_CREATE_SKIP_KVDATA_BIT,
|
|
&texture);
|
|
EXPECT_EQ(result, KTX_SUCCESS);
|
|
ASSERT_TRUE(texture != NULL) << "ktxTexture_CreateFromMemory failed: "
|
|
<< ktxErrorString(result);
|
|
ASSERT_TRUE(texture->kvData == NULL) << "Raw KVData should not be loaded";
|
|
ASSERT_TRUE(texture->kvDataHead == NULL) << "KVData should not be deserialized";
|
|
if (texture)
|
|
ktxTexture_Destroy(texture);
|
|
}
|
|
}
|
|
|
|
/////////////////////////////////////////
|
|
// ktxTexture_IterateLoadLevelFaces tests
|
|
////////////////////////////////////////
|
|
|
|
TEST_F(ktxTexture1_IterateLoadLevelFacesTest, InvalidValueOnNullCallback) {
|
|
ktxTexture* texture = 0;
|
|
KTX_error_code result;
|
|
ktxTexture1_IterateLoadLevelFacesTest* fixture = this;
|
|
|
|
if (ktxMemFile != NULL) {
|
|
result = ktxTexture_CreateFromMemory(ktxMemFile, ktxMemFileLen,
|
|
0, &texture);
|
|
EXPECT_EQ(result, KTX_SUCCESS);
|
|
ASSERT_TRUE(texture != NULL) << "ktxTexture_CreateFromMemory failed: "
|
|
<< ktxErrorString(result);
|
|
|
|
EXPECT_EQ(ktxTexture_IterateLoadLevelFaces(texture, 0, fixture),
|
|
KTX_INVALID_VALUE);
|
|
if (texture)
|
|
ktxTexture_Destroy(texture);
|
|
}
|
|
}
|
|
|
|
TEST_F(ktxTexture1_IterateLoadLevelFacesTest, InvalidOpWhenDataAlreadyLoaded) {
|
|
ktxTexture* texture = 0;
|
|
KTX_error_code result;
|
|
ktxTexture1_IterateLoadLevelFacesTest* fixture = this;
|
|
|
|
if (ktxMemFile != NULL) {
|
|
result = ktxTexture_CreateFromMemory(ktxMemFile, ktxMemFileLen,
|
|
KTX_TEXTURE_CREATE_LOAD_IMAGE_DATA_BIT,
|
|
&texture);
|
|
EXPECT_EQ(result, KTX_SUCCESS);
|
|
ASSERT_TRUE(texture != NULL) << "ktxTexture_CreateFromMemory failed: "
|
|
<< ktxErrorString(result);
|
|
ASSERT_TRUE(texture->pData != NULL) << "Image data not loaded";
|
|
EXPECT_EQ(ktxTexture_IterateLoadLevelFaces(texture, iterCallback, fixture),
|
|
KTX_INVALID_OPERATION);
|
|
if (texture)
|
|
ktxTexture_Destroy(texture);
|
|
}
|
|
}
|
|
|
|
TEST_F(ktxTexture1_IterateLoadLevelFacesTest, IterateImages) {
|
|
ktxTexture* texture = 0;
|
|
KTX_error_code result;
|
|
ktxTexture1_IterateLoadLevelFacesTest* fixture = this;
|
|
|
|
if (ktxMemFile != NULL) {
|
|
result = ktxTexture_CreateFromMemory(ktxMemFile, ktxMemFileLen,
|
|
0, &texture);
|
|
EXPECT_EQ(result, KTX_SUCCESS);
|
|
ASSERT_TRUE(texture != NULL) << "ktxTexture_CreateFromMemory failed: "
|
|
<< ktxErrorString(result);
|
|
|
|
EXPECT_EQ(ktxTexture_IterateLoadLevelFaces(texture, iterCallback, fixture),
|
|
KTX_SUCCESS);
|
|
EXPECT_EQ(iterCbCalls, mipLevels)
|
|
<< "No. of calls to iterCallback differs from number of mip levels";
|
|
if (texture)
|
|
ktxTexture_Destroy(texture);
|
|
}
|
|
}
|
|
|
|
/////////////////////////////////////////
|
|
// ktxTexture_IterateLevelFaces tests
|
|
////////////////////////////////////////
|
|
|
|
TEST_F(ktxTexture1_IterateLevelFacesTest, InvalidValueOnNullCallback) {
|
|
ktxTexture* texture = 0;
|
|
KTX_error_code result;
|
|
ktxTexture1_IterateLevelFacesTest* fixture = this;
|
|
|
|
if (ktxMemFile != NULL) {
|
|
result = ktxTexture_CreateFromMemory(ktxMemFile, ktxMemFileLen,
|
|
KTX_TEXTURE_CREATE_LOAD_IMAGE_DATA_BIT,
|
|
&texture);
|
|
EXPECT_EQ(result, KTX_SUCCESS);
|
|
ASSERT_TRUE(texture != NULL) << "ktxTexture_CreateFromMemory failed: "
|
|
<< ktxErrorString(result);
|
|
ASSERT_TRUE(texture->pData != NULL) << "Image data not loaded";
|
|
EXPECT_EQ(ktxTexture_IterateLevelFaces(texture, 0, fixture),
|
|
KTX_INVALID_VALUE);
|
|
if (texture)
|
|
ktxTexture_Destroy(texture);
|
|
}
|
|
}
|
|
|
|
TEST_F(ktxTexture1_IterateLevelFacesTest, IterateImages) {
|
|
ktxTexture* texture = 0;
|
|
KTX_error_code result;
|
|
ktxTexture1_IterateLevelFacesTest* fixture = this;
|
|
|
|
if (ktxMemFile != NULL) {
|
|
result = ktxTexture_CreateFromMemory(ktxMemFile, ktxMemFileLen,
|
|
KTX_TEXTURE_CREATE_LOAD_IMAGE_DATA_BIT,
|
|
&texture);
|
|
EXPECT_EQ(result, KTX_SUCCESS);
|
|
ASSERT_TRUE(texture != NULL) << "ktxTexture_CreateFromMemory failed: "
|
|
<< ktxErrorString(result);
|
|
|
|
EXPECT_EQ(ktxTexture_IterateLevelFaces(texture, iterCallback, fixture),
|
|
KTX_SUCCESS);
|
|
EXPECT_EQ(iterCbCalls, mipLevels)
|
|
<< "No. of calls to iterCallback differs from number of mip levels";
|
|
if (texture)
|
|
ktxTexture_Destroy(texture);
|
|
}
|
|
}
|
|
|
|
TEST_F(ktxTexture2_IterateLevelFacesTest, InvalidValueOnNullCallback) {
|
|
ktxTexture* texture;
|
|
KTX_error_code result;
|
|
ktxTexture2_IterateLevelFacesTest* fixture = this;
|
|
|
|
if (ktxMemFile != NULL) {
|
|
result = ktxTexture_CreateFromMemory(ktxMemFile, ktxMemFileLen,
|
|
KTX_TEXTURE_CREATE_LOAD_IMAGE_DATA_BIT,
|
|
&texture);
|
|
ASSERT_TRUE(result == KTX_SUCCESS);
|
|
ASSERT_TRUE(texture != NULL) << "ktxTexture_CreateFromMemory failed: "
|
|
<< ktxErrorString(result);
|
|
ASSERT_TRUE(texture->pData != NULL) << "Image data not loaded";
|
|
EXPECT_EQ(ktxTexture_IterateLevelFaces(texture, 0, fixture),
|
|
KTX_INVALID_VALUE);
|
|
if (texture)
|
|
ktxTexture_Destroy(texture);
|
|
}
|
|
}
|
|
|
|
TEST_F(ktxTexture2_IterateLevelFacesTest, IterateImages) {
|
|
ktxTexture* texture;
|
|
KTX_error_code result;
|
|
ktxTexture2_IterateLevelFacesTest* fixture = this;
|
|
|
|
if (ktxMemFile != NULL) {
|
|
result = ktxTexture_CreateFromMemory(ktxMemFile, ktxMemFileLen,
|
|
KTX_TEXTURE_CREATE_LOAD_IMAGE_DATA_BIT,
|
|
&texture);
|
|
ASSERT_TRUE(result == KTX_SUCCESS);
|
|
ASSERT_TRUE(texture != NULL) << "ktxTexture_CreateFromMemory failed: "
|
|
<< ktxErrorString(result);
|
|
|
|
EXPECT_EQ(ktxTexture_IterateLevelFaces(texture, iterCallback, fixture),
|
|
KTX_SUCCESS);
|
|
EXPECT_EQ(iterCbCalls, mipLevels)
|
|
<< "No. of calls to iterCallback differs from number of mip levels";
|
|
if (texture)
|
|
ktxTexture_Destroy(texture);
|
|
}
|
|
}
|
|
|
|
/////////////////////////////////////////
|
|
// ktxTexture_IterateLevels tests
|
|
////////////////////////////////////////
|
|
|
|
TEST_F(ktxTexture2_IterateLevelsTest, InvalidValueOnNullCallback) {
|
|
ktxTexture* texture;
|
|
KTX_error_code result;
|
|
ktxTexture2_IterateLevelsTest* fixture = this;
|
|
|
|
if (ktxMemFile != NULL) {
|
|
result = ktxTexture_CreateFromMemory(ktxMemFile, ktxMemFileLen,
|
|
KTX_TEXTURE_CREATE_LOAD_IMAGE_DATA_BIT,
|
|
&texture);
|
|
ASSERT_TRUE(result == KTX_SUCCESS);
|
|
ASSERT_TRUE(texture != NULL) << "ktxTexture_CreateFromMemory failed: "
|
|
<< ktxErrorString(result);
|
|
ASSERT_TRUE(texture->pData != NULL) << "Image data not loaded";
|
|
EXPECT_EQ(ktxTexture_IterateLevels(texture, 0, fixture),
|
|
KTX_INVALID_VALUE);
|
|
if (texture)
|
|
ktxTexture_Destroy(texture);
|
|
}
|
|
}
|
|
|
|
TEST_F(ktxTexture2_IterateLevelsTest, IterateLevels) {
|
|
ktxTexture* texture = 0;
|
|
KTX_error_code result;
|
|
ktxTexture2_IterateLevelsTest* fixture = this;
|
|
|
|
if (ktxMemFile != NULL) {
|
|
result = ktxTexture_CreateFromMemory(ktxMemFile, ktxMemFileLen,
|
|
KTX_TEXTURE_CREATE_LOAD_IMAGE_DATA_BIT,
|
|
&texture);
|
|
EXPECT_EQ(result, KTX_SUCCESS);
|
|
ASSERT_TRUE(texture != NULL) << "ktxTexture_CreateFromMemory failed: "
|
|
<< ktxErrorString(result);
|
|
|
|
EXPECT_EQ(ktxTexture_IterateLevelFaces(texture, iterCallback, fixture),
|
|
KTX_SUCCESS);
|
|
EXPECT_EQ(iterCbCalls, mipLevels)
|
|
<< "No. of calls to iterCallback differs from number of mip levels";
|
|
if (texture)
|
|
ktxTexture_Destroy(texture);
|
|
}
|
|
}
|
|
|
|
/////////////////////////////////////////
|
|
// ktxTexture_LoadImageData tests
|
|
////////////////////////////////////////
|
|
|
|
TEST_F(ktxTexture1_LoadImageDataTest, InvalidOpWhenDataAlreadyLoaded) {
|
|
ktxTexture* texture = 0;
|
|
KTX_error_code result;
|
|
ktx_uint8_t* buf;
|
|
|
|
if (ktxMemFile != NULL) {
|
|
result = ktxTexture_CreateFromMemory(ktxMemFile, ktxMemFileLen,
|
|
KTX_TEXTURE_CREATE_LOAD_IMAGE_DATA_BIT,
|
|
&texture);
|
|
EXPECT_EQ(result, KTX_SUCCESS);
|
|
ASSERT_TRUE(texture != NULL) << "ktxTexture_CreateFromMemory failed: "
|
|
<< ktxErrorString(result);
|
|
ASSERT_TRUE(texture->pData != NULL) << "Image data not loaded";
|
|
buf = new ktx_uint8_t[paddedImageDataSize];
|
|
EXPECT_EQ(ktxTexture_LoadImageData(texture, buf, paddedImageDataSize),
|
|
KTX_INVALID_OPERATION);
|
|
if (texture)
|
|
ktxTexture_Destroy(texture);
|
|
delete[] buf;
|
|
}
|
|
}
|
|
|
|
TEST_F(ktxTexture1_LoadImageDataTest, InvalidOpWhenDataAlreadyLoadedToExternal) {
|
|
ktxTexture* texture = 0;
|
|
KTX_error_code result;
|
|
ktx_uint8_t* buf;
|
|
|
|
if (ktxMemFile != NULL) {
|
|
result = ktxTexture_CreateFromMemory(ktxMemFile, ktxMemFileLen,
|
|
0,
|
|
&texture);
|
|
EXPECT_EQ(result, KTX_SUCCESS);
|
|
ASSERT_TRUE(texture != NULL) << "ktxTexture_CreateFromMemory failed: "
|
|
<< ktxErrorString(result);
|
|
ASSERT_TRUE(texture->pData == NULL) << "Image data must not be loaded";
|
|
buf = new ktx_uint8_t[paddedImageDataSize];
|
|
EXPECT_EQ(ktxTexture_LoadImageData(texture, buf, paddedImageDataSize),
|
|
KTX_SUCCESS);
|
|
EXPECT_EQ(ktxTexture_LoadImageData(texture, buf, paddedImageDataSize),
|
|
KTX_INVALID_OPERATION);
|
|
if (texture)
|
|
ktxTexture_Destroy(texture);
|
|
delete[] buf;
|
|
}
|
|
}
|
|
|
|
TEST_F(ktxTexture1_LoadImageDataTest, LoadImageDataInternal) {
|
|
ktxTexture* texture = 0;
|
|
KTX_error_code result;
|
|
|
|
if (ktxMemFile != NULL) {
|
|
result = ktxTexture_CreateFromMemory(ktxMemFile, ktxMemFileLen,
|
|
KTX_TEXTURE_CREATE_LOAD_IMAGE_DATA_BIT,
|
|
&texture);
|
|
EXPECT_EQ(result, KTX_SUCCESS);
|
|
ASSERT_TRUE(texture != NULL) << "ktxTexture_CreateFromMemory failed: "
|
|
<< ktxErrorString(result);
|
|
ASSERT_TRUE(texture->pData != NULL) << "Image data not loaded";
|
|
EXPECT_EQ(paddedImageDataSize, ktxTexture_GetDataSize(texture));
|
|
EXPECT_EQ(helper.compareTexture1Images(ktxTexture_GetData(texture)), true);
|
|
if (texture)
|
|
ktxTexture_Destroy(texture);
|
|
}
|
|
}
|
|
|
|
TEST_F(ktxTexture1_LoadImageDataTest, LoadImageDataExternal) {
|
|
ktxTexture* texture = 0;
|
|
KTX_error_code result;
|
|
ktx_uint8_t* buf;
|
|
|
|
if (ktxMemFile != NULL) {
|
|
result = ktxTexture_CreateFromMemory(ktxMemFile, ktxMemFileLen,
|
|
0,
|
|
&texture);
|
|
EXPECT_EQ(result, KTX_SUCCESS);
|
|
ASSERT_TRUE(texture != NULL) << "ktxTexture_CreateFromMemory failed: "
|
|
<< ktxErrorString(result);
|
|
buf = new ktx_uint8_t[paddedImageDataSize];
|
|
EXPECT_EQ(ktxTexture_LoadImageData(texture, buf, paddedImageDataSize),
|
|
KTX_SUCCESS);
|
|
EXPECT_EQ(paddedImageDataSize, ktxTexture_GetDataSize(texture));
|
|
EXPECT_EQ(helper.compareTexture1Images(buf), true);
|
|
if (texture)
|
|
ktxTexture_Destroy(texture);
|
|
delete[] buf;
|
|
}
|
|
}
|
|
|
|
TEST_F(ktxTexture2_LoadImageDataTest, InvalidOpWhenDataAlreadyLoaded) {
|
|
ktxTexture* texture = 0;
|
|
KTX_error_code result;
|
|
ktx_uint8_t* buf;
|
|
|
|
if (ktxMemFile != NULL) {
|
|
result = ktxTexture_CreateFromMemory(ktxMemFile, ktxMemFileLen,
|
|
KTX_TEXTURE_CREATE_LOAD_IMAGE_DATA_BIT,
|
|
&texture);
|
|
EXPECT_EQ(result, KTX_SUCCESS);
|
|
ASSERT_TRUE(texture != NULL) << "ktxTexture_CreateFromMemory failed: "
|
|
<< ktxErrorString(result);
|
|
ASSERT_TRUE(texture->pData != NULL) << "Image data not loaded";
|
|
buf = new ktx_uint8_t[paddedImageDataSize];
|
|
EXPECT_EQ(ktxTexture_LoadImageData(texture, buf, paddedImageDataSize),
|
|
KTX_INVALID_OPERATION);
|
|
if (texture)
|
|
ktxTexture_Destroy(texture);
|
|
delete[] buf;
|
|
}
|
|
}
|
|
|
|
TEST_F(ktxTexture2_LoadImageDataTest, InvalidOpWhenDataAlreadyLoadedToExternal) {
|
|
ktxTexture* texture = 0;
|
|
KTX_error_code result;
|
|
ktx_uint8_t* buf;
|
|
|
|
if (ktxMemFile != NULL) {
|
|
result = ktxTexture_CreateFromMemory(ktxMemFile, ktxMemFileLen,
|
|
0,
|
|
&texture);
|
|
EXPECT_EQ(result, KTX_SUCCESS);
|
|
ASSERT_TRUE(texture != NULL) << "ktxTexture_CreateFromMemory failed: "
|
|
<< ktxErrorString(result);
|
|
ASSERT_TRUE(texture->pData == NULL) << "Image data must not be loaded";
|
|
buf = new ktx_uint8_t[paddedImageDataSize];
|
|
EXPECT_EQ(ktxTexture_LoadImageData(texture, buf, paddedImageDataSize),
|
|
KTX_SUCCESS);
|
|
EXPECT_EQ(ktxTexture_LoadImageData(texture, buf, paddedImageDataSize),
|
|
KTX_INVALID_OPERATION);
|
|
if (texture)
|
|
ktxTexture_Destroy(texture);
|
|
delete[] buf;
|
|
}
|
|
}
|
|
|
|
TEST_F(ktxTexture2_LoadImageDataTest, LoadImageDataInternal) {
|
|
ktxTexture* texture = 0;
|
|
KTX_error_code result;
|
|
|
|
if (ktxMemFile != NULL) {
|
|
result = ktxTexture_CreateFromMemory(ktxMemFile, ktxMemFileLen,
|
|
KTX_TEXTURE_CREATE_LOAD_IMAGE_DATA_BIT,
|
|
&texture);
|
|
EXPECT_EQ(result, KTX_SUCCESS);
|
|
ASSERT_TRUE(texture != NULL) << "ktxTexture_CreateFromMemory failed: "
|
|
<< ktxErrorString(result);
|
|
ASSERT_TRUE(texture->pData != NULL) << "Image data not loaded";
|
|
EXPECT_EQ(paddedImageDataSize, ktxTexture_GetDataSize(texture));
|
|
EXPECT_EQ(helper.compareTexture2Images(ktxTexture_GetData(texture)), true);
|
|
if (texture)
|
|
ktxTexture_Destroy(texture);
|
|
}
|
|
}
|
|
|
|
TEST_F(ktxTexture2_LoadImageDataTest, LoadImageDataExternal) {
|
|
ktxTexture* texture = 0;
|
|
KTX_error_code result;
|
|
ktx_uint8_t* buf;
|
|
|
|
if (ktxMemFile != NULL) {
|
|
result = ktxTexture_CreateFromMemory(ktxMemFile, ktxMemFileLen,
|
|
0,
|
|
&texture);
|
|
EXPECT_EQ(result, KTX_SUCCESS);
|
|
ASSERT_TRUE(texture != NULL) << "ktxTexture_CreateFromMemory failed: "
|
|
<< ktxErrorString(result);
|
|
buf = new ktx_uint8_t[paddedImageDataSize];
|
|
EXPECT_EQ(ktxTexture_LoadImageData(texture, buf, paddedImageDataSize),
|
|
KTX_SUCCESS);
|
|
EXPECT_EQ(paddedImageDataSize, ktxTexture_GetDataSize(texture));
|
|
EXPECT_EQ(helper.compareTexture2Images(buf), true);
|
|
if (texture)
|
|
ktxTexture_Destroy(texture);
|
|
delete[] buf;
|
|
}
|
|
}
|
|
|
|
/////////////////////////////////////////////
|
|
// ktxTexture2_CreateCopyTest
|
|
////////////////////////////////////////////
|
|
|
|
TEST_F(ktxTexture2_CreateCopyTest, CreateCopy) {
|
|
ktxTexture2* texture = 0;
|
|
ktxTexture2* copyTexture = 0;
|
|
KTX_error_code result;
|
|
|
|
if (ktxMemFile != NULL) {
|
|
result = ktxTexture_CreateFromMemory(ktxMemFile, ktxMemFileLen,
|
|
0,
|
|
(ktxTexture**)&texture);
|
|
EXPECT_EQ(result, KTX_SUCCESS);
|
|
ASSERT_TRUE(texture != NULL) << "ktxTexture_CreateFromMemory failed: "
|
|
<< ktxErrorString(result);
|
|
result = ktxTexture2_CreateCopy(texture, ©Texture);
|
|
EXPECT_EQ(result, KTX_SUCCESS);
|
|
ASSERT_TRUE(copyTexture != NULL) << "ktxTexture_CreateFromMemory failed: "
|
|
<< ktxErrorString(result);
|
|
|
|
EXPECT_EQ(compareTexture(copyTexture), true);
|
|
EXPECT_EQ(memcmp(texture->pData, copyTexture->pData, texture->dataSize),
|
|
0);
|
|
EXPECT_EQ(memcmp(texture->_protected, copyTexture->_protected,
|
|
sizeof(ktxTexture_protected)), 0);
|
|
ktx_size_t privateSize = sizeof(ktxTexture2_private)
|
|
+ sizeof(ktxLevelIndexEntry)
|
|
* (texture->numLevels - 1);
|
|
EXPECT_EQ(memcmp(texture->_private, copyTexture->_private,
|
|
privateSize), 0);
|
|
|
|
if (texture)
|
|
ktxTexture_Destroy((ktxTexture*)texture);
|
|
if (copyTexture)
|
|
ktxTexture_Destroy((ktxTexture*)copyTexture);
|
|
}
|
|
}
|
|
|
|
/////////////////////////////////////////////
|
|
// TestCreateInfo for size and offset tests.
|
|
////////////////////////////////////////////
|
|
|
|
class TestCreateInfo : public ktxTextureCreateInfo {
|
|
public:
|
|
TestCreateInfo() : TestCreateInfo(16) { }
|
|
|
|
TestCreateInfo(ktx_uint32_t pixelSize)
|
|
: TestCreateInfo(pixelSize, pixelSize, 1) { }
|
|
|
|
TestCreateInfo(ktx_uint32_t width, ktx_uint32_t height, ktx_uint32_t depth)
|
|
: TestCreateInfo(width, height, depth, 2, GL_RGBA8,
|
|
VK_FORMAT_R8G8B8A8_UNORM, KTX_FALSE, 1, 1) { }
|
|
|
|
TestCreateInfo(ktx_uint32_t width, ktx_uint32_t height, ktx_uint32_t depth,
|
|
ktx_uint32_t dimensions, ktx_uint32_t internalformat,
|
|
ktx_uint32_t vkformat, ktx_bool_t array, ktx_uint32_t faces,
|
|
ktx_uint32_t layers) {
|
|
baseWidth = width;
|
|
baseHeight = height;
|
|
baseDepth = depth;
|
|
numDimensions = dimensions;
|
|
generateMipmaps = KTX_FALSE;
|
|
glInternalformat = internalformat;
|
|
vkFormat = vkformat;
|
|
isArray = array;
|
|
numFaces = faces;
|
|
numLayers = layers;
|
|
numLevels = levelsFromSize(width, height, depth);
|
|
};
|
|
|
|
static ktx_uint32_t
|
|
levelsFromSize(ktx_uint32_t width, ktx_uint32_t height, ktx_uint32_t depth) {
|
|
ktx_uint32_t mipLevels;
|
|
ktx_uint32_t max_dim = MAX(MAX(width, height), depth);
|
|
for (mipLevels = 1; max_dim != 1; mipLevels++, max_dim >>= 1) { }
|
|
return mipLevels;
|
|
}
|
|
};
|
|
|
|
/////////////////////////////////////////
|
|
// ktxTexture_calcImageSize tests
|
|
////////////////////////////////////////
|
|
|
|
TEST(ktxTexture_calcImageSize, ImageSizeAtEachLevelRGBA2D) {
|
|
ktxTexture* texture = 0;
|
|
TestCreateInfo createInfo;
|
|
KTX_error_code result;
|
|
// Sizes for 16x16, 5 level RGBA8 texture.
|
|
// level 0 ... level 4
|
|
ktx_uint32_t ktx1sizes[] = {1024, 256, 64, 16, 4};
|
|
ktx_uint32_t ktx2sizes[] = {1024, 256, 64, 16, 4};
|
|
|
|
result = ktxTexture1_Create(&createInfo, KTX_TEXTURE_CREATE_NO_STORAGE,
|
|
(ktxTexture1**)&texture);
|
|
EXPECT_EQ(result, KTX_SUCCESS);
|
|
ASSERT_TRUE(texture != NULL) << "ktxTexture1_Create failed: "
|
|
<< ktxErrorString(result);
|
|
for (ktx_uint32_t i = 0; i < createInfo.numLevels; i++) {
|
|
ktx_size_t imageSize;
|
|
imageSize = ktxTexture_calcImageSize(texture, i,
|
|
KTX_FORMAT_VERSION_ONE);
|
|
EXPECT_EQ(imageSize, ktx1sizes[i]);
|
|
imageSize = ktxTexture_calcImageSize(texture, i,
|
|
KTX_FORMAT_VERSION_TWO);
|
|
EXPECT_EQ(imageSize, ktx2sizes[i]);
|
|
}
|
|
if (texture)
|
|
ktxTexture_Destroy(texture);
|
|
}
|
|
|
|
TEST(ktxTexture_calcImageSize, ImageSizeAtEachLevelRGB2D) {
|
|
ktxTexture* texture = 0;
|
|
TestCreateInfo createInfo(9, 9, 1, 2, GL_RGB8,
|
|
VK_FORMAT_R8G8B8_UNORM, KTX_FALSE, 1, 1);
|
|
KTX_error_code result;
|
|
// Sizes for 9x9, 4 level RGB8 texture.
|
|
// level 0 ... level 4
|
|
ktx_uint32_t ktx1sizes[] = {28*9, 12*4, 8*2, 4*1};
|
|
ktx_uint32_t ktx2sizes[] = {27*9, 12*4, 6*2, 3*1};
|
|
|
|
result = ktxTexture1_Create(&createInfo, KTX_TEXTURE_CREATE_NO_STORAGE,
|
|
(ktxTexture1**)&texture);
|
|
EXPECT_EQ(result, KTX_SUCCESS);
|
|
ASSERT_TRUE(texture != NULL) << "ktxTexture1_Create failed: "
|
|
<< ktxErrorString(result);
|
|
for (ktx_uint32_t i = 0; i < createInfo.numLevels; i++) {
|
|
ktx_size_t imageSize;
|
|
imageSize = ktxTexture_calcImageSize(texture, i,
|
|
KTX_FORMAT_VERSION_ONE);
|
|
EXPECT_EQ(imageSize, ktx1sizes[i]);
|
|
imageSize = ktxTexture_calcImageSize(texture, i,
|
|
KTX_FORMAT_VERSION_TWO);
|
|
EXPECT_EQ(imageSize, ktx2sizes[i]);
|
|
}
|
|
if (texture)
|
|
ktxTexture_Destroy(texture);
|
|
}
|
|
|
|
/////////////////////////////////////////
|
|
// ktxTexture_calcLevelSize tests
|
|
////////////////////////////////////////
|
|
|
|
TEST(ktxTexture_calcLevelSize, SizeOfEachLevelRGBA2D) {
|
|
ktxTexture* texture = 0;
|
|
TestCreateInfo createInfo;
|
|
KTX_error_code result;
|
|
// Sizes for 16x16, 5 level RGBA8 texture.
|
|
// level 0 ... level 4
|
|
ktx_uint32_t ktx1sizes[] = {1024, 256, 64, 16, 4};
|
|
ktx_uint32_t ktx2sizes[] = {1024, 256, 64, 16, 4};
|
|
|
|
result = ktxTexture1_Create(&createInfo, KTX_TEXTURE_CREATE_NO_STORAGE,
|
|
(ktxTexture1**)&texture);
|
|
EXPECT_EQ(result, KTX_SUCCESS);
|
|
ASSERT_TRUE(texture != NULL) << "ktxTexture1_Create failed: "
|
|
<< ktxErrorString(result);
|
|
for (ktx_uint32_t i = 0; i < createInfo.numLevels; i++) {
|
|
ktx_size_t levelSize;
|
|
levelSize = ktxTexture_calcLevelSize(texture, i,
|
|
KTX_FORMAT_VERSION_ONE);
|
|
EXPECT_EQ(levelSize, ktx1sizes[i]);
|
|
levelSize = ktxTexture_calcLevelSize(texture, i,
|
|
KTX_FORMAT_VERSION_TWO);
|
|
EXPECT_EQ(levelSize, ktx2sizes[i]);
|
|
}
|
|
if (texture)
|
|
ktxTexture_Destroy(texture);
|
|
}
|
|
|
|
TEST(ktxTexture_calcLevelSize, SizeOfEachLevelRGB2D) {
|
|
ktxTexture* texture = 0;
|
|
TestCreateInfo createInfo(9, 9, 1, 2, GL_RGB8,
|
|
VK_FORMAT_R8G8B8_UNORM, KTX_FALSE, 1, 1);
|
|
KTX_error_code result;
|
|
// Sizes for 9x9, 4 level RGB8 texture.
|
|
// level 0 ... level 4
|
|
ktx_uint32_t ktx1sizes[] = {28*9, 12*4, 8*2, 4*1};
|
|
ktx_uint32_t ktx2sizes[] = {27*9, 12*4, 6*2, 3*1};
|
|
|
|
result = ktxTexture1_Create(&createInfo, KTX_TEXTURE_CREATE_NO_STORAGE,
|
|
(ktxTexture1**)&texture);
|
|
EXPECT_EQ(result, KTX_SUCCESS);
|
|
ASSERT_TRUE(texture != NULL) << "ktxTexture1_Create failed: "
|
|
<< ktxErrorString(result);
|
|
for (ktx_uint32_t i = 0; i < createInfo.numLevels; i++) {
|
|
ktx_size_t levelSize;
|
|
levelSize = ktxTexture_calcLevelSize(texture, i,
|
|
KTX_FORMAT_VERSION_ONE);
|
|
EXPECT_EQ(levelSize, ktx1sizes[i]);
|
|
levelSize = ktxTexture_calcLevelSize(texture, i,
|
|
KTX_FORMAT_VERSION_TWO);
|
|
EXPECT_EQ(levelSize, ktx2sizes[i]);
|
|
}
|
|
if (texture)
|
|
ktxTexture_Destroy(texture);
|
|
}
|
|
|
|
/////////////////////////////////////////
|
|
// ktxTexture_calcLevelOffset tests
|
|
////////////////////////////////////////
|
|
|
|
TEST(ktxTexture_calcLevelOffset, OffsetOfEachLevelRGBA2D) {
|
|
ktxTexture1* ktx1texture = 0;
|
|
ktxTexture2* ktx2texture = 0;
|
|
TestCreateInfo createInfo;
|
|
KTX_error_code result;
|
|
// Offsets for 16x16, 5 level RGBA8 texture.
|
|
// KTX 1: level 0 ... level 4
|
|
ktx_uint32_t ktx1offsets[] = {0, 1024, 1024+256, 1024+256+64, 1024+256+64+16};
|
|
// KTX 2: level 0 ... level 4 with mip padding to a 4 byte alignment.
|
|
ktx_uint32_t ktx2offsets[] = {4+16+64+256, 4+16+64, 4+16, 4, 0};
|
|
|
|
result = ktxTexture1_Create(&createInfo, KTX_TEXTURE_CREATE_NO_STORAGE,
|
|
&ktx1texture);
|
|
EXPECT_EQ(result, KTX_SUCCESS);
|
|
ASSERT_TRUE(ktx1texture != NULL) << "ktxTexture1_Create failed: "
|
|
<< ktxErrorString(result);
|
|
result = ktxTexture2_Create(&createInfo, KTX_TEXTURE_CREATE_NO_STORAGE,
|
|
&ktx2texture);
|
|
EXPECT_EQ(result, KTX_SUCCESS);
|
|
ASSERT_TRUE(ktx2texture != NULL) << "ktxTexture2_Create failed: "
|
|
<< ktxErrorString(result);
|
|
for (ktx_uint32_t i = 0; i < createInfo.numLevels; i++) {
|
|
ktx_size_t levelOffset;
|
|
levelOffset = ktxTexture1_calcLevelOffset(ktx1texture, i);
|
|
EXPECT_EQ(levelOffset, ktx1offsets[i]);
|
|
levelOffset = ktxTexture2_calcLevelOffset(ktx2texture, i);
|
|
EXPECT_EQ(levelOffset, ktx2offsets[i]);
|
|
}
|
|
if (ktx1texture)
|
|
ktxTexture_Destroy(ktxTexture(ktx1texture));
|
|
if (ktx2texture)
|
|
ktxTexture_Destroy(ktxTexture(ktx2texture));
|
|
}
|
|
|
|
TEST(ktxTexture_calcLevelOffset, OffsetOfEachLevelRGB2D) {
|
|
ktxTexture1* ktx1texture = 0;
|
|
ktxTexture2* ktx2texture = 0;
|
|
TestCreateInfo createInfo(9, 9, 1, 2, GL_RGB8,
|
|
VK_FORMAT_R8G8B8_UNORM, KTX_FALSE, 1, 1);
|
|
KTX_error_code result;
|
|
// Offsets for 9x9, 4 level RGB8 texture.
|
|
// KTX 1: level 0 ... level 4
|
|
ktx_uint32_t ktx1offsets[] = {0, 28*9, 28*9+12*4, 28*9+12*4+8*2};
|
|
// KTX 2: level 0 ... level 4 with mip padding to a 12 byte alignment.
|
|
ktx_uint32_t ktx2offsets[] = {12*4+24, 6*2+12, 3*1+9, 0};
|
|
|
|
result = ktxTexture1_Create(&createInfo, KTX_TEXTURE_CREATE_NO_STORAGE,
|
|
&ktx1texture);
|
|
EXPECT_EQ(result, KTX_SUCCESS);
|
|
ASSERT_TRUE(ktx1texture != NULL) << "ktxTexture1_Create failed: "
|
|
<< ktxErrorString(result);
|
|
result = ktxTexture2_Create(&createInfo, KTX_TEXTURE_CREATE_NO_STORAGE,
|
|
&ktx2texture);
|
|
EXPECT_EQ(result, KTX_SUCCESS);
|
|
ASSERT_TRUE(ktx2texture != NULL) << "ktxTexture2_Create failed: "
|
|
<< ktxErrorString(result);
|
|
|
|
for (ktx_uint32_t i = 0; i < createInfo.numLevels; i++) {
|
|
ktx_size_t levelOffset;
|
|
levelOffset = ktxTexture1_calcLevelOffset(ktx1texture, i);
|
|
EXPECT_EQ(levelOffset, ktx1offsets[i]);
|
|
levelOffset = ktxTexture2_calcLevelOffset(ktx2texture, i);
|
|
EXPECT_EQ(levelOffset, ktx2offsets[i]);
|
|
}
|
|
if (ktx1texture)
|
|
ktxTexture_Destroy(ktxTexture(ktx1texture));
|
|
if (ktx2texture)
|
|
ktxTexture_Destroy(ktxTexture(ktx2texture));
|
|
}
|
|
|
|
TEST(ktxTexture_calcLevelOffset, OffsetOfEachLevelD16_UNORM_S8_UINT) {
|
|
ktxTexture2* ktx2texture = 0;
|
|
TestCreateInfo createInfo(9, 9, 1, 2, 0,
|
|
VK_FORMAT_D16_UNORM_S8_UINT, KTX_FALSE, 1, 1);
|
|
KTX_error_code result;
|
|
// Offsets for 9x9, 4 level texture.
|
|
// KTX 2: level 0 ... level 4 with mip padding to a 4 byte alignment.
|
|
ktx_uint32_t ktx2offsets[] = {4+16+64, 4+16, 4, 0};
|
|
|
|
result = ktxTexture2_Create(&createInfo, KTX_TEXTURE_CREATE_NO_STORAGE,
|
|
&ktx2texture);
|
|
EXPECT_EQ(result, KTX_SUCCESS);
|
|
ASSERT_TRUE(ktx2texture != NULL) << "ktxTexture2_Create failed: "
|
|
<< ktxErrorString(result);
|
|
|
|
for (ktx_uint32_t i = 0; i < createInfo.numLevels; i++) {
|
|
ktx_size_t levelOffset;
|
|
levelOffset = ktxTexture2_calcLevelOffset(ktx2texture, i);
|
|
EXPECT_EQ(levelOffset, ktx2offsets[i]);
|
|
}
|
|
if (ktx2texture)
|
|
ktxTexture_Destroy(ktxTexture(ktx2texture));
|
|
}
|
|
|
|
TEST(ktxTexture_calcLevelOffset, OffsetOfEachLevelD32_SFLOAT_S8_UINT) {
|
|
ktxTexture2* ktx2texture = 0;
|
|
TestCreateInfo createInfo(9, 9, 1, 2, 0,
|
|
VK_FORMAT_D32_SFLOAT_S8_UINT, KTX_FALSE, 1, 1);
|
|
KTX_error_code result;
|
|
// Offsets for 9x9, 4 level texture.
|
|
// KTX 2: level 0 ... level 4 with mip padding to an 8 byte alignment.
|
|
ktx_uint32_t ktx2offsets[] = {8+32+128, 8+32, 8, 0};
|
|
|
|
result = ktxTexture2_Create(&createInfo, KTX_TEXTURE_CREATE_NO_STORAGE,
|
|
&ktx2texture);
|
|
EXPECT_EQ(result, KTX_SUCCESS);
|
|
ASSERT_TRUE(ktx2texture != NULL) << "ktxTexture2_Create failed: "
|
|
<< ktxErrorString(result);
|
|
|
|
for (ktx_uint32_t i = 0; i < createInfo.numLevels; i++) {
|
|
ktx_size_t levelOffset;
|
|
levelOffset = ktxTexture2_calcLevelOffset(ktx2texture, i);
|
|
EXPECT_EQ(levelOffset, ktx2offsets[i]);
|
|
}
|
|
if (ktx2texture)
|
|
ktxTexture_Destroy(ktxTexture(ktx2texture));
|
|
}
|
|
|
|
/////////////////////////////////////////
|
|
// ktxTexture_GetImageOffset tests
|
|
////////////////////////////////////////
|
|
|
|
TEST(ktxTexture_GetImageOffsetTest, InvalidOpOnLevelFaceLayerTooBig) {
|
|
ktxTexture* texture = 0;
|
|
TestCreateInfo createInfo;
|
|
KTX_error_code result;
|
|
ktx_size_t offset;
|
|
|
|
result = ktxTexture1_Create(&createInfo, KTX_TEXTURE_CREATE_NO_STORAGE,
|
|
(ktxTexture1**)&texture);
|
|
EXPECT_EQ(result, KTX_SUCCESS);
|
|
ASSERT_TRUE(texture != NULL) << "ktxTexture1_Create failed: "
|
|
<< ktxErrorString(result);
|
|
EXPECT_EQ(ktxTexture_GetImageOffset(texture, createInfo.numLevels, 0, 0, &offset),
|
|
KTX_INVALID_OPERATION);
|
|
EXPECT_EQ(ktxTexture_GetImageOffset(texture, 0, createInfo.numLayers, 0, &offset),
|
|
KTX_INVALID_OPERATION);
|
|
EXPECT_EQ(ktxTexture_GetImageOffset(texture, 0, 0, createInfo.numFaces, &offset),
|
|
KTX_INVALID_OPERATION);
|
|
if (texture)
|
|
ktxTexture_Destroy(texture);
|
|
}
|
|
|
|
TEST(ktxTexture_GetImageOffsetTest, ImageOffsetLevel) {
|
|
//using createFlagBits = typename WriterTestHelper<GLubyte, 4, GL_RGBA8>::createFlagBits;
|
|
TextureWriterTestHelper<GLubyte, 4, GL_RGBA8> helper;
|
|
|
|
helper.resize(createFlagBits::eMipmapped, 1, 1, 2, 16, 16, 1);
|
|
ktxTexture* texture = 0;
|
|
KTX_error_code result;
|
|
ktx_size_t expectedOffset, imageSize, offset;
|
|
|
|
result = ktxTexture1_Create(&helper.createInfo,
|
|
KTX_TEXTURE_CREATE_NO_STORAGE,
|
|
(ktxTexture1**)&texture);
|
|
EXPECT_EQ(result, KTX_SUCCESS);
|
|
ASSERT_TRUE(texture != NULL) << "ktxTexture1_Create failed: "
|
|
<< ktxErrorString(result);
|
|
EXPECT_EQ(ktxTexture_GetImageOffset(texture, 0, 0, 0, &offset),
|
|
KTX_SUCCESS);
|
|
EXPECT_EQ(offset, 0U);
|
|
// GL_RGBA8 is 1 x 4 bytes.
|
|
imageSize = helper.createInfo.baseWidth
|
|
* helper.createInfo.baseHeight * 1 * 4;
|
|
expectedOffset = imageSize;
|
|
EXPECT_EQ(ktxTexture_GetImageOffset(texture, 1, 0, 0, &offset),
|
|
KTX_SUCCESS);
|
|
EXPECT_EQ(offset, expectedOffset);
|
|
// The image used to calculate imageDataSize has the same dimensions and
|
|
// internalformat as those specified by createInfo.
|
|
expectedOffset = helper.imageDataSize - 4;
|
|
EXPECT_EQ(ktxTexture_GetImageOffset(texture, helper.createInfo.numLevels - 1, 0, 0, &offset),
|
|
KTX_SUCCESS);
|
|
EXPECT_EQ(offset, expectedOffset);
|
|
if (texture)
|
|
ktxTexture_Destroy(texture);
|
|
}
|
|
|
|
TEST(ktxTexture_GetImageOffsetTest, ImageOffsetWithRowPadding) {
|
|
ktxTexture* texture = 0;
|
|
TestCreateInfo createInfo;
|
|
KTX_error_code result;
|
|
ktx_size_t expectedOffset, imageSize, offset;
|
|
ktx_uint32_t rowBytes, rowRounding;
|
|
|
|
// Pick type and size that requires row padding for KTX_GL_UNPACK_ALIGNMENT.
|
|
createInfo.glInternalformat = GL_RGB8;
|
|
createInfo.baseWidth = 9;
|
|
result = ktxTexture1_Create(&createInfo, KTX_TEXTURE_CREATE_NO_STORAGE,
|
|
(ktxTexture1**)&texture);
|
|
EXPECT_EQ(result, KTX_SUCCESS);
|
|
ASSERT_TRUE(texture != NULL) << "ktxTexture1_Create failed: "
|
|
<< ktxErrorString(result);
|
|
rowBytes = 9 * 3;
|
|
rowRounding = ROUNDING(rowBytes);
|
|
imageSize = (rowBytes + rowRounding) * texture->baseHeight;
|
|
expectedOffset = imageSize;
|
|
EXPECT_EQ(ktxTexture_GetImageOffset(texture, 1, 0, 0, &offset),
|
|
KTX_SUCCESS);
|
|
EXPECT_EQ(offset, expectedOffset);
|
|
|
|
expectedOffset = 0;
|
|
for (ktx_uint32_t i = 0; i < texture->numLevels - 1; i++) {
|
|
ktx_uint32_t levelWidth = MAX(1, texture->baseWidth >> i);
|
|
ktx_uint32_t levelHeight = MAX(1, texture->baseHeight >> i);
|
|
|
|
int levelRowBytes = levelWidth * 3;
|
|
rowRounding = ROUNDING(levelRowBytes);
|
|
levelRowBytes += rowRounding;
|
|
imageSize = levelRowBytes * levelHeight;
|
|
expectedOffset += imageSize;
|
|
}
|
|
EXPECT_EQ(ktxTexture_GetImageOffset(texture, createInfo.numLevels - 1, 0, 0, &offset),
|
|
KTX_SUCCESS);
|
|
EXPECT_EQ(offset, expectedOffset);
|
|
if (texture)
|
|
ktxTexture_Destroy(texture);
|
|
}
|
|
|
|
TEST(ktxTexture_GetImageOffsetTest, ImageOffsetArray) {
|
|
ktxTexture* texture = 0;
|
|
TestCreateInfo createInfo;
|
|
KTX_error_code result;
|
|
ktx_size_t expectedOffset, offset;
|
|
ktx_uint32_t rowBytes, rowRounding, imageSize, layerSize;
|
|
ktx_uint32_t levelWidth, levelHeight, levelImageSize, levelRowBytes;
|
|
|
|
createInfo.glInternalformat = GL_RGB8;
|
|
createInfo.baseWidth = 9;
|
|
createInfo.numLayers = 3;
|
|
result = ktxTexture1_Create(&createInfo, KTX_TEXTURE_CREATE_NO_STORAGE,
|
|
(ktxTexture1**)&texture);
|
|
EXPECT_EQ(result, KTX_SUCCESS);
|
|
ASSERT_TRUE(texture != NULL) << "ktxTexture1_Create failed: "
|
|
<< ktxErrorString(result);
|
|
rowBytes = 9 * 3;
|
|
rowRounding = ROUNDING(rowBytes);
|
|
imageSize = (rowBytes + rowRounding) * createInfo.baseHeight;
|
|
layerSize = imageSize * texture->numFaces;
|
|
expectedOffset = layerSize * texture->numLayers;
|
|
EXPECT_EQ(ktxTexture_GetImageOffset(texture, 1, 0, 0, &offset),
|
|
KTX_SUCCESS);
|
|
EXPECT_EQ(offset, expectedOffset);
|
|
levelWidth = MAX(1, texture->baseWidth >> 1);
|
|
levelHeight = MAX(1, texture->baseHeight >> 1);
|
|
levelRowBytes = levelWidth * 3;
|
|
rowRounding = ROUNDING(levelRowBytes);
|
|
levelRowBytes += rowRounding;
|
|
levelImageSize = levelRowBytes * levelHeight;
|
|
expectedOffset += levelImageSize * 2;
|
|
EXPECT_EQ(ktxTexture_GetImageOffset(texture, 1, 2, 0, &offset),
|
|
KTX_SUCCESS);
|
|
EXPECT_EQ(offset, expectedOffset);
|
|
if (texture)
|
|
ktxTexture_Destroy(texture);
|
|
}
|
|
|
|
TEST(ktxTexture_GetImageOffsetTest, ImageOffsetFace) {
|
|
ktxTexture* texture = 0;
|
|
TestCreateInfo createInfo;
|
|
KTX_error_code result;
|
|
ktx_size_t expectedOffset, offset;
|
|
ktx_uint32_t rowBytes, rowRounding, imageSize, layerSize;
|
|
ktx_uint32_t levelWidth, levelHeight, levelImageSize, levelRowBytes;
|
|
|
|
createInfo.glInternalformat = GL_RGB8;
|
|
createInfo.baseWidth = 9;
|
|
createInfo.baseHeight = 9;
|
|
createInfo.numLevels = 4;
|
|
createInfo.numLayers = 1;
|
|
createInfo.numFaces = 6;
|
|
result = ktxTexture1_Create(&createInfo, KTX_TEXTURE_CREATE_NO_STORAGE,
|
|
(ktxTexture1**)&texture);
|
|
EXPECT_EQ(result, KTX_SUCCESS);
|
|
ASSERT_TRUE(texture != NULL) << "ktxTexture1_Create failed: "
|
|
<< ktxErrorString(result);
|
|
rowBytes = 9 * 3;
|
|
rowRounding = ROUNDING(rowBytes);
|
|
imageSize = (rowBytes + rowRounding) * texture->baseHeight;
|
|
layerSize = imageSize * texture->numFaces;
|
|
expectedOffset = imageSize * 4;
|
|
EXPECT_EQ(ktxTexture_GetImageOffset(texture, 0, 0, 4, &offset),
|
|
KTX_SUCCESS);
|
|
EXPECT_EQ(offset, expectedOffset);
|
|
levelWidth = MAX(1, texture->baseWidth >> 1);
|
|
levelHeight = MAX(1, texture->baseHeight >> 1);
|
|
levelRowBytes = levelWidth * 3;
|
|
rowRounding = ROUNDING(levelRowBytes);
|
|
levelRowBytes += rowRounding;
|
|
levelImageSize = levelRowBytes * levelHeight;
|
|
expectedOffset = layerSize + levelImageSize * 3;
|
|
EXPECT_EQ(ktxTexture_GetImageOffset(texture, 1, 0, 3, &offset),
|
|
KTX_SUCCESS);
|
|
EXPECT_EQ(offset, expectedOffset);
|
|
if (texture)
|
|
ktxTexture_Destroy(texture);
|
|
}
|
|
|
|
TEST(ktxTexture_GetImageOffsetTest, ImageOffsetArrayFace) {
|
|
ktxTexture* texture = 0;
|
|
TestCreateInfo createInfo;
|
|
KTX_error_code result;
|
|
ktx_size_t expectedOffset, offset;
|
|
ktx_uint32_t rowBytes, rowRounding, imageSize, layerSize;
|
|
ktx_uint32_t levelWidth, levelHeight, levelImageSize, levelRowBytes;
|
|
|
|
createInfo.glInternalformat = GL_RGB8;
|
|
createInfo.baseWidth = 9;
|
|
createInfo.baseWidth = 9;
|
|
createInfo.baseHeight = 9;
|
|
createInfo.numLevels = 4;
|
|
createInfo.numLayers = 3;
|
|
createInfo.numFaces = 6;
|
|
result = ktxTexture1_Create(&createInfo, KTX_TEXTURE_CREATE_NO_STORAGE,
|
|
(ktxTexture1**)&texture);
|
|
EXPECT_EQ(result, KTX_SUCCESS);
|
|
ASSERT_TRUE(texture != NULL) << "ktxTexture1_Create failed: "
|
|
<< ktxErrorString(result);
|
|
rowBytes = 9 * 3;
|
|
rowRounding = ROUNDING(rowBytes);
|
|
imageSize = (rowBytes + rowRounding) * createInfo.baseHeight;
|
|
layerSize = imageSize * texture->numFaces;
|
|
expectedOffset = layerSize * createInfo.numLayers;
|
|
EXPECT_EQ(ktxTexture_GetImageOffset(texture, 1, 0, 0, &offset),
|
|
KTX_SUCCESS);
|
|
EXPECT_EQ(offset, expectedOffset);
|
|
levelWidth = MAX(1, createInfo.baseWidth >> 1);
|
|
levelHeight = MAX(1, createInfo.baseHeight >> 1);
|
|
levelRowBytes = levelWidth * 3;
|
|
rowRounding = ROUNDING(levelRowBytes);
|
|
levelRowBytes += rowRounding;
|
|
levelImageSize = levelRowBytes * levelHeight;
|
|
expectedOffset += levelImageSize * texture->numFaces * 2;
|
|
EXPECT_EQ(ktxTexture_GetImageOffset(texture, 1, 2, 0, &offset),
|
|
KTX_SUCCESS);
|
|
EXPECT_EQ(offset, expectedOffset);
|
|
expectedOffset += levelImageSize * 3; // 3 faces
|
|
EXPECT_EQ(ktxTexture_GetImageOffset(texture, 1, 2, 3, &offset),
|
|
KTX_SUCCESS);
|
|
EXPECT_EQ(offset, expectedOffset);
|
|
if (texture)
|
|
ktxTexture_Destroy(texture);
|
|
}
|
|
|
|
/////////////////////////////////////////
|
|
// ktxTexture_Write tests
|
|
////////////////////////////////////////
|
|
|
|
TEST_F(ktxTexture1WriteTestRGB8, Write1D) {
|
|
helper.resize(createFlagBits::eNone, 1, 1, 1, 32, 1, 1);
|
|
runTest(false);
|
|
}
|
|
|
|
TEST_F(ktxTexture1WriteTestRGB8, Write1DNeedsPadding) {
|
|
helper.resize(createFlagBits::eNone, 1, 1, 1, 9, 1, 1);
|
|
runTest(false);
|
|
}
|
|
|
|
TEST_F(ktxTexture1WriteTestRGBA8, Write1DMipmap) {
|
|
helper.resize(createFlagBits::eMipmapped, 1, 1, 1, 32, 1, 1);
|
|
runTest(false);
|
|
}
|
|
|
|
TEST_F(ktxTexture1WriteTestRGB8, Write1DArray) {
|
|
helper.resize(createFlagBits::eArray, 4, 1, 1, 32, 1, 1);
|
|
runTest(false);
|
|
}
|
|
|
|
TEST_F(ktxTexture1WriteTestRGBA8, Write1DArrayMipmap) {
|
|
helper.resize(createFlagBits::eMipmapped | createFlagBits::eArray,
|
|
4, 1, 1, 32, 1, 1);
|
|
runTest(false);
|
|
}
|
|
|
|
TEST_F(ktxTexture1WriteTestRGB8, Write2D) {
|
|
helper.resize(createFlagBits::eNone, 1, 1, 2, 32, 32, 1);
|
|
runTest(true);
|
|
}
|
|
|
|
TEST_F(ktxTexture1WriteTestRGB8, Write2DMipmap) {
|
|
helper.resize(createFlagBits::eMipmapped, 1, 1, 2, 32, 32, 1);
|
|
runTest(true);
|
|
}
|
|
|
|
TEST_F(ktxTexture1WriteTestRGBA8, Write2DArray) {
|
|
helper.resize(createFlagBits::eArray, 4, 1, 2, 32, 32, 1);
|
|
runTest(true);
|
|
}
|
|
|
|
TEST_F(ktxTexture1WriteTestRGBA8, Write2DArrayMipmap) {
|
|
helper.resize(createFlagBits::eArray | createFlagBits::eMipmapped,
|
|
4, 1, 2, 32, 32, 1);
|
|
runTest(true);
|
|
}
|
|
|
|
TEST_F(ktxTexture1WriteTestRGB8, 3D) {
|
|
helper.resize(createFlagBits::eNone,1, 1, 3, 32, 32, 32);
|
|
runTest(true);
|
|
}
|
|
|
|
TEST_F(ktxTexture1WriteTestRGB8, Write3DMipmap) {
|
|
helper.resize(createFlagBits::eMipmapped, 1, 1, 3, 8, 8, 2);
|
|
runTest(true);
|
|
}
|
|
|
|
TEST_F(ktxTexture1WriteTestRGB8, WriteCubemap) {
|
|
helper.resize(createFlagBits::eNone, 1, 6, 2, 32, 32, 1);
|
|
runTest(true);
|
|
}
|
|
|
|
TEST_F(ktxTexture1WriteTestRGBA8, WriteCubemapMipmap) {
|
|
helper.resize(createFlagBits::eMipmapped,
|
|
1, 6, 2, 32, 32, 1);
|
|
runTest(true);
|
|
}
|
|
TEST_F(ktxTexture1WriteTestRGBA8, WriteCubemapArrayMipmap) {
|
|
helper.resize(createFlagBits::eMipmapped | createFlagBits::eArray,
|
|
4, 6, 2, 32, 32, 1);
|
|
runTest(true);
|
|
}
|
|
|
|
TEST_F(ktxTexture1WriteTestRG16, Write2DMipmap) {
|
|
helper.resize(createFlagBits::eMipmapped, 1, 1, 2, 32, 32, 1);
|
|
runTest(true);
|
|
}
|
|
|
|
//----------------------------------------------------------
|
|
// Template for base fixture for ktxTexture_WriteKTX2 tests.
|
|
//----------------------------------------------------------
|
|
|
|
#include "vkformat_enum.h"
|
|
#define LIBKTX // To make dfd.h not include vulkan/vulkan_core.h.
|
|
#include "dfdutils/dfd.h"
|
|
|
|
template<typename component_type, ktx_uint32_t numComponents,
|
|
GLenum internalformat>
|
|
class ktxTexture1WriteKTX2TestBase
|
|
: public ktxTexture1WriteTestBase<component_type, numComponents, internalformat> {
|
|
public:
|
|
using createFlags = typename WriterTestHelper<component_type, numComponents, internalformat>::createFlags;
|
|
using ktxTexture1WriteTestBase<component_type, numComponents, internalformat>::helper;
|
|
|
|
ktxTexture1WriteKTX2TestBase() {
|
|
requiredLevelAlignment = lcm4(sizeof(component_type) * numComponents);
|
|
}
|
|
|
|
void runTest(bool writeOrientationMeta, bool writeWriterMeta = true) {
|
|
ktxTexture1* texture = 0;
|
|
KTX_error_code result;
|
|
ktx_uint8_t* ktxMemFile;
|
|
ktx_size_t ktxMemFileLen;
|
|
ktx_uint8_t* filePtr;
|
|
ktxHashList* hl;
|
|
ktxHashList_Create(&hl);
|
|
ktx_uint8_t* kvData;
|
|
ktx_uint32_t kvDataLen;
|
|
|
|
result = ktxTexture1_Create(&helper.createInfo,
|
|
KTX_TEXTURE_CREATE_ALLOC_STORAGE,
|
|
&texture);
|
|
EXPECT_EQ(result, KTX_SUCCESS);
|
|
ASSERT_TRUE(texture != NULL) << "ktxTexture1_Create failed: "
|
|
<< ktxErrorString(result);
|
|
|
|
if (writeOrientationMeta) {
|
|
// Reminder: this is for the KTX 1 texture we have just created.
|
|
ktxHashList_AddKVPair(&texture->kvDataHead, KTX_ORIENTATION_KEY,
|
|
(unsigned int)strlen(helper.orientation) + 1,
|
|
helper.orientation);
|
|
// This is for the comparison metadata.
|
|
ktxHashList_AddKVPair(hl, KTX_ORIENTATION_KEY,
|
|
(unsigned int)strlen(helper.orientation_ktx2) + 1,
|
|
helper.orientation_ktx2);
|
|
}
|
|
// N.B. Writer metadata is not legal in a KTX v1 file but we know
|
|
// we're going to write this out as a v2 file so okay.
|
|
if (writeWriterMeta) {
|
|
ktxHashList_AddKVPair(&texture->kvDataHead, KTX_WRITER_KEY,
|
|
(uint32_t)helper.writer_ktx2.size(),
|
|
helper.writer_ktx2.data());
|
|
ktxHashList_AddKVPair(hl, KTX_WRITER_KEY,
|
|
(uint32_t)helper.writer_ktx2.size(),
|
|
helper.writer_ktx2.data());
|
|
}
|
|
// Now update the comparison metadata by doing the things WriteKTX2 is
|
|
// supposed to do so we can check it's actually doing it..
|
|
ktxHashListEntry* pWriter = nullptr;;
|
|
ktxHashList_FindEntry(hl, KTX_WRITER_KEY, &pWriter);
|
|
result = appendLibId(hl, pWriter);
|
|
EXPECT_EQ(result, KTX_SUCCESS);
|
|
ktxHashList_Sort(hl);
|
|
// And retrieve the comparison metadata.
|
|
ktxHashList_Serialize(hl, &kvDataLen, &kvData);
|
|
|
|
result = helper.copyImagesToTexture(texture);
|
|
EXPECT_EQ(result, KTX_SUCCESS);
|
|
|
|
EXPECT_EQ(helper.compareTexture1Images(texture->pData), true);
|
|
|
|
result = ktxTexture1_WriteKTX2ToMemory(texture,
|
|
&ktxMemFile,
|
|
&ktxMemFileLen);
|
|
|
|
ASSERT_TRUE(result == KTX_SUCCESS) << "ktxTexture_WriteKTX2ToMemory failed: "
|
|
<< ktxErrorString(result);
|
|
|
|
KTX_header2* header = (KTX_header2*)ktxMemFile;
|
|
|
|
EXPECT_EQ(memcmp(header, ktxId2, sizeof(ktxId2)), 0);
|
|
EXPECT_EQ(helper.texinfo.compare(header), true);
|
|
|
|
// Check the format descriptor.
|
|
// This uses the same code to generate the comparator DFD as the
|
|
// code under test. However we have separate tests for the
|
|
// generator, so can be reasonably confident in it. This test
|
|
// ensures there is a DFD in the file.
|
|
ktx_uint32_t* dfd = vk2dfd(static_cast<VkFormat>(header->vkFormat));
|
|
EXPECT_EQ(memcmp(ktxMemFile + header->dataFormatDescriptor.byteOffset,
|
|
dfd,
|
|
*dfd), 0);
|
|
|
|
// Check the metadata.
|
|
filePtr = ktxMemFile + header->keyValueData.byteOffset;
|
|
EXPECT_EQ(header->keyValueData.byteLength, kvDataLen);
|
|
EXPECT_EQ(memcmp(filePtr, kvData, kvDataLen), 0);
|
|
filePtr += kvDataLen;
|
|
|
|
#if 0
|
|
if (writeOrientationMeta) {
|
|
EXPECT_EQ(header->keyValueData.byteLength,
|
|
helper.kvDataLenAll_ktx2);
|
|
EXPECT_EQ(memcmp(filePtr, helper.kvDataAll_ktx2,
|
|
helper.kvDataLenAll_ktx2), 0);
|
|
filePtr += helper.kvDataLenAll_ktx2;
|
|
} else {
|
|
EXPECT_EQ(header->keyValueData.byteLength,
|
|
helper.kvDataLenWriter_ktx2);
|
|
EXPECT_EQ(memcmp(filePtr, helper.kvDataWriter_ktx2,
|
|
helper.kvDataLenWriter_ktx2), 0);
|
|
filePtr += helper.kvDataLenWriter_ktx2;
|
|
}
|
|
#endif
|
|
// Offset of level 0 is first item in leveIndex after header.
|
|
ktxLevelIndexEntry* levelIndex =
|
|
reinterpret_cast<ktxLevelIndexEntry*>(ktxMemFile + sizeof(*header));
|
|
|
|
ktx_uint64_t prevOffset = UINT64_MAX;
|
|
for (ktx_uint32_t level = 0; level < helper.numLevels; level++) {
|
|
ktx_uint64_t levelOffset = levelIndex[level].byteOffset;
|
|
// Check offset is properly aligned.
|
|
EXPECT_EQ(levelOffset % requiredLevelAlignment, 0U);
|
|
// Check mipmaps are in order of increasing size in the file
|
|
// therefore each offset should be smaller than the previous.
|
|
EXPECT_LE(levelOffset, prevOffset);
|
|
prevOffset = levelOffset;
|
|
}
|
|
|
|
EXPECT_EQ(helper.compareRawImages(levelIndex, ktxMemFile), true);
|
|
delete ktxMemFile;
|
|
ktxTexture_Destroy(ktxTexture(texture));
|
|
}
|
|
|
|
// Test rejection of unrecognized keys and passing of proprietary keys.
|
|
void runTest(const char* unrecognizedKey, const char* proprietaryKey) {
|
|
ktxTexture1* texture = 0;
|
|
KTX_error_code result;
|
|
ktx_uint8_t* ktxMemFile;
|
|
ktx_size_t ktxMemFileLen;
|
|
ktx_uint8_t* filePtr;
|
|
ktx_uint8_t* kvData;
|
|
ktx_uint32_t kvDataLen;
|
|
|
|
result = ktxTexture1_Create(&helper.createInfo,
|
|
KTX_TEXTURE_CREATE_ALLOC_STORAGE,
|
|
&texture);
|
|
EXPECT_EQ(result, KTX_SUCCESS);
|
|
ASSERT_TRUE(texture != NULL) << "ktxTexture1_Create failed: "
|
|
<< ktxErrorString(result);
|
|
|
|
ktxHashList* hl;
|
|
ktxHashList_Create(&hl);
|
|
ktxHashList* hlists[2] = {&texture->kvDataHead, hl};
|
|
// Add desired keys & values to both the texture and a comparator.
|
|
char rubbishValue[] = "some rubbish value";
|
|
for (uint32_t i = 0; i < 2; i++) {
|
|
// N.B. Writer metadata is not legal in a KTX v1 file but we know
|
|
// we're going to write this out as a v2 file so okay.
|
|
ktxHashList_AddKVPair(hlists[i], KTX_WRITER_KEY,
|
|
(uint32_t)helper.writer_ktx2.size(),
|
|
helper.writer_ktx2.data());
|
|
if (unrecognizedKey) {
|
|
ktxHashList_AddKVPair(hlists[i], unrecognizedKey,
|
|
sizeof(rubbishValue),
|
|
rubbishValue);
|
|
}
|
|
if (proprietaryKey) {
|
|
ktxHashList_AddKVPair(hlists[i], proprietaryKey,
|
|
sizeof(rubbishValue),
|
|
rubbishValue);
|
|
}
|
|
ktxHashList_Sort(hlists[i]);
|
|
}
|
|
// Get the library to add its Id to the writer key so it will be
|
|
// included in the serialized data.
|
|
ktxHashListEntry* pWriter;
|
|
ktxHashList_FindEntry(hl, KTX_WRITER_KEY, &pWriter);
|
|
appendLibId(hl, pWriter);
|
|
ktxHashList_Sort(hl);
|
|
ktxHashList_Serialize(hl, &kvDataLen, &kvData);
|
|
ktxHashList_Destruct(hl);
|
|
|
|
result = helper.copyImagesToTexture(texture);
|
|
EXPECT_EQ(result, KTX_SUCCESS);
|
|
|
|
EXPECT_EQ(helper.compareTexture1Images(texture->pData), true);
|
|
|
|
result = ktxTexture1_WriteKTX2ToMemory(texture,
|
|
&ktxMemFile,
|
|
&ktxMemFileLen);
|
|
|
|
if (unrecognizedKey == NULL) {
|
|
ASSERT_TRUE(result == KTX_SUCCESS) << "ktxTexture_WriteKTX2ToMemory failed: "
|
|
<< ktxErrorString(result);
|
|
|
|
KTX_header2* header = (KTX_header2*)ktxMemFile;
|
|
|
|
EXPECT_EQ(memcmp(header, ktxId2, sizeof(ktxId2)), 0);
|
|
EXPECT_EQ(helper.texinfo.compare(header), true);
|
|
|
|
// Check the format descriptor.
|
|
ktx_uint32_t* dfd = vk2dfd(static_cast<VkFormat>(header->vkFormat));
|
|
EXPECT_EQ(memcmp(ktxMemFile + header->dataFormatDescriptor.byteOffset,
|
|
dfd,
|
|
*dfd), 0);
|
|
|
|
// Check the metadata.
|
|
filePtr = ktxMemFile + header->keyValueData.byteOffset;
|
|
EXPECT_EQ(header->keyValueData.byteLength, kvDataLen);
|
|
EXPECT_EQ(memcmp(filePtr, kvData, kvDataLen), 0);
|
|
filePtr += helper.kvDataLen;
|
|
|
|
// Offset of level 0 is first item in leveIndex after header.
|
|
ktxLevelIndexEntry* levelIndex =
|
|
reinterpret_cast<ktxLevelIndexEntry*>(ktxMemFile + sizeof(*header));
|
|
|
|
ktx_uint64_t offset = UINT64_MAX;
|
|
for (ktx_uint32_t level = 0; level < helper.numLevels; level++) {
|
|
ktx_uint64_t levelOffset = levelIndex[level].byteOffset;
|
|
// Check offset is properly aligned.
|
|
EXPECT_EQ(levelOffset % requiredLevelAlignment, 0U);
|
|
// Check mipmaps are in order of increasing size in the file
|
|
// therefore each offset should be smaller than the previous.
|
|
EXPECT_LE(levelOffset, offset);
|
|
offset = levelOffset;
|
|
}
|
|
|
|
EXPECT_EQ(helper.compareRawImages(levelIndex, ktxMemFile), true);
|
|
|
|
delete ktxMemFile;
|
|
} else {
|
|
EXPECT_EQ(result, KTX_INVALID_OPERATION);
|
|
}
|
|
|
|
ktxTexture_Destroy(ktxTexture(texture));
|
|
delete kvData;
|
|
|
|
}
|
|
protected:
|
|
ktx_uint32_t requiredLevelAlignment;
|
|
};
|
|
|
|
class ktxTexture1WriteKTX2TestRGBA8: public ktxTexture1WriteKTX2TestBase<GLubyte, 4, GL_RGBA8> { };
|
|
class ktxTexture1WriteKTX2TestRGB8: public ktxTexture1WriteKTX2TestBase<GLubyte, 3, GL_RGB8> { };
|
|
class ktxTexture1WriteKTX2TestRG16: public ktxTexture1WriteKTX2TestBase<GLushort, 2, GL_RG16> { };
|
|
|
|
/////////////////////////////////////////
|
|
// ktxTexture_WriteKTX2 tests
|
|
////////////////////////////////////////
|
|
|
|
TEST_F(ktxTexture1WriteKTX2TestRGBA8, Write1DNoOrientationMetadata) {
|
|
helper.resize(createFlagBits::eNone, 1, 1, 1, 32, 1, 1);
|
|
runTest(false);
|
|
}
|
|
|
|
TEST_F(ktxTexture1WriteKTX2TestRGBA8, Write1DNoWriterMetadata) {
|
|
helper.resize(createFlagBits::eNone, 1, 1, 1, 32, 1, 1);
|
|
runTest(false, false);
|
|
}
|
|
|
|
TEST_F(ktxTexture1WriteKTX2TestRGBA8, Write1DMipmap) {
|
|
helper.resize(createFlagBits::eMipmapped, 1, 1, 1, 32, 1, 1);
|
|
runTest(false);
|
|
}
|
|
|
|
|
|
TEST_F(ktxTexture1WriteKTX2TestRGB8, Write1DArray) {
|
|
helper.resize(createFlagBits::eArray, 4, 1, 1, 32, 1, 1);
|
|
runTest(false);
|
|
}
|
|
|
|
TEST_F(ktxTexture1WriteKTX2TestRGBA8, Write1DArrayMipmap) {
|
|
helper.resize(createFlagBits::eMipmapped | createFlagBits::eArray,
|
|
4, 1, 1, 32, 1, 1);
|
|
runTest(false);
|
|
}
|
|
|
|
TEST_F(ktxTexture1WriteKTX2TestRGBA8, Write2DNoOrientationMetadata) {
|
|
helper.resize(createFlagBits::eNone, 1, 1, 2, 32, 32, 1);
|
|
runTest(false);
|
|
}
|
|
|
|
TEST_F(ktxTexture1WriteKTX2TestRGBA8, Write2DNoWriterMetadata) {
|
|
helper.resize(createFlagBits::eNone, 1, 1, 2, 32, 32, 1);
|
|
runTest(false, false);
|
|
}
|
|
|
|
TEST_F(ktxTexture1WriteKTX2TestRGB8, Write2DMipmap) {
|
|
helper.resize(createFlagBits::eMipmapped, 1, 1, 2, 32, 32, 1);
|
|
runTest(true);
|
|
}
|
|
|
|
TEST_F(ktxTexture1WriteKTX2TestRGB8, Write2DMipmapUnrecognizedMetadata1) {
|
|
helper.resize(createFlagBits::eMipmapped, 1, 1, 2, 32, 32, 1);
|
|
runTest("KTXOrientation", NULL);
|
|
}
|
|
|
|
TEST_F(ktxTexture1WriteKTX2TestRGB8, Write2DMipmapUnrecognizedMetadata2) {
|
|
helper.resize(createFlagBits::eMipmapped, 1, 1, 2, 32, 32, 1);
|
|
runTest("ktxOrientation", NULL);
|
|
}
|
|
|
|
TEST_F(ktxTexture1WriteKTX2TestRGB8, Write2DMipmapProprietaryMetadata) {
|
|
helper.resize(createFlagBits::eMipmapped, 1, 1, 2, 32, 32, 1);
|
|
runTest(NULL, "MyProprietaryKey");
|
|
}
|
|
|
|
TEST_F(ktxTexture1WriteKTX2TestRGB8, Write2DMipmapUnrecogAndPropMetadata) {
|
|
helper.resize(createFlagBits::eMipmapped, 1, 1, 2, 32, 32, 1);
|
|
runTest("KTXOrientation", "MyProprietaryKey");
|
|
}
|
|
TEST_F(ktxTexture1WriteKTX2TestRGBA8, Write2DArray) {
|
|
helper.resize(createFlagBits::eArray, 4, 1, 2, 32, 32, 1);
|
|
runTest(true);
|
|
}
|
|
|
|
TEST_F(ktxTexture1WriteKTX2TestRGBA8, Write2DArrayMipmap) {
|
|
helper.resize(createFlagBits::eArray | createFlagBits::eMipmapped,
|
|
4, 1, 2, 32, 32, 1);
|
|
runTest(true);
|
|
}
|
|
|
|
TEST_F(ktxTexture1WriteKTX2TestRGB8, 3D) {
|
|
helper.resize(createFlagBits::eNone,1, 1, 3, 32, 32, 32);
|
|
runTest(true);
|
|
}
|
|
|
|
TEST_F(ktxTexture1WriteKTX2TestRGB8, Write3DMipmap) {
|
|
helper.resize(createFlagBits::eMipmapped, 1, 1, 3, 8, 8, 2);
|
|
runTest(true);
|
|
}
|
|
|
|
TEST_F(ktxTexture1WriteKTX2TestRGB8, WriteCubemap) {
|
|
helper.resize(createFlagBits::eNone, 1, 6, 2, 32, 32, 1);
|
|
runTest(true);
|
|
}
|
|
|
|
TEST_F(ktxTexture1WriteKTX2TestRGBA8, WriteCubemapMipmap) {
|
|
helper.resize(createFlagBits::eMipmapped,
|
|
1, 6, 2, 32, 32, 1);
|
|
runTest(true);
|
|
}
|
|
|
|
TEST_F(ktxTexture1WriteKTX2TestRGBA8, WriteCubemapArrayMipmap) {
|
|
helper.resize(createFlagBits::eMipmapped | createFlagBits::eArray,
|
|
4, 6, 2, 32, 32, 1);
|
|
runTest(true);
|
|
}
|
|
|
|
TEST_F(ktxTexture1WriteKTX2TestRG16, Write2DMipmap) {
|
|
helper.resize(createFlagBits::eMipmapped, 1, 1, 2, 32, 32, 1);
|
|
runTest(true);
|
|
}
|
|
|
|
//----------------------------------------------------------
|
|
// Template for base fixture for ktxTexture2_Read tests.
|
|
//----------------------------------------------------------
|
|
|
|
template<typename component_type, ktx_uint32_t numComponents,
|
|
GLenum internalformat>
|
|
class ktxTexture2ReadTestBase
|
|
: public ktxTexture1WriteTestBase<component_type, numComponents, internalformat> {
|
|
public:
|
|
using createFlags = typename WriterTestHelper<component_type, numComponents, internalformat>::createFlags;
|
|
using ktxTexture1WriteTestBase<component_type, numComponents, internalformat>::helper;
|
|
|
|
ktxTexture2ReadTestBase() { }
|
|
|
|
~ktxTexture2ReadTestBase() {
|
|
if (ktx2MemFile) delete ktx2MemFile;
|
|
}
|
|
|
|
void resize(createFlags flags,
|
|
ktx_uint32_t numLayers, ktx_uint32_t numFaces,
|
|
ktx_uint32_t numDimensions,
|
|
ktx_uint32_t width, ktx_uint32_t height, ktx_uint32_t depth)
|
|
{
|
|
ktxTexture1* texture = 0;
|
|
KTX_error_code result;
|
|
|
|
helper.resize(flags, numLayers, numFaces, numDimensions,
|
|
width, height, depth);
|
|
|
|
result = ktxTexture1_Create(&helper.createInfo,
|
|
KTX_TEXTURE_CREATE_ALLOC_STORAGE,
|
|
&texture);
|
|
EXPECT_EQ(result, KTX_SUCCESS);
|
|
ASSERT_TRUE(texture != NULL) << "ktxTexture1_Create failed: "
|
|
<< ktxErrorString(result);
|
|
|
|
// Reminder: this is for the KTX 1 texture we have just created.
|
|
ktxHashList_AddKVPair(&texture->kvDataHead, KTX_ORIENTATION_KEY,
|
|
(unsigned int)strlen(helper.orientation) + 1,
|
|
helper.orientation);
|
|
ktxHashList_AddKVPair(&texture->kvDataHead, KTX_WRITER_KEY,
|
|
(uint32_t)helper.writer_ktx2.size(),
|
|
helper.writer_ktx2.data());
|
|
|
|
result = helper.copyImagesToTexture(texture);
|
|
EXPECT_EQ(result, KTX_SUCCESS);
|
|
|
|
EXPECT_EQ(helper.compareTexture1Images(texture->pData), true);
|
|
|
|
result = ktxTexture1_WriteKTX2ToMemory(texture,
|
|
&ktx2MemFile,
|
|
&ktx2MemFileLen);
|
|
ASSERT_TRUE(result == KTX_SUCCESS) << "ktxTexture1_WriteKTX2ToMemory failed: "
|
|
<< ktxErrorString(result);
|
|
fileHeader = (KTX_header2*)ktx2MemFile;
|
|
levelIndex = (ktxLevelIndexEntry*)(ktx2MemFile + sizeof(KTX_header2));
|
|
|
|
ktxTexture1_destruct(texture);
|
|
}
|
|
|
|
void runTest() {
|
|
ktxTexture2* texture2 = 0;
|
|
KTX_error_code result;
|
|
|
|
result = ktxTexture2_CreateFromMemory(ktx2MemFile, ktx2MemFileLen,
|
|
KTX_TEXTURE_CREATE_LOAD_IMAGE_DATA_BIT,
|
|
&texture2);
|
|
|
|
EXPECT_EQ(result, KTX_SUCCESS);
|
|
ASSERT_TRUE(texture2 != NULL) << "ktxTexture2_Create failed: "
|
|
<< ktxErrorString(result);
|
|
|
|
EXPECT_EQ(texture2->classId, ktxTexture2_c);
|
|
EXPECT_EQ(helper.texinfo.compare(texture2), true);
|
|
EXPECT_NE(texture2->kvDataHead, (ktxKVListEntry*)0);
|
|
|
|
// Check the levelOffsets are as expected.
|
|
ktx_size_t baseOffset = levelIndex[helper.numLevels - 1].byteOffset;
|
|
for (ktx_uint32_t level = 0; level < texture2->numLevels; level++) {
|
|
ktx_size_t levelOffset;
|
|
result = ktxTexture2_GetImageOffset(texture2, level, 0, 0,
|
|
&levelOffset);
|
|
EXPECT_EQ(result, KTX_SUCCESS);
|
|
EXPECT_EQ(levelOffset, levelIndex[level].byteOffset - baseOffset);
|
|
}
|
|
|
|
ktxTexture2_destruct(texture2);
|
|
|
|
}
|
|
|
|
protected:
|
|
ktx_uint8_t* ktx2MemFile;
|
|
ktx_size_t ktx2MemFileLen;
|
|
KTX_header2* fileHeader;
|
|
ktxLevelIndexEntry* levelIndex;
|
|
};
|
|
|
|
class ktxTexture2ReadTestRGBA8: public ktxTexture2ReadTestBase<GLubyte, 4, GL_RGBA8> { };
|
|
|
|
/////////////////////////////////////////
|
|
// ktxTexture_WriteKTX2 tests
|
|
////////////////////////////////////////
|
|
|
|
TEST_F(ktxTexture2ReadTestRGBA8, Read1D) {
|
|
resize(createFlagBits::eNone, 1, 1, 1, 32, 1, 1);
|
|
runTest();
|
|
}
|
|
|
|
TEST_F(ktxTexture2ReadTestRGBA8, Read2D) {
|
|
resize(createFlagBits::eNone, 1, 1, 2, 32, 32, 1);
|
|
runTest();
|
|
}
|
|
|
|
TEST_F(ktxTexture2ReadTestRGBA8, Read3D) {
|
|
resize(createFlagBits::eNone, 1, 1, 3, 32, 32, 32);
|
|
runTest();
|
|
}
|
|
|
|
TEST_F(ktxTexture2ReadTestRGBA8, Read1DMipmap) {
|
|
resize(createFlagBits::eMipmapped, 1, 1, 1, 64, 1, 1);
|
|
runTest();
|
|
}
|
|
|
|
TEST_F(ktxTexture2ReadTestRGBA8, Read2DMipmap) {
|
|
resize(createFlagBits::eMipmapped, 1, 1, 2, 64, 64, 1);
|
|
runTest();
|
|
}
|
|
|
|
TEST_F(ktxTexture2ReadTestRGBA8, Read3DMipmap) {
|
|
resize(createFlagBits::eMipmapped, 1, 1, 3, 64, 64, 32);
|
|
runTest();
|
|
}
|
|
|
|
class ktxTexture2_BasisCompressTest : public ktxTexture2TestBase<GLubyte, 4, GL_RGBA8> { };
|
|
|
|
/////////////////////////////////////////
|
|
// ktxTexture2_BasisCompress tests
|
|
////////////////////////////////////////
|
|
|
|
TEST_F(ktxTexture2_BasisCompressTest, Compress) {
|
|
ktxTexture2* texture;
|
|
ktx_uint64_t dataSize;
|
|
KTX_error_code result;
|
|
|
|
if (ktxMemFile != NULL) {
|
|
result = ktxTexture2_CreateFromMemory(ktxMemFile, ktxMemFileLen,
|
|
KTX_TEXTURE_CREATE_LOAD_IMAGE_DATA_BIT,
|
|
&texture);
|
|
ASSERT_TRUE(result == KTX_SUCCESS);
|
|
ASSERT_TRUE(texture != NULL) << "ktxTexture_CreateFromMemory failed: "
|
|
<< ktxErrorString(result);
|
|
ASSERT_TRUE(texture->pData != NULL) << "Image data not loaded";
|
|
|
|
dataSize = texture->dataSize;
|
|
result = ktxTexture2_CompressBasis(texture, 0);
|
|
EXPECT_EQ(result, KTX_SUCCESS);
|
|
EXPECT_EQ(texture->supercompressionScheme, KTX_SS_BASIS_LZ);
|
|
EXPECT_TRUE(texture->_private->_supercompressionGlobalData > (ktx_uint8_t*)0);
|
|
EXPECT_EQ(texture->numLevels, helper.numLevels);
|
|
EXPECT_LT(texture->dataSize, dataSize);
|
|
// How else to test the result?
|
|
|
|
result = ktxTexture2_TranscodeBasis(texture, KTX_TTF_BC1_RGB, 0);
|
|
EXPECT_EQ(result, KTX_SUCCESS);
|
|
if (texture)
|
|
ktxTexture_Destroy(ktxTexture(texture));
|
|
}
|
|
}
|
|
|
|
class ktxTexture2_GetNumComponentsTestR8 : public ktxTexture2TestBase<GLubyte, 1, GL_R8> { };
|
|
class ktxTexture2_GetNumComponentsTestRG8 : public ktxTexture2TestBase<GLubyte, 2, GL_RG8> { };
|
|
class ktxTexture2_GetNumComponentsTestRGB8 : public ktxTexture2TestBase<GLubyte, 3, GL_RGB8> { };
|
|
class ktxTexture2_GetNumComponentsTestRGBA8 : public ktxTexture2TestBase<GLubyte, 4, GL_RGBA8> { };
|
|
class ktxTexture2_MetadataTest : public ktxTexture2TestBase<GLubyte, 4, GL_RGBA8> { };
|
|
|
|
////////////////////////////////////////////
|
|
// ktxTexture2_GetNumComponents tests
|
|
///////////////////////////////////////////
|
|
|
|
TEST_F(ktxTexture2_GetNumComponentsTestR8, Uncompressed) {
|
|
ktxTexture2* texture;
|
|
KTX_error_code result;
|
|
|
|
if (ktxMemFile != NULL) {
|
|
result = ktxTexture2_CreateFromMemory(ktxMemFile, ktxMemFileLen,
|
|
KTX_TEXTURE_CREATE_LOAD_IMAGE_DATA_BIT,
|
|
&texture);
|
|
ASSERT_TRUE(result == KTX_SUCCESS);
|
|
ASSERT_TRUE(texture != NULL) << "ktxTexture_CreateFromMemory failed: "
|
|
<< ktxErrorString(result);
|
|
ASSERT_TRUE(texture->pData != NULL) << "Image data not loaded";
|
|
|
|
ktx_uint32_t components = ktxTexture2_GetNumComponents(texture);
|
|
EXPECT_EQ(components, 1U);
|
|
if (texture)
|
|
ktxTexture_Destroy(ktxTexture(texture));
|
|
}
|
|
}
|
|
|
|
TEST_F(ktxTexture2_GetNumComponentsTestR8, BasisLZ) {
|
|
ktxTexture2* texture;
|
|
KTX_error_code result;
|
|
|
|
if (ktxMemFile != NULL) {
|
|
result = ktxTexture2_CreateFromMemory(ktxMemFile, ktxMemFileLen,
|
|
KTX_TEXTURE_CREATE_LOAD_IMAGE_DATA_BIT,
|
|
&texture);
|
|
ASSERT_TRUE(result == KTX_SUCCESS);
|
|
ASSERT_TRUE(texture != NULL) << "ktxTexture_CreateFromMemory failed: "
|
|
<< ktxErrorString(result);
|
|
ASSERT_TRUE(texture->pData != NULL) << "Image data not loaded";
|
|
|
|
ktx_uint32_t components = ktxTexture2_GetNumComponents(texture);
|
|
EXPECT_EQ(components, 1U);
|
|
ktxTexture2_CompressBasis(texture, 0);
|
|
EXPECT_EQ(components, ktxTexture2_GetNumComponents(texture));
|
|
if (texture)
|
|
ktxTexture_Destroy(ktxTexture(texture));
|
|
}
|
|
}
|
|
|
|
TEST_F(ktxTexture2_GetNumComponentsTestR8, UASTC) {
|
|
ktxTexture2* texture;
|
|
KTX_error_code result;
|
|
ktxBasisParams cparams = { };
|
|
|
|
if (ktxMemFile != NULL) {
|
|
result = ktxTexture2_CreateFromMemory(ktxMemFile, ktxMemFileLen,
|
|
KTX_TEXTURE_CREATE_LOAD_IMAGE_DATA_BIT,
|
|
&texture);
|
|
ASSERT_TRUE(result == KTX_SUCCESS);
|
|
ASSERT_TRUE(texture != NULL) << "ktxTexture_CreateFromMemory failed: "
|
|
<< ktxErrorString(result);
|
|
ASSERT_TRUE(texture->pData != NULL) << "Image data not loaded";
|
|
|
|
ktx_uint32_t components = ktxTexture2_GetNumComponents(texture);
|
|
EXPECT_EQ(components, 1U);
|
|
cparams.uastc = KTX_TRUE;
|
|
ktxTexture2_CompressBasisEx(texture, &cparams);
|
|
EXPECT_EQ(components, ktxTexture2_GetNumComponents(texture));
|
|
if (texture)
|
|
ktxTexture_Destroy(ktxTexture(texture));
|
|
}
|
|
}
|
|
|
|
TEST_F(ktxTexture2_GetNumComponentsTestRG8, Uncompressed) {
|
|
ktxTexture2* texture;
|
|
KTX_error_code result;
|
|
|
|
if (ktxMemFile != NULL) {
|
|
result = ktxTexture2_CreateFromMemory(ktxMemFile, ktxMemFileLen,
|
|
KTX_TEXTURE_CREATE_LOAD_IMAGE_DATA_BIT,
|
|
&texture);
|
|
ASSERT_TRUE(result == KTX_SUCCESS);
|
|
ASSERT_TRUE(texture != NULL) << "ktxTexture_CreateFromMemory failed: "
|
|
<< ktxErrorString(result);
|
|
ASSERT_TRUE(texture->pData != NULL) << "Image data not loaded";
|
|
|
|
ktx_uint32_t components = ktxTexture2_GetNumComponents(texture);
|
|
EXPECT_EQ(components, 2U);
|
|
if (texture)
|
|
ktxTexture_Destroy(ktxTexture(texture));
|
|
}
|
|
}
|
|
|
|
TEST_F(ktxTexture2_GetNumComponentsTestRG8, BasisLZ) {
|
|
ktxTexture2* texture;
|
|
KTX_error_code result;
|
|
|
|
if (ktxMemFile != NULL) {
|
|
result = ktxTexture2_CreateFromMemory(ktxMemFile, ktxMemFileLen,
|
|
KTX_TEXTURE_CREATE_LOAD_IMAGE_DATA_BIT,
|
|
&texture);
|
|
ASSERT_TRUE(result == KTX_SUCCESS);
|
|
ASSERT_TRUE(texture != NULL) << "ktxTexture_CreateFromMemory failed: "
|
|
<< ktxErrorString(result);
|
|
ASSERT_TRUE(texture->pData != NULL) << "Image data not loaded";
|
|
|
|
ktx_uint32_t components = ktxTexture2_GetNumComponents(texture);
|
|
EXPECT_EQ(components, 2U);
|
|
ktxTexture2_CompressBasis(texture, 0);
|
|
EXPECT_EQ(components, ktxTexture2_GetNumComponents(texture));
|
|
}
|
|
}
|
|
|
|
TEST_F(ktxTexture2_GetNumComponentsTestRG8, UASTC) {
|
|
ktxTexture2* texture;
|
|
KTX_error_code result;
|
|
ktxBasisParams cparams = { };
|
|
|
|
if (ktxMemFile != NULL) {
|
|
result = ktxTexture2_CreateFromMemory(ktxMemFile, ktxMemFileLen,
|
|
KTX_TEXTURE_CREATE_LOAD_IMAGE_DATA_BIT,
|
|
&texture);
|
|
ASSERT_TRUE(result == KTX_SUCCESS);
|
|
ASSERT_TRUE(texture != NULL) << "ktxTexture_CreateFromMemory failed: "
|
|
<< ktxErrorString(result);
|
|
ASSERT_TRUE(texture->pData != NULL) << "Image data not loaded";
|
|
|
|
ktx_uint32_t components = ktxTexture2_GetNumComponents(texture);
|
|
EXPECT_EQ(components, 2U);
|
|
cparams.uastc = KTX_TRUE;
|
|
ktxTexture2_CompressBasisEx(texture, &cparams);
|
|
EXPECT_EQ(components, ktxTexture2_GetNumComponents(texture));
|
|
if (texture)
|
|
ktxTexture_Destroy(ktxTexture(texture));
|
|
}
|
|
}
|
|
|
|
TEST_F(ktxTexture2_GetNumComponentsTestRGB8, Uncompressed) {
|
|
ktxTexture2* texture;
|
|
KTX_error_code result;
|
|
|
|
if (ktxMemFile != NULL) {
|
|
result = ktxTexture2_CreateFromMemory(ktxMemFile, ktxMemFileLen,
|
|
KTX_TEXTURE_CREATE_LOAD_IMAGE_DATA_BIT,
|
|
&texture);
|
|
ASSERT_TRUE(result == KTX_SUCCESS);
|
|
ASSERT_TRUE(texture != NULL) << "ktxTexture_CreateFromMemory failed: "
|
|
<< ktxErrorString(result);
|
|
ASSERT_TRUE(texture->pData != NULL) << "Image data not loaded";
|
|
|
|
ktx_uint32_t components = ktxTexture2_GetNumComponents(texture);
|
|
EXPECT_EQ(components, 3U);
|
|
if (texture)
|
|
ktxTexture_Destroy(ktxTexture(texture));
|
|
}
|
|
}
|
|
|
|
TEST_F(ktxTexture2_GetNumComponentsTestRGB8, BasisLZ) {
|
|
ktxTexture2* texture;
|
|
KTX_error_code result;
|
|
|
|
if (ktxMemFile != NULL) {
|
|
result = ktxTexture2_CreateFromMemory(ktxMemFile, ktxMemFileLen,
|
|
KTX_TEXTURE_CREATE_LOAD_IMAGE_DATA_BIT,
|
|
&texture);
|
|
ASSERT_TRUE(result == KTX_SUCCESS);
|
|
ASSERT_TRUE(texture != NULL) << "ktxTexture_CreateFromMemory failed: "
|
|
<< ktxErrorString(result);
|
|
ASSERT_TRUE(texture->pData != NULL) << "Image data not loaded";
|
|
|
|
ktx_uint32_t components = ktxTexture2_GetNumComponents(texture);
|
|
EXPECT_EQ(components, 3U);
|
|
ktxTexture2_CompressBasis(texture, 0);
|
|
EXPECT_EQ(components, ktxTexture2_GetNumComponents(texture));
|
|
if (texture)
|
|
ktxTexture_Destroy(ktxTexture(texture));
|
|
}
|
|
}
|
|
|
|
TEST_F(ktxTexture2_GetNumComponentsTestRGB8, UASTC) {
|
|
ktxTexture2* texture;
|
|
KTX_error_code result;
|
|
ktxBasisParams cparams = { };
|
|
|
|
if (ktxMemFile != NULL) {
|
|
result = ktxTexture2_CreateFromMemory(ktxMemFile, ktxMemFileLen,
|
|
KTX_TEXTURE_CREATE_LOAD_IMAGE_DATA_BIT,
|
|
&texture);
|
|
ASSERT_TRUE(result == KTX_SUCCESS);
|
|
ASSERT_TRUE(texture != NULL) << "ktxTexture_CreateFromMemory failed: "
|
|
<< ktxErrorString(result);
|
|
ASSERT_TRUE(texture->pData != NULL) << "Image data not loaded";
|
|
|
|
ktx_uint32_t components = ktxTexture2_GetNumComponents(texture);
|
|
EXPECT_EQ(components, 3U);
|
|
cparams.uastc = KTX_TRUE;
|
|
ktxTexture2_CompressBasisEx(texture, &cparams);
|
|
EXPECT_EQ(components, ktxTexture2_GetNumComponents(texture));
|
|
if (texture)
|
|
ktxTexture_Destroy(ktxTexture(texture));
|
|
}
|
|
}
|
|
|
|
TEST_F(ktxTexture2_GetNumComponentsTestRGBA8, Uncompressed) {
|
|
ktxTexture2* texture;
|
|
KTX_error_code result;
|
|
|
|
if (ktxMemFile != NULL) {
|
|
result = ktxTexture2_CreateFromMemory(ktxMemFile, ktxMemFileLen,
|
|
KTX_TEXTURE_CREATE_LOAD_IMAGE_DATA_BIT,
|
|
&texture);
|
|
ASSERT_TRUE(result == KTX_SUCCESS);
|
|
ASSERT_TRUE(texture != NULL) << "ktxTexture_CreateFromMemory failed: "
|
|
<< ktxErrorString(result);
|
|
ASSERT_TRUE(texture->pData != NULL) << "Image data not loaded";
|
|
|
|
ktx_uint32_t components = ktxTexture2_GetNumComponents(texture);
|
|
EXPECT_EQ(components, 4U);
|
|
if (texture)
|
|
ktxTexture_Destroy(ktxTexture(texture));
|
|
}
|
|
}
|
|
|
|
TEST_F(ktxTexture2_GetNumComponentsTestRGBA8, BasisLZ) {
|
|
ktxTexture2* texture;
|
|
KTX_error_code result;
|
|
|
|
if (ktxMemFile != NULL) {
|
|
result = ktxTexture2_CreateFromMemory(ktxMemFile, ktxMemFileLen,
|
|
KTX_TEXTURE_CREATE_LOAD_IMAGE_DATA_BIT,
|
|
&texture);
|
|
ASSERT_TRUE(result == KTX_SUCCESS);
|
|
ASSERT_TRUE(texture != NULL) << "ktxTexture_CreateFromMemory failed: "
|
|
<< ktxErrorString(result);
|
|
ASSERT_TRUE(texture->pData != NULL) << "Image data not loaded";
|
|
|
|
ktx_uint32_t components = ktxTexture2_GetNumComponents(texture);
|
|
EXPECT_EQ(components, 4U);
|
|
ktxTexture2_CompressBasis(texture, 0);
|
|
EXPECT_EQ(components, ktxTexture2_GetNumComponents(texture));
|
|
if (texture)
|
|
ktxTexture_Destroy(ktxTexture(texture));
|
|
}
|
|
}
|
|
|
|
TEST_F(ktxTexture2_GetNumComponentsTestRGBA8, UASTC) {
|
|
ktxTexture2* texture;
|
|
KTX_error_code result;
|
|
ktxBasisParams cparams = { };
|
|
|
|
if (ktxMemFile != NULL) {
|
|
result = ktxTexture2_CreateFromMemory(ktxMemFile, ktxMemFileLen,
|
|
KTX_TEXTURE_CREATE_LOAD_IMAGE_DATA_BIT,
|
|
&texture);
|
|
ASSERT_TRUE(result == KTX_SUCCESS);
|
|
ASSERT_TRUE(texture != NULL) << "ktxTexture_CreateFromMemory failed: "
|
|
<< ktxErrorString(result);
|
|
ASSERT_TRUE(texture->pData != NULL) << "Image data not loaded";
|
|
|
|
ktx_uint32_t components = ktxTexture2_GetNumComponents(texture);
|
|
EXPECT_EQ(components, 4U);
|
|
cparams.uastc = KTX_TRUE;
|
|
ktxTexture2_CompressBasisEx(texture, &cparams);
|
|
EXPECT_EQ(components, ktxTexture2_GetNumComponents(texture));
|
|
if (texture)
|
|
ktxTexture_Destroy(ktxTexture(texture));
|
|
}
|
|
}
|
|
|
|
TEST_F(ktxTexture2_MetadataTest, EmptyValue) {
|
|
ktxTexture2* texture;
|
|
KTX_error_code result;
|
|
|
|
if (ktxMemFile != NULL) {
|
|
result = ktxTexture2_CreateFromMemory(ktxMemFile, ktxMemFileLen,
|
|
KTX_TEXTURE_CREATE_LOAD_IMAGE_DATA_BIT,
|
|
&texture);
|
|
ASSERT_TRUE(result == KTX_SUCCESS);
|
|
ASSERT_TRUE(texture != NULL) << "ktxTexture_CreateFromMemory failed: "
|
|
<< ktxErrorString(result);
|
|
ASSERT_TRUE(texture->pData != NULL) << "Image data not loaded";
|
|
|
|
result = ktxHashList_AddKVPair(&texture->kvDataHead,
|
|
"MSCtestKey", 0, nullptr);
|
|
EXPECT_EQ(result, KTX_SUCCESS);
|
|
|
|
ktx_size_t newMemFileLen;
|
|
ktx_uint8_t* newMemFile;
|
|
result = ktxTexture_WriteToMemory(ktxTexture(texture), &newMemFile,
|
|
&newMemFileLen);
|
|
EXPECT_EQ(result, KTX_SUCCESS);
|
|
if (texture)
|
|
ktxTexture_Destroy(ktxTexture(texture));
|
|
|
|
result = ktxTexture2_CreateFromMemory(newMemFile, newMemFileLen,
|
|
KTX_TEXTURE_CREATE_LOAD_IMAGE_DATA_BIT,
|
|
&texture);
|
|
ASSERT_TRUE(result == KTX_SUCCESS);
|
|
ASSERT_TRUE(texture != NULL) << "ktxTexture_CreateFromMemory failed: "
|
|
<< ktxErrorString(result);
|
|
ASSERT_TRUE(texture->pData != NULL) << "Image data not loaded";
|
|
|
|
ktx_uint32_t valueLen;
|
|
ktx_uint8_t* value;
|
|
result = ktxHashList_FindValue(&texture->kvDataHead,
|
|
"MSCtestKey", &valueLen, (void**)&value);
|
|
EXPECT_EQ(result, KTX_SUCCESS);
|
|
EXPECT_EQ(valueLen, 0U);
|
|
EXPECT_EQ(value, nullptr);
|
|
|
|
if (newMemFile)
|
|
free(newMemFile);
|
|
if (texture)
|
|
ktxTexture_Destroy(ktxTexture(texture));
|
|
}
|
|
}
|
|
|
|
#if defined(TestNoMetadata)
|
|
TEST_F(ktxTexture2_MetadataTest, NoMetadata) {
|
|
ktxTexture2* texture;
|
|
KTX_error_code result;
|
|
|
|
if (ktxMemFile != NULL) {
|
|
result = ktxTexture2_CreateFromMemory(ktxMemFile, ktxMemFileLen,
|
|
KTX_TEXTURE_CREATE_LOAD_IMAGE_DATA_BIT,
|
|
&texture);
|
|
ASSERT_TRUE(result == KTX_SUCCESS);
|
|
ASSERT_TRUE(texture != NULL) << "ktxTexture_CreateFromMemory failed: "
|
|
<< ktxErrorString(result);
|
|
ASSERT_TRUE(texture->pData != NULL) << "Image data not loaded";
|
|
|
|
ktxHashList_Destruct(&texture->kvDataHead);
|
|
ktxTexture(texture)->kvDataHead = nullptr;
|
|
ktxTexture(texture)->kvDataLen = 0;
|
|
|
|
|
|
ktx_size_t newMemFileLen;
|
|
ktx_uint8_t* newMemFile;
|
|
::__disableWriterMetadata__ = KTX_TRUE;
|
|
result = ktxTexture_WriteToMemory(ktxTexture(texture), &newMemFile,
|
|
&newMemFileLen);
|
|
::__disableWriterMetadata__ = KTX_FALSE;
|
|
EXPECT_EQ(result, KTX_SUCCESS);
|
|
if (texture)
|
|
ktxTexture_Destroy(ktxTexture(texture));
|
|
|
|
result = ktxTexture2_CreateFromMemory(newMemFile, newMemFileLen,
|
|
KTX_TEXTURE_CREATE_LOAD_IMAGE_DATA_BIT,
|
|
&texture);
|
|
ASSERT_TRUE(result == KTX_SUCCESS);
|
|
ASSERT_TRUE(texture != NULL) << "ktxTexture_CreateFromMemory failed: "
|
|
<< ktxErrorString(result);
|
|
ASSERT_TRUE(texture->pData != NULL) << "Image data not loaded";
|
|
|
|
ktx_uint32_t valueLen;
|
|
ktx_uint8_t* value;
|
|
EXPECT_EQ(result, KTX_SUCCESS);
|
|
EXPECT_EQ(texture->kvDataLen, 0U);
|
|
EXPECT_EQ(texture->kvDataHead, nullptr);
|
|
|
|
if (newMemFile)
|
|
free(newMemFile);
|
|
if (texture)
|
|
ktxTexture_Destroy(ktxTexture(texture));
|
|
}
|
|
}
|
|
#endif
|
|
|
|
TEST_F(ktxTexture2_MetadataTest, NoLibVersionDupOnMultipleWrites) {
|
|
ktxTexture2* texture;
|
|
KTX_error_code result;
|
|
|
|
if (ktxMemFile != NULL) {
|
|
result = ktxTexture2_CreateFromMemory(ktxMemFile, ktxMemFileLen,
|
|
KTX_TEXTURE_CREATE_LOAD_IMAGE_DATA_BIT,
|
|
&texture);
|
|
ASSERT_TRUE(result == KTX_SUCCESS);
|
|
ASSERT_TRUE(texture != NULL) << "ktxTexture_CreateFromMemory failed: "
|
|
<< ktxErrorString(result);
|
|
ASSERT_TRUE(texture->pData != NULL) << "Image data not loaded";
|
|
|
|
const ktx_uint32_t iterations = 2;
|
|
ktx_size_t newMemFileLens[iterations];
|
|
ktx_uint8_t* newMemFiles[iterations];
|
|
for (uint32_t i = 0; i < iterations; i++) {
|
|
result = ktxTexture_WriteToMemory(ktxTexture(texture),
|
|
&newMemFiles[i],
|
|
&newMemFileLens[i]);
|
|
EXPECT_EQ(result, KTX_SUCCESS);
|
|
}
|
|
for (uint32_t i = 1; i < iterations; i++) {
|
|
EXPECT_EQ(newMemFileLens[i-1], newMemFileLens[i]);
|
|
}
|
|
|
|
if (texture)
|
|
ktxTexture_Destroy(ktxTexture(texture));
|
|
|
|
std::string writers[iterations];
|
|
for (uint32_t i = 0; i < iterations; i++) {
|
|
ktx_uint32_t valueLen;
|
|
ktx_uint8_t* value;
|
|
result = ktxTexture2_CreateFromMemory(newMemFiles[i],
|
|
newMemFileLens[i],
|
|
KTX_TEXTURE_CREATE_LOAD_IMAGE_DATA_BIT,
|
|
&texture);
|
|
ASSERT_TRUE(result == KTX_SUCCESS);
|
|
ASSERT_TRUE(texture != NULL) << "ktxTexture_CreateFromMemory failed: "
|
|
<< ktxErrorString(result);
|
|
ASSERT_TRUE(texture->pData != NULL) << "Image data not loaded";
|
|
|
|
result = ktxHashList_FindValue(&texture->kvDataHead,
|
|
"KTXwriter",
|
|
&valueLen, (void**)&value);
|
|
EXPECT_EQ(result, KTX_SUCCESS);
|
|
// We want ktxWriteTo* to NUL terminate the value when adding
|
|
// the libktx version.
|
|
ASSERT_TRUE(value[valueLen-1] == '\0')
|
|
<< "KTXwriter not NUL terminated";
|
|
writers[i] = (char*)value;
|
|
if (texture)
|
|
ktxTexture_Destroy(ktxTexture(texture));
|
|
}
|
|
|
|
for (uint32_t i = 1; i < iterations; i++) {
|
|
// This is a valid test because we know all our calls to libktx
|
|
// use the same version of libktx.
|
|
EXPECT_EQ(0, writers[i-1].compare(writers[i]));
|
|
}
|
|
|
|
for (uint32_t i = 0; i < iterations; i++) {
|
|
if (newMemFiles[i])
|
|
free(newMemFiles[i]);
|
|
}
|
|
}
|
|
}
|
|
|
|
TEST_F(ktxTexture2_MetadataTest, LibVersionUpdatedCorrectly) {
|
|
ktxTexture2* texture;
|
|
KTX_error_code result;
|
|
|
|
if (ktxMemFile != NULL) {
|
|
result = ktxTexture2_CreateFromMemory(ktxMemFile, ktxMemFileLen,
|
|
KTX_TEXTURE_CREATE_LOAD_IMAGE_DATA_BIT,
|
|
&texture);
|
|
ASSERT_TRUE(result == KTX_SUCCESS);
|
|
ASSERT_TRUE(texture != NULL) << "ktxTexture_CreateFromMemory failed: "
|
|
<< ktxErrorString(result);
|
|
ASSERT_TRUE(texture->pData != NULL) << "Image data not loaded";
|
|
|
|
ktx_uint32_t curWriterLen;
|
|
ktx_uint8_t* curWriterVal;
|
|
result = ktxHashList_FindValue(&texture->kvDataHead,
|
|
"KTXwriter",
|
|
&curWriterLen, (void**)&curWriterVal);
|
|
EXPECT_EQ(result, KTX_SUCCESS);
|
|
// We want ktxWriteTo* to NUL terminate the value when adding
|
|
// the libktx version.
|
|
ASSERT_TRUE(curWriterVal[curWriterLen-1] == '\0')
|
|
<< "KTXwriter not NUL terminated";
|
|
// The pointer returned by FindValue becomes invalid when the texture
|
|
// is destroyed hence saving to this string. -1 to omit the terminator.
|
|
std::string curWriter((char*)curWriterVal, curWriterLen-1);
|
|
std::string writer(curWriter);
|
|
size_t slash_pos = writer.find_last_of('/');
|
|
ASSERT_TRUE(slash_pos != std::string::npos)
|
|
<< "KTXwriter does not have lib version.";
|
|
writer.replace(slash_pos + 2, std::string::npos, "libktx v3.0.0");
|
|
result = ktxHashList_AddKVPair(&texture->kvDataHead,
|
|
"KTXwriter",
|
|
(ktx_uint32_t)writer.length(),
|
|
writer.c_str());
|
|
EXPECT_EQ(result, KTX_SUCCESS);
|
|
|
|
|
|
ktx_size_t newMemFileLen;
|
|
ktx_uint8_t* newMemFile;
|
|
result = ktxTexture_WriteToMemory(ktxTexture(texture),
|
|
&newMemFile,
|
|
&newMemFileLen);
|
|
EXPECT_EQ(result, KTX_SUCCESS);
|
|
|
|
if (texture)
|
|
ktxTexture_Destroy(ktxTexture(texture));
|
|
|
|
ktx_uint32_t newWriterLen;
|
|
ktx_uint8_t* newWriterVal;
|
|
result = ktxTexture2_CreateFromMemory(newMemFile,
|
|
newMemFileLen,
|
|
KTX_TEXTURE_CREATE_LOAD_IMAGE_DATA_BIT,
|
|
&texture);
|
|
ASSERT_TRUE(result == KTX_SUCCESS);
|
|
ASSERT_TRUE(texture != NULL) << "ktxTexture_CreateFromMemory failed: "
|
|
<< ktxErrorString(result);
|
|
ASSERT_TRUE(texture->pData != NULL) << "Image data not loaded";
|
|
|
|
result = ktxHashList_FindValue(&texture->kvDataHead,
|
|
"KTXwriter",
|
|
&newWriterLen, (void**)&newWriterVal);
|
|
EXPECT_EQ(result, KTX_SUCCESS);
|
|
ASSERT_TRUE(newWriterVal[newWriterLen-1] == '\0')
|
|
<< "KTXwriter not NUL terminated";
|
|
|
|
EXPECT_EQ(0, curWriter.compare((char *)newWriterVal));
|
|
|
|
if (texture)
|
|
ktxTexture_Destroy(ktxTexture(texture));
|
|
|
|
if (newMemFile)
|
|
free(newMemFile);
|
|
}
|
|
}
|
|
|
|
////////////////////////////////////////////
|
|
// Unicode file name tests
|
|
///////////////////////////////////////////
|
|
|
|
fs::path imagePath;
|
|
|
|
TEST(UnicodeFileNames, CreateFrom) {
|
|
std::vector<std::string> fileSet = {
|
|
u8"hűtő.ktx",
|
|
u8"hűtő.ktx2",
|
|
u8"نَسِيج.ktx",
|
|
u8"نَسِيج.ktx2",
|
|
u8"テクスチャ.ktx",
|
|
u8"テクスチャ.ktx2",
|
|
u8"质地.ktx",
|
|
u8"质地.ktx2",
|
|
u8"조직.ktx",
|
|
u8"조직.ktx2"
|
|
};
|
|
|
|
std::vector<std::string>::const_iterator it;
|
|
|
|
|
|
fs::path filePath = imagePath;
|
|
for (it = fileSet.begin(); it < fileSet.end(); it++) {
|
|
ktx_error_code_e result;
|
|
ktxTexture* texture = nullptr;
|
|
|
|
filePath.replace_filename(fs::u8path(*it));
|
|
|
|
result = ktxTexture_CreateFromNamedFile(
|
|
filePath.u8string().c_str(),
|
|
KTX_TEXTURE_CREATE_NO_FLAGS,
|
|
&texture);
|
|
EXPECT_EQ(result, KTX_SUCCESS);
|
|
EXPECT_NE(texture, (ktxTexture*)0);
|
|
if (texture) {
|
|
ktxTexture_Destroy(texture);
|
|
texture = nullptr;
|
|
}
|
|
|
|
if (filePath.extension() == ".ktx") {
|
|
result = ktxTexture1_CreateFromNamedFile(
|
|
filePath.u8string().c_str(),
|
|
KTX_TEXTURE_CREATE_NO_FLAGS,
|
|
(ktxTexture1**)&texture);
|
|
} else {
|
|
result = ktxTexture2_CreateFromNamedFile(
|
|
filePath.u8string().c_str(),
|
|
KTX_TEXTURE_CREATE_NO_FLAGS,
|
|
(ktxTexture2**)&texture);
|
|
}
|
|
EXPECT_EQ(result, KTX_SUCCESS);
|
|
EXPECT_NE(texture, (ktxTexture*)0);
|
|
if (texture) ktxTexture_Destroy(texture);
|
|
}
|
|
}
|
|
|
|
// The ASTC encoder and decoder are heavily tested elsewhere hence the focus
|
|
// of these tests is the mechanics of encoding and decoding a ktxTexture2
|
|
// and the resulting changes to the ktxTexture2 object.
|
|
|
|
//------------------------------------------------------------
|
|
// Template for base fixture for ASTC encode and decode tests.
|
|
//------------------------------------------------------------
|
|
|
|
fs::path ktxdiffPath;
|
|
|
|
template<typename component_type, ktx_uint32_t numComponents,
|
|
GLenum internalformat>
|
|
class ktxTexture2AstcLdrEncodeDecodeTestBase
|
|
: public ktxTexture2TestBase<component_type, numComponents, internalformat> {
|
|
|
|
protected:
|
|
using ktxTextureTestBase<component_type, numComponents, internalformat>::helper;
|
|
using ktxTextureTestBase<component_type, numComponents, internalformat>::ktxMemFile;
|
|
using ktxTextureTestBase<component_type, numComponents, internalformat>::ktxMemFileLen;
|
|
|
|
public:
|
|
void runTest(ktx_pack_astc_block_dimension_e blockDimension) {
|
|
ktxTexture2* texture;
|
|
KTX_error_code result;
|
|
auto tmpDir = fs::temp_directory_path();
|
|
|
|
fs::path original = tmpDir / "CompressToAstcLdrThenDecode_original.ktx2";
|
|
fs::path decoded = tmpDir / "CompressToAstcLdrThenDecode_decoded.ktx2";
|
|
fs::path ktxdiffOut = tmpDir / "ktxdiffOut.txt";
|
|
|
|
if (ktxMemFile != NULL) {
|
|
result = ktxTexture2_CreateFromMemory(ktxMemFile, ktxMemFileLen,
|
|
KTX_TEXTURE_CREATE_LOAD_IMAGE_DATA_BIT,
|
|
&texture);
|
|
ASSERT_TRUE(result == KTX_SUCCESS);
|
|
ASSERT_TRUE(texture != NULL) << "ktxTexture_CreateFromMemory failed: "
|
|
<< ktxErrorString(result);
|
|
ASSERT_TRUE(texture->pData != NULL) << "Image data not loaded";
|
|
|
|
result = ktxTexture2_WriteToNamedFile(texture, original.u8string().c_str());
|
|
ASSERT_TRUE(result == KTX_SUCCESS);
|
|
|
|
auto depth = texture->baseDepth;
|
|
auto height = texture->baseHeight;
|
|
auto width = texture->baseWidth;
|
|
//ktx_uint64_t dataSize = texture->dataSize;
|
|
auto dataSize = texture->dataSize;
|
|
|
|
ASSERT_TRUE(depth == 1);
|
|
|
|
ktxAstcParams params;
|
|
params.structSize = sizeof(params);
|
|
params.threadCount = 1;
|
|
params.blockDimension = blockDimension;
|
|
params.mode = KTX_PACK_ASTC_ENCODER_MODE_DEFAULT;
|
|
params.qualityLevel = KTX_PACK_ASTC_QUALITY_LEVEL_FAST;
|
|
params.normalMap = false;
|
|
params.perceptual = false;
|
|
params.inputSwizzle[0] = 'R';
|
|
params.inputSwizzle[1] = 'G';
|
|
params.inputSwizzle[2] = 'B';
|
|
params.inputSwizzle[3] = 'A';
|
|
result = ktxTexture2_CompressAstcEx(texture, ¶ms);
|
|
|
|
EXPECT_EQ(result, KTX_SUCCESS);
|
|
VkFormat expectedFormat = blockDimensionToFormat(blockDimension);
|
|
// Oops! Maybe it was a mistake to define texture.vkFormat as unsigned.
|
|
EXPECT_TRUE(texture->vkFormat == (ktx_uint32_t)expectedFormat);
|
|
|
|
uint32_t* pBdb = texture->pDfd+1;
|
|
if (isFormatFloat()) {
|
|
EXPECT_TRUE(KHR_DFDSVAL(pBdb, 1, QUALIFIERS) & KHR_DF_SAMPLE_DATATYPE_FLOAT);
|
|
EXPECT_TRUE(KHR_DFDSVAL(pBdb, 1, QUALIFIERS) & KHR_DF_SAMPLE_DATATYPE_SIGNED);
|
|
} else if (isFormatSrgb()) {
|
|
EXPECT_TRUE(KHR_DFDVAL(pBdb, TRANSFER) == KHR_DF_TRANSFER_SRGB);
|
|
}
|
|
khr_df_model_e model = static_cast<khr_df_model_e>(KHR_DFDVAL(pBdb, MODEL));
|
|
EXPECT_EQ(model, KHR_DF_MODEL_ASTC);
|
|
EXPECT_EQ(texture->supercompressionScheme, KTX_SS_NONE);
|
|
EXPECT_TRUE(texture->_private->_supercompressionGlobalData == (ktx_uint8_t*)0);
|
|
EXPECT_EQ(texture->numLevels, helper.numLevels);
|
|
EXPECT_EQ(texture->baseDepth, depth);
|
|
EXPECT_EQ(texture->baseHeight, height);
|
|
EXPECT_EQ(texture->baseWidth, width);
|
|
EXPECT_LT(texture->dataSize, dataSize);
|
|
|
|
result = ktxTexture2_DecodeAstc(texture);
|
|
EXPECT_EQ(result, KTX_SUCCESS);
|
|
if (isFormatFloat())
|
|
EXPECT_EQ(texture->vkFormat, (ktx_uint32_t)VK_FORMAT_R32G32B32A32_SFLOAT);
|
|
else if (isFormatSrgb())
|
|
EXPECT_EQ(texture->vkFormat, (ktx_uint32_t)VK_FORMAT_R8G8B8A8_SRGB);
|
|
else
|
|
EXPECT_EQ(texture->vkFormat, (ktx_uint32_t)VK_FORMAT_R8G8B8A8_UNORM);
|
|
model = static_cast<khr_df_model_e>(KHR_DFDVAL(texture->pDfd+1, MODEL));
|
|
EXPECT_EQ(model, KHR_DF_MODEL_RGBSDA);
|
|
EXPECT_EQ(depth, texture->baseDepth);
|
|
result = ktxTexture2_WriteToNamedFile(texture, decoded.u8string().c_str());
|
|
int status;
|
|
if constexpr (internalformat != (GLenum)GL_RGB8 && internalformat != (GLenum)GL_SRGB8) {
|
|
std::string command = ktxdiffPath.u8string();
|
|
command += " " + original.string() + " " + decoded.string() + " 0.01 > " + ktxdiffOut.string();
|
|
status = std::system(command.c_str());
|
|
} else {
|
|
// ASTC formats always decode to a 4-component format as there is no way to
|
|
// tell prior to decode if any blocks have an alpha channel. Since we don't
|
|
// have a command comparing only some components of the image data, we can't
|
|
// test for a data match.
|
|
status = 0;
|
|
}
|
|
EXPECT_EQ(status, 0);
|
|
EXPECT_EQ(texture->baseHeight, height);
|
|
EXPECT_EQ(texture->baseWidth, width);
|
|
if (status != 0) {
|
|
std::cout << std::ifstream(ktxdiffOut).rdbuf();
|
|
}
|
|
if (texture) {
|
|
ktxTexture_Destroy(ktxTexture(texture));
|
|
fs::remove(original);
|
|
fs::remove(decoded);
|
|
fs::remove(ktxdiffOut);
|
|
}
|
|
}
|
|
}
|
|
protected:
|
|
bool isFormatFloat() {
|
|
// Test does not yet support float formats
|
|
return false;
|
|
}
|
|
|
|
bool isFormatSrgb() {
|
|
switch(internalformat) {
|
|
case GL_SRGB8_ALPHA8: [[fallthrough]];
|
|
case GL_SRGB8:
|
|
return true;
|
|
default:
|
|
return false;
|
|
}
|
|
}
|
|
|
|
VkFormat blockDimensionToFormat(ktx_pack_astc_block_dimension_e blockDimension) {
|
|
if (isFormatSrgb())
|
|
return blockDimensionToSrgbFormat(blockDimension);
|
|
else
|
|
return blockDimensionToUnormFormat(blockDimension);
|
|
}
|
|
|
|
VkFormat blockDimensionToSrgbFormat(ktx_pack_astc_block_dimension_e blockDimension) {
|
|
switch(blockDimension) {
|
|
case KTX_PACK_ASTC_BLOCK_DIMENSION_4x4: return VK_FORMAT_ASTC_4x4_SRGB_BLOCK;
|
|
case KTX_PACK_ASTC_BLOCK_DIMENSION_5x4: return VK_FORMAT_ASTC_5x4_SRGB_BLOCK;
|
|
case KTX_PACK_ASTC_BLOCK_DIMENSION_5x5: return VK_FORMAT_ASTC_5x5_SRGB_BLOCK;
|
|
case KTX_PACK_ASTC_BLOCK_DIMENSION_6x5: return VK_FORMAT_ASTC_6x5_SRGB_BLOCK;
|
|
case KTX_PACK_ASTC_BLOCK_DIMENSION_6x6: return VK_FORMAT_ASTC_6x6_SRGB_BLOCK;
|
|
case KTX_PACK_ASTC_BLOCK_DIMENSION_8x5: return VK_FORMAT_ASTC_8x5_SRGB_BLOCK;
|
|
case KTX_PACK_ASTC_BLOCK_DIMENSION_8x6: return VK_FORMAT_ASTC_8x6_SRGB_BLOCK;
|
|
case KTX_PACK_ASTC_BLOCK_DIMENSION_10x5: return VK_FORMAT_ASTC_10x5_SRGB_BLOCK;
|
|
case KTX_PACK_ASTC_BLOCK_DIMENSION_10x6: return VK_FORMAT_ASTC_10x6_SRGB_BLOCK;
|
|
case KTX_PACK_ASTC_BLOCK_DIMENSION_8x8: return VK_FORMAT_ASTC_8x8_SRGB_BLOCK;
|
|
case KTX_PACK_ASTC_BLOCK_DIMENSION_10x8: return VK_FORMAT_ASTC_10x8_SRGB_BLOCK;
|
|
case KTX_PACK_ASTC_BLOCK_DIMENSION_10x10: return VK_FORMAT_ASTC_10x10_SRGB_BLOCK;
|
|
case KTX_PACK_ASTC_BLOCK_DIMENSION_12x10: return VK_FORMAT_ASTC_12x10_SRGB_BLOCK;
|
|
case KTX_PACK_ASTC_BLOCK_DIMENSION_12x12: return VK_FORMAT_ASTC_12x12_SRGB_BLOCK;
|
|
// 3D formats
|
|
case KTX_PACK_ASTC_BLOCK_DIMENSION_3x3x3: return VK_FORMAT_ASTC_3x3x3_SRGB_BLOCK_EXT;
|
|
case KTX_PACK_ASTC_BLOCK_DIMENSION_4x3x3: return VK_FORMAT_ASTC_4x3x3_SRGB_BLOCK_EXT;
|
|
case KTX_PACK_ASTC_BLOCK_DIMENSION_4x4x3: return VK_FORMAT_ASTC_4x4x3_SRGB_BLOCK_EXT;
|
|
case KTX_PACK_ASTC_BLOCK_DIMENSION_4x4x4: return VK_FORMAT_ASTC_4x4x4_SRGB_BLOCK_EXT;
|
|
case KTX_PACK_ASTC_BLOCK_DIMENSION_5x4x4: return VK_FORMAT_ASTC_5x4x4_SRGB_BLOCK_EXT;
|
|
case KTX_PACK_ASTC_BLOCK_DIMENSION_5x5x4: return VK_FORMAT_ASTC_5x5x4_SRGB_BLOCK_EXT;
|
|
case KTX_PACK_ASTC_BLOCK_DIMENSION_5x5x5: return VK_FORMAT_ASTC_5x5x5_SRGB_BLOCK_EXT;
|
|
case KTX_PACK_ASTC_BLOCK_DIMENSION_6x5x5: return VK_FORMAT_ASTC_6x5x5_SRGB_BLOCK_EXT;
|
|
case KTX_PACK_ASTC_BLOCK_DIMENSION_6x6x5: return VK_FORMAT_ASTC_6x6x5_SRGB_BLOCK_EXT;
|
|
case KTX_PACK_ASTC_BLOCK_DIMENSION_6x6x6: return VK_FORMAT_ASTC_6x6x6_SRGB_BLOCK_EXT;
|
|
default: return VK_FORMAT_UNDEFINED;
|
|
};
|
|
}
|
|
|
|
VkFormat blockDimensionToUnormFormat(ktx_pack_astc_block_dimension_e blockDimension) {
|
|
switch(blockDimension) {
|
|
case KTX_PACK_ASTC_BLOCK_DIMENSION_4x4: return VK_FORMAT_ASTC_4x4_UNORM_BLOCK;
|
|
case KTX_PACK_ASTC_BLOCK_DIMENSION_5x4: return VK_FORMAT_ASTC_5x4_UNORM_BLOCK;
|
|
case KTX_PACK_ASTC_BLOCK_DIMENSION_5x5: return VK_FORMAT_ASTC_5x5_UNORM_BLOCK;
|
|
case KTX_PACK_ASTC_BLOCK_DIMENSION_6x5: return VK_FORMAT_ASTC_6x5_UNORM_BLOCK;
|
|
case KTX_PACK_ASTC_BLOCK_DIMENSION_6x6: return VK_FORMAT_ASTC_6x6_UNORM_BLOCK;
|
|
case KTX_PACK_ASTC_BLOCK_DIMENSION_8x5: return VK_FORMAT_ASTC_8x5_UNORM_BLOCK;
|
|
case KTX_PACK_ASTC_BLOCK_DIMENSION_8x6: return VK_FORMAT_ASTC_8x6_UNORM_BLOCK;
|
|
case KTX_PACK_ASTC_BLOCK_DIMENSION_10x5: return VK_FORMAT_ASTC_10x5_UNORM_BLOCK;
|
|
case KTX_PACK_ASTC_BLOCK_DIMENSION_10x6: return VK_FORMAT_ASTC_10x6_UNORM_BLOCK;
|
|
case KTX_PACK_ASTC_BLOCK_DIMENSION_8x8: return VK_FORMAT_ASTC_8x8_UNORM_BLOCK;
|
|
case KTX_PACK_ASTC_BLOCK_DIMENSION_10x8: return VK_FORMAT_ASTC_10x8_UNORM_BLOCK;
|
|
case KTX_PACK_ASTC_BLOCK_DIMENSION_10x10: return VK_FORMAT_ASTC_10x10_UNORM_BLOCK;
|
|
case KTX_PACK_ASTC_BLOCK_DIMENSION_12x10: return VK_FORMAT_ASTC_12x10_UNORM_BLOCK;
|
|
case KTX_PACK_ASTC_BLOCK_DIMENSION_12x12: return VK_FORMAT_ASTC_12x12_UNORM_BLOCK;
|
|
// 3D formats
|
|
case KTX_PACK_ASTC_BLOCK_DIMENSION_3x3x3: return VK_FORMAT_ASTC_3x3x3_UNORM_BLOCK_EXT;
|
|
case KTX_PACK_ASTC_BLOCK_DIMENSION_4x3x3: return VK_FORMAT_ASTC_4x3x3_UNORM_BLOCK_EXT;
|
|
case KTX_PACK_ASTC_BLOCK_DIMENSION_4x4x3: return VK_FORMAT_ASTC_4x4x3_UNORM_BLOCK_EXT;
|
|
case KTX_PACK_ASTC_BLOCK_DIMENSION_4x4x4: return VK_FORMAT_ASTC_4x4x4_UNORM_BLOCK_EXT;
|
|
case KTX_PACK_ASTC_BLOCK_DIMENSION_5x4x4: return VK_FORMAT_ASTC_5x4x4_UNORM_BLOCK_EXT;
|
|
case KTX_PACK_ASTC_BLOCK_DIMENSION_5x5x4: return VK_FORMAT_ASTC_5x5x4_UNORM_BLOCK_EXT;
|
|
case KTX_PACK_ASTC_BLOCK_DIMENSION_5x5x5: return VK_FORMAT_ASTC_5x5x5_UNORM_BLOCK_EXT;
|
|
case KTX_PACK_ASTC_BLOCK_DIMENSION_6x5x5: return VK_FORMAT_ASTC_6x5x5_UNORM_BLOCK_EXT;
|
|
case KTX_PACK_ASTC_BLOCK_DIMENSION_6x6x5: return VK_FORMAT_ASTC_6x6x5_UNORM_BLOCK_EXT;
|
|
case KTX_PACK_ASTC_BLOCK_DIMENSION_6x6x6: return VK_FORMAT_ASTC_6x6x6_UNORM_BLOCK_EXT;
|
|
default: return VK_FORMAT_UNDEFINED;
|
|
};
|
|
}
|
|
};
|
|
|
|
// Test fixtures for ASTC encode and decode tests.
|
|
|
|
class ktxTexture2_AstcLdrEncodeDecodeTestRGBA8_UNORM
|
|
: public ktxTexture2AstcLdrEncodeDecodeTestBase<GLubyte, 4, GL_RGBA8> { };
|
|
class ktxTexture2_AstcLdrEncodeDecodeTestRGBA8_SRGB
|
|
: public ktxTexture2AstcLdrEncodeDecodeTestBase<GLubyte, 4, GL_SRGB8_ALPHA8> { };
|
|
class ktxTexture2_AstcLdrEncodeDecodeTestRGB8_UNORM
|
|
: public ktxTexture2AstcLdrEncodeDecodeTestBase<GLubyte, 4, GL_RGB8> { };
|
|
class ktxTexture2_AstcLdrEncodeDecodeTestRGB8_SRGB
|
|
: public ktxTexture2AstcLdrEncodeDecodeTestBase<GLubyte, 4, GL_SRGB8> { };
|
|
|
|
////////////////////////////////////////////
|
|
// ASTC encode & decode tests
|
|
///////////////////////////////////////////
|
|
|
|
TEST_F(ktxTexture2_AstcLdrEncodeDecodeTestRGBA8_UNORM, CompressToAstc4x4LdrThenDecode) {
|
|
runTest(KTX_PACK_ASTC_BLOCK_DIMENSION_4x4);
|
|
}
|
|
|
|
TEST_F(ktxTexture2_AstcLdrEncodeDecodeTestRGBA8_SRGB, CompressToAstc4x4LdrThenDecode) {
|
|
runTest(KTX_PACK_ASTC_BLOCK_DIMENSION_4x4);
|
|
}
|
|
|
|
TEST_F(ktxTexture2_AstcLdrEncodeDecodeTestRGB8_UNORM, CompressToAstc4x4LdrThenDecode) {
|
|
runTest(KTX_PACK_ASTC_BLOCK_DIMENSION_4x4);
|
|
}
|
|
|
|
TEST_F(ktxTexture2_AstcLdrEncodeDecodeTestRGB8_SRGB, CompressToAstc4x4LdrThenDecode) {
|
|
runTest(KTX_PACK_ASTC_BLOCK_DIMENSION_4x4);
|
|
}
|
|
|
|
TEST_F(ktxTexture2_AstcLdrEncodeDecodeTestRGBA8_UNORM, CompressToAstc8x5LdrThenDecode) {
|
|
runTest(KTX_PACK_ASTC_BLOCK_DIMENSION_8x5);
|
|
}
|
|
|
|
TEST_F(ktxTexture2_AstcLdrEncodeDecodeTestRGBA8_SRGB, CompressToAstc8x5LdrThenDecode) {
|
|
runTest(KTX_PACK_ASTC_BLOCK_DIMENSION_8x5);
|
|
}
|
|
TEST_F(ktxTexture2_AstcLdrEncodeDecodeTestRGBA8_UNORM, CompressToAstc12x12LdrThenDecode) {
|
|
runTest(KTX_PACK_ASTC_BLOCK_DIMENSION_12x12);
|
|
}
|
|
|
|
TEST_F(ktxTexture2_AstcLdrEncodeDecodeTestRGBA8_SRGB, CompressToAstc12x12LdrThenDecode) {
|
|
runTest(KTX_PACK_ASTC_BLOCK_DIMENSION_12x12);
|
|
}
|
|
|
|
} // namespace
|
|
|
|
#if defined(_WIN32)
|
|
// For Windows, we convert the UTF-8 path to a UTF-16 path to force using
|
|
// the APIs that correctly handle unicode characters.
|
|
inline std::wstring
|
|
DecodeUTF8Path(std::string path) {
|
|
std::wstring result;
|
|
int len =
|
|
MultiByteToWideChar(CP_UTF8, 0, path.c_str(), static_cast<int>(path.length()), NULL, 0);
|
|
if (len > 0) {
|
|
result.resize(len);
|
|
MultiByteToWideChar(CP_UTF8, 0, path.c_str(), static_cast<int>(path.length()), &result[0],
|
|
len);
|
|
}
|
|
return result;
|
|
}
|
|
#else
|
|
// For other platforms there is no need for any conversion, they
|
|
// support UTF-8 natively.
|
|
inline std::string DecodeUTF8Path(std::string path) { return path; }
|
|
#endif
|
|
|
|
#if defined(WIN32)
|
|
#define stat _stat64i32
|
|
#endif
|
|
|
|
static int
|
|
statUTF8(const char* path, struct stat* info) {
|
|
#if defined(_WIN32)
|
|
return _wstat(DecodeUTF8Path(path).c_str(), info);
|
|
#else
|
|
return stat(path, info);
|
|
#endif
|
|
}
|
|
|
|
GTEST_API_ int main(int argc, char* argv[]) {
|
|
testing::InitGoogleTest(&argc, argv);
|
|
|
|
if (!::testing::FLAGS_gtest_list_tests) {
|
|
if (argc != 3) {
|
|
std::cerr << "Usage: " << argv[0] << " <test images path> <ktxdiff path>\n";
|
|
return -1;
|
|
}
|
|
|
|
#if defined(_WIN32)
|
|
// Manually acquire the wide char command line in case a unicode
|
|
// filename has been specified.
|
|
int allargc;
|
|
LPWSTR commandLine = GetCommandLineW();
|
|
LPWSTR* wideArgv = CommandLineToArgvW(commandLine, &allargc);
|
|
// commandLine still has all the arguments including those removed
|
|
// by InitGoogleTest, hence the arg index calculation.
|
|
imagePath = wideArgv[allargc - argc + 1];
|
|
ktxdiffPath = wideArgv[allargc - argc + 2];
|
|
#else
|
|
imagePath = argv[1];
|
|
ktxdiffPath = argv[2];
|
|
#endif
|
|
imagePath /= ""; // Ensure trailing / so path will be handled as a directory.
|
|
|
|
struct stat info;
|
|
|
|
if (statUTF8(imagePath.u8string().c_str(), &info) != 0) {
|
|
std::cerr << "Cannot access " << imagePath << std::endl;
|
|
return -2;
|
|
} else if (!(info.st_mode & S_IFDIR)) {
|
|
std::cerr << imagePath << " is not a valid directory\n";
|
|
return -3;
|
|
}
|
|
}
|
|
|
|
return RUN_ALL_TESTS();
|
|
}
|