diff --git a/libraries/gpu/src/gpu/Texture_ktx.cpp b/libraries/gpu/src/gpu/Texture_ktx.cpp index eb6bb169ce..533797a657 100644 --- a/libraries/gpu/src/gpu/Texture_ktx.cpp +++ b/libraries/gpu/src/gpu/Texture_ktx.cpp @@ -252,7 +252,7 @@ ktx::KTXUniquePointer Texture::serialize(const Texture& texture) { } images.emplace_back(ktx::Image(imageOffset, (uint32_t)mip->getSize(), 0, cubeFaces)); } - imageOffset += mip->getSize() + 4; + imageOffset += static_cast<uint32_t>(mip->getSize()) + 4; } } diff --git a/libraries/ktx/src/ktx/KTX.cpp b/libraries/ktx/src/ktx/KTX.cpp index 45820b9351..d9b5ea4a62 100644 --- a/libraries/ktx/src/ktx/KTX.cpp +++ b/libraries/ktx/src/ktx/KTX.cpp @@ -12,6 +12,7 @@ #include "KTX.h" #include <algorithm> //min max and more +#include <QDebug> using namespace ktx; @@ -90,6 +91,7 @@ size_t Header::evalPixelOrBlockSize() const { return 4; } } + qWarning() << "Unknown ktx format: " << glFormat << " " << glBaseInternalFormat << " " << glInternalFormat; throw std::runtime_error("Unknown format"); } @@ -119,7 +121,7 @@ ImageDescriptors Header::generateImageDescriptors() const { ImageDescriptors descriptors; uint32_t imageOffset = 0; - for (auto level = 0; level < numberOfMipmapLevels; ++level) { + for (uint32_t level = 0; level < numberOfMipmapLevels; ++level) { auto imageSize = static_cast<uint32_t>(evalImageSize(level)); ImageHeader header { numberOfFaces == NUM_CUBEMAPFACES, @@ -131,7 +133,7 @@ ImageDescriptors Header::generateImageDescriptors() const { imageOffset += imageSize + 4; ImageHeader::FaceOffsets offsets; - for (auto i = 0; i < numberOfFaces; ++i) { + for (uint32_t i = 0; i < numberOfFaces; ++i) { offsets.push_back(0); } descriptors.push_back(ImageDescriptor(header, offsets)); diff --git a/libraries/model-networking/src/model-networking/TextureCache.cpp b/libraries/model-networking/src/model-networking/TextureCache.cpp index 3e06142d8e..3d81dd51e9 100644 --- a/libraries/model-networking/src/model-networking/TextureCache.cpp +++ b/libraries/model-networking/src/model-networking/TextureCache.cpp @@ -38,6 +38,7 @@ #include <Finally.h> #include <Profile.h> +#include "NetworkLogging.h" #include "ModelNetworkingLogging.h" #include <Trace.h> #include <StatTracker.h> @@ -345,14 +346,12 @@ void NetworkTexture::makeRequest() { // We special-handle ktx requests to run 2 concurrent requests right off the bat PROFILE_ASYNC_BEGIN(resource, "Resource:" + getType(), QString::number(_requestID), { { "url", _url.toString() }, { "activeURL", _activeUrl.toString() } }); - if (!_ktxHeaderLoaded) { + if (!_ktxHeaderLoaded && !_highMipRequestFinished) { qDebug() << ">>> Making request to " << _url << " for header"; _ktxHeaderRequest = ResourceManager::createResourceRequest(this, _activeUrl); if (!_ktxHeaderRequest) { //qCDebug(networking).noquote() << "Failed to get request for" << _url.toDisplayString(); - ResourceCache::requestCompleted(_self); - finishedLoading(false); PROFILE_ASYNC_END(resource, "Resource:" + getType(), QString::number(_requestID)); return; } @@ -373,9 +372,14 @@ void NetworkTexture::makeRequest() { _bytesReceived = _bytesTotal = _bytes = 0; _ktxHeaderRequest->send(); + + startMipRangeRequest(NULL_MIP_LEVEL, NULL_MIP_LEVEL); + } else { + if (_lowestKnownPopulatedMip > 0) { + startMipRangeRequest(_lowestKnownPopulatedMip - 1, _lowestKnownPopulatedMip - 1); + } } - startMipRangeRequest(NULL_MIP_LEVEL, NULL_MIP_LEVEL); } void NetworkTexture::handleMipInterestCallback(uint16_t level) { @@ -384,13 +388,24 @@ void NetworkTexture::handleMipInterestCallback(uint16_t level) { void NetworkTexture::handleMipInterestLevel(int level) { _lowestRequestedMipLevel = std::min(static_cast<uint16_t>(level), _lowestRequestedMipLevel); - if (!_ktxMipRequest) { - startRequestForNextMipLevel(); + if (!_ktxMipRequest && _lowestKnownPopulatedMip > 0) { + //startRequestForNextMipLevel(); + clearLoadPriority(this); + setLoadPriority(this, _lowestKnownPopulatedMip - 1); + ResourceCache::attemptRequest(_self); } } void NetworkTexture::startRequestForNextMipLevel() { - startMipRangeRequest(std::max(0, _lowestKnownPopulatedMip - 1), std::max(0, _lowestKnownPopulatedMip - 1)); + if (_lowestKnownPopulatedMip == 0) { + qWarning(networking) << "Requesting next mip level but all have been fulfilled"; + return; + } + if (_pending) { + return; + } + + //startMipRangeRequest(std::max(0, _lowestKnownPopulatedMip - 1), std::max(0, _lowestKnownPopulatedMip - 1)); } // Load mips in the range [low, high] (inclusive) @@ -406,7 +421,7 @@ void NetworkTexture::startMipRangeRequest(uint16_t low, uint16_t high) { } _ktxMipRequest = ResourceManager::createResourceRequest(this, _activeUrl); - qDebug() << ">>> Making request to " << _url << " for " << low << " to " << high; + qDebug(networking) << ">>> Making request to " << _url << " for " << low << " to " << high; _ktxMipLevelRangeInFlight = { low, high }; if (isHighMipRequest) { @@ -437,7 +452,7 @@ void NetworkTexture::ktxHeaderRequestFinished() { if (_ktxHeaderRequest->getResult() == ResourceRequest::Success) { _ktxHeaderLoaded = true; _ktxHeaderData = _ktxHeaderRequest->getData(); - maybeCreateKTX(); + maybeHandleFinishedInitialLoad(); } else { handleFailedRequest(_ktxHeaderRequest->getResult()); } @@ -455,15 +470,18 @@ void NetworkTexture::ktxMipRequestFinished() { _lowestKnownPopulatedMip = _ktxMipLevelRangeInFlight.first; - _textureSource->getGPUTexture()->assignStoredMip(_ktxMipLevelRangeInFlight.first, - _ktxMipRequest->getData().size(), reinterpret_cast<uint8_t*>(_ktxMipRequest->getData().data())); - //texture->assignStoredMip(level, image._imageSize, ktxData); + auto texture = _textureSource->getGPUTexture(); + if (!texture) { + texture->assignStoredMip(_ktxMipLevelRangeInFlight.first, + _ktxMipRequest->getData().size(), reinterpret_cast<uint8_t*>(_ktxMipRequest->getData().data())); + } else { + qWarning(networking) << "Trying to update mips but texture is null"; + } } else { _highMipRequestFinished = true; _ktxHighMipData = _ktxMipRequest->getData(); - maybeCreateKTX(); + maybeHandleFinishedInitialLoad(); } - } else { handleFailedRequest(_ktxMipRequest->getResult()); } @@ -472,11 +490,13 @@ void NetworkTexture::ktxMipRequestFinished() { } // This is called when the header or top mips have been loaded -void NetworkTexture::maybeCreateKTX() { +void NetworkTexture::maybeHandleFinishedInitialLoad() { if (_headerRequestFinished && _highMipRequestFinished) { ResourceCache::requestCompleted(_self); - if (_ktxHeaderData.size() > 0 && _ktxHighMipData.size() > 0) { + if (_ktxHeaderData.size() == 0 || _ktxHighMipData.size() == 0) { + finishedLoading(false); + } else { // create ktx... auto header = reinterpret_cast<const ktx::Header*>(_ktxHeaderData.data()); @@ -490,6 +510,7 @@ void NetworkTexture::maybeCreateKTX() { auto kvSize = header->bytesOfKeyValueData; if (kvSize > _ktxHeaderData.size() - ktx::KTX_HEADER_SIZE) { qWarning() << "Cannot load " << _url << ", did not receive all kv data with initial request"; + finishedLoading(false); return; } @@ -505,23 +526,23 @@ void NetworkTexture::maybeCreateKTX() { std::string filename; if (found == keyValues.end()) { qWarning("Source hash key not found, bailing"); - filename = "test"; - //return; - + finishedLoading(false); + return; } else { - if (found->_value.size() < 16) { - filename = _activeUrl.fileName().toStdString(); - } - else { + if (found->_value.size() < 32) { + qWarning("Invalid source hash key found, bailing"); + finishedLoading(false); + return; + } else { filename = std::string(reinterpret_cast<char*>(found->_value.data()), 32); } } auto memKtx = ktx::KTX::createBare(*header, keyValues); - auto d = const_cast<uint8_t*>(memKtx->getStorage()->data()); - ///memcpy(d + memKtx->_storage->size() - _ktxHighMipData.size(), _ktxHighMipData.data(), _ktxHighMipData.size()); + //auto d = const_cast<uint8_t*>(memKtx->getStorage()->data()); + //memcpy(d + memKtx->_storage->size() - _ktxHighMipData.size(), _ktxHighMipData.data(), _ktxHighMipData.size()); auto textureCache = DependencyManager::get<TextureCache>(); @@ -531,7 +552,8 @@ void NetworkTexture::maybeCreateKTX() { KTXFilePointer file; auto& ktxCache = textureCache->_ktxCache; if (!memKtx || !(file = ktxCache.writeFile(data, KTXCache::Metadata(filename, length)))) { - qCWarning(modelnetworking) << _url << "file cache failed"; + qCWarning(modelnetworking) << _url << " failed to write cache file"; + finishedLoading(false); return; } else { @@ -581,36 +603,8 @@ void NetworkTexture::maybeCreateKTX() { break; } } - ResourceCache::requestCompleted(_self); setImage(texture, header->getPixelWidth(), header->getPixelHeight()); - - return; - - /* - // Force load the next two levels - { - QTimer* timer = new QTimer(); - connect(timer, &QTimer::timeout, this, [=]() { - //startMipRangeRequest(level, level); - startRequestForNextMipLevel(); - }); - timer->setSingleShot(true); - timer->setInterval(4000); - timer->start(); - } - - { - QTimer* timer = new QTimer(); - connect(timer, &QTimer::timeout, this, [=]() { - //startMipRangeRequest(level - 1, level - 1); - startRequestForNextMipLevel(); - }); - timer->setSingleShot(true); - timer->setInterval(6000); - timer->start(); - } - */ } } } diff --git a/libraries/model-networking/src/model-networking/TextureCache.h b/libraries/model-networking/src/model-networking/TextureCache.h index 30eb9d2d2e..3048f16eb8 100644 --- a/libraries/model-networking/src/model-networking/TextureCache.h +++ b/libraries/model-networking/src/model-networking/TextureCache.h @@ -84,7 +84,7 @@ protected: void startRequestForNextMipLevel(); void startMipRangeRequest(uint16_t low, uint16_t high); - void maybeCreateKTX(); + void maybeHandleFinishedInitialLoad(); private: friend class KTXReader; @@ -92,15 +92,28 @@ private: image::TextureUsage::Type _type; - KTXFilePointer _file; static const uint16_t NULL_MIP_LEVEL; + struct KTXResourceState { + NOT_LOADED = 0, + LOADING_INITIAL_DATA, // Loading KTX Header + Low Resolution Mips + WAITING_FOR_MIP_REQUEST, // Waiting for the gpu layer to report that it needs higher resolution mips + PENDING_MIP_REQUEST, // We have added ourselves to the ResourceCache queue + REQUESTING_MIP // We have a mip in flight + }; + + KTXResourceState _ktxResourceState{ NOT_LOADED }; + + KTXFilePointer _file; + bool _sourceIsKTX { false }; bool _ktxHeaderLoaded { false }; + bool _highMipRequestFinished { false }; + std::pair<uint16_t, uint16_t> _ktxMipLevelRangeInFlight{ NULL_MIP_LEVEL, NULL_MIP_LEVEL }; + ResourceRequest* _ktxHeaderRequest { nullptr }; ResourceRequest* _ktxMipRequest { nullptr }; - bool _headerRequestFinished{ false }; - bool _highMipRequestFinished{ false }; + bool _headerRequestFinished { false }; uint16_t _lowestRequestedMipLevel { NULL_MIP_LEVEL }; uint16_t _lowestKnownPopulatedMip { NULL_MIP_LEVEL }; QByteArray _ktxHeaderData; diff --git a/libraries/networking/src/ResourceCache.cpp b/libraries/networking/src/ResourceCache.cpp index 038ee7fb53..6716b7473f 100644 --- a/libraries/networking/src/ResourceCache.cpp +++ b/libraries/networking/src/ResourceCache.cpp @@ -474,8 +474,15 @@ int ResourceCache::getLoadingRequestCount() { bool ResourceCache::attemptRequest(QSharedPointer<Resource> resource) { Q_ASSERT(!resource.isNull()); - auto sharedItems = DependencyManager::get<ResourceCacheSharedItems>(); + if (resource->_pending) { + qWarning(networking) << "Attempted to request " << resource->getURL() << " but it was already pending"; + return false; + } + + resource->_pending = true; + + auto sharedItems = DependencyManager::get<ResourceCacheSharedItems>(); if (_requestsActive >= _requestLimit) { // wait until a slot becomes available sharedItems->appendPendingRequest(resource); @@ -490,6 +497,12 @@ bool ResourceCache::attemptRequest(QSharedPointer<Resource> resource) { void ResourceCache::requestCompleted(QWeakPointer<Resource> resource) { auto sharedItems = DependencyManager::get<ResourceCacheSharedItems>(); + + auto sharedResource = resource.lock(); + if (sharedResource) { + sharedResource->_pending = true; + } + sharedItems->removeRequest(resource); --_requestsActive; diff --git a/libraries/networking/src/ResourceCache.h b/libraries/networking/src/ResourceCache.h index e699c3d198..13162aac9d 100644 --- a/libraries/networking/src/ResourceCache.h +++ b/libraries/networking/src/ResourceCache.h @@ -424,6 +424,9 @@ protected slots: protected: virtual void init(); + /// Called by ResourceCache to begin loading this Resource. + /// This method can be overriden to provide custom request functionality. If this is done, + /// downloadFinished and ResourceCache::requestCompleted must be called. virtual void makeRequest(); /// Checks whether the resource is cacheable. @@ -460,6 +463,8 @@ protected: int _requestID; ResourceRequest* _request{ nullptr }; + + bool _pending{ false }; public slots: void handleDownloadProgress(uint64_t bytesReceived, uint64_t bytesTotal);