Merge pull request #1609 from aws-lumberyard-dev/Atom/mnaumov/cherryPick1571
Cherry-picking thumbnail performance improvements
This commit is contained in:
+8
-4
@@ -121,9 +121,9 @@ namespace AzToolsFramework
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
bool thumbnailLoading;
|
||||
ThumbnailerRequestsBus::BroadcastResult(thumbnailLoading, &ThumbnailerRequests::IsLoading, thumbnailKey, m_thumbnailContext.c_str());
|
||||
if (thumbnailLoading)
|
||||
|
||||
const Thumbnail::State thumbnailState = thumbnail->GetState();
|
||||
if (thumbnailState == Thumbnail::State::Loading)
|
||||
{
|
||||
AzQtComponents::StyledBusyLabel* busyLabel;
|
||||
AssetBrowserComponentRequestBus::BroadcastResult(busyLabel , &AssetBrowserComponentRequests::GetStyledBusyLabel);
|
||||
@@ -132,7 +132,7 @@ namespace AzToolsFramework
|
||||
busyLabel->DrawTo(painter, QRectF(point.x(), point.y(), size.width(), size.height()));
|
||||
}
|
||||
}
|
||||
else
|
||||
else if (thumbnailState == Thumbnail::State::Ready)
|
||||
{
|
||||
// Scaling and centering pixmap within bounds to preserve aspect ratio
|
||||
const QPixmap pixmap = thumbnail->GetPixmap().scaled(size, Qt::KeepAspectRatio, Qt::SmoothTransformation);
|
||||
@@ -140,6 +140,10 @@ namespace AzToolsFramework
|
||||
const QPoint pointDelta = QPoint(sizeDelta.width() / 2, sizeDelta.height() / 2);
|
||||
painter->drawPixmap(point + pointDelta, pixmap);
|
||||
}
|
||||
else
|
||||
{
|
||||
AZ_Assert(false, "Thumbnail state %d unexpected here", int(thumbnailState));
|
||||
}
|
||||
return m_iconSize;
|
||||
}
|
||||
|
||||
|
||||
@@ -46,6 +46,12 @@ namespace ImageProcessingAtom
|
||||
|
||||
ImagePreviewer::~ImagePreviewer()
|
||||
{
|
||||
AZ::SystemTickBus::Handler::BusDisconnect();
|
||||
|
||||
if (m_createDisplayTextureResult.isRunning())
|
||||
{
|
||||
m_createDisplayTextureResult.waitForFinished();
|
||||
}
|
||||
}
|
||||
|
||||
void ImagePreviewer::Clear() const
|
||||
@@ -209,21 +215,30 @@ namespace ImageProcessingAtom
|
||||
m_ui->m_fileInfoCtrl->show();
|
||||
m_fileinfo = QString::fromUtf8(product->GetName().c_str());
|
||||
m_fileinfo += GetFileSize(product->GetRelativePath().c_str());
|
||||
|
||||
AZ::Data::Asset<AZ::RPI::StreamingImageAsset> imageAsset = Utils::LoadImageAsset(product->GetAssetId());
|
||||
IImageObjectPtr image = Utils::LoadImageFromImageAsset(imageAsset);
|
||||
|
||||
if (image)
|
||||
CreateAndDisplayTextureItemAsync(
|
||||
[assetId = product->GetAssetId()]
|
||||
() -> CreateDisplayTextureResult
|
||||
{
|
||||
// Add product image info
|
||||
AZStd::string productInfo;
|
||||
GetImageInfoString(imageAsset, productInfo);
|
||||
AZ::Data::Asset<AZ::RPI::StreamingImageAsset> imageAsset = Utils::LoadImageAsset(assetId);
|
||||
IImageObjectPtr image = Utils::LoadImageFromImageAsset(imageAsset);
|
||||
|
||||
m_fileinfo += QStringLiteral("\r\n");
|
||||
m_fileinfo += productInfo.c_str();
|
||||
if (image)
|
||||
{
|
||||
// Add product image info
|
||||
AZStd::string productInfo;
|
||||
GetImageInfoString(imageAsset, productInfo);
|
||||
|
||||
m_previewImageObject = ConvertImageForPreview(image);
|
||||
}
|
||||
QString fileInfo = QStringLiteral("\r\n");
|
||||
fileInfo += productInfo.c_str();
|
||||
|
||||
return { ConvertImageForPreview(image), fileInfo };
|
||||
}
|
||||
else
|
||||
{
|
||||
return { nullptr, "" };
|
||||
}
|
||||
});
|
||||
|
||||
DisplayTextureItem();
|
||||
}
|
||||
@@ -234,19 +249,28 @@ namespace ImageProcessingAtom
|
||||
m_fileinfo = QString::fromUtf8(source->GetName().c_str());
|
||||
m_fileinfo += GetFileSize(source->GetFullPath().c_str());
|
||||
|
||||
IImageObjectPtr image = IImageObjectPtr(LoadImageFromFile(source->GetFullPath()));
|
||||
|
||||
if (image)
|
||||
CreateAndDisplayTextureItemAsync(
|
||||
[fullPath = source->GetFullPath()]
|
||||
() -> CreateDisplayTextureResult
|
||||
{
|
||||
// Add source image info
|
||||
AZStd::string sourceInfo;
|
||||
GetImageInfoString(image, sourceInfo);
|
||||
IImageObjectPtr image = IImageObjectPtr(LoadImageFromFile(fullPath));
|
||||
|
||||
m_fileinfo += QStringLiteral("\r\n");
|
||||
m_fileinfo += sourceInfo.c_str();
|
||||
if (image)
|
||||
{
|
||||
// Add source image info
|
||||
AZStd::string sourceInfo;
|
||||
GetImageInfoString(image, sourceInfo);
|
||||
|
||||
m_previewImageObject = ConvertImageForPreview(image);
|
||||
}
|
||||
QString fileInfo = QStringLiteral("\r\n");
|
||||
fileInfo += sourceInfo.c_str();
|
||||
|
||||
return { ConvertImageForPreview(image), fileInfo };
|
||||
}
|
||||
else
|
||||
{
|
||||
return { nullptr, "" };
|
||||
}
|
||||
});
|
||||
|
||||
DisplayTextureItem();
|
||||
}
|
||||
@@ -284,6 +308,27 @@ namespace ImageProcessingAtom
|
||||
updateGeometry();
|
||||
}
|
||||
|
||||
template<class CreateFn>
|
||||
void ImagePreviewer::CreateAndDisplayTextureItemAsync(CreateFn create)
|
||||
{
|
||||
AZ::SystemTickBus::Handler::BusConnect();
|
||||
m_createDisplayTextureResult = QtConcurrent::run(AZStd::move(create));
|
||||
}
|
||||
|
||||
void ImagePreviewer::OnSystemTick()
|
||||
{
|
||||
if (m_createDisplayTextureResult.isFinished())
|
||||
{
|
||||
CreateDisplayTextureResult result = m_createDisplayTextureResult.result();
|
||||
m_previewImageObject = AZStd::move(result.first);
|
||||
m_fileinfo += result.second;
|
||||
|
||||
AZ::SystemTickBus::Handler::BusDisconnect();
|
||||
|
||||
DisplayTextureItem();
|
||||
}
|
||||
}
|
||||
|
||||
void ImagePreviewer::PreviewSubImage(uint32_t mip)
|
||||
{
|
||||
QImage previewImage = GetSubImagePreview(m_previewImageObject, mip);
|
||||
|
||||
@@ -8,12 +8,15 @@
|
||||
|
||||
#if !defined(Q_MOC_RUN)
|
||||
#include <AzCore/Memory/SystemAllocator.h>
|
||||
#include <AzCore/Component/TickBus.h>
|
||||
#include <AzToolsFramework/AssetBrowser/Previewer/Previewer.h>
|
||||
|
||||
#include <Atom/ImageProcessing/ImageObject.h>
|
||||
|
||||
#include <QWidget>
|
||||
#include <QScopedPointer>
|
||||
#include <QFuture>
|
||||
#include <QtConcurrent/QtConcurrent>
|
||||
#endif
|
||||
|
||||
namespace Ui
|
||||
@@ -37,6 +40,7 @@ namespace ImageProcessingAtom
|
||||
{
|
||||
class ImagePreviewer
|
||||
: public AzToolsFramework::AssetBrowser::Previewer
|
||||
, private AZ::SystemTickBus::Handler
|
||||
{
|
||||
Q_OBJECT
|
||||
public:
|
||||
@@ -60,16 +64,27 @@ namespace ImageProcessingAtom
|
||||
QString GetFileSize(const char* path);
|
||||
|
||||
void DisplayTextureItem();
|
||||
template<class CreateFn>
|
||||
void CreateAndDisplayTextureItemAsync(CreateFn create);
|
||||
|
||||
void PreviewSubImage(uint32_t mip);
|
||||
|
||||
// QLabel word wrap does not break long words such as filenames, so manual word wrap needed
|
||||
static QString WordWrap(const QString& string, int maxLength);
|
||||
|
||||
// SystemTickBus
|
||||
void OnSystemTick() override;
|
||||
|
||||
QScopedPointer<Ui::ImagePreviewerClass> m_ui;
|
||||
QString m_fileinfo;
|
||||
QString m_name = "ImagePreviewer";
|
||||
|
||||
// Decompressed image in preview. Cache it so we can preview its sub images
|
||||
IImageObjectPtr m_previewImageObject;
|
||||
|
||||
// Properties for tracking the status of an asynchronous request to display an asset browser entry
|
||||
using CreateDisplayTextureResult = AZStd::pair<IImageObjectPtr, QString>;
|
||||
|
||||
QFuture<CreateDisplayTextureResult> m_createDisplayTextureResult;
|
||||
};
|
||||
}//namespace ImageProcessingAtom
|
||||
|
||||
+55
-35
@@ -10,6 +10,7 @@
|
||||
#include <AzCore/Serialization/EditContext.h>
|
||||
#include <AzCore/Serialization/SerializeContext.h>
|
||||
#include <AzCore/Utils/Utils.h>
|
||||
#include <AzCore/Jobs/JobFunction.h>
|
||||
#include <AzFramework/Asset/AssetSystemBus.h>
|
||||
#include <AzFramework/StringFunc/StringFunc.h>
|
||||
#include <AzToolsFramework/API/EditorAssetSystemAPI.h>
|
||||
@@ -110,8 +111,7 @@ namespace ImageProcessingAtom
|
||||
void ImageThumbnailSystemComponent::RenderThumbnail(
|
||||
AzToolsFramework::Thumbnailer::SharedThumbnailKey thumbnailKey, int thumbnailSize)
|
||||
{
|
||||
auto sourceKey = azrtti_cast<const AzToolsFramework::AssetBrowser::SourceThumbnailKey*>(thumbnailKey.data());
|
||||
if (sourceKey)
|
||||
if (auto sourceKey = azrtti_cast<const AzToolsFramework::AssetBrowser::SourceThumbnailKey*>(thumbnailKey.data()))
|
||||
{
|
||||
bool foundIt = false;
|
||||
AZ::Data::AssetInfo assetInfo;
|
||||
@@ -124,52 +124,72 @@ namespace ImageProcessingAtom
|
||||
{
|
||||
AZStd::string fullPath;
|
||||
AZ::StringFunc::Path::Join(watchFolder.c_str(), assetInfo.m_relativePath.c_str(), fullPath);
|
||||
if (RenderThumbnailFromImage(thumbnailKey, thumbnailSize, IImageObjectPtr(LoadImageFromFile(fullPath))))
|
||||
{
|
||||
return;
|
||||
}
|
||||
RenderThumbnailFromImage(thumbnailKey, thumbnailSize,
|
||||
[fullPath]() { return IImageObjectPtr(LoadImageFromFile(fullPath)); }
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
auto productKey = azrtti_cast<const AzToolsFramework::AssetBrowser::ProductThumbnailKey*>(thumbnailKey.data());
|
||||
if (productKey)
|
||||
else if (auto productKey = azrtti_cast<const AzToolsFramework::AssetBrowser::ProductThumbnailKey*>(thumbnailKey.data()))
|
||||
{
|
||||
if (RenderThumbnailFromImage(thumbnailKey, thumbnailSize, Utils::LoadImageFromImageAsset(productKey->GetAssetId())))
|
||||
{
|
||||
return;
|
||||
}
|
||||
RenderThumbnailFromImage(thumbnailKey, thumbnailSize,
|
||||
[assetId = productKey->GetAssetId()]() { return Utils::LoadImageFromImageAsset(assetId); }
|
||||
);
|
||||
}
|
||||
else
|
||||
{
|
||||
AzToolsFramework::Thumbnailer::ThumbnailerRendererNotificationBus::Event(
|
||||
thumbnailKey, &AzToolsFramework::Thumbnailer::ThumbnailerRendererNotifications::ThumbnailFailedToRender);
|
||||
}
|
||||
|
||||
AzToolsFramework::Thumbnailer::ThumbnailerRendererNotificationBus::Event(
|
||||
thumbnailKey, &AzToolsFramework::Thumbnailer::ThumbnailerRendererNotifications::ThumbnailFailedToRender);
|
||||
}
|
||||
|
||||
bool ImageThumbnailSystemComponent::RenderThumbnailFromImage(
|
||||
AzToolsFramework::Thumbnailer::SharedThumbnailKey thumbnailKey, int thumbnailSize, IImageObjectPtr previewImage) const
|
||||
template<class MkImageFn>
|
||||
void ImageThumbnailSystemComponent::RenderThumbnailFromImage(
|
||||
AzToolsFramework::Thumbnailer::SharedThumbnailKey thumbnailKey, int thumbnailSize, MkImageFn mkPreviewImage) const
|
||||
{
|
||||
if (!previewImage)
|
||||
const auto JobRunner = [mkPreviewImage, thumbnailKey, thumbnailSize]() mutable
|
||||
{
|
||||
return false;
|
||||
}
|
||||
IImageObjectPtr previewImage = mkPreviewImage();
|
||||
if (!previewImage)
|
||||
{
|
||||
AZ::SystemTickBus::QueueFunction(
|
||||
[
|
||||
thumbnailKey
|
||||
]()
|
||||
{
|
||||
AzToolsFramework::Thumbnailer::ThumbnailerRendererNotificationBus::Event(
|
||||
thumbnailKey, &AzToolsFramework::Thumbnailer::ThumbnailerRendererNotifications::ThumbnailFailedToRender);
|
||||
});
|
||||
|
||||
ImageToProcess imageToProcess(previewImage);
|
||||
imageToProcess.ConvertFormat(ePixelFormat_R8G8B8A8);
|
||||
previewImage = imageToProcess.Get();
|
||||
return;
|
||||
}
|
||||
|
||||
AZ::u8* imageBuf = nullptr;
|
||||
AZ::u32 mip = 0;
|
||||
AZ::u32 pitch = 0;
|
||||
previewImage->GetImagePointer(mip, imageBuf, pitch);
|
||||
const AZ::u32 width = previewImage->GetWidth(mip);
|
||||
const AZ::u32 height = previewImage->GetHeight(mip);
|
||||
ImageToProcess imageToProcess(previewImage);
|
||||
imageToProcess.ConvertFormat(ePixelFormat_R8G8B8A8);
|
||||
previewImage = imageToProcess.Get();
|
||||
|
||||
QImage image(imageBuf, width, height, pitch, QImage::Format_RGBA8888);
|
||||
AZ::u8* imageBuf = nullptr;
|
||||
AZ::u32 mip = 0;
|
||||
AZ::u32 pitch = 0;
|
||||
previewImage->GetImagePointer(mip, imageBuf, pitch);
|
||||
const AZ::u32 width = previewImage->GetWidth(mip);
|
||||
const AZ::u32 height = previewImage->GetHeight(mip);
|
||||
|
||||
AzToolsFramework::Thumbnailer::ThumbnailerRendererNotificationBus::Event(
|
||||
thumbnailKey, &AzToolsFramework::Thumbnailer::ThumbnailerRendererNotifications::ThumbnailRendered,
|
||||
QPixmap::fromImage(image.scaled(QSize(thumbnailSize, thumbnailSize), Qt::KeepAspectRatio, Qt::SmoothTransformation)));
|
||||
// Note that this image holds a non-owning pointer to the `previewImage' raw data buffer
|
||||
const QImage image(imageBuf, width, height, pitch, QImage::Format_RGBA8888);
|
||||
|
||||
return true;
|
||||
// Dispatch event on main thread
|
||||
AZ::SystemTickBus::QueueFunction(
|
||||
[
|
||||
thumbnailKey, thumbnailSize,
|
||||
pixmap = QPixmap::fromImage(image.scaled(QSize(thumbnailSize, thumbnailSize), Qt::KeepAspectRatio, Qt::SmoothTransformation))
|
||||
]() mutable
|
||||
{
|
||||
AzToolsFramework::Thumbnailer::ThumbnailerRendererNotificationBus::Event(
|
||||
thumbnailKey, &AzToolsFramework::Thumbnailer::ThumbnailerRendererNotifications::ThumbnailRendered,
|
||||
pixmap);
|
||||
});
|
||||
};
|
||||
AZ::CreateJobFunction(JobRunner, true)->Start();
|
||||
}
|
||||
} // namespace Thumbnails
|
||||
} // namespace ImageProcessingAtom
|
||||
|
||||
+3
-2
@@ -47,8 +47,9 @@ namespace ImageProcessingAtom
|
||||
bool Installed() const override;
|
||||
void RenderThumbnail(AzToolsFramework::Thumbnailer::SharedThumbnailKey thumbnailKey, int thumbnailSize) override;
|
||||
|
||||
bool RenderThumbnailFromImage(
|
||||
AzToolsFramework::Thumbnailer::SharedThumbnailKey thumbnailKey, int thumbnailSize, IImageObjectPtr previewImage) const;
|
||||
template<class MkImageFn>
|
||||
void RenderThumbnailFromImage(
|
||||
AzToolsFramework::Thumbnailer::SharedThumbnailKey thumbnailKey, int thumbnailSize, MkImageFn mkPreviewImage) const;
|
||||
};
|
||||
} // namespace Thumbnails
|
||||
} // namespace ImageProcessingAtom
|
||||
|
||||
Reference in New Issue
Block a user