[Impeller] Implement 'ui.Image.toByteData()' (flutter/engine#37709)
* [Impeller] Implement 'ui.Image.toByteData()' * Tweak code
This commit is contained in:
@@ -1771,7 +1771,11 @@ FILE: ../../../flutter/lib/ui/painting/image_descriptor.h
|
||||
FILE: ../../../flutter/lib/ui/painting/image_dispose_unittests.cc
|
||||
FILE: ../../../flutter/lib/ui/painting/image_encoding.cc
|
||||
FILE: ../../../flutter/lib/ui/painting/image_encoding.h
|
||||
FILE: ../../../flutter/lib/ui/painting/image_encoding_impeller.cc
|
||||
FILE: ../../../flutter/lib/ui/painting/image_encoding_impeller.h
|
||||
FILE: ../../../flutter/lib/ui/painting/image_encoding_impl.h
|
||||
FILE: ../../../flutter/lib/ui/painting/image_encoding_skia.cc
|
||||
FILE: ../../../flutter/lib/ui/painting/image_encoding_skia.h
|
||||
FILE: ../../../flutter/lib/ui/painting/image_encoding_unittests.cc
|
||||
FILE: ../../../flutter/lib/ui/painting/image_filter.cc
|
||||
FILE: ../../../flutter/lib/ui/painting/image_filter.h
|
||||
|
||||
@@ -9,11 +9,13 @@
|
||||
|
||||
namespace impeller {
|
||||
|
||||
sk_sp<DlImageImpeller> DlImageImpeller::Make(std::shared_ptr<Texture> texture) {
|
||||
sk_sp<DlImageImpeller> DlImageImpeller::Make(std::shared_ptr<Texture> texture,
|
||||
OwningContext owning_context) {
|
||||
if (!texture) {
|
||||
return nullptr;
|
||||
}
|
||||
return sk_sp<DlImageImpeller>(new DlImageImpeller(std::move(texture)));
|
||||
return sk_sp<DlImageImpeller>(
|
||||
new DlImageImpeller(std::move(texture), owning_context));
|
||||
}
|
||||
|
||||
sk_sp<DlImageImpeller> DlImageImpeller::MakeFromYUVTextures(
|
||||
@@ -33,8 +35,9 @@ sk_sp<DlImageImpeller> DlImageImpeller::MakeFromYUVTextures(
|
||||
return impeller::DlImageImpeller::Make(snapshot->texture);
|
||||
}
|
||||
|
||||
DlImageImpeller::DlImageImpeller(std::shared_ptr<Texture> texture)
|
||||
: texture_(std::move(texture)) {}
|
||||
DlImageImpeller::DlImageImpeller(std::shared_ptr<Texture> texture,
|
||||
OwningContext owning_context)
|
||||
: texture_(std::move(texture)), owning_context_(owning_context) {}
|
||||
|
||||
// |DlImage|
|
||||
DlImageImpeller::~DlImageImpeller() = default;
|
||||
|
||||
@@ -14,7 +14,9 @@ class AiksContext;
|
||||
|
||||
class DlImageImpeller final : public flutter::DlImage {
|
||||
public:
|
||||
static sk_sp<DlImageImpeller> Make(std::shared_ptr<Texture> texture);
|
||||
static sk_sp<DlImageImpeller> Make(
|
||||
std::shared_ptr<Texture> texture,
|
||||
OwningContext owning_context = OwningContext::kIO);
|
||||
|
||||
static sk_sp<DlImageImpeller> MakeFromYUVTextures(
|
||||
AiksContext* aiks_context,
|
||||
@@ -43,10 +45,15 @@ class DlImageImpeller final : public flutter::DlImage {
|
||||
// |DlImage|
|
||||
size_t GetApproximateByteSize() const override;
|
||||
|
||||
// |DlImage|
|
||||
OwningContext owning_context() const override { return owning_context_; }
|
||||
|
||||
private:
|
||||
std::shared_ptr<Texture> texture_;
|
||||
OwningContext owning_context_;
|
||||
|
||||
explicit DlImageImpeller(std::shared_ptr<Texture> texture);
|
||||
explicit DlImageImpeller(std::shared_ptr<Texture> texture,
|
||||
OwningContext owning_context = OwningContext::kIO);
|
||||
|
||||
FML_DISALLOW_COPY_AND_ASSIGN(DlImageImpeller);
|
||||
};
|
||||
|
||||
@@ -53,6 +53,8 @@ source_set("ui") {
|
||||
"painting/image_encoding.cc",
|
||||
"painting/image_encoding.h",
|
||||
"painting/image_encoding_impl.h",
|
||||
"painting/image_encoding_skia.cc",
|
||||
"painting/image_encoding_skia.h",
|
||||
"painting/image_filter.cc",
|
||||
"painting/image_filter.h",
|
||||
"painting/image_generator.cc",
|
||||
@@ -167,6 +169,8 @@ source_set("ui") {
|
||||
"painting/display_list_deferred_image_gpu_impeller.h",
|
||||
"painting/image_decoder_impeller.cc",
|
||||
"painting/image_decoder_impeller.h",
|
||||
"painting/image_encoding_impeller.cc",
|
||||
"painting/image_encoding_impeller.h",
|
||||
]
|
||||
|
||||
deps += [ "//flutter/impeller" ]
|
||||
|
||||
@@ -50,6 +50,11 @@ class DlDeferredImageGPUImpeller final : public DlImage {
|
||||
// |DlImage|
|
||||
size_t GetApproximateByteSize() const override;
|
||||
|
||||
// |DlImage|
|
||||
OwningContext owning_context() const override {
|
||||
return OwningContext::kRaster;
|
||||
}
|
||||
|
||||
private:
|
||||
class ImageWrapper final : public std::enable_shared_from_this<ImageWrapper>,
|
||||
public ContextListener {
|
||||
|
||||
@@ -13,6 +13,10 @@
|
||||
#include "flutter/fml/make_copyable.h"
|
||||
#include "flutter/fml/trace_event.h"
|
||||
#include "flutter/lib/ui/painting/image.h"
|
||||
#if IMPELLER_SUPPORTS_RENDERING
|
||||
#include "flutter/lib/ui/painting/image_encoding_impeller.h"
|
||||
#endif // IMPELLER_SUPPORTS_RENDERING
|
||||
#include "flutter/lib/ui/painting/image_encoding_skia.h"
|
||||
#include "third_party/skia/include/core/SkEncodedImageFormat.h"
|
||||
#include "third_party/tonic/dart_persistent_value.h"
|
||||
#include "third_party/tonic/logging/dart_invoke.h"
|
||||
@@ -22,6 +26,9 @@ using tonic::DartInvoke;
|
||||
using tonic::DartPersistentValue;
|
||||
using tonic::ToDart;
|
||||
|
||||
namespace impeller {
|
||||
class Context;
|
||||
} // namespace impeller
|
||||
namespace flutter {
|
||||
namespace {
|
||||
|
||||
@@ -60,84 +67,6 @@ void InvokeDataCallback(std::unique_ptr<DartPersistentValue> callback,
|
||||
DartInvoke(callback->value(), {dart_data});
|
||||
}
|
||||
|
||||
void ConvertImageToRaster(
|
||||
const sk_sp<DlImage>& dl_image,
|
||||
std::function<void(sk_sp<SkImage>)> encode_task,
|
||||
const fml::RefPtr<fml::TaskRunner>& raster_task_runner,
|
||||
const fml::RefPtr<fml::TaskRunner>& io_task_runner,
|
||||
const fml::WeakPtr<GrDirectContext>& resource_context,
|
||||
const fml::TaskRunnerAffineWeakPtr<SnapshotDelegate>& snapshot_delegate,
|
||||
const std::shared_ptr<const fml::SyncSwitch>& is_gpu_disabled_sync_switch) {
|
||||
// If the owning_context is kRaster, we can't access it on this task runner.
|
||||
if (dl_image->owning_context() != DlImage::OwningContext::kRaster) {
|
||||
auto image = dl_image->skia_image();
|
||||
|
||||
// Check validity of the image.
|
||||
if (image == nullptr) {
|
||||
FML_LOG(ERROR) << "Image was null.";
|
||||
encode_task(nullptr);
|
||||
return;
|
||||
}
|
||||
|
||||
auto dimensions = image->dimensions();
|
||||
|
||||
if (dimensions.isEmpty()) {
|
||||
FML_LOG(ERROR) << "Image dimensions were empty.";
|
||||
encode_task(nullptr);
|
||||
return;
|
||||
}
|
||||
|
||||
SkPixmap pixmap;
|
||||
if (image->peekPixels(&pixmap)) {
|
||||
// This is already a raster image.
|
||||
encode_task(image);
|
||||
return;
|
||||
}
|
||||
|
||||
if (sk_sp<SkImage> raster_image = image->makeRasterImage()) {
|
||||
// The image can be converted to a raster image.
|
||||
encode_task(raster_image);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
// Cross-context images do not support makeRasterImage. Convert these images
|
||||
// by drawing them into a surface. This must be done on the raster thread
|
||||
// to prevent concurrent usage of the image on both the IO and raster threads.
|
||||
raster_task_runner->PostTask([dl_image, encode_task = std::move(encode_task),
|
||||
resource_context, snapshot_delegate,
|
||||
io_task_runner, is_gpu_disabled_sync_switch,
|
||||
raster_task_runner]() {
|
||||
auto image = dl_image->skia_image();
|
||||
if (!image || !snapshot_delegate) {
|
||||
io_task_runner->PostTask(
|
||||
[encode_task = encode_task]() mutable { encode_task(nullptr); });
|
||||
return;
|
||||
}
|
||||
|
||||
sk_sp<SkImage> raster_image =
|
||||
snapshot_delegate->ConvertToRasterImage(image);
|
||||
|
||||
io_task_runner->PostTask([image, encode_task = encode_task,
|
||||
raster_image = std::move(raster_image),
|
||||
resource_context, is_gpu_disabled_sync_switch,
|
||||
owning_context = dl_image->owning_context(),
|
||||
raster_task_runner]() mutable {
|
||||
if (!raster_image) {
|
||||
// The rasterizer was unable to render the cross-context image
|
||||
// (presumably because it does not have a GrContext). In that case,
|
||||
// convert the image on the IO thread using the resource context.
|
||||
raster_image = ConvertToRasterUsingResourceContext(
|
||||
image, resource_context, is_gpu_disabled_sync_switch);
|
||||
}
|
||||
encode_task(raster_image);
|
||||
if (owning_context == DlImage::OwningContext::kRaster) {
|
||||
raster_task_runner->PostTask([image = std::move(image)]() {});
|
||||
}
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
sk_sp<SkData> CopyImageByteData(const sk_sp<SkImage>& raster_image,
|
||||
SkColorType color_type,
|
||||
SkAlphaType alpha_type) {
|
||||
@@ -221,7 +150,9 @@ void EncodeImageAndInvokeDataCallback(
|
||||
const fml::RefPtr<fml::TaskRunner>& io_task_runner,
|
||||
const fml::WeakPtr<GrDirectContext>& resource_context,
|
||||
const fml::TaskRunnerAffineWeakPtr<SnapshotDelegate>& snapshot_delegate,
|
||||
const std::shared_ptr<const fml::SyncSwitch>& is_gpu_disabled_sync_switch) {
|
||||
const std::shared_ptr<const fml::SyncSwitch>& is_gpu_disabled_sync_switch,
|
||||
const std::shared_ptr<impeller::Context>& impeller_context,
|
||||
bool is_impeller_enabled) {
|
||||
auto callback_task = fml::MakeCopyable(
|
||||
[callback = std::move(callback)](sk_sp<SkData> encoded) mutable {
|
||||
InvokeDataCallback(std::move(callback), std::move(encoded));
|
||||
@@ -239,9 +170,17 @@ void EncodeImageAndInvokeDataCallback(
|
||||
};
|
||||
|
||||
FML_DCHECK(image);
|
||||
ConvertImageToRaster(image, encode_task, raster_task_runner, io_task_runner,
|
||||
resource_context, snapshot_delegate,
|
||||
is_gpu_disabled_sync_switch);
|
||||
#if IMPELLER_SUPPORTS_RENDERING
|
||||
if (is_impeller_enabled) {
|
||||
ConvertImageToRasterImpeller(image, encode_task, raster_task_runner,
|
||||
io_task_runner, is_gpu_disabled_sync_switch,
|
||||
impeller_context);
|
||||
return;
|
||||
}
|
||||
#endif // IMPELLER_SUPPORTS_RENDERING
|
||||
ConvertImageToRasterSkia(image, encode_task, raster_task_runner,
|
||||
io_task_runner, resource_context, snapshot_delegate,
|
||||
is_gpu_disabled_sync_switch);
|
||||
}
|
||||
|
||||
} // namespace
|
||||
@@ -272,13 +211,15 @@ Dart_Handle EncodeImage(CanvasImage* canvas_image,
|
||||
raster_task_runner = task_runners.GetRasterTaskRunner(),
|
||||
io_task_runner = task_runners.GetIOTaskRunner(),
|
||||
io_manager = UIDartState::Current()->GetIOManager(),
|
||||
snapshot_delegate =
|
||||
UIDartState::Current()->GetSnapshotDelegate()]() mutable {
|
||||
snapshot_delegate = UIDartState::Current()->GetSnapshotDelegate(),
|
||||
is_impeller_enabled =
|
||||
UIDartState::Current()->IsImpellerEnabled()]() mutable {
|
||||
EncodeImageAndInvokeDataCallback(
|
||||
image, std::move(callback), image_format, ui_task_runner,
|
||||
raster_task_runner, io_task_runner,
|
||||
io_manager->GetResourceContext(), snapshot_delegate,
|
||||
io_manager->GetIsGpuDisabledSyncSwitch());
|
||||
io_manager->GetIsGpuDisabledSyncSwitch(),
|
||||
io_manager->GetImpellerContext(), is_impeller_enabled);
|
||||
}));
|
||||
|
||||
return Dart_Null();
|
||||
|
||||
162
engine/src/flutter/lib/ui/painting/image_encoding_impeller.cc
Normal file
162
engine/src/flutter/lib/ui/painting/image_encoding_impeller.cc
Normal file
@@ -0,0 +1,162 @@
|
||||
// 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/image.h"
|
||||
#include "impeller/renderer/command_buffer.h"
|
||||
#include "impeller/renderer/context.h"
|
||||
#include "impeller/renderer/device_buffer.h"
|
||||
#include "impeller/renderer/formats.h"
|
||||
|
||||
namespace flutter {
|
||||
namespace {
|
||||
|
||||
std::optional<SkColorType> ToSkColorType(impeller::PixelFormat format) {
|
||||
switch (format) {
|
||||
case impeller::PixelFormat::kR8G8B8A8UNormInt:
|
||||
return SkColorType::kRGBA_8888_SkColorType;
|
||||
case impeller::PixelFormat::kB8G8R8A8UNormInt:
|
||||
return SkColorType::kBGRA_8888_SkColorType;
|
||||
break;
|
||||
default:
|
||||
return std::nullopt;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
sk_sp<SkImage> ConvertBufferToSkImage(
|
||||
const std::shared_ptr<impeller::DeviceBuffer>& buffer,
|
||||
SkColorType color_type,
|
||||
SkISize dimensions) {
|
||||
auto buffer_view = buffer->AsBufferView();
|
||||
|
||||
SkImageInfo image_info = SkImageInfo::Make(dimensions, color_type,
|
||||
SkAlphaType::kPremul_SkAlphaType);
|
||||
|
||||
SkBitmap bitmap;
|
||||
auto func = [](void* addr, void* context) {
|
||||
auto buffer =
|
||||
static_cast<std::shared_ptr<impeller::DeviceBuffer>*>(context);
|
||||
buffer->reset();
|
||||
delete buffer;
|
||||
};
|
||||
auto bytes_per_pixel = image_info.bytesPerPixel();
|
||||
bitmap.installPixels(image_info, buffer_view.contents,
|
||||
dimensions.width() * bytes_per_pixel, func,
|
||||
new std::shared_ptr<impeller::DeviceBuffer>(buffer));
|
||||
bitmap.setImmutable();
|
||||
|
||||
sk_sp<SkImage> raster_image = SkImage::MakeFromBitmap(bitmap);
|
||||
return raster_image;
|
||||
}
|
||||
|
||||
void ConvertDlImageImpellerToSkImage(
|
||||
const sk_sp<DlImage>& dl_image,
|
||||
std::function<void(sk_sp<SkImage>)> encode_task,
|
||||
const std::shared_ptr<impeller::Context>& impeller_context) {
|
||||
auto texture = dl_image->impeller_texture();
|
||||
|
||||
if (impeller_context == nullptr) {
|
||||
FML_LOG(ERROR) << "Impeller context was null.";
|
||||
encode_task(nullptr);
|
||||
return;
|
||||
}
|
||||
|
||||
if (texture == nullptr) {
|
||||
FML_LOG(ERROR) << "Image was null.";
|
||||
encode_task(nullptr);
|
||||
return;
|
||||
}
|
||||
|
||||
auto dimensions = dl_image->dimensions();
|
||||
auto color_type = ToSkColorType(texture->GetTextureDescriptor().format);
|
||||
|
||||
if (dimensions.isEmpty()) {
|
||||
FML_LOG(ERROR) << "Image dimensions were empty.";
|
||||
encode_task(nullptr);
|
||||
return;
|
||||
}
|
||||
|
||||
if (!color_type.has_value()) {
|
||||
FML_LOG(ERROR) << "Failed to get color type from pixel format.";
|
||||
encode_task(nullptr);
|
||||
return;
|
||||
}
|
||||
|
||||
impeller::DeviceBufferDescriptor buffer_desc;
|
||||
buffer_desc.storage_mode = impeller::StorageMode::kHostVisible;
|
||||
buffer_desc.size =
|
||||
texture->GetTextureDescriptor().GetByteSizeOfBaseMipLevel();
|
||||
auto buffer =
|
||||
impeller_context->GetResourceAllocator()->CreateBuffer(buffer_desc);
|
||||
auto command_buffer = impeller_context->CreateCommandBuffer();
|
||||
command_buffer->SetLabel("BlitTextureToBuffer Command Buffer");
|
||||
auto pass = command_buffer->CreateBlitPass();
|
||||
pass->SetLabel("BlitTextureToBuffer Blit Pass");
|
||||
pass->AddCopy(texture, buffer);
|
||||
pass->EncodeCommands(impeller_context->GetResourceAllocator());
|
||||
auto completion = [buffer, color_type = color_type.value(), dimensions,
|
||||
encode_task = std::move(encode_task)](
|
||||
impeller::CommandBuffer::Status status) {
|
||||
if (status != impeller::CommandBuffer::Status::kCompleted) {
|
||||
encode_task(nullptr);
|
||||
return;
|
||||
}
|
||||
auto sk_image = ConvertBufferToSkImage(buffer, color_type, dimensions);
|
||||
encode_task(sk_image);
|
||||
};
|
||||
|
||||
if (!command_buffer->SubmitCommands(completion)) {
|
||||
FML_LOG(ERROR) << "Failed to submit commands.";
|
||||
}
|
||||
}
|
||||
|
||||
void DoConvertImageToRasterImpeller(
|
||||
const sk_sp<DlImage>& dl_image,
|
||||
std::function<void(sk_sp<SkImage>)> encode_task,
|
||||
const std::shared_ptr<const fml::SyncSwitch>& is_gpu_disabled_sync_switch,
|
||||
const std::shared_ptr<impeller::Context>& impeller_context) {
|
||||
is_gpu_disabled_sync_switch->Execute(
|
||||
fml::SyncSwitch::Handlers()
|
||||
.SetIfTrue([&encode_task] { encode_task(nullptr); })
|
||||
.SetIfFalse([&dl_image, &encode_task, &impeller_context] {
|
||||
ConvertDlImageImpellerToSkImage(dl_image, std::move(encode_task),
|
||||
impeller_context);
|
||||
}));
|
||||
}
|
||||
|
||||
} // namespace
|
||||
|
||||
void ConvertImageToRasterImpeller(
|
||||
const sk_sp<DlImage>& dl_image,
|
||||
std::function<void(sk_sp<SkImage>)> encode_task,
|
||||
const fml::RefPtr<fml::TaskRunner>& raster_task_runner,
|
||||
const fml::RefPtr<fml::TaskRunner>& io_task_runner,
|
||||
const std::shared_ptr<const fml::SyncSwitch>& is_gpu_disabled_sync_switch,
|
||||
const std::shared_ptr<impeller::Context>& impeller_context) {
|
||||
auto original_encode_task = std::move(encode_task);
|
||||
encode_task = [original_encode_task = std::move(original_encode_task),
|
||||
io_task_runner](sk_sp<SkImage> image) mutable {
|
||||
fml::TaskRunner::RunNowOrPostTask(
|
||||
io_task_runner,
|
||||
[original_encode_task = std::move(original_encode_task),
|
||||
image = std::move(image)]() { original_encode_task(image); });
|
||||
};
|
||||
|
||||
if (dl_image->owning_context() != DlImage::OwningContext::kRaster) {
|
||||
DoConvertImageToRasterImpeller(dl_image, std::move(encode_task),
|
||||
is_gpu_disabled_sync_switch,
|
||||
impeller_context);
|
||||
return;
|
||||
}
|
||||
|
||||
raster_task_runner->PostTask([dl_image, encode_task = std::move(encode_task),
|
||||
io_task_runner, is_gpu_disabled_sync_switch,
|
||||
impeller_context]() mutable {
|
||||
DoConvertImageToRasterImpeller(dl_image, std::move(encode_task),
|
||||
is_gpu_disabled_sync_switch,
|
||||
impeller_context);
|
||||
});
|
||||
}
|
||||
|
||||
} // namespace flutter
|
||||
28
engine/src/flutter/lib/ui/painting/image_encoding_impeller.h
Normal file
28
engine/src/flutter/lib/ui/painting/image_encoding_impeller.h
Normal file
@@ -0,0 +1,28 @@
|
||||
// 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.
|
||||
|
||||
#ifndef FLUTTER_LIB_UI_PAINTING_IMAGE_ENCODING_IMPELLER_H_
|
||||
#define FLUTTER_LIB_UI_PAINTING_IMAGE_ENCODING_IMPELLER_H_
|
||||
|
||||
#include "flutter/common/task_runners.h"
|
||||
#include "flutter/display_list/display_list_image.h"
|
||||
#include "flutter/fml/synchronization/sync_switch.h"
|
||||
|
||||
namespace impeller {
|
||||
class Context;
|
||||
} // namespace impeller
|
||||
|
||||
namespace flutter {
|
||||
|
||||
void ConvertImageToRasterImpeller(
|
||||
const sk_sp<DlImage>& dl_image,
|
||||
std::function<void(sk_sp<SkImage>)> encode_task,
|
||||
const fml::RefPtr<fml::TaskRunner>& raster_task_runner,
|
||||
const fml::RefPtr<fml::TaskRunner>& io_task_runner,
|
||||
const std::shared_ptr<const fml::SyncSwitch>& is_gpu_disabled_sync_switch,
|
||||
const std::shared_ptr<impeller::Context>& impeller_context);
|
||||
|
||||
} // namespace flutter
|
||||
|
||||
#endif // FLUTTER_LIB_UI_PAINTING_IMAGE_ENCODING_IMPELLER_H_
|
||||
102
engine/src/flutter/lib/ui/painting/image_encoding_skia.cc
Normal file
102
engine/src/flutter/lib/ui/painting/image_encoding_skia.cc
Normal file
@@ -0,0 +1,102 @@
|
||||
// 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/image_encoding.h"
|
||||
#include "flutter/lib/ui/painting/image_encoding_impl.h"
|
||||
|
||||
#include "flutter/lib/ui/painting/image.h"
|
||||
|
||||
namespace flutter {
|
||||
|
||||
void ConvertImageToRasterSkia(
|
||||
const sk_sp<DlImage>& dl_image,
|
||||
std::function<void(sk_sp<SkImage>)> encode_task,
|
||||
const fml::RefPtr<fml::TaskRunner>& raster_task_runner,
|
||||
const fml::RefPtr<fml::TaskRunner>& io_task_runner,
|
||||
const fml::WeakPtr<GrDirectContext>& resource_context,
|
||||
const fml::TaskRunnerAffineWeakPtr<SnapshotDelegate>& snapshot_delegate,
|
||||
const std::shared_ptr<const fml::SyncSwitch>& is_gpu_disabled_sync_switch) {
|
||||
// If the owning_context is kRaster, we can't access it on this task runner.
|
||||
if (dl_image->owning_context() != DlImage::OwningContext::kRaster) {
|
||||
auto image = dl_image->skia_image();
|
||||
|
||||
// Check validity of the image.
|
||||
if (image == nullptr) {
|
||||
FML_LOG(ERROR) << "Image was null.";
|
||||
encode_task(nullptr);
|
||||
return;
|
||||
}
|
||||
|
||||
auto dimensions = image->dimensions();
|
||||
|
||||
if (dimensions.isEmpty()) {
|
||||
FML_LOG(ERROR) << "Image dimensions were empty.";
|
||||
encode_task(nullptr);
|
||||
return;
|
||||
}
|
||||
|
||||
SkPixmap pixmap;
|
||||
if (image->peekPixels(&pixmap)) {
|
||||
// This is already a raster image.
|
||||
encode_task(image);
|
||||
return;
|
||||
}
|
||||
|
||||
if (sk_sp<SkImage> raster_image = image->makeRasterImage()) {
|
||||
// The image can be converted to a raster image.
|
||||
encode_task(raster_image);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
if (!raster_task_runner) {
|
||||
FML_LOG(ERROR) << "Raster task runner was null.";
|
||||
encode_task(nullptr);
|
||||
return;
|
||||
}
|
||||
|
||||
if (!io_task_runner) {
|
||||
FML_LOG(ERROR) << "IO task runner was null.";
|
||||
encode_task(nullptr);
|
||||
return;
|
||||
}
|
||||
|
||||
// Cross-context images do not support makeRasterImage. Convert these images
|
||||
// by drawing them into a surface. This must be done on the raster thread
|
||||
// to prevent concurrent usage of the image on both the IO and raster threads.
|
||||
raster_task_runner->PostTask([dl_image, encode_task = std::move(encode_task),
|
||||
resource_context, snapshot_delegate,
|
||||
io_task_runner, is_gpu_disabled_sync_switch,
|
||||
raster_task_runner]() {
|
||||
auto image = dl_image->skia_image();
|
||||
if (!image || !snapshot_delegate) {
|
||||
io_task_runner->PostTask(
|
||||
[encode_task = encode_task]() mutable { encode_task(nullptr); });
|
||||
return;
|
||||
}
|
||||
|
||||
sk_sp<SkImage> raster_image =
|
||||
snapshot_delegate->ConvertToRasterImage(image);
|
||||
|
||||
io_task_runner->PostTask([image, encode_task = encode_task,
|
||||
raster_image = std::move(raster_image),
|
||||
resource_context, is_gpu_disabled_sync_switch,
|
||||
owning_context = dl_image->owning_context(),
|
||||
raster_task_runner]() mutable {
|
||||
if (!raster_image) {
|
||||
// The rasterizer was unable to render the cross-context image
|
||||
// (presumably because it does not have a GrContext). In that case,
|
||||
// convert the image on the IO thread using the resource context.
|
||||
raster_image = ConvertToRasterUsingResourceContext(
|
||||
image, resource_context, is_gpu_disabled_sync_switch);
|
||||
}
|
||||
encode_task(raster_image);
|
||||
if (owning_context == DlImage::OwningContext::kRaster) {
|
||||
raster_task_runner->PostTask([image = std::move(image)]() {});
|
||||
}
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
} // namespace flutter
|
||||
26
engine/src/flutter/lib/ui/painting/image_encoding_skia.h
Normal file
26
engine/src/flutter/lib/ui/painting/image_encoding_skia.h
Normal file
@@ -0,0 +1,26 @@
|
||||
// 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.
|
||||
|
||||
#ifndef FLUTTER_LIB_UI_PAINTING_IMAGE_ENCODING_SKIA_H_
|
||||
#define FLUTTER_LIB_UI_PAINTING_IMAGE_ENCODING_SKIA_H_
|
||||
|
||||
#include "flutter/common/task_runners.h"
|
||||
#include "flutter/display_list/display_list_image.h"
|
||||
#include "flutter/fml/synchronization/sync_switch.h"
|
||||
#include "flutter/lib/ui/snapshot_delegate.h"
|
||||
|
||||
namespace flutter {
|
||||
|
||||
void ConvertImageToRasterSkia(
|
||||
const sk_sp<DlImage>& dl_image,
|
||||
std::function<void(sk_sp<SkImage>)> encode_task,
|
||||
const fml::RefPtr<fml::TaskRunner>& raster_task_runner,
|
||||
const fml::RefPtr<fml::TaskRunner>& io_task_runner,
|
||||
const fml::WeakPtr<GrDirectContext>& resource_context,
|
||||
const fml::TaskRunnerAffineWeakPtr<SnapshotDelegate>& snapshot_delegate,
|
||||
const std::shared_ptr<const fml::SyncSwitch>& is_gpu_disabled_sync_switch);
|
||||
|
||||
} // namespace flutter
|
||||
|
||||
#endif // FLUTTER_LIB_UI_PAINTING_IMAGE_ENCODING_SKIA_H_
|
||||
@@ -64,7 +64,8 @@ sk_sp<DlImage> SnapshotControllerImpeller::DoMakeRasterSnapshot(
|
||||
std::shared_ptr<impeller::Image> image =
|
||||
picture.ToImage(*context, render_target_size);
|
||||
if (image) {
|
||||
return impeller::DlImageImpeller::Make(image->GetTexture());
|
||||
return impeller::DlImageImpeller::Make(image->GetTexture(),
|
||||
DlImage::OwningContext::kRaster);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user