From 5594e81fe40779c5c20c1c3646d9e19464904dab Mon Sep 17 00:00:00 2001 From: Ryan Huffman Date: Tue, 18 Apr 2017 17:03:54 -0700 Subject: [PATCH] Improve gl backend handling of unavailable mips --- libraries/gpu-gl/src/gpu/gl/GLTexture.cpp | 1 + libraries/gpu-gl/src/gpu/gl/GLTexture.h | 1 + libraries/gpu-gl/src/gpu/gl41/GL41Backend.h | 1 + .../gpu-gl/src/gpu/gl41/GL41BackendTexture.cpp | 14 ++++++++++---- libraries/gpu-gl/src/gpu/gl45/GL45Backend.h | 1 + .../gpu-gl/src/gpu/gl45/GL45BackendTexture.cpp | 10 ++++++++++ .../src/gpu/gl45/GL45BackendVariableTexture.cpp | 10 +++++++++- libraries/gpu/src/gpu/Texture.h | 4 ++++ libraries/gpu/src/gpu/Texture_ktx.cpp | 7 ++++++- libraries/ktx/src/ktx/KTX.cpp | 6 ++++-- .../src/model-networking/TextureCache.cpp | 14 +++++++++++--- 11 files changed, 58 insertions(+), 11 deletions(-) diff --git a/libraries/gpu-gl/src/gpu/gl/GLTexture.cpp b/libraries/gpu-gl/src/gpu/gl/GLTexture.cpp index b7d2ee0b0f..3853d0a9cc 100644 --- a/libraries/gpu-gl/src/gpu/gl/GLTexture.cpp +++ b/libraries/gpu-gl/src/gpu/gl/GLTexture.cpp @@ -520,6 +520,7 @@ void GLVariableAllocationSupport::processWorkQueues() { _memoryPressureStateStale = true; } else if (MemoryPressureState::Undersubscribed == _memoryPressureState) { if (!vartexture->canPromote()) { + vartexture->populateTransferQueue(); continue; } vartexture->promote(); diff --git a/libraries/gpu-gl/src/gpu/gl/GLTexture.h b/libraries/gpu-gl/src/gpu/gl/GLTexture.h index 8b4b545b7d..c8ec4c5fe6 100644 --- a/libraries/gpu-gl/src/gpu/gl/GLTexture.h +++ b/libraries/gpu-gl/src/gpu/gl/GLTexture.h @@ -116,6 +116,7 @@ protected: bool canDemote() const { return _allocatedMip < _maxAllocatedMip; } bool hasPendingTransfers() const { return _populatedMip > _allocatedMip; } void executeNextTransfer(const TexturePointer& currentTexture); + virtual bool canPopulate() const = 0; virtual void populateTransferQueue() = 0; virtual void promote() = 0; virtual void demote() = 0; diff --git a/libraries/gpu-gl/src/gpu/gl41/GL41Backend.h b/libraries/gpu-gl/src/gpu/gl41/GL41Backend.h index 19979a1778..c0b9ea0e45 100644 --- a/libraries/gpu-gl/src/gpu/gl41/GL41Backend.h +++ b/libraries/gpu-gl/src/gpu/gl41/GL41Backend.h @@ -100,6 +100,7 @@ public: GL41VariableAllocationTexture(const std::weak_ptr& backend, const Texture& texture); ~GL41VariableAllocationTexture(); + bool canPopulate() const override { return _gpuObject.isStoredMipFaceAvailable(_populatedMip - 1, 0); } void allocateStorage(uint16 allocatedMip); void syncSampler() const override; void promote() override; diff --git a/libraries/gpu-gl/src/gpu/gl41/GL41BackendTexture.cpp b/libraries/gpu-gl/src/gpu/gl41/GL41BackendTexture.cpp index bff5bf3f2c..04c2201c75 100644 --- a/libraries/gpu-gl/src/gpu/gl41/GL41BackendTexture.cpp +++ b/libraries/gpu-gl/src/gpu/gl41/GL41BackendTexture.cpp @@ -392,8 +392,10 @@ void GL41VariableAllocationTexture::populateTransferQueue() { --sourceMip; auto targetMip = sourceMip - _allocatedMip; auto mipDimensions = _gpuObject.evalMipDimensions(sourceMip); + bool didQueueTransfer = false; for (uint8_t face = 0; face < maxFace; ++face) { if (!_gpuObject.isStoredMipFaceAvailable(sourceMip, face)) { + const_cast(_gpuObject).requestInterestInMip(sourceMip); continue; } @@ -401,6 +403,7 @@ void GL41VariableAllocationTexture::populateTransferQueue() { if (glm::all(glm::lessThanEqual(mipDimensions, MAX_TRANSFER_DIMENSIONS))) { // Can the mip be transferred in one go _pendingTransfers.emplace(new TransferJob(*this, sourceMip, targetMip, face)); + didQueueTransfer = true; continue; } @@ -416,14 +419,17 @@ void GL41VariableAllocationTexture::populateTransferQueue() { uint32_t linesToCopy = std::min(lines - lineOffset, linesPerTransfer); _pendingTransfers.emplace(new TransferJob(*this, sourceMip, targetMip, face, linesToCopy, lineOffset)); lineOffset += linesToCopy; + didQueueTransfer = true; } } // queue up the sampler and populated mip change for after the transfer has completed - _pendingTransfers.emplace(new TransferJob(*this, [=] { - _populatedMip = sourceMip; - syncSampler(); - })); + if (didQueueTransfer) { + _pendingTransfers.emplace(new TransferJob(*this, [=] { + _populatedMip = sourceMip; + syncSampler(); + })); + } } while (sourceMip != _allocatedMip); } diff --git a/libraries/gpu-gl/src/gpu/gl45/GL45Backend.h b/libraries/gpu-gl/src/gpu/gl45/GL45Backend.h index dbedd81c76..15e98c3af7 100644 --- a/libraries/gpu-gl/src/gpu/gl45/GL45Backend.h +++ b/libraries/gpu-gl/src/gpu/gl45/GL45Backend.h @@ -100,6 +100,7 @@ public: GL45VariableAllocationTexture(const std::weak_ptr& backend, const Texture& texture); ~GL45VariableAllocationTexture(); Size size() const override { return _size; } + bool canPopulate() const override { return _gpuObject.isStoredMipFaceAvailable(_populatedMip - 1, 0); } Size _size { 0 }; }; diff --git a/libraries/gpu-gl/src/gpu/gl45/GL45BackendTexture.cpp b/libraries/gpu-gl/src/gpu/gl45/GL45BackendTexture.cpp index a539b76b6c..54b2411a14 100644 --- a/libraries/gpu-gl/src/gpu/gl45/GL45BackendTexture.cpp +++ b/libraries/gpu-gl/src/gpu/gl45/GL45BackendTexture.cpp @@ -80,6 +80,16 @@ GLTexture* GL45Backend::syncGPUObject(const TexturePointer& texturePointer) { default: Q_UNREACHABLE(); } + } else { + + if (texture.getUsageType() == TextureUsageType::RESOURCE) { + auto varTex = static_cast (object); + + if (varTex->canPromoteAndPopulate()) { + GL45VariableAllocationTexture::_memoryPressureStateStale = true; + } + + } } return object; diff --git a/libraries/gpu-gl/src/gpu/gl45/GL45BackendVariableTexture.cpp b/libraries/gpu-gl/src/gpu/gl45/GL45BackendVariableTexture.cpp index 09361689d8..ac2b5f607f 100644 --- a/libraries/gpu-gl/src/gpu/gl45/GL45BackendVariableTexture.cpp +++ b/libraries/gpu-gl/src/gpu/gl45/GL45BackendVariableTexture.cpp @@ -62,6 +62,7 @@ GL45ResourceTexture::GL45ResourceTexture(const std::weak_ptr& backend //glObjectLabel(GL_TEXTURE, _id, _source.length(), _source.data()); uint16_t allocatedMip = _populatedMip - std::min(_populatedMip, 2); allocateStorage(allocatedMip); + _memoryPressureStateStale = true; copyMipsFromTexture(); syncSampler(); @@ -105,7 +106,12 @@ void GL45ResourceTexture::syncSampler() const { void GL45ResourceTexture::promote() { PROFILE_RANGE(render_gpu_gl, __FUNCTION__); - Q_ASSERT(_allocatedMip > 0); + //Q_ASSERT(_allocatedMip > 0); + uint16_t sourceMip = _populatedMip; + if (!_gpuObject.isStoredMipFaceAvailable(sourceMip, 0)) { + const_cast(_gpuObject).requestInterestInMip(sourceMip); + return; + } GLuint oldId = _id; auto oldSize = _size; // create new texture @@ -191,6 +197,7 @@ void GL45ResourceTexture::populateTransferQueue() { for (uint8_t face = 0; face < maxFace; ++face) { if (!_gpuObject.isStoredMipFaceAvailable(sourceMip, face)) { const_cast(_gpuObject).requestInterestInMip(sourceMip); + _minRequestedMip = sourceMip; continue; } @@ -218,6 +225,7 @@ void GL45ResourceTexture::populateTransferQueue() { lineOffset += linesToCopy; transferQueued = true; } + _minRequestedMip = std::min(_minRequestedMip, sourceMip); } // queue up the sampler and populated mip change for after the transfer has completed diff --git a/libraries/gpu/src/gpu/Texture.h b/libraries/gpu/src/gpu/Texture.h index e71cd63fbd..6e13598caa 100755 --- a/libraries/gpu/src/gpu/Texture.h +++ b/libraries/gpu/src/gpu/Texture.h @@ -275,6 +275,7 @@ public: 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; + virtual uint16 minAvailableMipLevel() const { return 0; } Texture::Type getType() const { return _type; } Stamp getStamp() const { return _stamp; } @@ -315,6 +316,7 @@ public: bool isMipAvailable(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; + uint16 minAvailableMipLevel() const override; void reset() override { } @@ -332,6 +334,8 @@ public: friend class Texture; }; + uint16 minAvailableMipLevel() const { return _storage->minAvailableMipLevel(); }; + static const uint16 MAX_NUM_MIPS = 0; static const uint16 SINGLE_MIP = 1; static TexturePointer create1D(const Element& texelFormat, uint16 width, uint16 numMips = SINGLE_MIP, const Sampler& sampler = Sampler()); diff --git a/libraries/gpu/src/gpu/Texture_ktx.cpp b/libraries/gpu/src/gpu/Texture_ktx.cpp index 533797a657..e2b9b8d9ae 100644 --- a/libraries/gpu/src/gpu/Texture_ktx.cpp +++ b/libraries/gpu/src/gpu/Texture_ktx.cpp @@ -115,9 +115,14 @@ bool KtxStorage::isMipAvailable(uint16 level, uint8 face) const { return avail; } +uint16 KtxStorage::minAvailableMipLevel() const { + return _minMipLevelAvailable; +} + void KtxStorage::assignMipData(uint16 level, const storage::StoragePointer& storage) { if (level != _minMipLevelAvailable - 1) { qWarning() << "Invalid level to be stored, expected: " << (_minMipLevelAvailable - 1) << ", got: " << level; + //throw std::runtime_error("Invalid image size for level"); return; } @@ -128,7 +133,7 @@ void KtxStorage::assignMipData(uint16 level, const storage::StoragePointer& stor if (storage->size() != _ktxDescriptor->images[level]._imageSize) { qDebug() << "Invalid image size: " << storage->size() << ", expected: " << _ktxDescriptor->images[level]._imageSize << ", filename: " << QString::fromStdString(_filename); - //throw std::runtime_error("Invalid image size for level"); + throw std::runtime_error("Invalid image size for level"); return; } diff --git a/libraries/ktx/src/ktx/KTX.cpp b/libraries/ktx/src/ktx/KTX.cpp index d9b5ea4a62..c9dd18d665 100644 --- a/libraries/ktx/src/ktx/KTX.cpp +++ b/libraries/ktx/src/ktx/KTX.cpp @@ -92,7 +92,8 @@ size_t Header::evalPixelOrBlockSize() const { } } qWarning() << "Unknown ktx format: " << glFormat << " " << glBaseInternalFormat << " " << glInternalFormat; - throw std::runtime_error("Unknown format"); + return 1; + //throw std::runtime_error("Unknown format"); } size_t Header::evalRowSize(uint32_t level) const { @@ -130,9 +131,10 @@ ImageDescriptors Header::generateImageDescriptors() const { 0 }; - imageOffset += imageSize + 4; + imageOffset += (imageSize * numberOfFaces) + 4; ImageHeader::FaceOffsets offsets; + // TODO Add correct face offsets for (uint32_t i = 0; i < numberOfFaces; ++i) { offsets.push_back(0); } diff --git a/libraries/model-networking/src/model-networking/TextureCache.cpp b/libraries/model-networking/src/model-networking/TextureCache.cpp index 25d7018a1a..11121570c1 100644 --- a/libraries/model-networking/src/model-networking/TextureCache.cpp +++ b/libraries/model-networking/src/model-networking/TextureCache.cpp @@ -388,6 +388,7 @@ void NetworkTexture::makeRequest() { } void NetworkTexture::handleMipInterestCallback(uint16_t level) { + //qDebug(networking) << "++++ Got request for mip level: " << _url << " " << level; QMetaObject::invokeMethod(this, "handleMipInterestLevel", Qt::QueuedConnection, Q_ARG(int, level)); } @@ -466,6 +467,7 @@ void NetworkTexture::ktxMipRequestFinished() { auto texture = _textureSource->getGPUTexture(); if (texture) { _lowestKnownPopulatedMip = _ktxMipLevelRangeInFlight.first; + qDebug() << "Writing mip for " << _url; texture->assignStoredMip(_ktxMipLevelRangeInFlight.first, _ktxMipRequest->getData().size(), reinterpret_cast(_ktxMipRequest->getData().data())); } else { @@ -542,9 +544,10 @@ void NetworkTexture::maybeHandleFinishedInitialLoad() { }); std::string filename; if (found == keyValues.end()) { - qWarning("Source hash key not found, bailing"); - finishedLoading(false); - return; + //qWarning("Source hash key not found, bailing"); + //finishedLoading(false); + //return; + filename = _url.fileName().toStdString(); } else { if (found->_value.size() < 32) { @@ -558,6 +561,11 @@ void NetworkTexture::maybeHandleFinishedInitialLoad() { } auto memKtx = ktx::KTX::createBare(*header, keyValues); + if (!memKtx) { + qWarning() << " Ktx could not be created, bailing"; + finishedLoading(false); + return; + } //auto d = const_cast(memKtx->getStorage()->data()); //memcpy(d + memKtx->_storage->size() - _ktxHighMipData.size(), _ktxHighMipData.data(), _ktxHighMipData.size());