diff --git a/libraries/gpu-gl/src/gpu/gl/GLTexture.h b/libraries/gpu-gl/src/gpu/gl/GLTexture.h index 7f3431b7eb..bc8467b808 100644 --- a/libraries/gpu-gl/src/gpu/gl/GLTexture.h +++ b/libraries/gpu-gl/src/gpu/gl/GLTexture.h @@ -114,7 +114,7 @@ protected: //bool canPromoteNoAllocate() const { return _allocatedMip < _populatedMip; } bool canPromote() const { return _allocatedMip > 0 || _populatedMip > 0; } bool canDemote() const { return _allocatedMip < _maxAllocatedMip; } - bool hasPendingTransfers() const { return _populatedMip > _allocatedMip; } + bool hasPendingTransfers() const { return _pendingTransfers.size() > 0; } void executeNextTransfer(const TexturePointer& currentTexture); virtual bool canPopulate() const = 0; virtual void populateTransferQueue() = 0; diff --git a/libraries/ktx/src/ktx/KTX.cpp b/libraries/ktx/src/ktx/KTX.cpp index 68b83b1682..e00937a67a 100644 --- a/libraries/ktx/src/ktx/KTX.cpp +++ b/libraries/ktx/src/ktx/KTX.cpp @@ -92,13 +92,16 @@ size_t Header::evalPixelOrBlockSize() const { } } qWarning() << "Unknown ktx format: " << glFormat << " " << glBaseInternalFormat << " " << glInternalFormat; - return 1; + return 0; //throw std::runtime_error("Unknown format"); } size_t Header::evalRowSize(uint32_t level) const { auto pixWidth = evalPixelOrBlockWidth(level); auto pixSize = evalPixelOrBlockSize(); + if (pixSize == 0) { + return 0; + } auto netSize = pixWidth * pixSize; auto padding = evalPadding(netSize); return netSize + padding; @@ -136,6 +139,9 @@ ImageDescriptors Header::generateImageDescriptors() const { uint32_t imageOffset = 0; for (uint32_t level = 0; level < numberOfMipmapLevels; ++level) { auto imageSize = static_cast(evalImageSize(level)); + if (imageSize == 0) { + return ImageDescriptors(); + } ImageHeader header { numberOfFaces == NUM_CUBEMAPFACES, imageOffset, diff --git a/libraries/ktx/src/ktx/KTX.h b/libraries/ktx/src/ktx/KTX.h index 65ecc430b9..713733b1dd 100644 --- a/libraries/ktx/src/ktx/KTX.h +++ b/libraries/ktx/src/ktx/KTX.h @@ -298,6 +298,8 @@ namespace ktx { struct ImageDescriptor; using ImageDescriptors = std::vector; + bool checkIdentifier(const Byte* identifier); + // Header struct Header { static const size_t IDENTIFIER_LENGTH = 12; diff --git a/libraries/model-networking/src/model-networking/TextureCache.cpp b/libraries/model-networking/src/model-networking/TextureCache.cpp index cf94192442..17f1d62b7b 100644 --- a/libraries/model-networking/src/model-networking/TextureCache.cpp +++ b/libraries/model-networking/src/model-networking/TextureCache.cpp @@ -399,14 +399,15 @@ void NetworkTexture::handleMipInterestLevel(int level) { void NetworkTexture::startRequestForNextMipLevel() { if (_lowestKnownPopulatedMip == 0) { - qWarning(networking) << "Requesting next mip level but all have been fulfilled: " << _url; + qWarning(networking) << "Requesting next mip level but all have been fulfilled: " << _lowestKnownPopulatedMip + << " " << _textureSource->getGPUTexture()->minAvailableMipLevel() << " " << _url; return; } if (_ktxResourceState == WAITING_FOR_MIP_REQUEST) { _ktxResourceState = PENDING_MIP_REQUEST; - setLoadPriority(this, _lowestKnownPopulatedMip); + setLoadPriority(this, -_originalKtxDescriptor->header.numberOfMipmapLevels + _lowestKnownPopulatedMip); init(); ResourceCache::attemptRequest(_self); @@ -449,8 +450,8 @@ void NetworkTexture::startMipRangeRequest(uint16_t low, uint16_t high) { void NetworkTexture::ktxHeaderRequestFinished() { Q_ASSERT(_ktxResourceState == LOADING_INITIAL_DATA); - _ktxHeaderRequestFinished = true; - maybeHandleFinishedInitialLoad(); +_ktxHeaderRequestFinished = true; +maybeHandleFinishedInitialLoad(); } void NetworkTexture::ktxMipRequestFinished() { @@ -459,7 +460,8 @@ void NetworkTexture::ktxMipRequestFinished() { if (_ktxResourceState == LOADING_INITIAL_DATA) { _ktxHighMipRequestFinished = true; maybeHandleFinishedInitialLoad(); - } else if (_ktxResourceState == REQUESTING_MIP) { + } + else if (_ktxResourceState == REQUESTING_MIP) { Q_ASSERT(_ktxMipLevelRangeInFlight.first != NULL_MIP_LEVEL); ResourceCache::requestCompleted(_self); @@ -472,15 +474,22 @@ void NetworkTexture::ktxMipRequestFinished() { //qDebug() << "Writing mip for " << _url; texture->assignStoredMip(_ktxMipLevelRangeInFlight.first, _ktxMipRequest->getData().size(), reinterpret_cast(_ktxMipRequest->getData().data())); - } else { + } + else { qWarning(networking) << "Trying to update mips but texture is null"; } finishedLoading(true); _ktxResourceState = WAITING_FOR_MIP_REQUEST; - } else { - _ktxResourceState = PENDING_MIP_REQUEST; + } + else { finishedLoading(false); - handleFailedRequest(_ktxMipRequest->getResult()); + if (handleFailedRequest(_ktxMipRequest->getResult())) { + _ktxResourceState = PENDING_MIP_REQUEST; + } + else { + qWarning() << "Failed to load mip: " << _url; + _ktxResourceState = FAILED_TO_LOAD; + } } _ktxMipRequest->deleteLater(); @@ -489,7 +498,8 @@ void NetworkTexture::ktxMipRequestFinished() { if (_ktxResourceState == WAITING_FOR_MIP_REQUEST && _lowestRequestedMipLevel < _lowestKnownPopulatedMip) { startRequestForNextMipLevel(); } - } else { + } + else { qWarning() << "Mip request finished in an unexpected state: " << _ktxResourceState; } } @@ -505,7 +515,8 @@ void NetworkTexture::maybeHandleFinishedInitialLoad() { if (_ktxHeaderRequest->getResult() != ResourceRequest::Success || _ktxMipRequest->getResult() != ResourceRequest::Success) { if (handleFailedRequest(_ktxMipRequest->getResult())) { _ktxResourceState = PENDING_INITIAL_LOAD; - } else { + } + else { _ktxResourceState = FAILED_TO_LOAD; } @@ -533,6 +544,12 @@ void NetworkTexture::maybeHandleFinishedInitialLoad() { qDebug() << "numberOfFaces:" << header->numberOfFaces; qDebug() << "numberOfMipmapLevels:" << header->numberOfMipmapLevels; + if (!ktx::checkIdentifier(header->identifier)) { + qWarning() << "Cannot load " << _url << ", invalid header identifier"; + _ktxResourceState = FAILED_TO_LOAD; + finishedLoading(false); + } + 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"; @@ -544,6 +561,11 @@ void NetworkTexture::maybeHandleFinishedInitialLoad() { auto keyValues = ktx::KTX::parseKeyValues(header->bytesOfKeyValueData, reinterpret_cast(ktxHeaderData.data()) + ktx::KTX_HEADER_SIZE); auto imageDescriptors = header->generateImageDescriptors(); + if (imageDescriptors.size() == 0) { + qWarning(networking) << "Failed to process ktx file " << _url; + _ktxResourceState = FAILED_TO_LOAD; + finishedLoading(false); + } _originalKtxDescriptor.reset(new ktx::KTXDescriptor(*header, keyValues, imageDescriptors)); // Create bare ktx in memory diff --git a/libraries/render-utils/src/MeshPartPayload.cpp b/libraries/render-utils/src/MeshPartPayload.cpp index 51ce0fffa7..e6ae6d21a1 100644 --- a/libraries/render-utils/src/MeshPartPayload.cpp +++ b/libraries/render-utils/src/MeshPartPayload.cpp @@ -544,7 +544,8 @@ void ModelMeshPartPayload::render(RenderArgs* args) const { } if (_fadeState == FADE_WAITING_TO_START) { - if (_model->isLoaded() && _model->getGeometry()->areTexturesLoaded()) { + //if (_model->isLoaded() && _model->getGeometry()->areTexturesLoaded()) { + if (_model->isLoaded()) { if (EntityItem::getEntitiesShouldFadeFunction()()) { _fadeStartTime = usecTimestampNow(); _fadeState = FADE_IN_PROGRESS; diff --git a/tests/gpu-test/CMakeLists.txt b/tests/gpu-test/CMakeLists.txt index 1712a5a3e1..c37e36b53b 100644 --- a/tests/gpu-test/CMakeLists.txt +++ b/tests/gpu-test/CMakeLists.txt @@ -3,7 +3,7 @@ AUTOSCRIBE_SHADER_LIB(gpu model render-utils) # This is not a testcase -- just set it up as a regular hifi project setup_hifi_project(Quick Gui OpenGL Script Widgets) set_target_properties(${TARGET_NAME} PROPERTIES FOLDER "Tests/manual-tests/") -link_hifi_libraries(networking gl gpu gpu-gl procedural shared fbx model model-networking animation script-engine render render-utils octree image) +link_hifi_libraries(networking gl gpu gpu-gl procedural shared fbx model model-networking animation script-engine render render-utils octree image ktx) package_libraries_for_deployment() target_nsight()