Merge pull request #1609 from aws-lumberyard-dev/Atom/mnaumov/cherryPick1571

Cherry-picking thumbnail performance improvements
main
AMZN-mnaumov 5 years ago committed by GitHub
commit 83d142d7dc
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23

@ -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

@ -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;
}
ImageToProcess imageToProcess(previewImage);
imageToProcess.ConvertFormat(ePixelFormat_R8G8B8A8);
previewImage = imageToProcess.Get();
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);
QImage image(imageBuf, width, height, pitch, QImage::Format_RGBA8888);
IImageObjectPtr previewImage = mkPreviewImage();
if (!previewImage)
{
AZ::SystemTickBus::QueueFunction(
[
thumbnailKey
]()
{
AzToolsFramework::Thumbnailer::ThumbnailerRendererNotificationBus::Event(
thumbnailKey, &AzToolsFramework::Thumbnailer::ThumbnailerRendererNotifications::ThumbnailFailedToRender);
});
AzToolsFramework::Thumbnailer::ThumbnailerRendererNotificationBus::Event(
thumbnailKey, &AzToolsFramework::Thumbnailer::ThumbnailerRendererNotifications::ThumbnailRendered,
QPixmap::fromImage(image.scaled(QSize(thumbnailSize, thumbnailSize), Qt::KeepAspectRatio, Qt::SmoothTransformation)));
return;
}
return true;
ImageToProcess imageToProcess(previewImage);
imageToProcess.ConvertFormat(ePixelFormat_R8G8B8A8);
previewImage = imageToProcess.Get();
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);
// 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);
// 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

@ -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

Loading…
Cancel
Save