From ce12a216c07bc654381eb42e4816f2f8e3812360 Mon Sep 17 00:00:00 2001 From: Ryan Huffman Date: Wed, 19 Apr 2017 01:20:03 -0700 Subject: [PATCH] I think it might be working. --- libraries/gpu-gl/src/gpu/gl/GLTexture.cpp | 3 + libraries/gpu-gl/src/gpu/gl/GLTexture.h | 2 +- libraries/gpu/src/gpu/Texture_ktx.cpp | 5 +- .../src/model-networking/ModelCache.cpp | 1 + .../src/model-networking/TextureCache.cpp | 147 ++++++++++-------- .../networking/src/HTTPResourceRequest.cpp | 3 +- 6 files changed, 90 insertions(+), 71 deletions(-) diff --git a/libraries/gpu-gl/src/gpu/gl/GLTexture.cpp b/libraries/gpu-gl/src/gpu/gl/GLTexture.cpp index c82fa4c744..652dc3c46f 100644 --- a/libraries/gpu-gl/src/gpu/gl/GLTexture.cpp +++ b/libraries/gpu-gl/src/gpu/gl/GLTexture.cpp @@ -459,10 +459,13 @@ void GLVariableAllocationSupport::updateMemoryPressure() { auto newState = MemoryPressureState::Idle; if (hasTransfers) { + qDebug() << "Transferring"; newState = MemoryPressureState::Transfer; } else if (pressure > OVERSUBSCRIBED_PRESSURE_VALUE && canDemote) { + qDebug() << "Demoting"; newState = MemoryPressureState::Oversubscribed; } else if (pressure < UNDERSUBSCRIBED_PRESSURE_VALUE && unallocated != 0 && canPromote) { + qDebug() << "Promoting"; newState = MemoryPressureState::Undersubscribed; } diff --git a/libraries/gpu-gl/src/gpu/gl/GLTexture.h b/libraries/gpu-gl/src/gpu/gl/GLTexture.h index c8ec4c5fe6..7f3431b7eb 100644 --- a/libraries/gpu-gl/src/gpu/gl/GLTexture.h +++ b/libraries/gpu-gl/src/gpu/gl/GLTexture.h @@ -112,7 +112,7 @@ protected: static void manageMemory(); //bool canPromoteNoAllocate() const { return _allocatedMip < _populatedMip; } - bool canPromote() const { return _allocatedMip > 0; } + bool canPromote() const { return _allocatedMip > 0 || _populatedMip > 0; } bool canDemote() const { return _allocatedMip < _maxAllocatedMip; } bool hasPendingTransfers() const { return _populatedMip > _allocatedMip; } void executeNextTransfer(const TexturePointer& currentTexture); diff --git a/libraries/gpu/src/gpu/Texture_ktx.cpp b/libraries/gpu/src/gpu/Texture_ktx.cpp index c0fe3f5c9c..a7af329505 100644 --- a/libraries/gpu/src/gpu/Texture_ktx.cpp +++ b/libraries/gpu/src/gpu/Texture_ktx.cpp @@ -51,6 +51,9 @@ KtxStorage::KtxStorage(const std::string& filename) : _filename(filename) { ktx::StoragePointer storage{ new storage::FileStorage(_filename.c_str()) }; auto ktxPointer = ktx::KTX::create(storage); _ktxDescriptor.reset(new ktx::KTXDescriptor(ktxPointer->toDescriptor())); + if (_ktxDescriptor->images.size() < _ktxDescriptor->header.numberOfMipmapLevels) { + qDebug() << "bad images found"; + } auto& keyValues = _ktxDescriptor->keyValues; auto found = std::find_if(keyValues.begin(), keyValues.end(), [](const ktx::KeyValue& val) -> bool { return val._key.compare(ktx::HIFI_MIN_POPULATED_MIP_KEY) == 0; @@ -167,7 +170,7 @@ void KtxStorage::assignMipData(uint16 level, const storage::StoragePointer& stor memcpy(data, storage->data(), _ktxDescriptor->images[level]._imageSize); _minMipLevelAvailable = level; if (offset > 0) { - memcpy(file->mutableData() + ktx::KTX_HEADER_SIZE + offset, (uint8_t)_minMipLevelAvailable, 1); + memcpy(file->mutableData() + ktx::KTX_HEADER_SIZE + offset, (void*)&_minMipLevelAvailable, 1); } } } diff --git a/libraries/model-networking/src/model-networking/ModelCache.cpp b/libraries/model-networking/src/model-networking/ModelCache.cpp index 623832aaa8..defe868abc 100644 --- a/libraries/model-networking/src/model-networking/ModelCache.cpp +++ b/libraries/model-networking/src/model-networking/ModelCache.cpp @@ -364,6 +364,7 @@ void Geometry::setTextures(const QVariantMap& textureMap) { bool Geometry::areTexturesLoaded() const { if (!_areTexturesLoaded) { + qDebug() << "Textures not loaded for " << _fbxGeometry->originalURL; for (auto& material : _materials) { // Check if material textures are loaded bool materialMissingTexture = std::any_of(material->_textures.cbegin(), material->_textures.cend(), diff --git a/libraries/model-networking/src/model-networking/TextureCache.cpp b/libraries/model-networking/src/model-networking/TextureCache.cpp index 8b6530b5b9..4c40075daa 100644 --- a/libraries/model-networking/src/model-networking/TextureCache.cpp +++ b/libraries/model-networking/src/model-networking/TextureCache.cpp @@ -422,7 +422,7 @@ void NetworkTexture::startMipRangeRequest(uint16_t low, uint16_t high) { bool isHighMipRequest = low == NULL_MIP_LEVEL && high == NULL_MIP_LEVEL; _ktxMipRequest = ResourceManager::createResourceRequest(this, _activeUrl); - qDebug(networking) << ">>> Making request to " << _url << " for " << low << " to " << high; + //qDebug(networking) << ">>> Making request to " << _url << " for " << low << " to " << high; _ktxMipLevelRangeInFlight = { low, high }; if (isHighMipRequest) { @@ -460,6 +460,7 @@ void NetworkTexture::ktxMipRequestFinished() { _ktxHighMipRequestFinished = true; maybeHandleFinishedInitialLoad(); } else if (_ktxResourceState == REQUESTING_MIP) { + Q_ASSERT(_ktxMipLevelRangeInFlight.first != NULL_MIP_LEVEL); ResourceCache::requestCompleted(_self); if (_ktxMipRequest->getResult() == ResourceRequest::Success) { @@ -468,20 +469,26 @@ void NetworkTexture::ktxMipRequestFinished() { auto texture = _textureSource->getGPUTexture(); if (texture) { _lowestKnownPopulatedMip = _ktxMipLevelRangeInFlight.first; - qDebug() << "Writing mip for " << _url; + //qDebug() << "Writing mip for " << _url; texture->assignStoredMip(_ktxMipLevelRangeInFlight.first, _ktxMipRequest->getData().size(), reinterpret_cast(_ktxMipRequest->getData().data())); } else { qWarning(networking) << "Trying to update mips but texture is null"; } + finishedLoading(true); _ktxResourceState = WAITING_FOR_MIP_REQUEST; } else { _ktxResourceState = PENDING_MIP_REQUEST; + finishedLoading(false); handleFailedRequest(_ktxMipRequest->getResult()); } _ktxMipRequest->deleteLater(); _ktxMipRequest = nullptr; + + if (_ktxResourceState == WAITING_FOR_MIP_REQUEST && _lowestRequestedMipLevel < _lowestKnownPopulatedMip) { + startRequestForNextMipLevel(); + } } else { qWarning() << "Mip request finished in an unexpected state: " << _ktxResourceState; } @@ -544,85 +551,88 @@ void NetworkTexture::maybeHandleFinishedInitialLoad() { return val._key.compare(gpu::SOURCE_HASH_KEY) == 0; }); std::string filename; - if (found == keyValues.end()) { - //qWarning("Source hash key not found, bailing"); - //finishedLoading(false); - //return; - filename = _url.fileName().toStdString(); - } - else { - if (found->_value.size() < 32) { - qWarning("Invalid source hash key found, bailing"); - _ktxResourceState = FAILED_TO_LOAD; - finishedLoading(false); - return; - } else { - filename = std::string(reinterpret_cast(found->_value.data()), 32); - } - } - - 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()); - - auto textureCache = DependencyManager::get(); - - // Move ktx to file - const char* data = reinterpret_cast(memKtx->_storage->data()); - size_t length = memKtx->_storage->size(); - KTXFilePointer file; - auto& ktxCache = textureCache->_ktxCache; - if (!memKtx || !(file = ktxCache.writeFile(data, KTXCache::Metadata(filename, length)))) { - qCWarning(modelnetworking) << _url << " failed to write cache file"; + std::string hash; + if (found == keyValues.end() || found->_value.size() != 32) { + qWarning("Invalid source hash key found, bailing"); _ktxResourceState = FAILED_TO_LOAD; finishedLoading(false); return; } else { - _file = file; + hash = filename = std::string(reinterpret_cast(found->_value.data()), 32); + //hash = filename = _url.path().replace("/", "_").toStdString(); } - //_ktxDescriptor.reset(new ktx::KTXDescriptor(memKtx->toDescriptor())); - auto newKtxDescriptor = memKtx->toDescriptor(); + auto textureCache = DependencyManager::get(); - //auto texture = gpu::Texture::serializeHeader("test.ktx", *header, keyValues); - gpu::TexturePointer texture; - texture.reset(gpu::Texture::unserialize(_file->getFilepath(), newKtxDescriptor)); - texture->setKtxBacking(file->getFilepath()); - texture->setSource(filename); - texture->registerMipInterestListener(this); + gpu::TexturePointer texture = textureCache->getTextureByHash(hash); - auto& images = _originalKtxDescriptor->images; - size_t imageSizeRemaining = ktxHighMipData.size(); - uint8_t* ktxData = reinterpret_cast(ktxHighMipData.data()); - ktxData += ktxHighMipData.size(); - // TODO Move image offset calculation to ktx ImageDescriptor - int level; - for (level = images.size() - 1; level >= 0; --level) { - auto& image = images[level]; - if (image._imageSize > imageSizeRemaining) { - break; + if (!texture) { + KTXFilePointer ktxFile = textureCache->_ktxCache.getFile(hash); + if (ktxFile) { + texture.reset(gpu::Texture::unserialize(ktxFile->getFilepath())); + if (texture) { + texture = textureCache->cacheTextureByHash(hash, texture); + } } - qDebug() << "Transferring " << level; - ktxData -= image._imageSize; - texture->assignStoredMip(level, image._imageSize, ktxData); - ktxData -= 4; - imageSizeRemaining -= (image._imageSize + 4); } - // We replace the texture with the one stored in the cache. This deals with the possible race condition of two different - // images with the same hash being loaded concurrently. Only one of them will make it into the cache by hash first and will - // be the winner - if (textureCache) { + if (!texture) { + + auto memKtx = ktx::KTX::createBare(*header, keyValues); + if (!memKtx) { + qWarning() << " Ktx could not be created, bailing"; + finishedLoading(false); + return; + } + + // Move ktx to file + const char* data = reinterpret_cast(memKtx->_storage->data()); + size_t length = memKtx->_storage->size(); + KTXFilePointer file; + auto& ktxCache = textureCache->_ktxCache; + if (!memKtx || !(file = ktxCache.writeFile(data, KTXCache::Metadata(filename, length)))) { + qCWarning(modelnetworking) << _url << " failed to write cache file"; + _ktxResourceState = FAILED_TO_LOAD; + finishedLoading(false); + return; + } + else { + _file = file; + } + + auto newKtxDescriptor = memKtx->toDescriptor(); + + //auto texture = gpu::Texture::serializeHeader("test.ktx", *header, keyValues); + texture.reset(gpu::Texture::unserialize(_file->getFilepath(), newKtxDescriptor)); + texture->setKtxBacking(file->getFilepath()); + texture->setSource(filename); + + auto& images = _originalKtxDescriptor->images; + size_t imageSizeRemaining = ktxHighMipData.size(); + uint8_t* ktxData = reinterpret_cast(ktxHighMipData.data()); + ktxData += ktxHighMipData.size(); + // TODO Move image offset calculation to ktx ImageDescriptor + int level; + for (level = images.size() - 1; level >= 0; --level) { + auto& image = images[level]; + if (image._imageSize > imageSizeRemaining) { + break; + } + //qDebug() << "Transferring " << level; + ktxData -= image._imageSize; + texture->assignStoredMip(level, image._imageSize, ktxData); + ktxData -= 4; + imageSizeRemaining -= (image._imageSize + 4); + } + + // We replace the texture with the one stored in the cache. This deals with the possible race condition of two different + // images with the same hash being loaded concurrently. Only one of them will make it into the cache by hash first and will + // be the winner texture = textureCache->cacheTextureByHash(filename, texture); - } + } + _lowestKnownPopulatedMip = _originalKtxDescriptor->header.numberOfMipmapLevels; for (uint16_t l = 0; l < 200; l++) { if (texture->isStoredMipFaceAvailable(l)) { @@ -631,8 +641,11 @@ void NetworkTexture::maybeHandleFinishedInitialLoad() { } } + + texture->registerMipInterestListener(this); _ktxResourceState = WAITING_FOR_MIP_REQUEST; setImage(texture, header->getPixelWidth(), header->getPixelHeight()); + qDebug() << "Loaded KTX: " << QString::fromStdString(hash) << " : " << _url; } } } diff --git a/libraries/networking/src/HTTPResourceRequest.cpp b/libraries/networking/src/HTTPResourceRequest.cpp index 8958eeaf3b..0023ecb09c 100644 --- a/libraries/networking/src/HTTPResourceRequest.cpp +++ b/libraries/networking/src/HTTPResourceRequest.cpp @@ -132,7 +132,7 @@ void HTTPResourceRequest::onRequestFinished() { uint64_t size; std::tie(success, size) = parseContentRangeHeader(contentRangeHeader); if (success) { - qWarning(networking) << "Total http resource size is: " << size; + //qWarning(networking) << "Total http resource size is: " << size; _totalSizeOfResource = size; } else { qWarning(networking) << "Error parsing content-range header: " << contentRangeHeader; @@ -187,7 +187,6 @@ 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