blob: 11692cd7118608843989b89c5d09a3151d3bbb5c [file] [log] [blame]
// Copyright 2013 The Flutter Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include "flutter/lib/ui/painting/display_list_deferred_image_gpu_impeller.h"
#include <utility>
#include "display_list_deferred_image_gpu_impeller.h"
#include "flutter/fml/make_copyable.h"
namespace flutter {
sk_sp<DlDeferredImageGPUImpeller> DlDeferredImageGPUImpeller::Make(
std::unique_ptr<LayerTree> layer_tree,
fml::TaskRunnerAffineWeakPtr<SnapshotDelegate> snapshot_delegate,
const fml::RefPtr<fml::TaskRunner>& raster_task_runner) {
return sk_sp<DlDeferredImageGPUImpeller>(new DlDeferredImageGPUImpeller(
DlDeferredImageGPUImpeller::ImageWrapper::Make(
std::move(layer_tree), std::move(snapshot_delegate),
raster_task_runner)));
}
sk_sp<DlDeferredImageGPUImpeller> DlDeferredImageGPUImpeller::Make(
sk_sp<DisplayList> display_list,
const SkISize& size,
fml::TaskRunnerAffineWeakPtr<SnapshotDelegate> snapshot_delegate,
const fml::RefPtr<fml::TaskRunner>& raster_task_runner) {
return sk_sp<DlDeferredImageGPUImpeller>(new DlDeferredImageGPUImpeller(
DlDeferredImageGPUImpeller::ImageWrapper::Make(
std::move(display_list), size, std::move(snapshot_delegate),
raster_task_runner)));
}
sk_sp<DlDeferredImageGPUImpeller> DlDeferredImageGPUImpeller::Make(
const std::shared_ptr<const impeller::Picture>& impeller_picture,
const SkISize& size,
fml::TaskRunnerAffineWeakPtr<SnapshotDelegate> snapshot_delegate,
const fml::RefPtr<fml::TaskRunner>& raster_task_runner) {
return sk_sp<DlDeferredImageGPUImpeller>(new DlDeferredImageGPUImpeller(
DlDeferredImageGPUImpeller::ImageWrapper::Make(
impeller_picture, size, std::move(snapshot_delegate),
raster_task_runner)));
}
DlDeferredImageGPUImpeller::DlDeferredImageGPUImpeller(
std::shared_ptr<ImageWrapper> wrapper)
: wrapper_(std::move(wrapper)) {}
// |DlImage|
DlDeferredImageGPUImpeller::~DlDeferredImageGPUImpeller() = default;
// |DlImage|
sk_sp<SkImage> DlDeferredImageGPUImpeller::skia_image() const {
return nullptr;
};
// |DlImage|
std::shared_ptr<impeller::Texture>
DlDeferredImageGPUImpeller::impeller_texture() const {
if (!wrapper_) {
return nullptr;
}
return wrapper_->texture();
}
// |DlImage|
bool DlDeferredImageGPUImpeller::isOpaque() const {
// Impeller doesn't currently implement opaque alpha types.
return false;
}
// |DlImage|
bool DlDeferredImageGPUImpeller::isTextureBacked() const {
return wrapper_ && wrapper_->isTextureBacked();
}
// |DlImage|
bool DlDeferredImageGPUImpeller::isUIThreadSafe() const {
return true;
}
// |DlImage|
SkISize DlDeferredImageGPUImpeller::dimensions() const {
if (!wrapper_) {
return SkISize::MakeEmpty();
}
return wrapper_->size();
}
// |DlImage|
size_t DlDeferredImageGPUImpeller::GetApproximateByteSize() const {
auto size = sizeof(DlDeferredImageGPUImpeller);
if (wrapper_) {
if (wrapper_->texture()) {
size += wrapper_->texture()
->GetTextureDescriptor()
.GetByteSizeOfBaseMipLevel();
} else {
size += wrapper_->size().width() * wrapper_->size().height() * 4;
}
}
return size;
}
std::shared_ptr<DlDeferredImageGPUImpeller::ImageWrapper>
DlDeferredImageGPUImpeller::ImageWrapper::Make(
sk_sp<DisplayList> display_list,
const SkISize& size,
fml::TaskRunnerAffineWeakPtr<SnapshotDelegate> snapshot_delegate,
const fml::RefPtr<fml::TaskRunner>& raster_task_runner) {
auto wrapper = std::shared_ptr<ImageWrapper>(
new ImageWrapper(std::move(display_list), size,
std::move(snapshot_delegate), raster_task_runner));
wrapper->SnapshotDisplayList();
return wrapper;
}
std::shared_ptr<DlDeferredImageGPUImpeller::ImageWrapper>
DlDeferredImageGPUImpeller::ImageWrapper::Make(
const std::shared_ptr<const impeller::Picture>& impeller_picture,
const SkISize& size,
fml::TaskRunnerAffineWeakPtr<SnapshotDelegate> snapshot_delegate,
const fml::RefPtr<fml::TaskRunner>& raster_task_runner) {
auto wrapper = std::shared_ptr<ImageWrapper>(new ImageWrapper(size));
wrapper->SnapshotPicture(impeller_picture, std::move(snapshot_delegate),
raster_task_runner);
return wrapper;
}
std::shared_ptr<DlDeferredImageGPUImpeller::ImageWrapper>
DlDeferredImageGPUImpeller::ImageWrapper::Make(
std::unique_ptr<LayerTree> layer_tree,
fml::TaskRunnerAffineWeakPtr<SnapshotDelegate> snapshot_delegate,
const fml::RefPtr<fml::TaskRunner>& raster_task_runner) {
if (layer_tree) {
auto wrapper = std::shared_ptr<ImageWrapper>(
new ImageWrapper(layer_tree->frame_size()));
wrapper->SnapshotLayer(std::move(layer_tree), std::move(snapshot_delegate),
raster_task_runner);
return wrapper;
}
auto wrapper = std::shared_ptr<ImageWrapper>(
new ImageWrapper(sk_sp<DisplayList>(), layer_tree->frame_size(),
std::move(snapshot_delegate), raster_task_runner));
wrapper->SnapshotDisplayList(std::move(layer_tree));
return wrapper;
}
DlDeferredImageGPUImpeller::ImageWrapper::ImageWrapper(
sk_sp<DisplayList> display_list,
const SkISize& size,
fml::TaskRunnerAffineWeakPtr<SnapshotDelegate> snapshot_delegate,
fml::RefPtr<fml::TaskRunner> raster_task_runner)
: size_(size),
display_list_(std::move(display_list)),
snapshot_delegate_(std::move(snapshot_delegate)),
raster_task_runner_(std::move(raster_task_runner)) {}
DlDeferredImageGPUImpeller::ImageWrapper::ImageWrapper(const SkISize& size)
: size_(size) {}
void DlDeferredImageGPUImpeller::ImageWrapper::SnapshotPicture(
const std::shared_ptr<const impeller::Picture>& impeller_picture,
fml::TaskRunnerAffineWeakPtr<SnapshotDelegate> snapshot_delegate,
const fml::RefPtr<fml::TaskRunner>& raster_task_runner) {
fml::TaskRunner::RunNowOrPostTask(
raster_task_runner,
fml::MakeCopyable([weak_this = weak_from_this(), impeller_picture,
snapshot_delegate = std::move(snapshot_delegate)]() {
TRACE_EVENT0("flutter", "SnapshotPicture (impeller)");
auto wrapper = weak_this.lock();
if (!wrapper) {
return;
}
if (!snapshot_delegate) {
return;
}
wrapper->texture_registry_ = snapshot_delegate->GetTextureRegistry();
auto snapshot = snapshot_delegate->MakeRasterSnapshot(impeller_picture,
wrapper->size_);
if (!snapshot) {
std::scoped_lock lock(wrapper->error_mutex_);
wrapper->error_ = "Failed to create snapshot.";
return;
}
wrapper->texture_ = snapshot->impeller_texture();
}));
}
void DlDeferredImageGPUImpeller::ImageWrapper::SnapshotLayer(
std::unique_ptr<LayerTree> layer_tree,
fml::TaskRunnerAffineWeakPtr<SnapshotDelegate> snapshot_delegate,
const fml::RefPtr<fml::TaskRunner>& raster_task_runner) {
fml::TaskRunner::RunNowOrPostTask(
raster_task_runner,
fml::MakeCopyable([weak_this = weak_from_this(),
layer_tree = std::move(layer_tree),
snapshot_delegate = std::move(snapshot_delegate)]() {
TRACE_EVENT0("flutter", "SnapshotLayer (impeller)");
auto wrapper = weak_this.lock();
if (!wrapper) {
return;
}
if (!snapshot_delegate) {
return;
}
wrapper->texture_registry_ = snapshot_delegate->GetTextureRegistry();
auto impeller_picture = layer_tree->FlattenToImpellerPicture(
SkRect::MakeWH(wrapper->size_.width(), wrapper->size_.height()),
wrapper->texture_registry_);
auto snapshot = snapshot_delegate->MakeRasterSnapshot(impeller_picture,
wrapper->size_);
if (!snapshot) {
std::scoped_lock lock(wrapper->error_mutex_);
wrapper->error_ = "Failed to create snapshot.";
return;
}
wrapper->texture_ = snapshot->impeller_texture();
}));
}
DlDeferredImageGPUImpeller::ImageWrapper::~ImageWrapper() {
if (display_list_) {
fml::TaskRunner::RunNowOrPostTask(
raster_task_runner_,
[id = reinterpret_cast<uintptr_t>(this),
texture_registry = std::move(texture_registry_)]() {
if (texture_registry) {
texture_registry->UnregisterContextListener(id);
}
});
}
}
void DlDeferredImageGPUImpeller::ImageWrapper::OnGrContextCreated() {
FML_DCHECK(raster_task_runner_->RunsTasksOnCurrentThread());
SnapshotDisplayList();
}
void DlDeferredImageGPUImpeller::ImageWrapper::OnGrContextDestroyed() {
if (display_list_) {
texture_.reset();
}
}
bool DlDeferredImageGPUImpeller::ImageWrapper::isTextureBacked() const {
return texture_ && texture_->IsValid();
}
void DlDeferredImageGPUImpeller::ImageWrapper::SnapshotDisplayList(
std::unique_ptr<LayerTree> layer_tree) {
FML_DCHECK(display_list_ || layer_tree);
fml::TaskRunner::RunNowOrPostTask(
raster_task_runner_,
fml::MakeCopyable([weak_this = weak_from_this(),
layer_tree = std::move(layer_tree)]() {
TRACE_EVENT0("flutter", "SnapshotDisplayList (impeller)");
auto wrapper = weak_this.lock();
if (!wrapper) {
return;
}
auto snapshot_delegate = wrapper->snapshot_delegate_;
if (!snapshot_delegate) {
return;
}
wrapper->texture_registry_ = snapshot_delegate->GetTextureRegistry();
wrapper->texture_registry_->RegisterContextListener(
reinterpret_cast<uintptr_t>(wrapper.get()), weak_this);
if (layer_tree) {
wrapper->display_list_ = layer_tree->Flatten(
SkRect::MakeWH(wrapper->size_.width(), wrapper->size_.height()),
wrapper->texture_registry_);
}
auto snapshot = snapshot_delegate->MakeRasterSnapshot(
wrapper->display_list_, wrapper->size_);
if (!snapshot) {
std::scoped_lock lock(wrapper->error_mutex_);
wrapper->error_ = "Failed to create snapshot.";
return;
}
wrapper->texture_ = snapshot->impeller_texture();
}));
}
std::optional<std::string>
DlDeferredImageGPUImpeller::ImageWrapper::get_error() {
std::scoped_lock lock(error_mutex_);
return error_;
}
} // namespace flutter