Skip to content
This repository was archived by the owner on Feb 25, 2025. It is now read-only.

Commit 1353018

Browse files
committed
[Impeller] Support 'ui.Image.toByteData()'
1 parent 4464920 commit 1353018

File tree

11 files changed

+328
-87
lines changed

11 files changed

+328
-87
lines changed

ci/licenses_golden/licenses_flutter

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1690,7 +1690,11 @@ FILE: ../../../flutter/lib/ui/painting/image_descriptor.h
16901690
FILE: ../../../flutter/lib/ui/painting/image_dispose_unittests.cc
16911691
FILE: ../../../flutter/lib/ui/painting/image_encoding.cc
16921692
FILE: ../../../flutter/lib/ui/painting/image_encoding.h
1693+
FILE: ../../../flutter/lib/ui/painting/image_encoding_impeller.cc
1694+
FILE: ../../../flutter/lib/ui/painting/image_encoding_impeller.h
16931695
FILE: ../../../flutter/lib/ui/painting/image_encoding_impl.h
1696+
FILE: ../../../flutter/lib/ui/painting/image_encoding_skia.cc
1697+
FILE: ../../../flutter/lib/ui/painting/image_encoding_skia.h
16941698
FILE: ../../../flutter/lib/ui/painting/image_encoding_unittests.cc
16951699
FILE: ../../../flutter/lib/ui/painting/image_filter.cc
16961700
FILE: ../../../flutter/lib/ui/painting/image_filter.h

display_list/display_list_image.h

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -67,6 +67,11 @@ class DlImage : public SkRefCnt {
6767

6868
virtual bool isTextureBacked() const = 0;
6969

70+
//----------------------------------------------------------------------------
71+
/// @return Whether this image was created deferred.
72+
///
73+
virtual bool IsDeferred() const { return false; }
74+
7075
//----------------------------------------------------------------------------
7176
/// @return The dimensions of the pixel grid.
7277
///

impeller/renderer/backend/gles/blit_command_gles.cc

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -126,8 +126,10 @@ std::string BlitCopyTextureToBufferCommandGLES::GetLabel() const {
126126

127127
bool BlitCopyTextureToBufferCommandGLES::Encode(
128128
const ReactorGLES& reactor) const {
129-
if (source->GetTextureDescriptor().format != PixelFormat::kR8G8B8A8UNormInt) {
130-
VALIDATION_LOG << "Only textures with pixel format RGBA are supported yet.";
129+
if (source->GetTextureDescriptor().format != PixelFormat::kR8G8B8A8UNormInt &&
130+
source->GetTextureDescriptor().format != PixelFormat::kB8G8R8A8UNormInt) {
131+
VALIDATION_LOG
132+
<< "Only textures with pixel format RGBA or BGAR are supported yet.";
131133
return false;
132134
}
133135

lib/ui/BUILD.gn

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -53,6 +53,8 @@ source_set("ui") {
5353
"painting/image_encoding.cc",
5454
"painting/image_encoding.h",
5555
"painting/image_encoding_impl.h",
56+
"painting/image_encoding_skia.cc",
57+
"painting/image_encoding_skia.h",
5658
"painting/image_filter.cc",
5759
"painting/image_filter.h",
5860
"painting/image_generator.cc",
@@ -167,6 +169,8 @@ source_set("ui") {
167169
"painting/display_list_deferred_image_gpu_impeller.h",
168170
"painting/image_decoder_impeller.cc",
169171
"painting/image_decoder_impeller.h",
172+
"painting/image_encoding_impeller.cc",
173+
"painting/image_encoding_impeller.h",
170174
]
171175

172176
deps += [ "//flutter/impeller" ]

lib/ui/painting/display_list_deferred_image_gpu_impeller.h

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -44,6 +44,9 @@ class DlDeferredImageGPUImpeller final : public DlImage {
4444
// |DlImage|
4545
bool isTextureBacked() const override;
4646

47+
// |DlImage|
48+
bool IsDeferred() const override { return true; }
49+
4750
// |DlImage|
4851
SkISize dimensions() const override;
4952

lib/ui/painting/display_list_deferred_image_gpu_skia.h

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -55,6 +55,9 @@ class DlDeferredImageGPUSkia final : public DlImage {
5555
// |DlImage|
5656
bool isTextureBacked() const override;
5757

58+
// |DlImage|
59+
bool IsDeferred() const override { return true; }
60+
5861
// |DlImage|
5962
SkISize dimensions() const override;
6063

lib/ui/painting/image_encoding.cc

Lines changed: 25 additions & 85 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,10 @@
1313
#include "flutter/fml/make_copyable.h"
1414
#include "flutter/fml/trace_event.h"
1515
#include "flutter/lib/ui/painting/image.h"
16+
#if IMPELLER_SUPPORTS_RENDERING
17+
#include "flutter/lib/ui/painting/image_encoding_impeller.h"
18+
#endif // IMPELLER_SUPPORTS_RENDERING
19+
#include "flutter/lib/ui/painting/image_encoding_skia.h"
1620
#include "third_party/skia/include/core/SkEncodedImageFormat.h"
1721
#include "third_party/tonic/dart_persistent_value.h"
1822
#include "third_party/tonic/logging/dart_invoke.h"
@@ -22,6 +26,9 @@ using tonic::DartInvoke;
2226
using tonic::DartPersistentValue;
2327
using tonic::ToDart;
2428

29+
namespace impeller {
30+
class Context;
31+
} // namespace impeller
2532
namespace flutter {
2633
namespace {
2734

@@ -60,84 +67,6 @@ void InvokeDataCallback(std::unique_ptr<DartPersistentValue> callback,
6067
DartInvoke(callback->value(), {dart_data});
6168
}
6269

63-
void ConvertImageToRaster(
64-
const sk_sp<DlImage>& dl_image,
65-
std::function<void(sk_sp<SkImage>)> encode_task,
66-
const fml::RefPtr<fml::TaskRunner>& raster_task_runner,
67-
const fml::RefPtr<fml::TaskRunner>& io_task_runner,
68-
const fml::WeakPtr<GrDirectContext>& resource_context,
69-
const fml::TaskRunnerAffineWeakPtr<SnapshotDelegate>& snapshot_delegate,
70-
const std::shared_ptr<const fml::SyncSwitch>& is_gpu_disabled_sync_switch) {
71-
// If the owning_context is kRaster, we can't access it on this task runner.
72-
if (dl_image->owning_context() != DlImage::OwningContext::kRaster) {
73-
auto image = dl_image->skia_image();
74-
75-
// Check validity of the image.
76-
if (image == nullptr) {
77-
FML_LOG(ERROR) << "Image was null.";
78-
encode_task(nullptr);
79-
return;
80-
}
81-
82-
auto dimensions = image->dimensions();
83-
84-
if (dimensions.isEmpty()) {
85-
FML_LOG(ERROR) << "Image dimensions were empty.";
86-
encode_task(nullptr);
87-
return;
88-
}
89-
90-
SkPixmap pixmap;
91-
if (image->peekPixels(&pixmap)) {
92-
// This is already a raster image.
93-
encode_task(image);
94-
return;
95-
}
96-
97-
if (sk_sp<SkImage> raster_image = image->makeRasterImage()) {
98-
// The image can be converted to a raster image.
99-
encode_task(raster_image);
100-
return;
101-
}
102-
}
103-
104-
// Cross-context images do not support makeRasterImage. Convert these images
105-
// by drawing them into a surface. This must be done on the raster thread
106-
// to prevent concurrent usage of the image on both the IO and raster threads.
107-
raster_task_runner->PostTask([dl_image, encode_task = std::move(encode_task),
108-
resource_context, snapshot_delegate,
109-
io_task_runner, is_gpu_disabled_sync_switch,
110-
raster_task_runner]() {
111-
auto image = dl_image->skia_image();
112-
if (!image || !snapshot_delegate) {
113-
io_task_runner->PostTask(
114-
[encode_task = encode_task]() mutable { encode_task(nullptr); });
115-
return;
116-
}
117-
118-
sk_sp<SkImage> raster_image =
119-
snapshot_delegate->ConvertToRasterImage(image);
120-
121-
io_task_runner->PostTask([image, encode_task = encode_task,
122-
raster_image = std::move(raster_image),
123-
resource_context, is_gpu_disabled_sync_switch,
124-
owning_context = dl_image->owning_context(),
125-
raster_task_runner]() mutable {
126-
if (!raster_image) {
127-
// The rasterizer was unable to render the cross-context image
128-
// (presumably because it does not have a GrContext). In that case,
129-
// convert the image on the IO thread using the resource context.
130-
raster_image = ConvertToRasterUsingResourceContext(
131-
image, resource_context, is_gpu_disabled_sync_switch);
132-
}
133-
encode_task(raster_image);
134-
if (owning_context == DlImage::OwningContext::kRaster) {
135-
raster_task_runner->PostTask([image = std::move(image)]() {});
136-
}
137-
});
138-
});
139-
}
140-
14170
sk_sp<SkData> CopyImageByteData(const sk_sp<SkImage>& raster_image,
14271
SkColorType color_type,
14372
SkAlphaType alpha_type) {
@@ -221,7 +150,9 @@ void EncodeImageAndInvokeDataCallback(
221150
const fml::RefPtr<fml::TaskRunner>& io_task_runner,
222151
const fml::WeakPtr<GrDirectContext>& resource_context,
223152
const fml::TaskRunnerAffineWeakPtr<SnapshotDelegate>& snapshot_delegate,
224-
const std::shared_ptr<const fml::SyncSwitch>& is_gpu_disabled_sync_switch) {
153+
const std::shared_ptr<const fml::SyncSwitch>& is_gpu_disabled_sync_switch,
154+
const std::shared_ptr<impeller::Context>& impeller_context,
155+
bool is_impeller_enabled) {
225156
auto callback_task = fml::MakeCopyable(
226157
[callback = std::move(callback)](sk_sp<SkData> encoded) mutable {
227158
InvokeDataCallback(std::move(callback), std::move(encoded));
@@ -239,9 +170,16 @@ void EncodeImageAndInvokeDataCallback(
239170
};
240171

241172
FML_DCHECK(image);
242-
ConvertImageToRaster(image, encode_task, raster_task_runner, io_task_runner,
243-
resource_context, snapshot_delegate,
244-
is_gpu_disabled_sync_switch);
173+
#if IMPELLER_SUPPORTS_RENDERING
174+
if (is_impeller_enabled) {
175+
ConvertImageToRasterImpeller(image, encode_task, raster_task_runner,
176+
io_task_runner, is_gpu_disabled_sync_switch,
177+
impeller_context);
178+
}
179+
#endif // IMPELLER_SUPPORTS_RENDERING
180+
ConvertImageToRasterSkia(image, encode_task, raster_task_runner,
181+
io_task_runner, resource_context, snapshot_delegate,
182+
is_gpu_disabled_sync_switch);
245183
}
246184

247185
} // namespace
@@ -272,13 +210,15 @@ Dart_Handle EncodeImage(CanvasImage* canvas_image,
272210
raster_task_runner = task_runners.GetRasterTaskRunner(),
273211
io_task_runner = task_runners.GetIOTaskRunner(),
274212
io_manager = UIDartState::Current()->GetIOManager(),
275-
snapshot_delegate =
276-
UIDartState::Current()->GetSnapshotDelegate()]() mutable {
213+
snapshot_delegate = UIDartState::Current()->GetSnapshotDelegate(),
214+
is_impeller_enabled =
215+
UIDartState::Current()->IsImpellerEnabled()]() mutable {
277216
EncodeImageAndInvokeDataCallback(
278217
image, std::move(callback), image_format, ui_task_runner,
279218
raster_task_runner, io_task_runner,
280219
io_manager->GetResourceContext(), snapshot_delegate,
281-
io_manager->GetIsGpuDisabledSyncSwitch());
220+
io_manager->GetIsGpuDisabledSyncSwitch(),
221+
io_manager->GetImpellerContext(), is_impeller_enabled);
282222
}));
283223

284224
return Dart_Null();
Lines changed: 136 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,136 @@
1+
// Copyright 2013 The Flutter Authors. All rights reserved.
2+
// Use of this source code is governed by a BSD-style license that can be
3+
// found in the LICENSE file.
4+
5+
#include "flutter/lib/ui/painting/image.h"
6+
#include "impeller/renderer/command_buffer.h"
7+
#include "impeller/renderer/context.h"
8+
#include "impeller/renderer/device_buffer.h"
9+
#include "impeller/renderer/formats.h"
10+
11+
namespace flutter {
12+
namespace {
13+
14+
std::optional<SkColorType> ToSkColorType(impeller::PixelFormat format) {
15+
switch (format) {
16+
case impeller::PixelFormat::kR8G8B8A8UNormInt:
17+
return SkColorType::kRGBA_8888_SkColorType;
18+
case impeller::PixelFormat::kB8G8R8A8UNormInt:
19+
return SkColorType::kBGRA_8888_SkColorType;
20+
break;
21+
default:
22+
return std::nullopt;
23+
break;
24+
}
25+
}
26+
27+
sk_sp<SkImage> ConvertDlImageImpellerToSkImage(
28+
const sk_sp<DlImage>& dl_image,
29+
const std::shared_ptr<impeller::Context>& impeller_context) {
30+
auto texture = dl_image->impeller_texture();
31+
32+
if (impeller_context == nullptr) {
33+
FML_LOG(ERROR) << "Impeller context was null.";
34+
return nullptr;
35+
}
36+
37+
if (texture == nullptr) {
38+
FML_LOG(ERROR) << "Image was null.";
39+
return nullptr;
40+
}
41+
42+
auto dimensions = dl_image->dimensions();
43+
44+
if (dimensions.isEmpty()) {
45+
FML_LOG(ERROR) << "Image dimensions were empty.";
46+
return nullptr;
47+
}
48+
49+
impeller::DeviceBufferDescriptor buffer_desc;
50+
buffer_desc.storage_mode = impeller::StorageMode::kHostVisible;
51+
buffer_desc.size =
52+
texture->GetTextureDescriptor().GetByteSizeOfBaseMipLevel();
53+
auto buffer =
54+
impeller_context->GetResourceAllocator()->CreateBuffer(buffer_desc);
55+
auto command_buffer = impeller_context->CreateCommandBuffer();
56+
command_buffer->SetLabel("BlitTextureToBuffer Command Buffer");
57+
auto pass = command_buffer->CreateBlitPass();
58+
pass->SetLabel("BlitTextureToBuffer Blit Pass");
59+
pass->AddCopy(texture, buffer);
60+
pass->EncodeCommands(impeller_context->GetResourceAllocator());
61+
if (!command_buffer->SubmitCommands()) {
62+
FML_LOG(ERROR) << "Failed to submit commands.";
63+
return nullptr;
64+
}
65+
impeller_context->WaitUntilCommandsCompleted();
66+
auto buffer_view = buffer->AsBufferView();
67+
68+
auto color_type = ToSkColorType(texture->GetTextureDescriptor().format);
69+
if (!color_type.has_value()) {
70+
FML_LOG(ERROR) << "Failed to get color type from pixel format.";
71+
}
72+
SkImageInfo image_info = SkImageInfo::Make(dimensions, color_type.value(),
73+
SkAlphaType::kPremul_SkAlphaType);
74+
75+
SkBitmap bitmap;
76+
auto func = [](void* addr, void* context) {
77+
auto buffer =
78+
static_cast<std::shared_ptr<impeller::DeviceBuffer>*>(context);
79+
buffer->reset();
80+
delete buffer;
81+
};
82+
auto bytes_per_pixel = impeller::BytesPerPixelForPixelFormat(
83+
texture->GetTextureDescriptor().format);
84+
bitmap.installPixels(image_info, buffer_view.contents,
85+
dimensions.width() * bytes_per_pixel, func,
86+
new std::shared_ptr<impeller::DeviceBuffer>(buffer));
87+
bitmap.setImmutable();
88+
89+
sk_sp<SkImage> raster_image = SkImage::MakeFromBitmap(bitmap);
90+
return raster_image;
91+
}
92+
93+
void DoConvertImageToRasterImpeller(
94+
const sk_sp<DlImage>& dl_image,
95+
std::function<void(sk_sp<SkImage>)> encode_task,
96+
const std::shared_ptr<const fml::SyncSwitch>& is_gpu_disabled_sync_switch,
97+
const std::shared_ptr<impeller::Context>& impeller_context) {
98+
is_gpu_disabled_sync_switch->Execute(
99+
fml::SyncSwitch::Handlers()
100+
.SetIfTrue([&encode_task] { encode_task(nullptr); })
101+
.SetIfFalse([&dl_image, &encode_task, &impeller_context] {
102+
encode_task(
103+
ConvertDlImageImpellerToSkImage(dl_image, impeller_context));
104+
}));
105+
}
106+
107+
} // namespace
108+
109+
void ConvertImageToRasterImpeller(
110+
const sk_sp<DlImage>& dl_image,
111+
std::function<void(sk_sp<SkImage>)> encode_task,
112+
const fml::RefPtr<fml::TaskRunner>& raster_task_runner,
113+
const fml::RefPtr<fml::TaskRunner>& io_task_runner,
114+
const std::shared_ptr<const fml::SyncSwitch>& is_gpu_disabled_sync_switch,
115+
const std::shared_ptr<impeller::Context>& impeller_context) {
116+
if (!dl_image->IsDeferred() || dl_image->impeller_texture() != nullptr) {
117+
DoConvertImageToRasterImpeller(dl_image, std::move(encode_task),
118+
is_gpu_disabled_sync_switch,
119+
impeller_context);
120+
return;
121+
}
122+
123+
raster_task_runner->PostTask([dl_image, encode_task = std::move(encode_task),
124+
io_task_runner, is_gpu_disabled_sync_switch,
125+
impeller_context]() mutable {
126+
io_task_runner->PostTask([dl_image, encode_task = std::move(encode_task),
127+
is_gpu_disabled_sync_switch,
128+
impeller_context]() mutable {
129+
DoConvertImageToRasterImpeller(dl_image, std::move(encode_task),
130+
is_gpu_disabled_sync_switch,
131+
impeller_context);
132+
});
133+
});
134+
}
135+
136+
} // namespace flutter
Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,28 @@
1+
// Copyright 2013 The Flutter Authors. All rights reserved.
2+
// Use of this source code is governed by a BSD-style license that can be
3+
// found in the LICENSE file.
4+
5+
#ifndef FLUTTER_LIB_UI_PAINTING_IMAGE_ENCODING_IMPELLER_H_
6+
#define FLUTTER_LIB_UI_PAINTING_IMAGE_ENCODING_IMPELLER_H_
7+
8+
#include "flutter/common/task_runners.h"
9+
#include "flutter/display_list/display_list_image.h"
10+
#include "flutter/fml/synchronization/sync_switch.h"
11+
12+
namespace impeller {
13+
class Context;
14+
} // namespace impeller
15+
16+
namespace flutter {
17+
18+
void ConvertImageToRasterImpeller(
19+
const sk_sp<DlImage>& dl_image,
20+
std::function<void(sk_sp<SkImage>)> encode_task,
21+
const fml::RefPtr<fml::TaskRunner>& raster_task_runner,
22+
const fml::RefPtr<fml::TaskRunner>& io_task_runner,
23+
const std::shared_ptr<const fml::SyncSwitch>& is_gpu_disabled_sync_switch,
24+
const std::shared_ptr<impeller::Context>& impeller_context);
25+
26+
} // namespace flutter
27+
28+
#endif // FLUTTER_LIB_UI_PAINTING_IMAGE_ENCODING_IMPELLER_H_

0 commit comments

Comments
 (0)