Files
how-to-vulkan/ktx/tests/transcodetests/transcodetests.cc
T
2026-06-14 19:09:18 +01:00

244 lines
6.1 KiB
C++

// Copyright 2019 Andreas Atteneder, All Rights Reserved.
// SPDX-License-Identifier: Apache-2.0
#if defined(_WIN32)
#define _CRT_SECURE_NO_WARNINGS
#define OS_SEP '\\'
#define UNIX_SEP '/'
#else
#define OS_SEP '/'
#endif
#include <string.h>
#include <sys/types.h>
#include <sys/stat.h>
#include "gl_format.h"
#include "ktx.h"
extern "C" {
#include "ktxint.h"
#include "filestream.h"
#include "memstream.h"
}
#include "gtest/gtest.h"
#include <vector>
#include <cstring>
#include "basisu_c_binding.h"
using namespace std;
string image_path;
namespace {
typedef struct {
string ktxPath;
string basisuPath;
bool isPo2;
bool hasAlpha;
} TextureSet;
std::ostream& operator<<(std::ostream& out, const TextureSet& h)
{
return out << h.ktxPath;
}
typedef struct {
ktx_transcode_fmt_e format;
bool supportsNonPo2;
bool supportsNonAlpha;
} FormatFeature;
std::ostream& operator<<(std::ostream& out, const FormatFeature& h)
{
return out << ktxTranscodeFormatString(h.format);
}
vector<TextureSet> allTextureSets = {
{"color_grid_basis.ktx2","color_grid.basis",true,false},
#if 1
{"kodim17_basis.ktx2","kodim17.basis",false,false},
{"alpha_simple_basis.ktx2","alpha_simple.basis",true,true}
#endif
};
vector<FormatFeature> allFormats = {
#if 1
{KTX_TTF_ETC1_RGB,true,true},
{KTX_TTF_ETC2_RGBA,true,true},
{KTX_TTF_BC1_RGB,true,true},
{KTX_TTF_BC3_RGBA,true,true},
{KTX_TTF_BC4_R,true,true},
{KTX_TTF_BC5_RG,true,true},
{KTX_TTF_BC7_RGBA,true,true},
{KTX_TTF_PVRTC1_4_RGB,false,true},
{KTX_TTF_PVRTC1_4_RGBA,false,false},
{KTX_TTF_ASTC_4x4_RGBA,true,true},
{KTX_TTF_PVRTC2_4_RGB,true,true},
{KTX_TTF_PVRTC2_4_RGBA,true,true},
// {KTX_TTF_ETC2_EAC_R11,true,true},
{KTX_TTF_ETC2_EAC_RG11,true,true},
{KTX_TTF_RGBA32,true,true},
{KTX_TTF_RGB565,true,true},
{KTX_TTF_BGR565,true,true},
#endif
{KTX_TTF_RGBA4444,true,true}
// ATC and FXT1 formats are not supported by KTX2 as there
// are no equivalent VkFormats.
};
class TextureCombinationsTest :
public ::testing::TestWithParam<tuple<TextureSet,FormatFeature>> {};
INSTANTIATE_TEST_SUITE_P(AllCombinations,
TextureCombinationsTest,
::testing::Combine(::testing::ValuesIn(allTextureSets),
::testing::ValuesIn(allFormats)));
bool read_file( string path, void** data, unsigned long *fsize ) {
FILE *f = fopen(path.data(),"rb");
if(f==NULL) {
return false;
}
fseek(f, 0, SEEK_END);
*fsize = ftell(f);
fseek(f, 0, SEEK_SET); /* same as rewind(f); */
*data = malloc(*fsize);
size_t numRead = fread(*data, 1, *fsize, f);
fclose(f);
return numRead == *fsize;
}
bool isPo2(uint32_t i) {
return (i&(i-1))==0;
}
string combine_paths(string const a, string const b) {
if (a.back() == OS_SEP) {
return a + b;
#if defined(_WIN32)
} else if (a.back() == UNIX_SEP) {
return a + b;
#endif
} else {
return a+OS_SEP+b;
}
}
void test_texture_set( TextureSet & textureSet, FormatFeature & format ) {
void * basisData = nullptr;
unsigned long basisSize = 0;
string path = combine_paths(image_path,textureSet.basisuPath);
bool read_success = read_file(path, &basisData, &basisSize);
ASSERT_TRUE(read_success) << "Could not open or read texture file " << path;
basis_file basisu;
basisu.open((uint8_t*)basisData, (uint32_t)basisSize);
uint32_t bWidth = basisu.getImageWidth(0,0);
uint32_t bHeight = basisu.getImageHeight(0,0);
bool hasAlpha = basisu.getHasAlpha() > 0;
ASSERT_EQ(hasAlpha,textureSet.hasAlpha);
if( !hasAlpha && !format.supportsNonAlpha ) {
return;
}
if(!(isPo2(bWidth) && isPo2(bHeight))
&& !format.supportsNonPo2 ) {
return;
}
uint32_t finalSize = basisu.getImageTranscodedSizeInBytes(0,0,format.format);
ktx_uint8_t* basisTranscodedData = (ktx_uint8_t*) malloc(finalSize);
basisu.startTranscoding();
uint32_t bRes = basisu.transcodeImage((void*)basisTranscodedData,finalSize,0,0,format.format,0,0);
ASSERT_TRUE(bRes);
basisu.close();
void * data = 0; // = 0 to silence over-enthusiastic gcc 11 warning.
unsigned long fsize;
path = combine_paths(image_path,textureSet.ktxPath);
read_success = read_file(path, &data, &fsize);
ASSERT_TRUE(read_success) << "Could not open texture file " << path;
KTX_error_code result;
ktxTexture2* newTex = 0;
result = ktxTexture2_CreateFromMemory(
(const ktx_uint8_t*) data,
(ktx_size_t) fsize,
KTX_TEXTURE_CREATE_LOAD_IMAGE_DATA_BIT,
(ktxTexture2**)&newTex
);
ASSERT_EQ(result,KTX_SUCCESS);
result = ktxTexture2_TranscodeBasis(
newTex,
format.format,
0
);
ASSERT_EQ(result,KTX_SUCCESS) << "Format " << format.format;
EXPECT_EQ(bWidth,newTex->baseWidth);
EXPECT_EQ(bHeight,newTex->baseHeight);
EXPECT_EQ(finalSize,newTex->dataSize);
int cmp = std::memcmp(basisTranscodedData,newTex->pData,finalSize);
ASSERT_EQ(cmp,0);
ktxTexture_Destroy(ktxTexture(newTex));
free(data);
free(basisTranscodedData);
free(basisData);
}
TEST_P(TextureCombinationsTest, Basic) {
TextureSet ts = get<0>(GetParam());
FormatFeature format = get<1>(GetParam());
test_texture_set(ts,format);
}
} // namespace
int main(int argc, char **argv) {
::testing::InitGoogleTest(&argc, argv);
if(!::testing::FLAGS_gtest_list_tests) {
if(argc!=2) {
cerr << "Usage: " << argv[0] << " <test images path>\n";
return -1;
}
image_path = string(argv[1]);
struct stat info;
if( stat( image_path.data(), &info ) != 0 ) {
cerr << "Cannot access " << image_path << '\n';
return -2;
} else if( ! (info.st_mode & S_IFDIR) ) {
cerr << image_path << "is not a valid directory\n";
return -3;
}
}
ktx_basisu_basis_init();
return RUN_ALL_TESTS();
}