| // 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_skia.h" |
| |
| #include "flutter/fml/make_copyable.h" |
| #include "third_party/skia/include/core/SkColorSpace.h" |
| #include "third_party/skia/include/core/SkImage.h" |
| #include "third_party/skia/include/gpu/ganesh/SkImageGanesh.h" |
| |
| namespace flutter { |
| |
| sk_sp<DlDeferredImageGPUSkia> DlDeferredImageGPUSkia::Make( |
| const SkImageInfo& image_info, |
| sk_sp<DisplayList> display_list, |
| fml::TaskRunnerAffineWeakPtr<SnapshotDelegate> snapshot_delegate, |
| const fml::RefPtr<fml::TaskRunner>& raster_task_runner, |
| fml::RefPtr<SkiaUnrefQueue> unref_queue) { |
| return sk_sp<DlDeferredImageGPUSkia>(new DlDeferredImageGPUSkia( |
| ImageWrapper::Make(image_info, std::move(display_list), |
| std::move(snapshot_delegate), raster_task_runner, |
| std::move(unref_queue)), |
| raster_task_runner)); |
| } |
| |
| sk_sp<DlDeferredImageGPUSkia> DlDeferredImageGPUSkia::MakeFromLayerTree( |
| const SkImageInfo& image_info, |
| std::unique_ptr<LayerTree> layer_tree, |
| fml::TaskRunnerAffineWeakPtr<SnapshotDelegate> snapshot_delegate, |
| const fml::RefPtr<fml::TaskRunner>& raster_task_runner, |
| fml::RefPtr<SkiaUnrefQueue> unref_queue) { |
| return sk_sp<DlDeferredImageGPUSkia>(new DlDeferredImageGPUSkia( |
| ImageWrapper::MakeFromLayerTree( |
| image_info, std::move(layer_tree), std::move(snapshot_delegate), |
| raster_task_runner, std::move(unref_queue)), |
| raster_task_runner)); |
| } |
| |
| DlDeferredImageGPUSkia::DlDeferredImageGPUSkia( |
| std::shared_ptr<ImageWrapper> image_wrapper, |
| fml::RefPtr<fml::TaskRunner> raster_task_runner) |
| : image_wrapper_(std::move(image_wrapper)), |
| raster_task_runner_(std::move(raster_task_runner)) {} |
| |
| // |DlImage| |
| DlDeferredImageGPUSkia::~DlDeferredImageGPUSkia() { |
| fml::TaskRunner::RunNowOrPostTask(raster_task_runner_, |
| [image_wrapper = image_wrapper_]() { |
| if (!image_wrapper) { |
| return; |
| } |
| image_wrapper->Unregister(); |
| image_wrapper->DeleteTexture(); |
| }); |
| } |
| |
| // |DlImage| |
| sk_sp<SkImage> DlDeferredImageGPUSkia::skia_image() const { |
| return image_wrapper_ ? image_wrapper_->CreateSkiaImage() : nullptr; |
| }; |
| |
| // |DlImage| |
| std::shared_ptr<impeller::Texture> DlDeferredImageGPUSkia::impeller_texture() |
| const { |
| return nullptr; |
| } |
| |
| // |DlImage| |
| bool DlDeferredImageGPUSkia::isOpaque() const { |
| return image_wrapper_ ? image_wrapper_->image_info().isOpaque() : false; |
| } |
| |
| // |DlImage| |
| bool DlDeferredImageGPUSkia::isTextureBacked() const { |
| return image_wrapper_ ? image_wrapper_->isTextureBacked() : false; |
| } |
| |
| // |DlImage| |
| bool DlDeferredImageGPUSkia::isUIThreadSafe() const { |
| return true; |
| } |
| |
| // |DlImage| |
| SkISize DlDeferredImageGPUSkia::dimensions() const { |
| return image_wrapper_ ? image_wrapper_->image_info().dimensions() |
| : SkISize::MakeEmpty(); |
| } |
| |
| // |DlImage| |
| size_t DlDeferredImageGPUSkia::GetApproximateByteSize() const { |
| return sizeof(*this) + |
| (image_wrapper_ ? image_wrapper_->image_info().computeMinByteSize() |
| : 0); |
| } |
| |
| std::optional<std::string> DlDeferredImageGPUSkia::get_error() const { |
| return image_wrapper_ ? image_wrapper_->get_error() : std::nullopt; |
| } |
| |
| std::shared_ptr<DlDeferredImageGPUSkia::ImageWrapper> |
| DlDeferredImageGPUSkia::ImageWrapper::Make( |
| const SkImageInfo& image_info, |
| sk_sp<DisplayList> display_list, |
| fml::TaskRunnerAffineWeakPtr<SnapshotDelegate> snapshot_delegate, |
| fml::RefPtr<fml::TaskRunner> raster_task_runner, |
| fml::RefPtr<SkiaUnrefQueue> unref_queue) { |
| auto wrapper = std::shared_ptr<ImageWrapper>(new ImageWrapper( |
| image_info, std::move(display_list), std::move(snapshot_delegate), |
| std::move(raster_task_runner), std::move(unref_queue))); |
| wrapper->SnapshotDisplayList(); |
| return wrapper; |
| } |
| |
| std::shared_ptr<DlDeferredImageGPUSkia::ImageWrapper> |
| DlDeferredImageGPUSkia::ImageWrapper::MakeFromLayerTree( |
| const SkImageInfo& image_info, |
| std::unique_ptr<LayerTree> layer_tree, |
| fml::TaskRunnerAffineWeakPtr<SnapshotDelegate> snapshot_delegate, |
| fml::RefPtr<fml::TaskRunner> raster_task_runner, |
| fml::RefPtr<SkiaUnrefQueue> unref_queue) { |
| auto wrapper = std::shared_ptr<ImageWrapper>( |
| new ImageWrapper(image_info, nullptr, std::move(snapshot_delegate), |
| std::move(raster_task_runner), std::move(unref_queue))); |
| wrapper->SnapshotDisplayList(std::move(layer_tree)); |
| return wrapper; |
| } |
| |
| DlDeferredImageGPUSkia::ImageWrapper::ImageWrapper( |
| const SkImageInfo& image_info, |
| sk_sp<DisplayList> display_list, |
| fml::TaskRunnerAffineWeakPtr<SnapshotDelegate> snapshot_delegate, |
| fml::RefPtr<fml::TaskRunner> raster_task_runner, |
| fml::RefPtr<SkiaUnrefQueue> unref_queue) |
| : image_info_(image_info), |
| display_list_(std::move(display_list)), |
| snapshot_delegate_(std::move(snapshot_delegate)), |
| raster_task_runner_(std::move(raster_task_runner)), |
| unref_queue_(std::move(unref_queue)) {} |
| |
| void DlDeferredImageGPUSkia::ImageWrapper::OnGrContextCreated() { |
| FML_DCHECK(raster_task_runner_->RunsTasksOnCurrentThread()); |
| SnapshotDisplayList(); |
| } |
| |
| void DlDeferredImageGPUSkia::ImageWrapper::OnGrContextDestroyed() { |
| FML_DCHECK(raster_task_runner_->RunsTasksOnCurrentThread()); |
| DeleteTexture(); |
| } |
| |
| sk_sp<SkImage> DlDeferredImageGPUSkia::ImageWrapper::CreateSkiaImage() const { |
| FML_DCHECK(raster_task_runner_->RunsTasksOnCurrentThread()); |
| |
| if (texture_.isValid() && context_) { |
| return SkImages::BorrowTextureFrom( |
| context_.get(), texture_, kTopLeft_GrSurfaceOrigin, |
| image_info_.colorType(), image_info_.alphaType(), |
| image_info_.refColorSpace()); |
| } |
| return image_; |
| } |
| |
| bool DlDeferredImageGPUSkia::ImageWrapper::isTextureBacked() const { |
| return texture_.isValid(); |
| } |
| |
| void DlDeferredImageGPUSkia::ImageWrapper::SnapshotDisplayList( |
| std::unique_ptr<LayerTree> layer_tree) { |
| fml::TaskRunner::RunNowOrPostTask( |
| raster_task_runner_, |
| fml::MakeCopyable([weak_this = weak_from_this(), |
| layer_tree = std::move(layer_tree)]() mutable { |
| auto wrapper = weak_this.lock(); |
| if (!wrapper) { |
| return; |
| } |
| auto snapshot_delegate = wrapper->snapshot_delegate_; |
| if (!snapshot_delegate) { |
| return; |
| } |
| if (layer_tree) { |
| auto display_list = |
| layer_tree->Flatten(SkRect::MakeWH(wrapper->image_info_.width(), |
| wrapper->image_info_.height()), |
| snapshot_delegate->GetTextureRegistry(), |
| snapshot_delegate->GetGrContext()); |
| wrapper->display_list_ = std::move(display_list); |
| } |
| auto result = snapshot_delegate->MakeSkiaGpuImage( |
| wrapper->display_list_, wrapper->image_info_); |
| if (result->texture.isValid()) { |
| wrapper->texture_ = result->texture; |
| wrapper->context_ = std::move(result->context); |
| wrapper->texture_registry_ = |
| wrapper->snapshot_delegate_->GetTextureRegistry(); |
| wrapper->texture_registry_->RegisterContextListener( |
| reinterpret_cast<uintptr_t>(wrapper.get()), weak_this); |
| } else if (result->image) { |
| wrapper->image_ = std::move(result->image); |
| } else { |
| std::scoped_lock lock(wrapper->error_mutex_); |
| wrapper->error_ = result->error; |
| } |
| })); |
| } |
| |
| std::optional<std::string> DlDeferredImageGPUSkia::ImageWrapper::get_error() { |
| std::scoped_lock lock(error_mutex_); |
| return error_; |
| } |
| |
| void DlDeferredImageGPUSkia::ImageWrapper::Unregister() { |
| if (texture_registry_) { |
| texture_registry_->UnregisterContextListener( |
| reinterpret_cast<uintptr_t>(this)); |
| } |
| } |
| |
| void DlDeferredImageGPUSkia::ImageWrapper::DeleteTexture() { |
| if (texture_.isValid()) { |
| unref_queue_->DeleteTexture(texture_); |
| texture_ = GrBackendTexture(); |
| } |
| image_.reset(); |
| context_.reset(); |
| } |
| |
| } // namespace flutter |