Merge pull request #7553 from zzmp/fix/tex-invoke-method

Fix ImageReader threading issues
This commit is contained in:
Brad Hefta-Gaub 2016-04-04 18:29:24 -07:00
commit ff4f693267

View file

@ -13,20 +13,22 @@
#include <mutex> #include <mutex>
#include <glm/glm.hpp>
#include <glm/gtc/random.hpp>
#include <QNetworkReply> #include <QNetworkReply>
#include <QPainter> #include <QPainter>
#include <QRunnable> #include <QRunnable>
#include <QThreadPool> #include <QThreadPool>
#include <qimagereader.h> #include <QImageReader>
#include <shared/NsightHelpers.h> #include <glm/glm.hpp>
#include <PathUtils.h> #include <glm/gtc/random.hpp>
#include <gpu/Batch.h> #include <gpu/Batch.h>
#include <shared/NsightHelpers.h>
#include <Finally.h>
#include <PathUtils.h>
#include "ModelNetworkingLogging.h" #include "ModelNetworkingLogging.h"
TextureCache::TextureCache() { TextureCache::TextureCache() {
@ -242,14 +244,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;
}; };
@ -263,9 +265,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)
{ {
@ -286,17 +288,19 @@ void ImageReader::run() {
originalPriority = QThread::NormalPriority; originalPriority = QThread::NormalPriority;
} }
QThread::currentThread()->setPriority(QThread::LowPriority); QThread::currentThread()->setPriority(QThread::LowPriority);
Finally restorePriority([originalPriority]{
QThread::currentThread()->setPriority(originalPriority);
});
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";
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());
@ -315,17 +319,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.
PROFILE_RANGE_EX(__FUNCTION__"::textureLoader", 0xffffff00, nullptr); auto resource = _resource.toStrongRef();
theTexture = ntex->getTextureLoader()(image, _url.toString().toStdString()); if (!resource) {
qCWarning(modelnetworking) << "Abandoning load of" << _url << "; could not get strong ref";
return;
} }
QMetaObject::invokeMethod(texture.data(), "setImage", auto url = _url.toString().toStdString();
Q_ARG(void*, theTexture),
PROFILE_RANGE_EX(__FUNCTION__"::textureLoader", 0xffffff00, nullptr);
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)); Q_ARG(int, originalWidth), Q_ARG(int, originalHeight));
QThread::currentThread()->setPriority(originalPriority); }
} }
void NetworkTexture::setImage(void* voidTexture, int originalWidth, void NetworkTexture::setImage(void* voidTexture, int originalWidth,