Fix ImageReader threading issues

This commit is contained in:
Zach Pomerantz 2016-04-03 11:53:59 -07:00
parent d899d7d696
commit 79e5286335

View file

@ -196,7 +196,7 @@ NetworkTexture::NetworkTexture(const QUrl& url, const TextureLoaderFunc& texture
{ {
_textureLoader = textureLoader; _textureLoader = textureLoader;
} }
NetworkTexture::TextureLoaderFunc NetworkTexture::getTextureLoader() const { NetworkTexture::TextureLoaderFunc NetworkTexture::getTextureLoader() const {
switch (_type) { switch (_type) {
case CUBE_TEXTURE: { case CUBE_TEXTURE: {
@ -240,14 +240,14 @@ NetworkTexture::TextureLoaderFunc NetworkTexture::getTextureLoader() const {
class ImageReader : public QRunnable { class ImageReader : public QRunnable {
public: public:
ImageReader(const QWeakPointer<Resource>& texture, const QByteArray& data, const QUrl& url = QUrl()); ImageReader(const QWeakPointer<Resource>& resource, const QByteArray& data, const QUrl& url = QUrl());
virtual void run(); virtual void run();
private: private:
static void listSupportedImageFormats(); static void listSupportedImageFormats();
QWeakPointer<Resource> _texture; QWeakPointer<Resource> _resource;
QUrl _url; QUrl _url;
QByteArray _content; QByteArray _content;
}; };
@ -261,9 +261,9 @@ void NetworkTexture::loadContent(const QByteArray& content) {
QThreadPool::globalInstance()->start(new ImageReader(_self, content, _url)); QThreadPool::globalInstance()->start(new ImageReader(_self, content, _url));
} }
ImageReader::ImageReader(const QWeakPointer<Resource>& texture, const QByteArray& data, ImageReader::ImageReader(const QWeakPointer<Resource>& resource, const QByteArray& data,
const QUrl& url) : const QUrl& url) :
_texture(texture), _resource(resource),
_url(url), _url(url),
_content(data) _content(data)
{ {
@ -284,25 +284,25 @@ void ImageReader::run() {
} }
QThread::currentThread()->setPriority(QThread::LowPriority); QThread::currentThread()->setPriority(QThread::LowPriority);
auto texture = _texture.toStrongRef(); if (!_resource.data()) {
if (!texture) { qCWarning(modelnetworking) << "Abandoning load of" << _url << "; could not get strong ref";
qCWarning(modelnetworking) << "Could not get strong ref"; QThread::currentThread()->setPriority(originalPriority);
return; return;
} }
listSupportedImageFormats(); listSupportedImageFormats();
// try to help the QImage loader by extracting the image file format from the url filename ext // Help the QImage loader by extracting the image file format from the url filename ext.
// Some tga are not created properly for example without it // Some tga are not created properly without it.
auto filename = _url.fileName().toStdString(); auto filename = _url.fileName().toStdString();
auto filenameExtension = filename.substr(filename.find_last_of('.') + 1); auto filenameExtension = filename.substr(filename.find_last_of('.') + 1);
QImage image = QImage::fromData(_content, filenameExtension.c_str()); QImage image = QImage::fromData(_content, filenameExtension.c_str());
// Note that QImage.format is the pixel format which is different from the "format" of the image file... // Note that QImage.format is the pixel format which is different from the "format" of the image file...
auto imageFormat = image.format(); auto imageFormat = image.format();
int originalWidth = image.width(); int originalWidth = image.width();
int originalHeight = image.height(); int originalHeight = image.height();
if (originalWidth == 0 || originalHeight == 0 || imageFormat == QImage::Format_Invalid) { if (originalWidth == 0 || originalHeight == 0 || imageFormat == QImage::Format_Invalid) {
if (filenameExtension.empty()) { if (filenameExtension.empty()) {
qCDebug(modelnetworking) << "QImage failed to create from content, no file extension:" << _url; qCDebug(modelnetworking) << "QImage failed to create from content, no file extension:" << _url;
@ -312,15 +312,31 @@ void ImageReader::run() {
return; return;
} }
gpu::Texture* theTexture = nullptr; gpu::Texture* texture = nullptr;
auto ntex = texture.dynamicCast<NetworkTexture>(); {
if (ntex) { // Double-check the resource still exists between long operations.
theTexture = ntex->getTextureLoader()(image, _url.toString().toStdString()); auto resource = _resource.toStrongRef();
if (!resource) {
qCWarning(modelnetworking) << "Abandoning load of" << _url << "; could not get strong ref";
QThread::currentThread()->setPriority(originalPriority);
return;
}
auto url = _url.toString().toStdString();
texture = resource.dynamicCast<NetworkTexture>()->getTextureLoader()(image, url);
}
// Ensure the resource has not been deleted, and won't be while invokeMethod is in flight.
auto resource = _resource.toStrongRef();
if (!resource) {
qCWarning(modelnetworking) << "Abandoning load of" << _url << "; could not get strong ref";
delete texture;
} else {
QMetaObject::invokeMethod(resource.data(), "setImage", Qt::BlockingQueuedConnection,
Q_ARG(void*, texture),
Q_ARG(int, originalWidth), Q_ARG(int, originalHeight));
} }
QMetaObject::invokeMethod(texture.data(), "setImage",
Q_ARG(void*, theTexture),
Q_ARG(int, originalWidth), Q_ARG(int, originalHeight));
QThread::currentThread()->setPriority(originalPriority); QThread::currentThread()->setPriority(originalPriority);
} }
@ -328,9 +344,9 @@ void NetworkTexture::setImage(void* voidTexture, int originalWidth,
int originalHeight) { int originalHeight) {
_originalWidth = originalWidth; _originalWidth = originalWidth;
_originalHeight = originalHeight; _originalHeight = originalHeight;
gpu::Texture* texture = static_cast<gpu::Texture*>(voidTexture); gpu::Texture* texture = static_cast<gpu::Texture*>(voidTexture);
// Passing ownership // Passing ownership
_textureSource->resetTexture(texture); _textureSource->resetTexture(texture);
auto gpuTexture = _textureSource->getGPUTexture(); auto gpuTexture = _textureSource->getGPUTexture();