Merge pull request #10689 from Atlante45/fix/ktx

Fix KTX performance problems
This commit is contained in:
Brad Davis 2017-06-19 14:44:52 -07:00 committed by GitHub
commit 8aeeab30e7
4 changed files with 304 additions and 217 deletions

View file

@ -16,6 +16,8 @@
using namespace ktx; using namespace ktx;
int ktxDescriptorMetaTypeId = qRegisterMetaType<KTXDescriptor*>();
const Header::Identifier ktx::Header::IDENTIFIER {{ const Header::Identifier ktx::Header::IDENTIFIER {{
0xAB, 0x4B, 0x54, 0x58, 0x20, 0x31, 0x31, 0xBB, 0x0D, 0x0A, 0x1A, 0x0A 0xAB, 0x4B, 0x54, 0x58, 0x20, 0x31, 0x31, 0xBB, 0x0D, 0x0A, 0x1A, 0x0A
}}; }};

View file

@ -387,4 +387,6 @@ namespace ktx {
} }
Q_DECLARE_METATYPE(ktx::KTXDescriptor*);
#endif // hifi_ktx_KTX_h #endif // hifi_ktx_KTX_h

View file

@ -13,6 +13,8 @@
#include <mutex> #include <mutex>
#include <QtConcurrent/QtConcurrentRun>
#include <QCryptographicHash> #include <QCryptographicHash>
#include <QImageReader> #include <QImageReader>
#include <QRunnable> #include <QRunnable>
@ -303,13 +305,11 @@ void NetworkTexture::setImage(gpu::TexturePointer texture, int originalWidth,
_width = texture->getWidth(); _width = texture->getWidth();
_height = texture->getHeight(); _height = texture->getHeight();
setSize(texture->getStoredSize()); setSize(texture->getStoredSize());
} else {
// FIXME: If !gpuTexture, we failed to load!
_width = _height = 0;
qWarning() << "Texture did not load";
}
finishedLoading(true); finishedLoading(true);
} else {
_width = _height = 0;
finishedLoading(false);
}
emit networkTextureCreated(qWeakPointerCast<NetworkTexture, Resource> (_self)); emit networkTextureCreated(qWeakPointerCast<NetworkTexture, Resource> (_self));
} }
@ -382,8 +382,7 @@ void NetworkTexture::makeRequest() {
emit loading(); emit loading();
connect(_ktxHeaderRequest, &ResourceRequest::progress, this, &NetworkTexture::ktxHeaderRequestProgress); connect(_ktxHeaderRequest, &ResourceRequest::finished, this, &NetworkTexture::ktxInitialDataRequestFinished);
connect(_ktxHeaderRequest, &ResourceRequest::finished, this, &NetworkTexture::ktxHeaderRequestFinished);
_bytesReceived = _bytesTotal = _bytes = 0; _bytesReceived = _bytesTotal = _bytes = 0;
@ -407,18 +406,18 @@ void NetworkTexture::makeRequest() {
} }
void NetworkTexture::startRequestForNextMipLevel() { void NetworkTexture::startRequestForNextMipLevel() {
if (_lowestKnownPopulatedMip == 0) {
qWarning(networking) << "Requesting next mip level but all have been fulfilled: " << _lowestKnownPopulatedMip
<< " " << _textureSource->getGPUTexture()->minAvailableMipLevel() << " " << _url;
return;
}
if (_ktxResourceState == WAITING_FOR_MIP_REQUEST) {
auto self = _self.lock(); auto self = _self.lock();
if (!self) { if (!self) {
return; return;
} }
auto texture = _textureSource->getGPUTexture();
if (!texture || _ktxResourceState != WAITING_FOR_MIP_REQUEST) {
return;
}
_lowestKnownPopulatedMip = texture->minAvailableMipLevel();
if (_lowestRequestedMipLevel < _lowestKnownPopulatedMip) {
_ktxResourceState = PENDING_MIP_REQUEST; _ktxResourceState = PENDING_MIP_REQUEST;
init(false); init(false);
@ -453,6 +452,8 @@ void NetworkTexture::startMipRangeRequest(uint16_t low, uint16_t high) {
ByteRange range; ByteRange range;
range.fromInclusive = -HIGH_MIP_MAX_SIZE; range.fromInclusive = -HIGH_MIP_MAX_SIZE;
_ktxMipRequest->setByteRange(range); _ktxMipRequest->setByteRange(range);
connect(_ktxMipRequest, &ResourceRequest::finished, this, &NetworkTexture::ktxInitialDataRequestFinished);
} else { } else {
ByteRange range; ByteRange range;
range.fromInclusive = ktx::KTX_HEADER_SIZE + _originalKtxDescriptor->header.bytesOfKeyValueData range.fromInclusive = ktx::KTX_HEADER_SIZE + _originalKtxDescriptor->header.bytesOfKeyValueData
@ -460,120 +461,202 @@ void NetworkTexture::startMipRangeRequest(uint16_t low, uint16_t high) {
range.toExclusive = ktx::KTX_HEADER_SIZE + _originalKtxDescriptor->header.bytesOfKeyValueData range.toExclusive = ktx::KTX_HEADER_SIZE + _originalKtxDescriptor->header.bytesOfKeyValueData
+ _originalKtxDescriptor->images[high + 1]._imageOffset; + _originalKtxDescriptor->images[high + 1]._imageOffset;
_ktxMipRequest->setByteRange(range); _ktxMipRequest->setByteRange(range);
}
connect(_ktxMipRequest, &ResourceRequest::progress, this, &NetworkTexture::ktxMipRequestProgress);
connect(_ktxMipRequest, &ResourceRequest::finished, this, &NetworkTexture::ktxMipRequestFinished); connect(_ktxMipRequest, &ResourceRequest::finished, this, &NetworkTexture::ktxMipRequestFinished);
}
_ktxMipRequest->send(); _ktxMipRequest->send();
} }
void NetworkTexture::ktxHeaderRequestFinished() { // This is called when the header or top mips have been loaded
Q_ASSERT(_ktxResourceState == LOADING_INITIAL_DATA); void NetworkTexture::ktxInitialDataRequestFinished() {
if (!_ktxHeaderRequest || _ktxHeaderRequest->getState() != ResourceRequest::Finished ||
if (!_ktxHeaderRequest) { !_ktxMipRequest || _ktxMipRequest->getState() != ResourceRequest::Finished) {
// Wait for both request to be finished
return; return;
} }
_ktxHeaderRequestFinished = true; Q_ASSERT(_ktxResourceState == LOADING_INITIAL_DATA);
maybeHandleFinishedInitialLoad(); Q_ASSERT_X(_ktxHeaderRequest && _ktxMipRequest, __FUNCTION__, "Request should not be null while in ktxInitialDataRequestFinished");
PROFILE_ASYNC_END(resource, "Resource:" + getType(), QString::number(_requestID), {
{ "from_cache", _ktxHeaderRequest->loadedFromCache() },
{ "size_mb", _bytesTotal / 1000000.0 }
});
PROFILE_RANGE_EX(resource_parse_image, __FUNCTION__, 0xffff0000, 0, { { "url", _url.toString() } });
setSize(_bytesTotal);
TextureCache::requestCompleted(_self);
auto result = _ktxHeaderRequest->getResult();
if (result == ResourceRequest::Success) {
result = _ktxMipRequest->getResult();
}
if (result == ResourceRequest::Success) {
auto extraInfo = _url == _activeUrl ? "" : QString(", %1").arg(_activeUrl.toDisplayString());
qCDebug(networking).noquote() << QString("Request finished for %1%2").arg(_url.toDisplayString(), extraInfo);
_ktxHeaderData = _ktxHeaderRequest->getData();
_ktxHighMipData = _ktxMipRequest->getData();
handleFinishedInitialLoad();
} else {
if (handleFailedRequest(result)) {
_ktxResourceState = PENDING_INITIAL_LOAD;
} else {
_ktxResourceState = FAILED_TO_LOAD;
}
}
_ktxHeaderRequest->disconnect(this);
_ktxHeaderRequest->deleteLater();
_ktxHeaderRequest = nullptr;
_ktxMipRequest->disconnect(this);
_ktxMipRequest->deleteLater();
_ktxMipRequest = nullptr;
} }
void NetworkTexture::ktxMipRequestFinished() { void NetworkTexture::ktxMipRequestFinished() {
Q_ASSERT(_ktxResourceState == LOADING_INITIAL_DATA || _ktxResourceState == REQUESTING_MIP); Q_ASSERT_X(_ktxMipRequest, __FUNCTION__, "Request should not be null while in ktxMipRequestFinished");
Q_ASSERT(_ktxResourceState == REQUESTING_MIP);
if (!_ktxMipRequest) { PROFILE_ASYNC_END(resource, "Resource:" + getType(), QString::number(_requestID), {
{ "from_cache", _ktxMipRequest->loadedFromCache() },
{ "size_mb", _bytesTotal / 1000000.0 }
});
PROFILE_RANGE_EX(resource_parse_image, __FUNCTION__, 0xffff0000, 0, { { "url", _url.toString() } });
setSize(_bytesTotal);
if (!_ktxMipRequest || _ktxMipRequest != sender()) {
// This can happen in the edge case that a request is timed out, but a `finished` signal is emitted before it is deleted.
qWarning(networking) << "Received signal NetworkTexture::ktxMipRequestFinished from ResourceRequest that is not the current"
<< " request: " << sender() << ", " << _ktxMipRequest;
return; return;
} }
if (_ktxResourceState == LOADING_INITIAL_DATA) {
_ktxHighMipRequestFinished = true;
maybeHandleFinishedInitialLoad();
} else if (_ktxResourceState == REQUESTING_MIP) {
Q_ASSERT(_ktxMipLevelRangeInFlight.first != NULL_MIP_LEVEL);
TextureCache::requestCompleted(_self); TextureCache::requestCompleted(_self);
if (_ktxMipRequest->getResult() == ResourceRequest::Success) { auto result = _ktxMipRequest->getResult();
if (result == ResourceRequest::Success) {
auto extraInfo = _url == _activeUrl ? "" : QString(", %1").arg(_activeUrl.toDisplayString());
qCDebug(networking).noquote() << QString("Request finished for %1%2").arg(_url.toDisplayString(), extraInfo);
if (_ktxResourceState == REQUESTING_MIP) {
Q_ASSERT(_ktxMipLevelRangeInFlight.first != NULL_MIP_LEVEL);
Q_ASSERT(_ktxMipLevelRangeInFlight.second - _ktxMipLevelRangeInFlight.first == 0); Q_ASSERT(_ktxMipLevelRangeInFlight.second - _ktxMipLevelRangeInFlight.first == 0);
auto texture = _textureSource->getGPUTexture(); _ktxResourceState = WAITING_FOR_MIP_REQUEST;
if (texture) {
texture->assignStoredMip(_ktxMipLevelRangeInFlight.first,
_ktxMipRequest->getData().size(), reinterpret_cast<uint8_t*>(_ktxMipRequest->getData().data()));
if (texture->minAvailableMipLevel() <= _ktxMipLevelRangeInFlight.first) { auto self = _self;
_lowestKnownPopulatedMip = texture->minAvailableMipLevel(); auto url = _url;
_ktxResourceState = WAITING_FOR_MIP_REQUEST; auto data = _ktxMipRequest->getData();
} else { auto mipLevel = _ktxMipLevelRangeInFlight.first;
qWarning(networking) << "Failed to load mip: " << _url << ":" << _ktxMipLevelRangeInFlight.first; auto texture = _textureSource->getGPUTexture();
_ktxResourceState = FAILED_TO_LOAD; DependencyManager::get<StatTracker>()->incrementStat("PendingProcessing");
QtConcurrent::run(QThreadPool::globalInstance(), [self, data, mipLevel, url, texture] {
PROFILE_RANGE_EX(resource_parse_image, "NetworkTexture - Processing Mip Data", 0xffff0000, 0, { { "url", url.toString() } });
DependencyManager::get<StatTracker>()->decrementStat("PendingProcessing");
CounterStat counter("Processing");
auto originalPriority = QThread::currentThread()->priority();
if (originalPriority == QThread::InheritPriority) {
originalPriority = QThread::NormalPriority;
} }
} else { QThread::currentThread()->setPriority(QThread::LowPriority);
_ktxResourceState = WAITING_FOR_MIP_REQUEST; Finally restorePriority([originalPriority] { QThread::currentThread()->setPriority(originalPriority); });
qWarning(networking) << "Trying to update mips but texture is null";
auto resource = self.lock();
if (!resource) {
// Resource no longer exists, bail
return;
} }
finishedLoading(true);
Q_ASSERT_X(texture, "Async - NetworkTexture::ktxMipRequestFinished", "NetworkTexture should have been assigned a GPU texture by now.");
texture->assignStoredMip(mipLevel, data.size(), reinterpret_cast<const uint8_t*>(data.data()));
QMetaObject::invokeMethod(resource.data(), "setImage",
Q_ARG(gpu::TexturePointer, texture),
Q_ARG(int, texture->getWidth()),
Q_ARG(int, texture->getHeight()));
QMetaObject::invokeMethod(resource.data(), "startRequestForNextMipLevel");
});
} else { } else {
qWarning(networking) << "Mip request finished in an unexpected state: " << _ktxResourceState;
finishedLoading(false); finishedLoading(false);
if (handleFailedRequest(_ktxMipRequest->getResult())) { }
} else {
if (handleFailedRequest(result)) {
_ktxResourceState = PENDING_MIP_REQUEST; _ktxResourceState = PENDING_MIP_REQUEST;
} else { } else {
qWarning(networking) << "Failed to load mip: " << _url;
_ktxResourceState = FAILED_TO_LOAD; _ktxResourceState = FAILED_TO_LOAD;
} }
} }
_ktxMipRequest->disconnect(this);
_ktxMipRequest->deleteLater(); _ktxMipRequest->deleteLater();
_ktxMipRequest = nullptr; _ktxMipRequest = nullptr;
if (_ktxResourceState == WAITING_FOR_MIP_REQUEST && _lowestRequestedMipLevel < _lowestKnownPopulatedMip) {
startRequestForNextMipLevel();
}
} else {
qWarning() << "Mip request finished in an unexpected state: " << _ktxResourceState;
}
} }
// This is called when the header or top mips have been loaded // This is called when the header and top mips have been loaded
void NetworkTexture::maybeHandleFinishedInitialLoad() { void NetworkTexture::handleFinishedInitialLoad() {
Q_ASSERT(_ktxResourceState == LOADING_INITIAL_DATA); Q_ASSERT(_ktxResourceState == LOADING_INITIAL_DATA);
Q_ASSERT(!_ktxHeaderData.isEmpty() && !_ktxHighMipData.isEmpty());
if (_ktxHeaderRequestFinished && _ktxHighMipRequestFinished) {
TextureCache::requestCompleted(_self);
if (_ktxHeaderRequest->getResult() != ResourceRequest::Success || _ktxMipRequest->getResult() != ResourceRequest::Success) {
if (handleFailedRequest(_ktxMipRequest->getResult())) {
_ktxResourceState = PENDING_INITIAL_LOAD;
}
else {
_ktxResourceState = FAILED_TO_LOAD;
}
_ktxHeaderRequest->deleteLater();
_ktxHeaderRequest = nullptr;
_ktxMipRequest->deleteLater();
_ktxMipRequest = nullptr;
} else {
// create ktx... // create ktx...
auto ktxHeaderData = _ktxHeaderRequest->getData(); auto ktxHeaderData = _ktxHeaderData;
auto ktxHighMipData = _ktxMipRequest->getData(); auto ktxHighMipData = _ktxHighMipData;
_ktxHeaderData.clear();
_ktxHighMipData.clear();
_ktxResourceState = WAITING_FOR_MIP_REQUEST;
auto self = _self;
auto url = _url;
DependencyManager::get<StatTracker>()->incrementStat("PendingProcessing");
QtConcurrent::run(QThreadPool::globalInstance(), [self, ktxHeaderData, ktxHighMipData, url] {
PROFILE_RANGE_EX(resource_parse_image, "NetworkTexture - Processing Initial Data", 0xffff0000, 0, { { "url", url.toString() } });
DependencyManager::get<StatTracker>()->decrementStat("PendingProcessing");
CounterStat counter("Processing");
auto originalPriority = QThread::currentThread()->priority();
if (originalPriority == QThread::InheritPriority) {
originalPriority = QThread::NormalPriority;
}
QThread::currentThread()->setPriority(QThread::LowPriority);
Finally restorePriority([originalPriority] { QThread::currentThread()->setPriority(originalPriority); });
auto resource = self.lock();
if (!resource) {
// Resource no longer exists, bail
return;
}
auto header = reinterpret_cast<const ktx::Header*>(ktxHeaderData.data()); auto header = reinterpret_cast<const ktx::Header*>(ktxHeaderData.data());
if (!ktx::checkIdentifier(header->identifier)) { if (!ktx::checkIdentifier(header->identifier)) {
qWarning() << "Cannot load " << _url << ", invalid header identifier"; qWarning() << "Cannot load " << url << ", invalid header identifier";
_ktxResourceState = FAILED_TO_LOAD; QMetaObject::invokeMethod(resource.data(), "setImage",
finishedLoading(false); Q_ARG(gpu::TexturePointer, nullptr),
Q_ARG(int, 0),
Q_ARG(int, 0));
return; return;
} }
auto kvSize = header->bytesOfKeyValueData; auto kvSize = header->bytesOfKeyValueData;
if (kvSize > (ktxHeaderData.size() - ktx::KTX_HEADER_SIZE)) { if (kvSize > (ktxHeaderData.size() - ktx::KTX_HEADER_SIZE)) {
qWarning() << "Cannot load " << _url << ", did not receive all kv data with initial request"; qWarning() << "Cannot load " << url << ", did not receive all kv data with initial request";
_ktxResourceState = FAILED_TO_LOAD; QMetaObject::invokeMethod(resource.data(), "setImage",
finishedLoading(false); Q_ARG(gpu::TexturePointer, nullptr),
Q_ARG(int, 0),
Q_ARG(int, 0));
return; return;
} }
@ -581,11 +664,16 @@ void NetworkTexture::maybeHandleFinishedInitialLoad() {
auto imageDescriptors = header->generateImageDescriptors(); auto imageDescriptors = header->generateImageDescriptors();
if (imageDescriptors.size() == 0) { if (imageDescriptors.size() == 0) {
qWarning(networking) << "Failed to process ktx file " << _url; qWarning(networking) << "Failed to process ktx file " << url;
_ktxResourceState = FAILED_TO_LOAD; QMetaObject::invokeMethod(resource.data(), "setImage",
finishedLoading(false); Q_ARG(gpu::TexturePointer, nullptr),
Q_ARG(int, 0),
Q_ARG(int, 0));
return;
} }
_originalKtxDescriptor.reset(new ktx::KTXDescriptor(*header, keyValues, imageDescriptors)); auto originalKtxDescriptor = new ktx::KTXDescriptor(*header, keyValues, imageDescriptors);
QMetaObject::invokeMethod(resource.data(), "setOriginalDescriptor",
Q_ARG(ktx::KTXDescriptor*, originalKtxDescriptor));
// Create bare ktx in memory // Create bare ktx in memory
auto found = std::find_if(keyValues.begin(), keyValues.end(), [](const ktx::KeyValue& val) -> bool { auto found = std::find_if(keyValues.begin(), keyValues.end(), [](const ktx::KeyValue& val) -> bool {
@ -595,8 +683,10 @@ void NetworkTexture::maybeHandleFinishedInitialLoad() {
std::string hash; std::string hash;
if (found == keyValues.end() || found->_value.size() != gpu::SOURCE_HASH_BYTES) { if (found == keyValues.end() || found->_value.size() != gpu::SOURCE_HASH_BYTES) {
qWarning("Invalid source hash key found, bailing"); qWarning("Invalid source hash key found, bailing");
_ktxResourceState = FAILED_TO_LOAD; QMetaObject::invokeMethod(resource.data(), "setImage",
finishedLoading(false); Q_ARG(gpu::TexturePointer, nullptr),
Q_ARG(int, 0),
Q_ARG(int, 0));
return; return;
} else { } else {
// at this point the source hash is in binary 16-byte form // at this point the source hash is in binary 16-byte form
@ -615,7 +705,6 @@ void NetworkTexture::maybeHandleFinishedInitialLoad() {
texture = gpu::Texture::unserialize(ktxFile); texture = gpu::Texture::unserialize(ktxFile);
if (texture) { if (texture) {
texture = textureCache->cacheTextureByHash(hash, texture); texture = textureCache->cacheTextureByHash(hash, texture);
_file = ktxFile;
} }
} }
} }
@ -625,7 +714,10 @@ void NetworkTexture::maybeHandleFinishedInitialLoad() {
auto memKtx = ktx::KTX::createBare(*header, keyValues); auto memKtx = ktx::KTX::createBare(*header, keyValues);
if (!memKtx) { if (!memKtx) {
qWarning() << " Ktx could not be created, bailing"; qWarning() << " Ktx could not be created, bailing";
finishedLoading(false); QMetaObject::invokeMethod(resource.data(), "setImage",
Q_ARG(gpu::TexturePointer, nullptr),
Q_ARG(int, 0),
Q_ARG(int, 0));
return; return;
} }
@ -635,12 +727,12 @@ void NetworkTexture::maybeHandleFinishedInitialLoad() {
KTXFilePointer file; KTXFilePointer file;
auto& ktxCache = textureCache->_ktxCache; auto& ktxCache = textureCache->_ktxCache;
if (!memKtx || !(file = ktxCache.writeFile(data, KTXCache::Metadata(filename, length)))) { if (!memKtx || !(file = ktxCache.writeFile(data, KTXCache::Metadata(filename, length)))) {
qCWarning(modelnetworking) << _url << " failed to write cache file"; qCWarning(modelnetworking) << url << " failed to write cache file";
_ktxResourceState = FAILED_TO_LOAD; QMetaObject::invokeMethod(resource.data(), "setImage",
finishedLoading(false); Q_ARG(gpu::TexturePointer, nullptr),
Q_ARG(int, 0),
Q_ARG(int, 0));
return; return;
} else {
_file = file;
} }
auto newKtxDescriptor = memKtx->toDescriptor(); auto newKtxDescriptor = memKtx->toDescriptor();
@ -649,9 +741,9 @@ void NetworkTexture::maybeHandleFinishedInitialLoad() {
texture->setKtxBacking(file); texture->setKtxBacking(file);
texture->setSource(filename); texture->setSource(filename);
auto& images = _originalKtxDescriptor->images; auto& images = originalKtxDescriptor->images;
size_t imageSizeRemaining = ktxHighMipData.size(); size_t imageSizeRemaining = ktxHighMipData.size();
uint8_t* ktxData = reinterpret_cast<uint8_t*>(ktxHighMipData.data()); const uint8_t* ktxData = reinterpret_cast<const uint8_t*>(ktxHighMipData.data());
ktxData += ktxHighMipData.size(); ktxData += ktxHighMipData.size();
// TODO Move image offset calculation to ktx ImageDescriptor // TODO Move image offset calculation to ktx ImageDescriptor
for (int level = static_cast<int>(images.size()) - 1; level >= 0; --level) { for (int level = static_cast<int>(images.size()) - 1; level >= 0; --level) {
@ -671,18 +763,13 @@ void NetworkTexture::maybeHandleFinishedInitialLoad() {
texture = textureCache->cacheTextureByHash(filename, texture); texture = textureCache->cacheTextureByHash(filename, texture);
} }
_lowestKnownPopulatedMip = texture->minAvailableMipLevel(); QMetaObject::invokeMethod(resource.data(), "setImage",
Q_ARG(gpu::TexturePointer, texture),
Q_ARG(int, texture->getWidth()),
Q_ARG(int, texture->getHeight()));
_ktxResourceState = WAITING_FOR_MIP_REQUEST; QMetaObject::invokeMethod(resource.data(), "startRequestForNextMipLevel");
setImage(texture, header->getPixelWidth(), header->getPixelHeight()); });
_ktxHeaderRequest->deleteLater();
_ktxHeaderRequest = nullptr;
_ktxMipRequest->deleteLater();
_ktxMipRequest = nullptr;
}
startRequestForNextMipLevel();
}
} }
void NetworkTexture::downloadFinished(const QByteArray& data) { void NetworkTexture::downloadFinished(const QByteArray& data) {
@ -845,11 +932,11 @@ void ImageReader::read() {
const char* data = reinterpret_cast<const char*>(memKtx->_storage->data()); const char* data = reinterpret_cast<const char*>(memKtx->_storage->data());
size_t length = memKtx->_storage->size(); size_t length = memKtx->_storage->size();
auto& ktxCache = textureCache->_ktxCache; auto& ktxCache = textureCache->_ktxCache;
networkTexture->_file = ktxCache.writeFile(data, KTXCache::Metadata(hash, length)); // auto file = ktxCache.writeFile(data, KTXCache::Metadata(hash, length));
if (!networkTexture->_file) { if (!file) {
qCWarning(modelnetworking) << _url << "file cache failed"; qCWarning(modelnetworking) << _url << "file cache failed";
} else { } else {
texture->setKtxBacking(networkTexture->_file); texture->setKtxBacking(file);
} }
} else { } else {
qCWarning(modelnetworking) << "Unable to serialize texture to KTX " << _url; qCWarning(modelnetworking) << "Unable to serialize texture to KTX " << _url;

View file

@ -58,14 +58,13 @@ public:
void refresh() override; void refresh() override;
Q_INVOKABLE void setOriginalDescriptor(ktx::KTXDescriptor* descriptor) { _originalKtxDescriptor.reset(descriptor); }
signals: signals:
void networkTextureCreated(const QWeakPointer<NetworkTexture>& self); void networkTextureCreated(const QWeakPointer<NetworkTexture>& self);
public slots: public slots:
void ktxHeaderRequestProgress(uint64_t bytesReceived, uint64_t bytesTotal) { } void ktxInitialDataRequestFinished();
void ktxHeaderRequestFinished();
void ktxMipRequestProgress(uint64_t bytesReceived, uint64_t bytesTotal) { }
void ktxMipRequestFinished(); void ktxMipRequestFinished();
protected: protected:
@ -78,10 +77,10 @@ protected:
Q_INVOKABLE void loadContent(const QByteArray& content); Q_INVOKABLE void loadContent(const QByteArray& content);
Q_INVOKABLE void setImage(gpu::TexturePointer texture, int originalWidth, int originalHeight); Q_INVOKABLE void setImage(gpu::TexturePointer texture, int originalWidth, int originalHeight);
void startRequestForNextMipLevel(); Q_INVOKABLE void startRequestForNextMipLevel();
void startMipRangeRequest(uint16_t low, uint16_t high); void startMipRangeRequest(uint16_t low, uint16_t high);
void maybeHandleFinishedInitialLoad(); void handleFinishedInitialLoad();
private: private:
friend class KTXReader; friend class KTXReader;
@ -102,16 +101,13 @@ private:
bool _sourceIsKTX { false }; bool _sourceIsKTX { false };
KTXResourceState _ktxResourceState { PENDING_INITIAL_LOAD }; KTXResourceState _ktxResourceState { PENDING_INITIAL_LOAD };
// TODO Can this be removed?
KTXFilePointer _file;
// The current mips that are currently being requested w/ _ktxMipRequest // The current mips that are currently being requested w/ _ktxMipRequest
std::pair<uint16_t, uint16_t> _ktxMipLevelRangeInFlight{ NULL_MIP_LEVEL, NULL_MIP_LEVEL }; std::pair<uint16_t, uint16_t> _ktxMipLevelRangeInFlight{ NULL_MIP_LEVEL, NULL_MIP_LEVEL };
ResourceRequest* _ktxHeaderRequest { nullptr }; ResourceRequest* _ktxHeaderRequest { nullptr };
ResourceRequest* _ktxMipRequest { nullptr }; ResourceRequest* _ktxMipRequest { nullptr };
bool _ktxHeaderRequestFinished{ false }; QByteArray _ktxHeaderData;
bool _ktxHighMipRequestFinished{ false }; QByteArray _ktxHighMipData;
uint16_t _lowestRequestedMipLevel { NULL_MIP_LEVEL }; uint16_t _lowestRequestedMipLevel { NULL_MIP_LEVEL };
uint16_t _lowestKnownPopulatedMip { NULL_MIP_LEVEL }; uint16_t _lowestKnownPopulatedMip { NULL_MIP_LEVEL };