Add some testing / validation for KTX

This commit is contained in:
Brad Davis 2017-02-22 12:07:06 -08:00
parent c6b72dfe3c
commit a2269f488f
7 changed files with 176 additions and 96 deletions

View file

@ -93,6 +93,27 @@ ktx::KTXUniquePointer Texture::serialize(const Texture& texture) {
}
auto ktxBuffer = ktx::KTX::create(header, images);
assert(0 == memcmp(&header, ktxBuffer->getHeader(), sizeof(ktx::Header)));
assert(ktxBuffer->_images.size() == images.size());
auto start = ktxBuffer->_storage->data();
for (size_t i = 0; i < images.size(); ++i) {
auto expected = images[i];
auto actual = ktxBuffer->_images[i];
assert(expected._padding == actual._padding);
assert(expected._numFaces == actual._numFaces);
assert(expected._imageSize == actual._imageSize);
assert(expected._faceSize == actual._faceSize);
assert(actual._faceBytes.size() == actual._numFaces);
for (uint32_t face = 0; face < expected._numFaces; ++face) {
auto expectedFace = expected._faceBytes[face];
auto actualFace = actual._faceBytes[face];
auto offset = actualFace - start;
assert(offset % 4 == 0);
assert(expectedFace != actualFace);
assert(0 == memcmp(expectedFace, actualFace, expected._faceSize));
}
}
return ktxBuffer;
}

View file

@ -86,11 +86,10 @@ void KTX::resetStorage(Storage* storage) {
}
const Header* KTX::getHeader() const {
if (_storage) {
return reinterpret_cast<const Header*> (_storage->_bytes);
} else {
if (!_storage) {
return nullptr;
}
}
return reinterpret_cast<const Header*>(_storage->data());
}
@ -105,7 +104,7 @@ size_t KTX::getKeyValueDataSize() const {
size_t KTX::getTexelsDataSize() const {
if (_storage) {
//return _storage->size() - (sizeof(Header) + getKeyValueDataSize());
return (_storage->_bytes + _storage->_size) - getTexelsData();
return (_storage->data() + _storage->size()) - getTexelsData();
} else {
return 0;
}
@ -113,7 +112,7 @@ size_t KTX::getTexelsDataSize() const {
const Byte* KTX::getKeyValueData() const {
if (_storage) {
return (_storage->_bytes + sizeof(Header));
return (_storage->data() + sizeof(Header));
} else {
return nullptr;
}
@ -121,16 +120,9 @@ const Byte* KTX::getKeyValueData() const {
const Byte* KTX::getTexelsData() const {
if (_storage) {
return (_storage->_bytes + sizeof(Header) + getKeyValueDataSize());
return (_storage->data() + sizeof(Header) + getKeyValueDataSize());
} else {
return nullptr;
}
}
Byte* KTX::getTexelsData() {
if (_storage) {
return (_storage->_bytes + sizeof(Header) + getKeyValueDataSize());
} else {
return nullptr;
}
}

View file

@ -19,6 +19,8 @@
#include <cstring>
#include <memory>
#include <shared/Storage.h>
/* KTX Spec:
Byte[12] identifier
@ -291,46 +293,8 @@ namespace ktx {
NUM_CUBEMAPFACES = 6,
};
// Chunk of data
struct Storage {
size_t _size {0};
Byte* _bytes {nullptr};
Byte* data() {
return _bytes;
}
const Byte* data() const {
return _bytes;
}
size_t size() const { return _size; }
~Storage() { if (_bytes) { delete _bytes; } }
Storage() {}
Storage(size_t size) :
_size(size)
{
if (_size) { _bytes = new Byte[_size]; }
}
Storage(size_t size, Byte* bytes) :
_size(size)
{
if (_size && _bytes) { _bytes = bytes; }
}
Storage(size_t size, const Byte* bytes) :
Storage(size)
{
if (_size && _bytes && bytes) {
memcpy(_bytes, bytes, size);
}
}
Storage(const Storage& src) :
Storage(src.size(), src.data())
{}
};
using Storage = storage::Storage;
using StoragePointer = std::unique_ptr<Storage>;
// Header
struct Header {
@ -382,7 +346,8 @@ namespace ktx {
void setUncompressed(GLType type, uint32_t typeSize, GLFormat format, GLInternalFormat_Uncompressed internalFormat, GLBaseInternalFormat baseInternalFormat) {
glType = (uint32_t) type;
glTypeSize = 0;
// FIXME this should correspond to the size of glType
glTypeSize = 1;
glFormat = (uint32_t) format;
glInternalFormat = (uint32_t) internalFormat;
glBaseInternalFormat = (uint32_t) baseInternalFormat;
@ -456,13 +421,9 @@ namespace ktx {
};
using Images = std::vector<Image>;
class KTX {
void resetStorage(Storage* src);
void resetHeader(const Header& header);
void resetImages(const Images& images);
KTX();
public:
@ -498,12 +459,12 @@ namespace ktx {
const Header* getHeader() const;
const Byte* getKeyValueData() const;
const Byte* getTexelsData() const;
Byte* getTexelsData();
const StoragePointer& getStorage() const { return _storage; }
size_t getKeyValueDataSize() const;
size_t getTexelsDataSize() const;
std::unique_ptr<Storage> _storage;
StoragePointer _storage;
KeyValues _keyValues;
Images _images;
};

View file

@ -26,40 +26,15 @@ namespace ktx {
const std::string _explanation;
};
void KTX::resetHeader(const Header& header) {
if (!_storage) {
return;
}
memcpy(_storage->_bytes, &header, sizeof(Header));
}
void KTX::resetImages(const Images& srcImages) {
auto imagesDataPtr = getTexelsData();
if (!imagesDataPtr) {
return;
}
auto allocatedImagesDataSize = getTexelsDataSize();
// Just copy in our storage
_images = writeImages(imagesDataPtr, allocatedImagesDataSize, srcImages);
}
std::unique_ptr<KTX> KTX::create(const Header& header, const Images& images, const KeyValues& keyValues) {
auto storageSize = evalStorageSize(header, images, keyValues);
std::unique_ptr<KTX> result(new KTX());
result->resetStorage(new Storage(storageSize));
result->resetHeader(header);
// read metadata
result->_keyValues = keyValues;
// populate image table
result->resetImages(images);
return result;
std::unique_ptr<storage::Storage> storagePointer;
{
auto storageSize = ktx::KTX::evalStorageSize(header, images);
auto memoryStorage = new storage::MemoryStorage(storageSize);
ktx::KTX::write(memoryStorage->data(), memoryStorage->size(), header, images);
storagePointer.reset(memoryStorage);
}
return create(storagePointer);
}
size_t KTX::evalStorageSize(const Header& header, const Images& images, const KeyValues& keyValues) {
@ -117,8 +92,6 @@ namespace ktx {
size_t currentDataSize = 0;
auto currentPtr = imagesDataPtr;
for (uint32_t l = 0; l < srcImages.size(); l++) {
if (currentDataSize + sizeof(uint32_t) < allocatedImagesDataSize) {
size_t imageSize = srcImages[l]._imageSize;

1
scripts/developer/tests/.gitignore vendored Normal file
View file

@ -0,0 +1 @@
cube_texture.ktx

15
tests/ktx/CMakeLists.txt Normal file
View file

@ -0,0 +1,15 @@
set(TARGET_NAME ktx-test)
if (WIN32)
SET(CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} /ignore:4049 /ignore:4217")
endif()
# This is not a testcase -- just set it up as a regular hifi project
setup_hifi_project(Quick Gui OpenGL)
set_target_properties(${TARGET_NAME} PROPERTIES FOLDER "Tests/manual-tests/")
# link in the shared libraries
link_hifi_libraries(shared octree ktx gl gpu gpu-gl render model model-networking networking render-utils fbx entities entities-renderer animation audio avatars script-engine physics)
package_libraries_for_deployment()

117
tests/ktx/src/main.cpp Normal file
View file

@ -0,0 +1,117 @@
//
// Created by Bradley Austin Davis on 2016/07/01
// Copyright 2014 High Fidelity, Inc.
//
// Distributed under the Apache License, Version 2.0.
// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
//
#include <iostream>
#include <string>
#include <vector>
#include <sstream>
#include <QProcessEnvironment>
#include <QtCore/QDir>
#include <QtCore/QElapsedTimer>
#include <QtCore/QLoggingCategory>
#include <QtCore/QRegularExpression>
#include <QtCore/QSettings>
#include <QtCore/QTimer>
#include <QtCore/QThread>
#include <QtCore/QThreadPool>
#include <QtGui/QGuiApplication>
#include <QtGui/QResizeEvent>
#include <QtGui/QWindow>
#include <QtWidgets/QFileDialog>
#include <QtWidgets/QInputDialog>
#include <QtWidgets/QMessageBox>
#include <QtWidgets/QApplication>
#include <shared/RateCounter.h>
#include <shared/NetworkUtils.h>
#include <shared/FileLogger.h>
#include <shared/FileUtils.h>
#include <StatTracker.h>
#include <LogHandler.h>
#include <Windows.h>
#include <gpu/Texture.h>
#include <gl/Config.h>
#include <model/TextureMap.h>
#include <ktx/KTX.h>
QSharedPointer<FileLogger> logger;
gpu::Texture* cacheTexture(const std::string& name, gpu::Texture* srcTexture, bool write = true, bool read = true);
void messageHandler(QtMsgType type, const QMessageLogContext& context, const QString& message) {
QString logMessage = LogHandler::getInstance().printMessage((LogMsgType)type, context, message);
if (!logMessage.isEmpty()) {
#ifdef Q_OS_WIN
OutputDebugStringA(logMessage.toLocal8Bit().constData());
OutputDebugStringA("\n");
#endif
logger->addMessage(qPrintable(logMessage + "\n"));
}
}
const char * LOG_FILTER_RULES = R"V0G0N(
hifi.gpu=true
)V0G0N";
QString getRootPath() {
static std::once_flag once;
static QString result;
std::call_once(once, [&] {
QFileInfo file(__FILE__);
QDir parent = file.absolutePath();
result = QDir::cleanPath(parent.currentPath() + "/../../..");
});
return result;
}
const QString TEST_IMAGE = getRootPath() + "/scripts/developer/tests/cube_texture.png";
const QString TEST_IMAGE_KTX = getRootPath() + "/scripts/developer/tests/cube_texture.ktx";
int main(int argc, char** argv) {
QApplication app(argc, argv);
QCoreApplication::setApplicationName("KTX");
QCoreApplication::setOrganizationName("High Fidelity");
QCoreApplication::setOrganizationDomain("highfidelity.com");
logger.reset(new FileLogger());
DependencyManager::set<tracing::Tracer>();
qInstallMessageHandler(messageHandler);
QLoggingCategory::setFilterRules(LOG_FILTER_RULES);
QImage image(TEST_IMAGE);
gpu::Texture* testTexture = model::TextureUsage::process2DTextureColorFromImage(image, TEST_IMAGE.toStdString(), true, false, true);
auto ktxPtr = gpu::Texture::serialize(*testTexture);
const auto& ktxStorage = ktxPtr->getStorage();
auto header = ktxPtr->getHeader();
assert(sizeof(ktx::Header) == 12 + (sizeof(uint32_t) * 13));
QFile outFile(TEST_IMAGE_KTX);
if (!outFile.open(QFile::Truncate | QFile::ReadWrite)) {
throw std::runtime_error("Unable to open file");
}
//auto ktxSize = sizeof(ktx::Header); // ktxStorage->size()
auto ktxSize = ktxStorage->size();
outFile.resize(ktxSize);
auto dest = outFile.map(0, ktxSize);
memcpy(dest, ktxStorage->data(), ktxSize);
outFile.unmap(dest);
outFile.close();
// gpu::Texture* ktxTexture = cacheTexture(TEST_IMAGE.toStdString(), testTexture, true, true);
return 0;
}
#include "main.moc"