From 27e8750b9bf3b5b8039fb3700c50c285891173e1 Mon Sep 17 00:00:00 2001
From: Brad Davis <bdavis@saintandreas.org>
Date: Fri, 17 Feb 2017 17:17:56 -0800
Subject: [PATCH] Adding new storage backing for gpu::Texture, moving mip
 format into Storage abstraction

---
 .../display-plugins/OpenGLDisplayPlugin.cpp   |   3 +-
 .../display-plugins/hmd/HmdDisplayPlugin.cpp  |   3 +-
 .../src/gpu/gl41/GL41BackendTexture.cpp       |   3 +-
 .../src/gpu/gl45/GL45BackendTexture.cpp       |   2 +-
 .../gpu/gl45/GL45BackendVariableTexture.cpp   |   2 +-
 libraries/gpu/src/gpu/Texture.cpp             | 119 ++++++++----------
 libraries/gpu/src/gpu/Texture.h               | 100 +++++++++------
 libraries/gpu/src/gpu/Texture_ktx.cpp         |   3 +-
 .../src/model-networking/TextureCache.cpp     |  15 ++-
 libraries/model/src/model/TextureMap.cpp      |  48 +++----
 libraries/render-utils/src/text/Font.cpp      |   3 +-
 libraries/shared/src/shared/Storage.cpp       |   9 +-
 libraries/shared/src/shared/Storage.h         |  20 +--
 tests/render-perf/CMakeLists.txt              |   2 +-
 14 files changed, 178 insertions(+), 154 deletions(-)

diff --git a/libraries/display-plugins/src/display-plugins/OpenGLDisplayPlugin.cpp b/libraries/display-plugins/src/display-plugins/OpenGLDisplayPlugin.cpp
index 1bfe4f3dcc..dca5ac4b77 100644
--- a/libraries/display-plugins/src/display-plugins/OpenGLDisplayPlugin.cpp
+++ b/libraries/display-plugins/src/display-plugins/OpenGLDisplayPlugin.cpp
@@ -362,7 +362,8 @@ void OpenGLDisplayPlugin::customizeContext() {
                 cursorData.texture->setSource("cursor texture");
                 auto usage = gpu::Texture::Usage::Builder().withColor().withAlpha();
                 cursorData.texture->setUsage(usage.build());
-                cursorData.texture->assignStoredMip(0, gpu::Element(gpu::VEC4, gpu::NUINT8, gpu::RGBA), image.byteCount(), image.constBits());
+                cursorData.texture->setStoredMipFormat(gpu::Element(gpu::VEC4, gpu::NUINT8, gpu::RGBA));
+                cursorData.texture->assignStoredMip(0, image.byteCount(), image.constBits());
                 cursorData.texture->autoGenerateMips(-1);
             }
         }
diff --git a/libraries/display-plugins/src/display-plugins/hmd/HmdDisplayPlugin.cpp b/libraries/display-plugins/src/display-plugins/hmd/HmdDisplayPlugin.cpp
index 24f4e429ef..c55d985a62 100644
--- a/libraries/display-plugins/src/display-plugins/hmd/HmdDisplayPlugin.cpp
+++ b/libraries/display-plugins/src/display-plugins/hmd/HmdDisplayPlugin.cpp
@@ -302,7 +302,8 @@ void HmdDisplayPlugin::internalPresent() {
                 gpu::Sampler(gpu::Sampler::FILTER_MIN_MAG_MIP_LINEAR)));
             _previewTexture->setSource("HMD Preview Texture");
             _previewTexture->setUsage(gpu::Texture::Usage::Builder().withColor().build());
-            _previewTexture->assignStoredMip(0, gpu::Element(gpu::VEC4, gpu::NUINT8, gpu::RGBA), image.byteCount(), image.constBits());
+            _previewTexture->setStoredMipFormat(gpu::Element(gpu::VEC4, gpu::NUINT8, gpu::RGBA));
+            _previewTexture->assignStoredMip(0, image.byteCount(), image.constBits());
             _previewTexture->autoGenerateMips(-1);
         }
         
diff --git a/libraries/gpu-gl/src/gpu/gl41/GL41BackendTexture.cpp b/libraries/gpu-gl/src/gpu/gl41/GL41BackendTexture.cpp
index efbc6903b1..80649c4d64 100644
--- a/libraries/gpu-gl/src/gpu/gl41/GL41BackendTexture.cpp
+++ b/libraries/gpu-gl/src/gpu/gl41/GL41BackendTexture.cpp
@@ -71,7 +71,7 @@ GL41Texture::GL41Texture(const std::weak_ptr<GLBackend>& backend, const Texture&
     : GLTexture(backend, texture, allocate()), _storageStamp { texture.getStamp() }, _size(texture.evalTotalSize()) {
     incrementTextureGPUCount();
     withPreservedTexture([&] {
-        GLTexelFormat texelFormat = GLTexelFormat::evalGLTexelFormat(_gpuObject.getTexelFormat());
+        GLTexelFormat texelFormat = GLTexelFormat::evalGLTexelFormat(_gpuObject.getTexelFormat(), _gpuObject.getStoredMipFormat());
         const Sampler& sampler = _gpuObject.getSampler();
         auto numMips = _gpuObject.evalNumMips();
         for (uint16_t mipLevel = 0; mipLevel < numMips; ++mipLevel) {
@@ -83,7 +83,6 @@ GL41Texture::GL41Texture(const std::weak_ptr<GLBackend>& backend, const Texture&
                 if (_gpuObject.isStoredMipFaceAvailable(mipLevel, face)) {
                     auto mip = _gpuObject.accessStoredMipFace(mipLevel, face);
                     mipData = mip->readData();
-                    texelFormat = GLTexelFormat::evalGLTexelFormat(_gpuObject.getTexelFormat(), mip->getFormat());
                 }
                 glTexImage2D(target, mipLevel, texelFormat.internalFormat, dimensions.x, dimensions.y, 0, texelFormat.format, texelFormat.type, mipData);
                 (void)CHECK_GL_ERROR();
diff --git a/libraries/gpu-gl/src/gpu/gl45/GL45BackendTexture.cpp b/libraries/gpu-gl/src/gpu/gl45/GL45BackendTexture.cpp
index 6dd1d6aea3..95837c16d9 100644
--- a/libraries/gpu-gl/src/gpu/gl45/GL45BackendTexture.cpp
+++ b/libraries/gpu-gl/src/gpu/gl45/GL45BackendTexture.cpp
@@ -142,7 +142,7 @@ void GL45Texture::copyMipFaceFromTexture(uint16_t sourceMip, uint16_t targetMip,
     }
     auto size = _gpuObject.evalMipDimensions(sourceMip);
     auto mipData = _gpuObject.accessStoredMipFace(sourceMip, face);
-    GLTexelFormat texelFormat = GLTexelFormat::evalGLTexelFormat(_gpuObject.getTexelFormat(), mipData->getFormat());
+    GLTexelFormat texelFormat = GLTexelFormat::evalGLTexelFormat(_gpuObject.getTexelFormat(), _gpuObject.getStoredMipFormat());
     copyMipFaceLinesFromTexture(targetMip, face, size, 0, texelFormat.format, texelFormat.type, mipData->readData());
 }
 
diff --git a/libraries/gpu-gl/src/gpu/gl45/GL45BackendVariableTexture.cpp b/libraries/gpu-gl/src/gpu/gl45/GL45BackendVariableTexture.cpp
index 8c93ed6a65..0e2053ad06 100644
--- a/libraries/gpu-gl/src/gpu/gl45/GL45BackendVariableTexture.cpp
+++ b/libraries/gpu-gl/src/gpu/gl45/GL45BackendVariableTexture.cpp
@@ -84,7 +84,7 @@ TransferJob::TransferJob(const GL45VariableAllocationTexture& parent, uint16_t s
     GLenum format;
     GLenum type;
     auto mipData = _parent._gpuObject.accessStoredMipFace(sourceMip, face);
-    GLTexelFormat texelFormat = GLTexelFormat::evalGLTexelFormat(_parent._gpuObject.getTexelFormat(), mipData->getFormat());
+    GLTexelFormat texelFormat = GLTexelFormat::evalGLTexelFormat(_parent._gpuObject.getTexelFormat(), _parent._gpuObject.getStoredMipFormat());
     format = texelFormat.format;
     type = texelFormat.type;
 
diff --git a/libraries/gpu/src/gpu/Texture.cpp b/libraries/gpu/src/gpu/Texture.cpp
index 281d768182..6afab476de 100755
--- a/libraries/gpu/src/gpu/Texture.cpp
+++ b/libraries/gpu/src/gpu/Texture.cpp
@@ -120,18 +120,6 @@ void Texture::setAllowedGPUMemoryUsage(Size size) {
 
 uint8 Texture::NUM_FACES_PER_TYPE[NUM_TYPES] = { 1, 1, 1, 6 };
 
-Texture::Pixels::Pixels(const Element& format, Size size, const Byte* bytes) :
-    _format(format),
-    _storage(new storage::MemoryStorage(size, bytes)) {
-    Texture::updateTextureCPUMemoryUsage(0, _storage->size());
-}
-
-Texture::Pixels::~Pixels() {
-    if (_storage) {
-        Texture::updateTextureCPUMemoryUsage(_storage->size(), 0);
-    }
-}
-
 void Texture::Storage::assignTexture(Texture* texture) {
     _texture = texture;
     if (_texture) {
@@ -139,21 +127,12 @@ void Texture::Storage::assignTexture(Texture* texture) {
     }
 }
 
-void Texture::Storage::reset() {
+void Texture::MemoryStorage::reset() {
     _mips.clear();
     bumpStamp();
 }
 
-Texture::PixelsPointer Texture::Storage::editMipFace(uint16 level, uint8 face) {
-    if (level < _mips.size()) {
-        assert(face < _mips[level].size());
-        bumpStamp();
-        return _mips[level][face];
-    }
-    return PixelsPointer();
-}
-
-const Texture::PixelsPointer Texture::Storage::getMipFace(uint16 level, uint8 face) const {
+const Texture::PixelsPointer Texture::MemoryStorage::getMipFace(uint16 level, uint8 face) const {
     if (level < _mips.size()) {
         assert(face < _mips[level].size());
         return _mips[level][face];
@@ -161,12 +140,12 @@ const Texture::PixelsPointer Texture::Storage::getMipFace(uint16 level, uint8 fa
     return PixelsPointer();
 }
 
-bool Texture::Storage::isMipAvailable(uint16 level, uint8 face) const {
+bool Texture::MemoryStorage::isMipAvailable(uint16 level, uint8 face) const {
     PixelsPointer mipFace = getMipFace(level, face);
     return (mipFace && mipFace->getSize());
 }
 
-bool Texture::Storage::allocateMip(uint16 level) {
+bool Texture::MemoryStorage::allocateMip(uint16 level) {
     bool changed = false;
     if (level >= _mips.size()) {
         _mips.resize(level+1, std::vector<PixelsPointer>(Texture::NUM_FACES_PER_TYPE[getType()]));
@@ -176,7 +155,6 @@ bool Texture::Storage::allocateMip(uint16 level) {
     auto& mip = _mips[level];
     for (auto& face : mip) {
         if (!face) {
-            face = std::make_shared<Pixels>();
             changed = true;
         }
     }
@@ -186,7 +164,7 @@ bool Texture::Storage::allocateMip(uint16 level) {
     return changed;
 }
 
-bool Texture::Storage::assignMipData(uint16 level, const Element& format, Size size, const Byte* bytes) {
+void Texture::MemoryStorage::assignMipData(uint16 level, const storage::StoragePointer& storagePointer) {
 
     allocateMip(level);
     auto& mip = _mips[level];
@@ -195,33 +173,24 @@ bool Texture::Storage::assignMipData(uint16 level, const Element& format, Size s
     // The bytes assigned here are supposed to contain all the faces bytes of the mip.
     // For tex1D, 2D, 3D there is only one face
     // For Cube, we expect the 6 faces in the order X+, X-, Y+, Y-, Z+, Z-
-    auto sizePerFace = size / mip.size();
-    auto faceBytes = bytes;
-    Size allocated = 0;
+    auto sizePerFace = storagePointer->size() / mip.size();
+    size_t offset = 0;
     for (auto& face : mip) {
-        face.reset(new Pixels(format, size, bytes));
-        allocated += size;
-        faceBytes += sizePerFace;
+        face = storagePointer->createView(sizePerFace, offset);
+        offset += sizePerFace;
     }
 
     bumpStamp();
-
-    return allocated == size;
 }
 
 
-bool Texture::Storage::assignMipFaceData(uint16 level, const Element& format, Size size, const Byte* bytes, uint8 face) {
-
+void Texture::MemoryStorage::assignMipFaceData(uint16 level, uint8 face, const storage::StoragePointer& storagePointer) {
     allocateMip(level);
     auto& mip = _mips[level];
-    Size allocated = 0;
     if (face < mip.size()) { 
-        mip[face].reset(new Pixels(format, size, bytes));
-        allocated += size;
+        mip[face] = storagePointer;
         bumpStamp();
     }
-
-    return allocated == size;
 }
 
 Texture* Texture::createExternal(const ExternalRecycler& recycler, const Sampler& sampler) {
@@ -260,7 +229,7 @@ Texture* Texture::createCube(const Element& texelFormat, uint16 width, const Sam
 Texture* Texture::create(TextureUsageType usageType, Type type, const Element& texelFormat, uint16 width, uint16 height, uint16 depth, uint16 numSamples, uint16 numSlices, const Sampler& sampler)
 {
     Texture* tex = new Texture(usageType);
-    tex->_storage.reset(new Storage());
+    tex->_storage.reset(new MemoryStorage());
     tex->_type = type;
     tex->_storage->assignTexture(tex);
     tex->_maxMip = 0;
@@ -402,69 +371,83 @@ uint16 Texture::evalNumMips() const {
     return evalNumMips({ _width, _height, _depth });
 }
 
-bool Texture::assignStoredMip(uint16 level, const Element& format, Size size, const Byte* bytes) {
+void Texture::setStoredMipFormat(const Element& format) {
+    _storage->setFormat(format);
+}
+
+const Element& Texture::getStoredMipFormat() const {
+    return _storage->getFormat();
+}
+
+void Texture::assignStoredMip(uint16 level, Size size, const Byte* bytes) {
+    storage::StoragePointer storage { new storage::MemoryStorage(size, bytes) };
+    assignStoredMip(level, storage);
+}
+
+void Texture::assignStoredMipFace(uint16 level, uint8 face, Size size, const Byte* bytes) {
+    storage::StoragePointer storage { new storage::MemoryStorage(size, bytes) };
+    assignStoredMipFace(level, face, storage);
+}
+
+void Texture::assignStoredMip(uint16 level, storage::StoragePointer& storage) {
     // Check that level accessed make sense
     if (level != 0) {
         if (_autoGenerateMips) {
-            return false;
+            return;
         }
         if (level >= evalNumMips()) {
-            return false;
+            return;
         }
     }
 
     // THen check that the mem texture passed make sense with its format
-    Size expectedSize = evalStoredMipSize(level, format);
-    if (size == expectedSize) {
-        _storage->assignMipData(level, format, size, bytes);
+    Size expectedSize = evalStoredMipSize(level, getStoredMipFormat());
+    auto size = storage->size();
+    auto bytes = storage->data();
+    if (storage->size() == expectedSize) {
+        _storage->assignMipData(level, storage);
         _maxMip = std::max(_maxMip, level);
         _stamp++;
-        return true;
     } else if (size > expectedSize) {
         // NOTE: We are facing this case sometime because apparently QImage (from where we get the bits) is generating images
         // and alligning the line of pixels to 32 bits.
         // We should probably consider something a bit more smart to get the correct result but for now (UI elements)
         // it seems to work...
-        _storage->assignMipData(level, format, size, bytes);
+        _storage->assignMipData(level, storage);
         _maxMip = std::max(_maxMip, level);
         _stamp++;
-        return true;
     }
-
-    return false;
 }
 
-
-bool Texture::assignStoredMipFace(uint16 level, const Element& format, Size size, const Byte* bytes, uint8 face) {
+void Texture::assignStoredMipFace(uint16 level, uint8 face, storage::StoragePointer& storage) {
     // Check that level accessed make sense
     if (level != 0) {
         if (_autoGenerateMips) {
-            return false;
+            return;
         }
         if (level >= evalNumMips()) {
-            return false;
+            return;
         }
     }
 
     // THen check that the mem texture passed make sense with its format
-    Size expectedSize = evalStoredMipFaceSize(level, format);
+    Size expectedSize = evalStoredMipFaceSize(level, getStoredMipFormat());
+    auto size = storage->size();
+    auto bytes = storage->data();
     if (size == expectedSize) {
-        _storage->assignMipFaceData(level, format, size, bytes, face);
+        _storage->assignMipFaceData(level, face, storage);
         _stamp++;
-        return true;
     } else if (size > expectedSize) {
         // NOTE: We are facing this case sometime because apparently QImage (from where we get the bits) is generating images
         // and alligning the line of pixels to 32 bits.
         // We should probably consider something a bit more smart to get the correct result but for now (UI elements)
         // it seems to work...
-        _storage->assignMipFaceData(level, format, size, bytes, face);
+        _storage->assignMipFaceData(level, face, storage);
         _stamp++;
-        return true;
     }
-
-    return false;
 }
 
+
 uint16 Texture::autoGenerateMips(uint16 maxMip) {
     bool changed = false;
     if (!_autoGenerateMips) {
@@ -498,7 +481,7 @@ uint16 Texture::getStoredMipHeight(uint16 level) const {
     if (mip && mip->getSize()) {
         return evalMipHeight(level);
     }
-        return 0;
+    return 0;
 }
 
 uint16 Texture::getStoredMipDepth(uint16 level) const {
@@ -770,8 +753,8 @@ bool sphericalHarmonicsFromTexture(const gpu::Texture& cubeTexture, std::vector<
     for(int face=0; face < gpu::Texture::NUM_CUBE_FACES; face++) {
         PROFILE_RANGE(render_gpu, "ProcessFace");
 
-        auto numComponents = cubeTexture.accessStoredMipFace(0,face)->getFormat().getScalarCount();
-        auto data = cubeTexture.accessStoredMipFace(0,face)->readData();
+        auto numComponents = cubeTexture.getStoredMipFormat().getScalarCount();
+        auto data = cubeTexture.accessStoredMipFace(0,face)->data();
         if (data == nullptr) {
             continue;
         }
diff --git a/libraries/gpu/src/gpu/Texture.h b/libraries/gpu/src/gpu/Texture.h
index 0a5afe78c3..84241442c5 100755
--- a/libraries/gpu/src/gpu/Texture.h
+++ b/libraries/gpu/src/gpu/Texture.h
@@ -226,30 +226,7 @@ public:
         bool operator!=(const Usage& usage) { return (_flags != usage._flags); }
     };
 
-
-    class Pixels {
-    public:
-        using StoragePointer = storage::StoragePointer;
-
-        Pixels() {}
-        Pixels(const Pixels& pixels) = default;
-        Pixels(const Element& format, Size size, const Byte* bytes);
-        Pixels(const Element& format, StoragePointer& storage) : _format(format), _storage(storage.release()) {}
-        ~Pixels();
-
-        const Byte* readData() const { return _storage->data(); }
-        Size getSize() const { return _storage->size(); }
-        
-        const Element& getFormat() const { return _format; }
-
-
-    protected:
-        Element _format;
-        StoragePointer _storage;
-        
-        friend class Texture;
-    };
-    typedef std::shared_ptr< Pixels > PixelsPointer;
+    using PixelsPointer = storage::StoragePointer;
 
     enum Type {
         TEX_1D = 0,
@@ -272,35 +249,68 @@ public:
         NUM_CUBE_FACES, // Not a valid vace index
     };
 
+
     class Storage {
     public:
         Storage() {}
         virtual ~Storage() {}
-        virtual void reset();
-        virtual PixelsPointer editMipFace(uint16 level, uint8 face = 0);
-        virtual const PixelsPointer getMipFace(uint16 level, uint8 face = 0) const;
-        virtual bool allocateMip(uint16 level);
-        virtual bool assignMipData(uint16 level, const Element& format, Size size, const Byte* bytes);
-        virtual bool assignMipFaceData(uint16 level, const Element& format, Size size, const Byte* bytes, uint8 face);
-        virtual bool isMipAvailable(uint16 level, uint8 face = 0) const;
 
+        virtual void reset() = 0;
+        virtual const PixelsPointer getMipFace(uint16 level, uint8 face = 0) const = 0;
+        virtual void assignMipData(uint16 level, const storage::StoragePointer& storage) = 0;
+        virtual void assignMipFaceData(uint16 level, uint8 face, const storage::StoragePointer& storage) = 0;
+        virtual bool isMipAvailable(uint16 level, uint8 face = 0) const = 0;
         Texture::Type getType() const { return _type; }
-        
+
         Stamp getStamp() const { return _stamp; }
         Stamp bumpStamp() { return ++_stamp; }
-    protected:
-        Stamp _stamp = 0;
-        Texture* _texture = nullptr; // Points to the parent texture (not owned)
-        Texture::Type _type = Texture::TEX_2D; // The type of texture is needed to know the number of faces to expect
-        std::vector<std::vector<PixelsPointer>> _mips; // an array of mips, each mip is an array of faces
 
+        void setFormat(const Element& format) { _format = format; }
+        const Element& getFormat() const { return _format; }
+
+    private:
+        Stamp _stamp { 0 };
+        Element _format;
+        Texture::Type _type { Texture::TEX_2D }; // The type of texture is needed to know the number of faces to expect
+        Texture* _texture { nullptr }; // Points to the parent texture (not owned)
         virtual void assignTexture(Texture* tex); // Texture storage is pointing to ONE corrresponding Texture.
         const Texture* getTexture() const { return _texture; }
- 
         friend class Texture;
     };
 
- 
+    class MemoryStorage : public Storage {
+    public:
+        void reset() override;
+        const PixelsPointer getMipFace(uint16 level, uint8 face = 0) const override;
+        void assignMipData(uint16 level, const storage::StoragePointer& storage) override;
+        void assignMipFaceData(uint16 level, uint8 face, const storage::StoragePointer& storage) override;
+        bool isMipAvailable(uint16 level, uint8 face = 0) const override;
+
+    protected:
+        bool allocateMip(uint16 level);
+        std::vector<std::vector<PixelsPointer>> _mips; // an array of mips, each mip is an array of faces
+    };
+
+    class KtxStorage : public Storage {
+    public:
+        KtxStorage(ktx::KTXUniquePointer& ktxData);
+        const PixelsPointer getMipFace(uint16 level, uint8 face = 0) const override;
+        bool isMipAvailable(uint16 level, uint8 face = 0) const override;
+
+        void assignMipData(uint16 level, const storage::StoragePointer& storage) override {
+            throw std::runtime_error("Invalid call");
+        }
+
+        void assignMipFaceData(uint16 level, uint8 face, const storage::StoragePointer& storage) override {
+            throw std::runtime_error("Invalid call");
+        }
+        void reset() override { }
+
+    protected:
+        ktx::KTXUniquePointer _ktxData;
+        friend class Texture;
+    };
+
     static Texture* create1D(const Element& texelFormat, uint16 width, const Sampler& sampler = Sampler());
     static Texture* create2D(const Element& texelFormat, uint16 width, uint16 height, const Sampler& sampler = Sampler());
     static Texture* create3D(const Element& texelFormat, uint16 width, uint16 height, uint16 depth, const Sampler& sampler = Sampler());
@@ -444,13 +454,21 @@ public:
 
     // Managing Storage and mips
 
+    // Mip storage format is constant across all mips
+    void setStoredMipFormat(const Element& format);
+    const Element& getStoredMipFormat() const;
+
     // Manually allocate the mips down until the specified maxMip
     // this is just allocating the sysmem version of it
     // in case autoGen is on, this doesn't allocate
     // Explicitely assign mip data for a certain level
     // If Bytes is NULL then simply allocate the space so mip sysmem can be accessed
-    bool assignStoredMip(uint16 level, const Element& format, Size size, const Byte* bytes);
-    bool assignStoredMipFace(uint16 level, const Element& format, Size size, const Byte* bytes, uint8 face);
+
+    void assignStoredMip(uint16 level, Size size, const Byte* bytes);
+    void assignStoredMipFace(uint16 level, uint8 face, Size size, const Byte* bytes);
+
+    void assignStoredMip(uint16 level, storage::StoragePointer& storage);
+    void assignStoredMipFace(uint16 level, uint8 face, storage::StoragePointer& storage);
 
     // Access the the sub mips
     bool isStoredMipFaceAvailable(uint16 level, uint8 face = 0) const { return _storage->isMipAvailable(level, face); }
diff --git a/libraries/gpu/src/gpu/Texture_ktx.cpp b/libraries/gpu/src/gpu/Texture_ktx.cpp
index 404aca77a4..13d4c2a464 100644
--- a/libraries/gpu/src/gpu/Texture_ktx.cpp
+++ b/libraries/gpu/src/gpu/Texture_ktx.cpp
@@ -116,9 +116,10 @@ Texture* Texture::unserialize(TextureUsageType usageType, const ktx::KTXUniquePo
                                 Sampler());
 
     // Assing the mips availables
+    tex->setStoredMipFormat(mipFormat);
     uint16_t level = 0;
     for (auto& image : srcData->_images) {
-        tex->assignStoredMip(level, mipFormat, image._imageSize, image._bytes);
+        tex->assignStoredMip(level, image._imageSize, image._bytes);
         level++;
     }
 
diff --git a/libraries/model-networking/src/model-networking/TextureCache.cpp b/libraries/model-networking/src/model-networking/TextureCache.cpp
index 6a84fc960f..1f21e9e78d 100644
--- a/libraries/model-networking/src/model-networking/TextureCache.cpp
+++ b/libraries/model-networking/src/model-networking/TextureCache.cpp
@@ -108,7 +108,8 @@ const gpu::TexturePointer& TextureCache::getPermutationNormalTexture() {
         }
 
         _permutationNormalTexture = gpu::TexturePointer(gpu::Texture::create2D(gpu::Element(gpu::VEC3, gpu::NUINT8, gpu::RGB), 256, 2));
-        _permutationNormalTexture->assignStoredMip(0, _blueTexture->getTexelFormat(), sizeof(data), data);
+        _permutationNormalTexture->setStoredMipFormat(_permutationNormalTexture->getTexelFormat());
+        _permutationNormalTexture->assignStoredMip(0, sizeof(data), data);
     }
     return _permutationNormalTexture;
 }
@@ -122,7 +123,8 @@ const gpu::TexturePointer& TextureCache::getWhiteTexture() {
     if (!_whiteTexture) {
         _whiteTexture = gpu::TexturePointer(gpu::Texture::createStrict(gpu::Element::COLOR_RGBA_32, 1, 1));
         _whiteTexture->setSource("TextureCache::_whiteTexture");
-        _whiteTexture->assignStoredMip(0, _whiteTexture->getTexelFormat(), sizeof(OPAQUE_WHITE), OPAQUE_WHITE);
+        _whiteTexture->setStoredMipFormat(_whiteTexture->getTexelFormat());
+        _whiteTexture->assignStoredMip(0, sizeof(OPAQUE_WHITE), OPAQUE_WHITE);
     }
     return _whiteTexture;
 }
@@ -131,7 +133,8 @@ const gpu::TexturePointer& TextureCache::getGrayTexture() {
     if (!_grayTexture) {
         _grayTexture = gpu::TexturePointer(gpu::Texture::createStrict(gpu::Element::COLOR_RGBA_32, 1, 1));
         _grayTexture->setSource("TextureCache::_grayTexture");
-        _grayTexture->assignStoredMip(0, _grayTexture->getTexelFormat(), sizeof(OPAQUE_GRAY), OPAQUE_GRAY);
+        _grayTexture->setStoredMipFormat(_grayTexture->getTexelFormat());
+        _grayTexture->assignStoredMip(0, sizeof(OPAQUE_GRAY), OPAQUE_GRAY);
     }
     return _grayTexture;
 }
@@ -140,7 +143,8 @@ const gpu::TexturePointer& TextureCache::getBlueTexture() {
     if (!_blueTexture) {
         _blueTexture = gpu::TexturePointer(gpu::Texture::createStrict(gpu::Element::COLOR_RGBA_32, 1, 1));
         _blueTexture->setSource("TextureCache::_blueTexture");
-        _blueTexture->assignStoredMip(0, _blueTexture->getTexelFormat(), sizeof(OPAQUE_BLUE), OPAQUE_BLUE);
+        _blueTexture->setStoredMipFormat(_blueTexture->getTexelFormat());
+        _blueTexture->assignStoredMip(0, sizeof(OPAQUE_BLUE), OPAQUE_BLUE);
     }
     return _blueTexture;
 }
@@ -149,7 +153,8 @@ const gpu::TexturePointer& TextureCache::getBlackTexture() {
     if (!_blackTexture) {
         _blackTexture = gpu::TexturePointer(gpu::Texture::createStrict(gpu::Element::COLOR_RGBA_32, 1, 1));
         _blackTexture->setSource("TextureCache::_blackTexture");
-        _blackTexture->assignStoredMip(0, _blackTexture->getTexelFormat(), sizeof(OPAQUE_BLACK), OPAQUE_BLACK);
+        _blackTexture->setStoredMipFormat(_blackTexture->getTexelFormat());
+        _blackTexture->assignStoredMip(0, sizeof(OPAQUE_BLACK), OPAQUE_BLACK);
     }
     return _blackTexture;
 }
diff --git a/libraries/model/src/model/TextureMap.cpp b/libraries/model/src/model/TextureMap.cpp
index 3f10f66256..0a1eb705eb 100755
--- a/libraries/model/src/model/TextureMap.cpp
+++ b/libraries/model/src/model/TextureMap.cpp
@@ -96,7 +96,7 @@ gpu::Texture* cacheTexture(const std::string& name, gpu::Texture* srcTexture, bo
         // Prepare cache directory
         QString path("hifi_ktx/");
         QFileInfo originalFileInfo(path);
-        QString docsLocation = QStandardPaths::writableLocation(QStandardPaths::DocumentsLocation);
+        QString docsLocation = QStandardPaths::writableLocation(QStandardPaths::AppDataLocation);
         path = docsLocation + "/" + path;
         QFileInfo info(path);
         if (!info.absoluteDir().exists()) {
@@ -262,7 +262,7 @@ const QImage& image, bool isLinear, bool doCompress) {
 
 #define CPU_MIPMAPS 1
 
-void generateMips(gpu::Texture* texture, QImage& image, gpu::Element formatMip, bool fastResize) {
+void generateMips(gpu::Texture* texture, QImage& image, bool fastResize) {
 #if CPU_MIPMAPS
     PROFILE_RANGE(resource_parse, "generateMips");
     auto numMips = texture->evalNumMips();
@@ -270,10 +270,10 @@ void generateMips(gpu::Texture* texture, QImage& image, gpu::Element formatMip,
         QSize mipSize(texture->evalMipWidth(level), texture->evalMipHeight(level));
         if (fastResize) {
             image = image.scaled(mipSize);
-            texture->assignStoredMip(level, formatMip, image.byteCount(), image.constBits());
+            texture->assignStoredMip(level, image.byteCount(), image.constBits());
         } else {
             QImage mipImage = image.scaled(mipSize, Qt::IgnoreAspectRatio, Qt::SmoothTransformation);
-            texture->assignStoredMip(level, formatMip, mipImage.byteCount(), mipImage.constBits());
+            texture->assignStoredMip(level, mipImage.byteCount(), mipImage.constBits());
         }
     }
 #else
@@ -281,14 +281,14 @@ void generateMips(gpu::Texture* texture, QImage& image, gpu::Element formatMip,
 #endif
 }
 
-void generateFaceMips(gpu::Texture* texture, QImage& image, gpu::Element formatMip, uint8 face) {
+void generateFaceMips(gpu::Texture* texture, QImage& image, uint8 face) {
 #if CPU_MIPMAPS
     PROFILE_RANGE(resource_parse, "generateFaceMips");
     auto numMips = texture->evalNumMips();
     for (uint16 level = 1; level < numMips; ++level) {
         QSize mipSize(texture->evalMipWidth(level), texture->evalMipHeight(level));
         QImage mipImage = image.scaled(mipSize, Qt::IgnoreAspectRatio, Qt::SmoothTransformation);
-        texture->assignStoredMipFace(level, formatMip, mipImage.byteCount(), mipImage.constBits(), face);
+        texture->assignStoredMipFace(level, face, mipImage.byteCount(), mipImage.constBits());
     }
 #else
     texture->autoGenerateMips(-1);
@@ -322,11 +322,11 @@ gpu::Texture* TextureUsage::process2DTextureColorFromImage(const QImage& srcImag
             }
         }
         theTexture->setUsage(usage.build());
-
-        theTexture->assignStoredMip(0, formatMip, image.byteCount(), image.constBits());
+        theTexture->setStoredMipFormat(formatMip);
+        theTexture->assignStoredMip(0, image.byteCount(), image.constBits());
 
         if (generateMips) {
-            ::generateMips(theTexture, image, formatMip, false);
+            ::generateMips(theTexture, image, false);
         }
 
         theTexture = cacheTexture(std::to_string((size_t) theTexture), theTexture);
@@ -373,8 +373,9 @@ gpu::Texture* TextureUsage::createNormalTextureFromNormalImage(const QImage& src
 
         theTexture = (gpu::Texture::create2D(formatGPU, image.width(), image.height(), gpu::Sampler(gpu::Sampler::FILTER_MIN_MAG_MIP_LINEAR)));
         theTexture->setSource(srcImageName);
-        theTexture->assignStoredMip(0, formatMip, image.byteCount(), image.constBits());
-        generateMips(theTexture, image, formatMip, true);
+        theTexture->setStoredMipFormat(formatMip);
+        theTexture->assignStoredMip(0, image.byteCount(), image.constBits());
+        generateMips(theTexture, image, true);
 
         theTexture = cacheTexture(std::to_string((size_t) theTexture), theTexture);
     }
@@ -461,8 +462,9 @@ gpu::Texture* TextureUsage::createNormalTextureFromBumpImage(const QImage& srcIm
 
         theTexture = (gpu::Texture::create2D(formatGPU, image.width(), image.height(), gpu::Sampler(gpu::Sampler::FILTER_MIN_MAG_MIP_LINEAR)));
         theTexture->setSource(srcImageName);
-        theTexture->assignStoredMip(0, formatMip, image.byteCount(), image.constBits());
-        generateMips(theTexture, image, formatMip, true);
+        theTexture->setStoredMipFormat(formatMip);
+        theTexture->assignStoredMip(0, image.byteCount(), image.constBits());
+        generateMips(theTexture, image, true);
 
         theTexture = cacheTexture(std::to_string((size_t) theTexture), theTexture);
     }
@@ -496,8 +498,9 @@ gpu::Texture* TextureUsage::createRoughnessTextureFromImage(const QImage& srcIma
 
         theTexture = (gpu::Texture::create2D(formatGPU, image.width(), image.height(), gpu::Sampler(gpu::Sampler::FILTER_MIN_MAG_MIP_LINEAR)));
         theTexture->setSource(srcImageName);
-        theTexture->assignStoredMip(0, formatMip, image.byteCount(), image.constBits());
-        generateMips(theTexture, image, formatMip, true);
+        theTexture->setStoredMipFormat(formatMip);
+        theTexture->assignStoredMip(0, image.byteCount(), image.constBits());
+        generateMips(theTexture, image, true);
         
         theTexture = cacheTexture(std::to_string((size_t) theTexture), theTexture);
     }
@@ -535,8 +538,9 @@ gpu::Texture* TextureUsage::createRoughnessTextureFromGlossImage(const QImage& s
 
         theTexture = (gpu::Texture::create2D(formatGPU, image.width(), image.height(), gpu::Sampler(gpu::Sampler::FILTER_MIN_MAG_MIP_LINEAR)));
         theTexture->setSource(srcImageName);
-        theTexture->assignStoredMip(0, formatMip, image.byteCount(), image.constBits());
-        generateMips(theTexture, image, formatMip, true);
+        theTexture->setStoredMipFormat(formatMip);
+        theTexture->assignStoredMip(0, image.byteCount(), image.constBits());
+        generateMips(theTexture, image, true);
 
         theTexture = cacheTexture(std::to_string((size_t) theTexture), theTexture);
     }
@@ -571,8 +575,9 @@ gpu::Texture* TextureUsage::createMetallicTextureFromImage(const QImage& srcImag
 
         theTexture = (gpu::Texture::create2D(formatGPU, image.width(), image.height(), gpu::Sampler(gpu::Sampler::FILTER_MIN_MAG_MIP_LINEAR)));
         theTexture->setSource(srcImageName);
-        theTexture->assignStoredMip(0, formatMip, image.byteCount(), image.constBits());
-        generateMips(theTexture, image, formatMip, true);
+        theTexture->setStoredMipFormat(formatMip);
+        theTexture->assignStoredMip(0, image.byteCount(), image.constBits());
+        generateMips(theTexture, image, true);
 
         theTexture = cacheTexture(std::to_string((size_t) theTexture), theTexture);
     }
@@ -886,11 +891,12 @@ gpu::Texture* TextureUsage::processCubeTextureColorFromImage(const QImage& srcIm
         if (faces.size() == gpu::Texture::NUM_FACES_PER_TYPE[gpu::Texture::TEX_CUBE]) {
             theTexture = gpu::Texture::createCube(formatGPU, faces[0].width(), gpu::Sampler(gpu::Sampler::FILTER_MIN_MAG_MIP_LINEAR, gpu::Sampler::WRAP_CLAMP));
             theTexture->setSource(srcImageName);
+            theTexture->setStoredMipFormat(formatMip);
             int f = 0;
             for (auto& face : faces) {
-                theTexture->assignStoredMipFace(0, formatMip, face.byteCount(), face.constBits(), f);
+                theTexture->assignStoredMipFace(0, f, face.byteCount(), face.constBits());
                 if (generateMips) {
-                    generateFaceMips(theTexture, face, formatMip, f);
+                    generateFaceMips(theTexture, face, f);
                 }
                 f++;
             }
diff --git a/libraries/render-utils/src/text/Font.cpp b/libraries/render-utils/src/text/Font.cpp
index 4f4ee12622..c405f6d6ae 100644
--- a/libraries/render-utils/src/text/Font.cpp
+++ b/libraries/render-utils/src/text/Font.cpp
@@ -209,7 +209,8 @@ void Font::read(QIODevice& in) {
     }
     _texture = gpu::TexturePointer(gpu::Texture::create2D(formatGPU, image.width(), image.height(),
                                    gpu::Sampler(gpu::Sampler::FILTER_MIN_POINT_MAG_LINEAR)));
-    _texture->assignStoredMip(0, formatMip, image.byteCount(), image.constBits());
+    _texture->setStoredMipFormat(formatMip);
+    _texture->assignStoredMip(0, image.byteCount(), image.constBits());
 }
 
 void Font::setupGPU() {
diff --git a/libraries/shared/src/shared/Storage.cpp b/libraries/shared/src/shared/Storage.cpp
index d3f1f3c5d3..dacb840de7 100644
--- a/libraries/shared/src/shared/Storage.cpp
+++ b/libraries/shared/src/shared/Storage.cpp
@@ -14,10 +14,13 @@ using namespace storage;
 
 ViewStoragePointer Storage::createView(size_t viewSize, size_t offset) const {
     auto selfSize = size();
-    if ((viewSize + offset) > selfSize) {
-        throw std::runtime_error("Unable to map file");
+    if (0 == viewSize) {
+        viewSize = selfSize;
     }
-    return ViewStoragePointer(new ViewStorage(viewSize, data() + offset));
+    if ((viewSize + offset) > selfSize) {
+        throw std::runtime_error("Invalid mapping range");
+    }
+    return ViewStoragePointer(new ViewStorage(shared_from_this(), viewSize, data() + offset));
 }
 
 MemoryStoragePointer Storage::toMemoryStorage() const {
diff --git a/libraries/shared/src/shared/Storage.h b/libraries/shared/src/shared/Storage.h
index 8096b631ed..4dbb2a03a5 100644
--- a/libraries/shared/src/shared/Storage.h
+++ b/libraries/shared/src/shared/Storage.h
@@ -18,22 +18,27 @@
 
 namespace storage {
     class Storage;
-    using StoragePointer = std::unique_ptr<Storage>;
+    using StoragePointer = std::shared_ptr<const Storage>;
     class MemoryStorage;
-    using MemoryStoragePointer = std::unique_ptr<MemoryStorage>;
+    using MemoryStoragePointer = std::shared_ptr<const MemoryStorage>;
     class FileStorage;
-    using FileStoragePointer = std::unique_ptr<FileStorage>;
+    using FileStoragePointer = std::shared_ptr<const FileStorage>;
     class ViewStorage;
-    using ViewStoragePointer = std::unique_ptr<ViewStorage>;
+    using ViewStoragePointer = std::shared_ptr<const ViewStorage>;
 
-    class Storage {
+    class Storage : public std::enable_shared_from_this<Storage> {
     public:
         virtual ~Storage() {}
         virtual const uint8_t* data() const = 0;
         virtual size_t size() const = 0;
-        ViewStoragePointer createView(size_t size, size_t offset = 0) const;
+
+        ViewStoragePointer createView(size_t size = 0, size_t offset = 0) const;
         FileStoragePointer toFileStorage(const QString& filename) const;
         MemoryStoragePointer toMemoryStorage() const;
+
+        // Aliases to prevent having to re-write a ton of code
+        inline size_t getSize() const { return size(); }
+        inline const uint8_t* readData() const { return data(); }
     };
 
     class MemoryStorage : public Storage {
@@ -63,10 +68,11 @@ namespace storage {
 
     class ViewStorage : public Storage {
     public:
-        ViewStorage(size_t size, const uint8_t* data) : _size(size), _data(data) {}
+        ViewStorage(const storage::StoragePointer& owner, size_t size, const uint8_t* data) : _owner(owner), _size(size), _data(data) {}
         const uint8_t* data() const override { return _data; }
         size_t size() const override { return _size; }
     private:
+        const storage::StoragePointer _owner;
         const size_t _size;
         const uint8_t* _data;
     };
diff --git a/tests/render-perf/CMakeLists.txt b/tests/render-perf/CMakeLists.txt
index d4f90fdace..96cede9c43 100644
--- a/tests/render-perf/CMakeLists.txt
+++ b/tests/render-perf/CMakeLists.txt
@@ -10,7 +10,7 @@ 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 gl gpu gpu-gl render model model-networking networking render-utils fbx entities entities-renderer animation audio avatars script-engine physics)
+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()