mirror of
https://thingvellir.net/git/overte
synced 2025-03-27 23:52:03 +01:00
Add some testing / validation for KTX
This commit is contained in:
parent
c6b72dfe3c
commit
a2269f488f
7 changed files with 176 additions and 96 deletions
|
@ -93,6 +93,27 @@ ktx::KTXUniquePointer Texture::serialize(const Texture& texture) {
|
||||||
}
|
}
|
||||||
|
|
||||||
auto ktxBuffer = ktx::KTX::create(header, images);
|
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;
|
return ktxBuffer;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -86,11 +86,10 @@ void KTX::resetStorage(Storage* storage) {
|
||||||
}
|
}
|
||||||
|
|
||||||
const Header* KTX::getHeader() const {
|
const Header* KTX::getHeader() const {
|
||||||
if (_storage) {
|
if (!_storage) {
|
||||||
return reinterpret_cast<const Header*> (_storage->_bytes);
|
|
||||||
} else {
|
|
||||||
return nullptr;
|
return nullptr;
|
||||||
}
|
}
|
||||||
|
return reinterpret_cast<const Header*>(_storage->data());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -105,7 +104,7 @@ size_t KTX::getKeyValueDataSize() const {
|
||||||
size_t KTX::getTexelsDataSize() const {
|
size_t KTX::getTexelsDataSize() const {
|
||||||
if (_storage) {
|
if (_storage) {
|
||||||
//return _storage->size() - (sizeof(Header) + getKeyValueDataSize());
|
//return _storage->size() - (sizeof(Header) + getKeyValueDataSize());
|
||||||
return (_storage->_bytes + _storage->_size) - getTexelsData();
|
return (_storage->data() + _storage->size()) - getTexelsData();
|
||||||
} else {
|
} else {
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
@ -113,7 +112,7 @@ size_t KTX::getTexelsDataSize() const {
|
||||||
|
|
||||||
const Byte* KTX::getKeyValueData() const {
|
const Byte* KTX::getKeyValueData() const {
|
||||||
if (_storage) {
|
if (_storage) {
|
||||||
return (_storage->_bytes + sizeof(Header));
|
return (_storage->data() + sizeof(Header));
|
||||||
} else {
|
} else {
|
||||||
return nullptr;
|
return nullptr;
|
||||||
}
|
}
|
||||||
|
@ -121,16 +120,9 @@ const Byte* KTX::getKeyValueData() const {
|
||||||
|
|
||||||
const Byte* KTX::getTexelsData() const {
|
const Byte* KTX::getTexelsData() const {
|
||||||
if (_storage) {
|
if (_storage) {
|
||||||
return (_storage->_bytes + sizeof(Header) + getKeyValueDataSize());
|
return (_storage->data() + sizeof(Header) + getKeyValueDataSize());
|
||||||
} else {
|
} else {
|
||||||
return nullptr;
|
return nullptr;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
Byte* KTX::getTexelsData() {
|
|
||||||
if (_storage) {
|
|
||||||
return (_storage->_bytes + sizeof(Header) + getKeyValueDataSize());
|
|
||||||
} else {
|
|
||||||
return nullptr;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
|
@ -19,6 +19,8 @@
|
||||||
#include <cstring>
|
#include <cstring>
|
||||||
#include <memory>
|
#include <memory>
|
||||||
|
|
||||||
|
#include <shared/Storage.h>
|
||||||
|
|
||||||
/* KTX Spec:
|
/* KTX Spec:
|
||||||
|
|
||||||
Byte[12] identifier
|
Byte[12] identifier
|
||||||
|
@ -291,46 +293,8 @@ namespace ktx {
|
||||||
NUM_CUBEMAPFACES = 6,
|
NUM_CUBEMAPFACES = 6,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
using Storage = storage::Storage;
|
||||||
// Chunk of data
|
using StoragePointer = std::unique_ptr<Storage>;
|
||||||
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())
|
|
||||||
{}
|
|
||||||
|
|
||||||
};
|
|
||||||
|
|
||||||
// Header
|
// Header
|
||||||
struct Header {
|
struct Header {
|
||||||
|
@ -382,7 +346,8 @@ namespace ktx {
|
||||||
|
|
||||||
void setUncompressed(GLType type, uint32_t typeSize, GLFormat format, GLInternalFormat_Uncompressed internalFormat, GLBaseInternalFormat baseInternalFormat) {
|
void setUncompressed(GLType type, uint32_t typeSize, GLFormat format, GLInternalFormat_Uncompressed internalFormat, GLBaseInternalFormat baseInternalFormat) {
|
||||||
glType = (uint32_t) type;
|
glType = (uint32_t) type;
|
||||||
glTypeSize = 0;
|
// FIXME this should correspond to the size of glType
|
||||||
|
glTypeSize = 1;
|
||||||
glFormat = (uint32_t) format;
|
glFormat = (uint32_t) format;
|
||||||
glInternalFormat = (uint32_t) internalFormat;
|
glInternalFormat = (uint32_t) internalFormat;
|
||||||
glBaseInternalFormat = (uint32_t) baseInternalFormat;
|
glBaseInternalFormat = (uint32_t) baseInternalFormat;
|
||||||
|
@ -456,13 +421,9 @@ namespace ktx {
|
||||||
};
|
};
|
||||||
using Images = std::vector<Image>;
|
using Images = std::vector<Image>;
|
||||||
|
|
||||||
|
|
||||||
class KTX {
|
class KTX {
|
||||||
void resetStorage(Storage* src);
|
void resetStorage(Storage* src);
|
||||||
|
|
||||||
void resetHeader(const Header& header);
|
|
||||||
void resetImages(const Images& images);
|
|
||||||
|
|
||||||
KTX();
|
KTX();
|
||||||
public:
|
public:
|
||||||
|
|
||||||
|
@ -498,12 +459,12 @@ namespace ktx {
|
||||||
const Header* getHeader() const;
|
const Header* getHeader() const;
|
||||||
const Byte* getKeyValueData() const;
|
const Byte* getKeyValueData() const;
|
||||||
const Byte* getTexelsData() const;
|
const Byte* getTexelsData() const;
|
||||||
Byte* getTexelsData();
|
const StoragePointer& getStorage() const { return _storage; }
|
||||||
|
|
||||||
size_t getKeyValueDataSize() const;
|
size_t getKeyValueDataSize() const;
|
||||||
size_t getTexelsDataSize() const;
|
size_t getTexelsDataSize() const;
|
||||||
|
|
||||||
std::unique_ptr<Storage> _storage;
|
StoragePointer _storage;
|
||||||
KeyValues _keyValues;
|
KeyValues _keyValues;
|
||||||
Images _images;
|
Images _images;
|
||||||
};
|
};
|
||||||
|
|
|
@ -26,40 +26,15 @@ namespace ktx {
|
||||||
const std::string _explanation;
|
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) {
|
std::unique_ptr<KTX> KTX::create(const Header& header, const Images& images, const KeyValues& keyValues) {
|
||||||
auto storageSize = evalStorageSize(header, images, keyValues);
|
std::unique_ptr<storage::Storage> storagePointer;
|
||||||
|
{
|
||||||
std::unique_ptr<KTX> result(new KTX());
|
auto storageSize = ktx::KTX::evalStorageSize(header, images);
|
||||||
|
auto memoryStorage = new storage::MemoryStorage(storageSize);
|
||||||
result->resetStorage(new Storage(storageSize));
|
ktx::KTX::write(memoryStorage->data(), memoryStorage->size(), header, images);
|
||||||
|
storagePointer.reset(memoryStorage);
|
||||||
result->resetHeader(header);
|
}
|
||||||
|
return create(storagePointer);
|
||||||
// read metadata
|
|
||||||
result->_keyValues = keyValues;
|
|
||||||
|
|
||||||
// populate image table
|
|
||||||
result->resetImages(images);
|
|
||||||
|
|
||||||
return result;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
size_t KTX::evalStorageSize(const Header& header, const Images& images, const KeyValues& keyValues) {
|
size_t KTX::evalStorageSize(const Header& header, const Images& images, const KeyValues& keyValues) {
|
||||||
|
@ -117,8 +92,6 @@ namespace ktx {
|
||||||
size_t currentDataSize = 0;
|
size_t currentDataSize = 0;
|
||||||
auto currentPtr = imagesDataPtr;
|
auto currentPtr = imagesDataPtr;
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
for (uint32_t l = 0; l < srcImages.size(); l++) {
|
for (uint32_t l = 0; l < srcImages.size(); l++) {
|
||||||
if (currentDataSize + sizeof(uint32_t) < allocatedImagesDataSize) {
|
if (currentDataSize + sizeof(uint32_t) < allocatedImagesDataSize) {
|
||||||
size_t imageSize = srcImages[l]._imageSize;
|
size_t imageSize = srcImages[l]._imageSize;
|
||||||
|
|
1
scripts/developer/tests/.gitignore
vendored
Normal file
1
scripts/developer/tests/.gitignore
vendored
Normal file
|
@ -0,0 +1 @@
|
||||||
|
cube_texture.ktx
|
15
tests/ktx/CMakeLists.txt
Normal file
15
tests/ktx/CMakeLists.txt
Normal 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
117
tests/ktx/src/main.cpp
Normal 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"
|
||||||
|
|
Loading…
Reference in a new issue