Merge pull request #186 from aws-lumberyard-dev/Atom/mnaumov/ATOM-15296

[ATOM-15296] Fixing deadlock related to thumbnails
This commit is contained in:
AMZN-mnaumov
2021-04-21 21:24:38 -07:00
committed by GitHub
6 changed files with 43 additions and 4 deletions
@@ -140,7 +140,7 @@ namespace AzToolsFramework
else
{
QPixmap pixmap = thumbnail->GetPixmap(size);
painter->drawPixmap(point.x(), point.y(), size.width(), size.height(), pixmap);
painter->drawPixmap(point, pixmap.scaled(size, Qt::IgnoreAspectRatio, Qt::SmoothTransformation));
}
return m_iconSize;
}
@@ -10,12 +10,14 @@
*
*/
#include <AzToolsFramework/Thumbnails/ThumbnailerBus.h>
#include <AzToolsFramework/Thumbnails/Thumbnail.h>
AZ_PUSH_DISABLE_WARNING(4127 4251 4800 4244, "-Wunknown-warning-option") // 4127: conditional expression is constant
// 4251: 'QTextCodec::ConverterState::flags': class 'QFlags<QTextCodec::ConversionFlag>' needs to have dll-interface to be used by clients of struct 'QTextCodec::ConverterState'
// 4800: 'QTextBoundaryFinderPrivate *const ': forcing value to bool 'true' or 'false' (performance warning)
// 4244: conversion from 'int' to 'qint8', possible loss of data
#include <QtConcurrent/QtConcurrent>
#include <QThreadPool>
AZ_POP_DISABLE_WARNING
namespace AzToolsFramework
@@ -80,7 +82,11 @@ namespace AzToolsFramework
if (m_state == State::Unloaded)
{
m_state = State::Loading;
QFuture<void> future = QtConcurrent::run([this](){ LoadThread(); });
QThreadPool* threadPool;
ThumbnailContextRequestBus::BroadcastResult(
threadPool,
&ThumbnailContextRequestBus::Handler::GetThreadPool);
QFuture<void> future = QtConcurrent::run(threadPool, [this](){ LoadThread(); });
m_watcher.setFuture(future);
}
}
@@ -28,10 +28,15 @@ namespace AzToolsFramework
: m_missingThumbnail(new MissingThumbnail(thumbnailSize))
, m_loadingThumbnail(new LoadingThumbnail(thumbnailSize))
, m_thumbnailSize(thumbnailSize)
, m_threadPool(this)
{
ThumbnailContextRequestBus::Handler::BusConnect();
}
ThumbnailContext::~ThumbnailContext() = default;
ThumbnailContext::~ThumbnailContext()
{
ThumbnailContextRequestBus::Handler::BusDisconnect();
}
bool ThumbnailContext::IsLoading(SharedThumbnailKey key)
{
@@ -53,6 +58,11 @@ namespace AzToolsFramework
AzToolsFramework::AssetBrowser::AssetBrowserViewRequestBus::Broadcast(&AzToolsFramework::AssetBrowser::AssetBrowserViewRequests::Update);
}
QThreadPool* ThumbnailContext::GetThreadPool()
{
return &m_threadPool;
}
SharedThumbnail ThumbnailContext::GetThumbnail(SharedThumbnailKey key)
{
SharedThumbnail thumbnail;
@@ -19,6 +19,7 @@
#include <QObject>
#include <QList>
#include <QThreadPool>
#endif
class QString;
@@ -40,6 +41,7 @@ namespace AzToolsFramework
*/
class ThumbnailContext
: public QObject
, public ThumbnailContextRequestBus::Handler
{
Q_OBJECT
public:
@@ -58,10 +60,13 @@ namespace AzToolsFramework
void UnregisterThumbnailProvider(const char* providerName);
void RedrawThumbnail();
//! Default context used for most thumbnails
static constexpr const char* DefaultContext = "Default";
// ThumbnailContextRequestBus::Handler interface overrides...
QThreadPool* GetThreadPool() override;
private:
struct ProviderCompare {
bool operator() (const SharedThumbnailProvider& lhs, const SharedThumbnailProvider& rhs) const
@@ -79,6 +84,9 @@ namespace AzToolsFramework
SharedThumbnail m_loadingThumbnail;
//! Thumbnail size (width and height in pixels)
int m_thumbnailSize;
//! There is only a limited number of threads on global threadPool, because there can be many thumbnails rendering at once
//! an individual threadPool is needed to avoid deadlocks
QThreadPool m_threadPool;
};
} // namespace Thumbnailer
} // namespace AzToolsFramework
@@ -81,6 +81,9 @@ namespace AzToolsFramework
int x = (originalWidth - realWidth) / 2;
// pixmap needs to be manually scaled to produce smoother result and avoid looking pixelated
// using painter.setRenderHint(QPainter::SmoothPixmapTransform); does not seem to work
// Note: there is a potential issue with pixmap.scaled:
// it is multithreaded (using global threadPool) and blocking until finished.
// A deadlock will happen if global threadPool has no free threads available.
painter.drawPixmap(QPoint(x, 0), pixmap.scaled(realWidth, realHeight, Qt::IgnoreAspectRatio, Qt::SmoothTransformation));
}
QWidget::paintEvent(event);
@@ -17,11 +17,23 @@
#include <AzToolsFramework/Thumbnails/Thumbnail.h>
class QPixmap;
class QThreadPool;
namespace AzToolsFramework
{
namespace Thumbnailer
{
//! Interaction with thumbnail context
class ThumbnailContextRequests
: public AZ::EBusTraits
{
public:
//! Get thread pool for drawing thumbnails
virtual QThreadPool* GetThreadPool() = 0;
};
using ThumbnailContextRequestBus = AZ::EBus<ThumbnailContextRequests>;
//! Interaction with thumbnailer
class ThumbnailerRequests
: public AZ::EBusTraits