Fix loading standalone baked textures from Asset Server

NetworkTexture was not properly handling redirected ATP files. For
instance, if going from .jpg -> .ktx, the NetworkTexture class needs to
be aware of this so it can stop the current request and make multiple
requests for the individual mip levels.
This commit is contained in:
Ryan Huffman 2017-08-28 15:37:15 -07:00
parent ca62e7168c
commit e9258ec97a
9 changed files with 63 additions and 18 deletions

View file

@ -49,7 +49,7 @@ static const int INTERFACE_RUNNING_CHECK_FREQUENCY_MS = 1000;
const QString ASSET_SERVER_LOGGING_TARGET_NAME = "asset-server";
static const QStringList BAKEABLE_MODEL_EXTENSIONS = { "fbx" };
static const QList<QByteArray> BAKEABLE_TEXTURE_EXTENSIONS = QImageReader::supportedImageFormats();
static QStringList BAKEABLE_TEXTURE_EXTENSIONS;
static const QString BAKED_MODEL_SIMPLE_NAME = "asset.fbx";
static const QString BAKED_TEXTURE_SIMPLE_NAME = "texture.ktx";
@ -71,7 +71,8 @@ void BakeAssetTask::run() {
};
} else {
baker = std::unique_ptr<TextureBaker> {
new TextureBaker(QUrl("file:///" + _filePath), image::TextureUsage::CUBE_TEXTURE, PathUtils::generateTemporaryDir())
new TextureBaker(QUrl("file:///" + _filePath), image::TextureUsage::CUBE_TEXTURE,
PathUtils::generateTemporaryDir())
};
}
@ -198,7 +199,7 @@ bool AssetServer::needsToBeBaked(const AssetPath& path, const AssetHash& assetHa
auto extension = path.mid(dotIndex + 1);
QString bakedFilename;
if (BAKEABLE_MODEL_EXTENSIONS.contains(extension)) {
bakedFilename = BAKED_MODEL_SIMPLE_NAME;
} else if (BAKEABLE_TEXTURE_EXTENSIONS.contains(extension.toLocal8Bit()) && hasMetaFile(assetHash)) {
@ -247,6 +248,8 @@ AssetServer::AssetServer(ReceivedMessage& message) :
_transferTaskPool(this),
_bakingTaskPool(this)
{
BAKEABLE_TEXTURE_EXTENSIONS = TextureBaker::getSupportedFormats();
qDebug() << "Supported baking texture formats:" << BAKEABLE_MODEL_EXTENSIONS;
// Most of the work will be I/O bound, reading from disk and constructing packet objects,
// so the ideal is greater than the number of cores on the system.

View file

@ -43,6 +43,14 @@ void TextureBaker::bake() {
loadTexture();
}
const QStringList TextureBaker::getSupportedFormats() {
auto formats = QImageReader::supportedImageFormats();
QStringList stringFormats;
std::transform(formats.begin(), formats.end(), std::back_inserter(stringFormats),
[](auto& format) -> QString { return format; });
return stringFormats;
}
void TextureBaker::loadTexture() {
// check if the texture is local or first needs to be downloaded
if (_textureURL.isLocalFile()) {

View file

@ -15,6 +15,7 @@
#include <QtCore/QObject>
#include <QtCore/QUrl>
#include <QtCore/QRunnable>
#include <QImageReader>
#include <image/Image.h>
@ -28,6 +29,8 @@ class TextureBaker : public Baker {
public:
TextureBaker(const QUrl& textureURL, image::TextureUsage::Type textureType, const QDir& outputDirectory);
static const QStringList getSupportedFormats();
const QByteArray& getOriginalTexture() const { return _originalTexture; }
QUrl getTextureURL() const { return _textureURL; }

View file

@ -299,6 +299,8 @@ NetworkTexture::NetworkTexture(const QUrl& url, image::TextureUsage::Type type,
_textureSource = std::make_shared<gpu::TextureSource>();
_lowestRequestedMipLevel = 0;
_shouldFailOnRedirect = !_sourceIsKTX;
if (type == image::TextureUsage::CUBE_TEXTURE) {
setLoadPriority(this, SKYBOX_LOAD_PRIORITY);
} else if (_sourceIsKTX) {
@ -428,6 +430,21 @@ void NetworkTexture::makeRequest() {
}
bool NetworkTexture::handleFailedRequest(ResourceRequest::Result result) {
if (!_sourceIsKTX && result == ResourceRequest::Result::RedirectFail) {
auto newPath = _request->getRelativePathUrl();
if (newPath.fileName().endsWith(".ktx")) {
qDebug() << "Redirecting to" << newPath << "from" << _url;
_sourceIsKTX = true;
_activeUrl = newPath;
_shouldFailOnRedirect = false;
makeRequest();
return true;
}
}
return Resource::handleFailedRequest(result);
}
void NetworkTexture::startRequestForNextMipLevel() {
auto self = _self.lock();
if (!self) {
@ -527,7 +544,7 @@ void NetworkTexture::ktxInitialDataRequestFinished() {
_ktxHighMipData = _ktxMipRequest->getData();
handleFinishedInitialLoad();
} else {
if (handleFailedRequest(result)) {
if (Resource::handleFailedRequest(result)) {
_ktxResourceState = PENDING_INITIAL_LOAD;
} else {
_ktxResourceState = FAILED_TO_LOAD;
@ -616,7 +633,7 @@ void NetworkTexture::ktxMipRequestFinished() {
finishedLoading(false);
}
} else {
if (handleFailedRequest(result)) {
if (Resource::handleFailedRequest(result)) {
_ktxResourceState = PENDING_MIP_REQUEST;
} else {
_ktxResourceState = FAILED_TO_LOAD;

View file

@ -75,6 +75,8 @@ protected:
virtual void downloadFinished(const QByteArray& data) override;
bool handleFailedRequest(ResourceRequest::Result result) override;
Q_INVOKABLE void loadContent(const QByteArray& content);
Q_INVOKABLE void setImage(gpu::TexturePointer texture, int originalWidth, int originalHeight);

View file

@ -82,19 +82,23 @@ void AssetResourceRequest::requestMappingForPath(const AssetPath& path) {
Q_ASSERT(_state == InProgress);
Q_ASSERT(request == _assetMappingRequest);
bool failed = false;
switch (request->getError()) {
case MappingRequest::NoError:
// we have no error, we should have a resulting hash - use that to send of a request for that asset
qCDebug(networking) << "Got mapping for:" << path << "=>" << request->getHash();
requestHash(request->getHash());
statTracker->incrementStat(STAT_ATP_MAPPING_REQUEST_SUCCESS);
// if we got a redirected path we need to store that with the resource request as relative path URL
if (request->wasRedirected()) {
qDebug() << "Request was redirected";
if (request->wasRedirected() && _failOnRedirect) {
_relativePathURL = ATP_SCHEME + request->getRedirectedPath();
_result = RedirectFail;
failed = true;
} else {
requestHash(request->getHash());
}
break;
@ -113,17 +117,20 @@ void AssetResourceRequest::requestMappingForPath(const AssetPath& path) {
break;
}
// since we've failed we know we are finished
_state = Finished;
emit finished();
statTracker->incrementStat(STAT_ATP_MAPPING_REQUEST_FAILED);
statTracker->incrementStat(STAT_ATP_REQUEST_FAILED);
failed = true;
break;
}
}
if (failed) {
_state = Finished;
emit finished();
statTracker->incrementStat(STAT_ATP_MAPPING_REQUEST_FAILED);
statTracker->incrementStat(STAT_ATP_REQUEST_FAILED);
}
_assetMappingRequest->deleteLater();
_assetMappingRequest = nullptr;
});

View file

@ -687,8 +687,9 @@ void Resource::makeRequest() {
PROFILE_ASYNC_END(resource, "Resource:" + getType(), QString::number(_requestID));
return;
}
_request->setByteRange(_requestByteRange);
_request->setFailOnRedirect(_shouldFailOnRedirect);
qCDebug(resourceLog).noquote() << "Starting request for:" << _url.toDisplayString();
emit loading();

View file

@ -449,12 +449,13 @@ protected:
Q_INVOKABLE void allReferencesCleared();
/// Return true if the resource will be retried
bool handleFailedRequest(ResourceRequest::Result result);
virtual bool handleFailedRequest(ResourceRequest::Result result);
QUrl _url;
QUrl _effectiveBaseURL{ _url };
QUrl _activeUrl;
ByteRange _requestByteRange;
bool _shouldFailOnRedirect { false };
// _loaded == true means we are in a loaded and usable state. It is possible that there may still be
// active requests/loading while in this state. Example: Progressive KTX downloads, where higher resolution

View file

@ -57,7 +57,8 @@ public:
AccessDenied,
InvalidByteRange,
InvalidURL,
NotFound
NotFound,
RedirectFail
};
Q_ENUM(Result)
@ -70,6 +71,7 @@ public:
bool loadedFromCache() const { return _loadedFromCache; }
bool getRangeRequestSuccessful() const { return _rangeRequestSuccessful; }
bool getTotalSizeOfResource() const { return _totalSizeOfResource; }
void setFailOnRedirect(bool failOnRedirect) { _failOnRedirect = failOnRedirect; }
void setCacheEnabled(bool value) { _cacheEnabled = value; }
void setByteRange(ByteRange byteRange) { _byteRange = byteRange; }
@ -89,6 +91,7 @@ protected:
State _state { NotStarted };
Result _result;
QByteArray _data;
bool _failOnRedirect { false };
bool _cacheEnabled { true };
bool _loadedFromCache { false };
ByteRange _byteRange;