diff --git a/libraries/gpu/src/gpu/Texture_ktx.cpp b/libraries/gpu/src/gpu/Texture_ktx.cpp index f1d91d39ab..47e7bde333 100644 --- a/libraries/gpu/src/gpu/Texture_ktx.cpp +++ b/libraries/gpu/src/gpu/Texture_ktx.cpp @@ -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; } diff --git a/libraries/ktx/src/ktx/KTX.cpp b/libraries/ktx/src/ktx/KTX.cpp index 8635fbb684..ea7653e1ed 100644 --- a/libraries/ktx/src/ktx/KTX.cpp +++ b/libraries/ktx/src/ktx/KTX.cpp @@ -86,11 +86,10 @@ void KTX::resetStorage(Storage* storage) { } const Header* KTX::getHeader() const { - if (_storage) { - return reinterpret_cast (_storage->_bytes); - } else { + if (!_storage) { return nullptr; - } + } + return reinterpret_cast(_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; - } -} diff --git a/libraries/ktx/src/ktx/KTX.h b/libraries/ktx/src/ktx/KTX.h index 94529d6e68..c1521a52b9 100644 --- a/libraries/ktx/src/ktx/KTX.h +++ b/libraries/ktx/src/ktx/KTX.h @@ -19,6 +19,8 @@ #include #include +#include + /* 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; // 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; - 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; + StoragePointer _storage; KeyValues _keyValues; Images _images; }; diff --git a/libraries/ktx/src/ktx/Writer.cpp b/libraries/ktx/src/ktx/Writer.cpp index 1839624038..7fcf4c60d2 100644 --- a/libraries/ktx/src/ktx/Writer.cpp +++ b/libraries/ktx/src/ktx/Writer.cpp @@ -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::create(const Header& header, const Images& images, const KeyValues& keyValues) { - auto storageSize = evalStorageSize(header, images, keyValues); - - std::unique_ptr 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 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; diff --git a/scripts/developer/tests/.gitignore b/scripts/developer/tests/.gitignore new file mode 100644 index 0000000000..7cacbf042c --- /dev/null +++ b/scripts/developer/tests/.gitignore @@ -0,0 +1 @@ +cube_texture.ktx \ No newline at end of file diff --git a/tests/ktx/CMakeLists.txt b/tests/ktx/CMakeLists.txt new file mode 100644 index 0000000000..d72379efd6 --- /dev/null +++ b/tests/ktx/CMakeLists.txt @@ -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() diff --git a/tests/ktx/src/main.cpp b/tests/ktx/src/main.cpp new file mode 100644 index 0000000000..a3c3b99960 --- /dev/null +++ b/tests/ktx/src/main.cpp @@ -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 +#include +#include +#include + +#include + +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include + +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include + + +QSharedPointer 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(); + 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" +