From b20fcbfcdb7d0b19cff97295dc27d46f6542efec Mon Sep 17 00:00:00 2001
From: Ryan Huffman <ryanhuffman@gmail.com>
Date: Wed, 12 Apr 2017 09:40:08 -0700
Subject: [PATCH] Add a way to write data to a storage object

---
 .../gpu-gl/src/gpu/gl/GLBackendPipeline.cpp     |  4 +++-
 libraries/gpu/src/gpu/Texture.cpp               |  1 +
 libraries/gpu/src/gpu/Texture_ktx.cpp           |  4 +++-
 libraries/ktx/src/ktx/KTX.cpp                   |  1 +
 libraries/ktx/src/ktx/KTX.h                     |  4 +++-
 libraries/ktx/src/ktx/Writer.cpp                |  7 +++++++
 .../src/model-networking/TextureCache.cpp       | 17 +++++++++++++++--
 .../networking/src/HTTPResourceRequest.cpp      |  6 ++++++
 libraries/networking/src/ResourceCache.cpp      |  1 +
 libraries/shared/src/shared/Storage.cpp         |  4 +++-
 libraries/shared/src/shared/Storage.h           |  4 ++++
 11 files changed, 47 insertions(+), 6 deletions(-)

diff --git a/libraries/gpu-gl/src/gpu/gl/GLBackendPipeline.cpp b/libraries/gpu-gl/src/gpu/gl/GLBackendPipeline.cpp
index 1d1f92b297..008b658205 100644
--- a/libraries/gpu-gl/src/gpu/gl/GLBackendPipeline.cpp
+++ b/libraries/gpu-gl/src/gpu/gl/GLBackendPipeline.cpp
@@ -259,7 +259,9 @@ void GLBackend::do_setResourceTexture(const Batch& batch, size_t paramOffset) {
         glActiveTexture(GL_TEXTURE0 + slot);
         glBindTexture(target, to);
 
-        (void) CHECK_GL_ERROR();
+        if (CHECK_GL_ERROR()) {
+            qDebug() << "slot: " << slot << ", target: " << target << ", to: " << to;
+        }
 
         _resource._textures[slot] = resourceTexture;
 
diff --git a/libraries/gpu/src/gpu/Texture.cpp b/libraries/gpu/src/gpu/Texture.cpp
index ebde9d4d27..6a1e5ca699 100755
--- a/libraries/gpu/src/gpu/Texture.cpp
+++ b/libraries/gpu/src/gpu/Texture.cpp
@@ -411,6 +411,7 @@ const Element& Texture::getStoredMipFormat() const {
 }
 
 void Texture::assignStoredMip(uint16 level, Size size, const Byte* bytes) {
+    // TODO Skip the extra allocation here
     storage::StoragePointer storage = std::make_shared<storage::MemoryStorage>(size, bytes);
     assignStoredMip(level, storage);
 }
diff --git a/libraries/gpu/src/gpu/Texture_ktx.cpp b/libraries/gpu/src/gpu/Texture_ktx.cpp
index 487d32f91d..1e6fe1115e 100644
--- a/libraries/gpu/src/gpu/Texture_ktx.cpp
+++ b/libraries/gpu/src/gpu/Texture_ktx.cpp
@@ -45,6 +45,7 @@ std::string GPUKTXPayload::KEY { "hifi.gpu" };
 
 KtxStorage::KtxStorage(const std::string& filename) : _filename(filename) {
     {
+        // We are doing a lot of work here just to get descriptor data
         ktx::StoragePointer storage { new storage::FileStorage(_filename.c_str()) };
         auto ktxPointer = ktx::KTX::create(storage);
         _ktxDescriptor.reset(new ktx::KTXDescriptor(ktxPointer->toDescriptor()));
@@ -74,8 +75,9 @@ Size KtxStorage::getMipFaceSize(uint16 level, uint8 face) const {
 
 
 bool KtxStorage::isMipAvailable(uint16 level, uint8 face) const {
+    return true;
     auto numLevels = _ktxDescriptor->header.numberOfMipmapLevels;
-    auto minLevel = 7 > numLevels ? 0 : numLevels - 7;
+    auto minLevel = 7 > numLevels ? 0 : numLevels - 10;
     auto avail = level >= minLevel;
     qDebug() << "isMipAvailable: " << level << " " << face << avail << minLevel << " " << _ktxDescriptor->header.numberOfMipmapLevels;
     //return true;
diff --git a/libraries/ktx/src/ktx/KTX.cpp b/libraries/ktx/src/ktx/KTX.cpp
index 0580d9a8c3..1f22514226 100644
--- a/libraries/ktx/src/ktx/KTX.cpp
+++ b/libraries/ktx/src/ktx/KTX.cpp
@@ -211,6 +211,7 @@ Image ImageDescriptor::toImage(const ktx::StoragePointer& storage) const {
     FaceBytes faces;
     faces.resize(_faceOffsets.size());
     for (size_t face = 0; face < _numFaces; ++face) {
+        // TODO Should we be storing pointers to unowned data?
         faces[face] = storage->data() + _faceOffsets[face];
     }
     // Note, implicit cast of *this to const ImageHeader&
diff --git a/libraries/ktx/src/ktx/KTX.h b/libraries/ktx/src/ktx/KTX.h
index fb8927eca0..988c921ce9 100644
--- a/libraries/ktx/src/ktx/KTX.h
+++ b/libraries/ktx/src/ktx/KTX.h
@@ -384,7 +384,7 @@ namespace ktx {
         ImageDescriptors generateImageDescriptors() const;
     };
     static const size_t KTX_HEADER_SIZE = 64;
-    static_assert(sizeof(Header) == KTX_HEADER_SIZE, "KTX Header size is static");
+    static_assert(sizeof(Header) == KTX_HEADER_SIZE, "KTX Header size is static and should not change from the spec");
 
     // Key Values
     struct KeyValue {
@@ -497,6 +497,8 @@ namespace ktx {
         static size_t writeKeyValues(Byte* destBytes, size_t destByteSize, const KeyValues& keyValues);
         static Images writeImages(Byte* destBytes, size_t destByteSize, const Images& images);
 
+        void writeMipData(uint16_t level, const Byte* sourceBytes, size_t source_size);
+
         // Parse a block of memory and create a KTX object from it
         static std::unique_ptr<KTX> create(const StoragePointer& src);
 
diff --git a/libraries/ktx/src/ktx/Writer.cpp b/libraries/ktx/src/ktx/Writer.cpp
index e2803a2258..0d6cd737b6 100644
--- a/libraries/ktx/src/ktx/Writer.cpp
+++ b/libraries/ktx/src/ktx/Writer.cpp
@@ -235,4 +235,11 @@ namespace ktx {
         return destImages;
     }
 
+    void KTX::writeMipData(uint16_t level, const Byte* sourceBytes, size_t sourceSize) {
+        Q_ASSERT(level > 0);
+        Q_ASSERT(level < _images.size());
+        Q_ASSERT(sourceSize == _images[level]._imageSize);
+
+        //memcpy(reinterpret_cast<void*>(_images[level]._faceBytes[0]), sourceBytes, sourceSize);
+    }
 }
diff --git a/libraries/model-networking/src/model-networking/TextureCache.cpp b/libraries/model-networking/src/model-networking/TextureCache.cpp
index f4fe192a4a..706c62c8a1 100644
--- a/libraries/model-networking/src/model-networking/TextureCache.cpp
+++ b/libraries/model-networking/src/model-networking/TextureCache.cpp
@@ -545,7 +545,6 @@ void NetworkTexture::loadContent(const QByteArray& content) {
                 texture = textureCache->cacheTextureByHash(filename, texture);
             }
 
-            setImage(texture, header->getPixelWidth(), header->getPixelHeight());
 
 
             auto desc = memKtx->toDescriptor();
@@ -559,10 +558,24 @@ void NetworkTexture::loadContent(const QByteArray& content) {
             }
             _requestByteRange.fromInclusive = length - sizeOfTopMips;
             _requestByteRange.toExclusive = length;
-            attemptRequest();
+            QMetaObject::invokeMethod(this, "attemptRequest", Qt::QueuedConnection);
+
+
+            //texture->setMinMip(desc.images.size() - 1);
+            setImage(texture, header->getPixelWidth(), header->getPixelHeight());
 
         } else {
             qDebug() << "Got highest 6 mips";
+
+            ktx::StoragePointer storage { new storage::FileStorage(QString::fromStdString(_file->getFilepath())) };
+            auto data = storage->mutableData();
+            auto size = storage->getSize();
+            //*data = 'H';
+            memcpy(data + _requestByteRange.fromInclusive, content.data(), content.size());
+            //getGPUTexture()->setMinMip(getGPUTexture()->getMinMip() - 6);
+            //auto ktxPointer = ktx::KTX::create(storage);
+
+            //ktxPointer->writeMipData(level, data, size);
         }
         return;
     }
diff --git a/libraries/networking/src/HTTPResourceRequest.cpp b/libraries/networking/src/HTTPResourceRequest.cpp
index 1bb292a3ef..499708b12d 100644
--- a/libraries/networking/src/HTTPResourceRequest.cpp
+++ b/libraries/networking/src/HTTPResourceRequest.cpp
@@ -22,6 +22,7 @@
 #include "NetworkLogging.h"
 
 HTTPResourceRequest::~HTTPResourceRequest() {
+    qDebug() << "Cleaning up:" << _url << " " << _byteRange.fromInclusive << "-" << _byteRange.toExclusive;
     if (_reply) {
         _reply->disconnect(this);
         _reply->deleteLater();
@@ -76,9 +77,12 @@ void HTTPResourceRequest::doSend() {
     connect(_reply, &QNetworkReply::downloadProgress, this, &HTTPResourceRequest::onDownloadProgress);
 
     setupTimer();
+    qDebug() << "Sent: " << _url;
 }
 
 void HTTPResourceRequest::onRequestFinished() {
+    qDebug() << "On request finished: " << _url;
+
     Q_ASSERT(_state == InProgress);
     Q_ASSERT(_reply);
 
@@ -181,6 +185,7 @@ void HTTPResourceRequest::onRequestFinished() {
 }
 
 void HTTPResourceRequest::onDownloadProgress(qint64 bytesReceived, qint64 bytesTotal) {
+    qDebug() << "Progress: " << _url;
     Q_ASSERT(_state == InProgress);
     
     // We've received data, so reset the timer
@@ -190,6 +195,7 @@ void HTTPResourceRequest::onDownloadProgress(qint64 bytesReceived, qint64 bytesT
 }
 
 void HTTPResourceRequest::onTimeout() {
+    qDebug() << "Timeout: " << _url << ":" << _reply->isFinished();
     Q_ASSERT(_state == InProgress);
     _reply->disconnect(this);
     _reply->abort();
diff --git a/libraries/networking/src/ResourceCache.cpp b/libraries/networking/src/ResourceCache.cpp
index 62ea85bc86..038ee7fb53 100644
--- a/libraries/networking/src/ResourceCache.cpp
+++ b/libraries/networking/src/ResourceCache.cpp
@@ -698,6 +698,7 @@ void Resource::handleDownloadProgress(uint64_t bytesReceived, uint64_t bytesTota
 }
 
 void Resource::handleReplyFinished() {
+    qDebug() << "Got response for " << _activeUrl;
     Q_ASSERT_X(_request, "Resource::handleReplyFinished", "Request should not be null while in handleReplyFinished");
 
     PROFILE_ASYNC_END(resource, "Resource:" + getType(), QString::number(_requestID), {
diff --git a/libraries/shared/src/shared/Storage.cpp b/libraries/shared/src/shared/Storage.cpp
index 8999caf1e8..0f2b696a66 100644
--- a/libraries/shared/src/shared/Storage.cpp
+++ b/libraries/shared/src/shared/Storage.cpp
@@ -69,7 +69,8 @@ StoragePointer FileStorage::create(const QString& filename, size_t size, const u
 
 // Represents a memory mapped file
 FileStorage::FileStorage(const QString& filename) : _file(filename) {
-    if (_file.open(QFile::ReadOnly)) {
+    if (_file.open(QFile::ReadWrite)) {
+        qDebug() << ">>> Opening mmapped file: " << filename;
         _mapped = _file.map(0, _file.size());
         if (_mapped) {
             _valid = true;
@@ -82,6 +83,7 @@ FileStorage::FileStorage(const QString& filename) : _file(filename) {
 }
 
 FileStorage::~FileStorage() {
+    qDebug() << ">>> Closing mmapped file: " << _file.fileName();
     if (_mapped) {
         if (!_file.unmap(_mapped)) {
             throw std::runtime_error("Unable to unmap file");
diff --git a/libraries/shared/src/shared/Storage.h b/libraries/shared/src/shared/Storage.h
index 46f45cfdc5..3983387c15 100644
--- a/libraries/shared/src/shared/Storage.h
+++ b/libraries/shared/src/shared/Storage.h
@@ -25,6 +25,7 @@ namespace storage {
     public:
         virtual ~Storage() {}
         virtual const uint8_t* data() const = 0;
+        virtual uint8_t* mutableData() = 0;
         virtual size_t size() const = 0;
         virtual operator bool() const { return true; }
 
@@ -42,6 +43,7 @@ namespace storage {
         MemoryStorage(size_t size, const uint8_t* data = nullptr);
         const uint8_t* data() const override { return _data.data(); }
         uint8_t* data() { return _data.data(); }
+        uint8_t* mutableData() override { return 0; }
         size_t size() const override { return _data.size(); }
         operator bool() const override { return true; }
     private:
@@ -58,6 +60,7 @@ namespace storage {
         FileStorage& operator=(const FileStorage& other) = delete;
 
         const uint8_t* data() const override { return _mapped; }
+        uint8_t* mutableData() override { return _mapped; }
         size_t size() const override { return _file.size(); }
         operator bool() const override { return _valid; }
     private:
@@ -70,6 +73,7 @@ namespace storage {
     public:
         ViewStorage(const storage::StoragePointer& owner, size_t size, const uint8_t* data);
         const uint8_t* data() const override { return _data; }
+        uint8_t* mutableData() override { return 0; }
         size_t size() const override { return _size; }
         operator bool() const override { return *_owner; }
     private: