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

Commit d7c89e0

Browse files
committed
MakeFromTexture
1 parent da2fe09 commit d7c89e0

File tree

9 files changed

+190
-137
lines changed

9 files changed

+190
-137
lines changed

lib/ui/painting/display_list_deferred_image_gpu.cc

Lines changed: 53 additions & 40 deletions
Original file line numberDiff line numberDiff line change
@@ -6,21 +6,23 @@
66

77
#include <atomic>
88

9+
#include "third_party/skia/include/core/SkColorSpace.h"
10+
911
namespace flutter {
1012

1113
sk_sp<DlDeferredImageGPU> DlDeferredImageGPU::Make(
12-
SkISize size,
14+
const SkImageInfo& image_info,
1315
fml::RefPtr<fml::TaskRunner> raster_task_runner,
1416
fml::RefPtr<SkiaUnrefQueue> unref_queue) {
1517
return sk_sp<DlDeferredImageGPU>(new DlDeferredImageGPU(
16-
size, std::move(raster_task_runner), std::move(unref_queue)));
18+
image_info, std::move(raster_task_runner), std::move(unref_queue)));
1719
}
1820

1921
DlDeferredImageGPU::DlDeferredImageGPU(
20-
SkISize size,
22+
const SkImageInfo& image_info,
2123
fml::RefPtr<fml::TaskRunner> raster_task_runner,
2224
fml::RefPtr<SkiaUnrefQueue> unref_queue)
23-
: size_(size),
25+
: image_info_(image_info),
2426
raster_task_runner_(std::move(raster_task_runner)),
2527
unref_queue_(std::move(unref_queue)) {}
2628

@@ -33,13 +35,8 @@ DlDeferredImageGPU::~DlDeferredImageGPU() {
3335
if (!image_wrapper) {
3436
return;
3537
}
36-
auto image = image_wrapper->image;
37-
if (image) {
38-
GrBackendTexture texture = image->releaseBackendTexture(true);
39-
if (!texture.isValid()) {
40-
return;
41-
}
42-
38+
auto texture = image_wrapper->texture();
39+
if (texture.isValid()) {
4340
unref_queue->DeleteTexture(std::move(texture));
4441
}
4542
});
@@ -48,7 +45,7 @@ DlDeferredImageGPU::~DlDeferredImageGPU() {
4845
// |DlImage|
4946
sk_sp<SkImage> DlDeferredImageGPU::skia_image() const {
5047
auto image_wrapper = std::atomic_load(&image_wrapper_);
51-
return image_wrapper ? image_wrapper->image : nullptr;
48+
return image_wrapper ? image_wrapper->CreateSkiaImage(image_info_) : image_;
5249
};
5350

5451
// |DlImage|
@@ -59,42 +56,45 @@ std::shared_ptr<impeller::Texture> DlDeferredImageGPU::impeller_texture()
5956

6057
// |DlImage|
6158
bool DlDeferredImageGPU::isTextureBacked() const {
62-
if (auto image = skia_image()) {
63-
return image->isTextureBacked();
59+
if (auto image_wrapper = std::atomic_load(&image_wrapper_)) {
60+
return image_wrapper->isTextureBacked();
6461
}
6562
return false;
6663
}
6764

6865
// |DlImage|
6966
SkISize DlDeferredImageGPU::dimensions() const {
70-
return size_;
67+
return image_info_.dimensions();
7168
}
7269

7370
// |DlImage|
7471
size_t DlDeferredImageGPU::GetApproximateByteSize() const {
7572
// This call is accessed on the UI thread, and image_ may not be available
76-
// yet. The image is not mipmapped and it's created using N32 pixels, so this
77-
// is safe.
78-
if (size_.isEmpty()) {
79-
return sizeof(this);
80-
}
81-
return sizeof(this) + size_.width() * size_.height() * 4;
73+
// yet. The image is not mipmapped.
74+
return sizeof(this) + image_info_.computeMinByteSize();
8275
}
8376

84-
void DlDeferredImageGPU::set_image(
85-
sk_sp<SkImage> image,
77+
void DlDeferredImageGPU::set_texture(
78+
const GrBackendTexture& texture,
79+
sk_sp<GrDirectContext> context,
8680
std::shared_ptr<TextureRegistry> texture_registry) {
8781
FML_DCHECK(raster_task_runner_->RunsTasksOnCurrentThread());
88-
FML_DCHECK(image);
89-
FML_DCHECK(image->dimensions() == size_);
82+
FML_DCHECK(texture.isValid());
83+
FML_DCHECK(context);
9084

85+
image_ = nullptr;
9186
auto image_wrapper = std::make_shared<ImageWrapper>(
92-
std::move(image), raster_task_runner_, unref_queue_);
87+
texture, std::move(context), raster_task_runner_, unref_queue_);
9388
texture_registry_ = std::move(texture_registry);
9489
texture_registry_->RegisterContextDestroyedListener(image_wrapper);
9590
std::atomic_store(&image_wrapper_, image_wrapper);
9691
}
9792

93+
void DlDeferredImageGPU::set_image(sk_sp<SkImage> image) {
94+
FML_DCHECK(image && !image->isTextureBacked());
95+
image_ = std::move(image);
96+
}
97+
9898
void DlDeferredImageGPU::set_error(const std::string& error) {
9999
std::scoped_lock lock(error_mutex_);
100100
error_ = std::move(error);
@@ -106,23 +106,36 @@ std::optional<std::string> DlDeferredImageGPU::get_error() const {
106106
}
107107

108108
DlDeferredImageGPU::ImageWrapper::ImageWrapper(
109-
sk_sp<SkImage> p_image,
110-
fml::RefPtr<fml::TaskRunner> p_raster_task_runner,
111-
fml::RefPtr<SkiaUnrefQueue> p_unref_queue)
112-
: image(std::move(p_image)),
113-
raster_task_runner(std::move(p_raster_task_runner)),
114-
unref_queue(std::move(p_unref_queue)) {}
109+
const GrBackendTexture& texture,
110+
sk_sp<GrDirectContext> context,
111+
fml::RefPtr<fml::TaskRunner> raster_task_runner,
112+
fml::RefPtr<SkiaUnrefQueue> unref_queue)
113+
: texture_(texture),
114+
context_(std::move(context)),
115+
raster_task_runner_(std::move(raster_task_runner)),
116+
unref_queue_(std::move(unref_queue)) {}
115117

116118
void DlDeferredImageGPU::ImageWrapper::OnGrContextDestroyed() {
117-
FML_DCHECK(raster_task_runner->RunsTasksOnCurrentThread());
118-
if (image) {
119-
GrBackendTexture texture = image->releaseBackendTexture(true);
120-
image.reset();
121-
if (!texture.isValid()) {
122-
return;
123-
}
124-
unref_queue->DeleteTexture(std::move(texture));
119+
FML_DCHECK(raster_task_runner_->RunsTasksOnCurrentThread());
120+
121+
if (texture_.isValid()) {
122+
unref_queue_->DeleteTexture(std::move(texture_));
125123
}
126124
}
127125

126+
sk_sp<SkImage> DlDeferredImageGPU::ImageWrapper::CreateSkiaImage(
127+
const SkImageInfo& image_info) {
128+
FML_DCHECK(raster_task_runner_->RunsTasksOnCurrentThread());
129+
FML_DCHECK(texture_.isValid());
130+
FML_DCHECK(context_.get());
131+
132+
return SkImage::MakeFromTexture(
133+
context_.get(), texture_, kTopLeft_GrSurfaceOrigin,
134+
kRGBA_8888_SkColorType, kPremul_SkAlphaType, image_info.refColorSpace());
135+
}
136+
137+
bool DlDeferredImageGPU::ImageWrapper::isTextureBacked() {
138+
return texture_.isValid();
139+
}
140+
128141
} // namespace flutter

lib/ui/painting/display_list_deferred_image_gpu.h

Lines changed: 30 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,7 @@ namespace flutter {
1919
class DlDeferredImageGPU final : public DlImage {
2020
public:
2121
static sk_sp<DlDeferredImageGPU> Make(
22-
SkISize size,
22+
const SkImageInfo& image_info,
2323
fml::RefPtr<fml::TaskRunner> raster_task_runner,
2424
fml::RefPtr<SkiaUnrefQueue> unref_queue);
2525

@@ -28,6 +28,7 @@ class DlDeferredImageGPU final : public DlImage {
2828

2929
// |DlImage|
3030
// This method is only safe to call from the raster thread.
31+
// The image created here must not be added to the unref queue.
3132
sk_sp<SkImage> skia_image() const override;
3233

3334
// |DlImage|
@@ -43,8 +44,11 @@ class DlDeferredImageGPU final : public DlImage {
4344
virtual size_t GetApproximateByteSize() const override;
4445

4546
// This method must only be called from the raster thread.
46-
void set_image(sk_sp<SkImage> image,
47-
std::shared_ptr<TextureRegistry> texture_registry);
47+
void set_texture(const GrBackendTexture& texture,
48+
sk_sp<GrDirectContext> context,
49+
std::shared_ptr<TextureRegistry> texture_registry);
50+
51+
void set_image(sk_sp<SkImage> image);
4852

4953
// This method is safe to call from any thread.
5054
void set_error(const std::string& error);
@@ -53,36 +57,50 @@ class DlDeferredImageGPU final : public DlImage {
5357
// This method is safe to call from any thread.
5458
std::optional<std::string> get_error() const override;
5559

60+
const SkImageInfo& image_info() { return image_info_; }
61+
5662
// |DlImage|
5763
OwningContext owning_context() const override {
5864
return OwningContext::kRaster;
5965
}
6066

6167
private:
62-
struct ImageWrapper final : public ContextDestroyedListener {
63-
ImageWrapper(sk_sp<SkImage> p_image,
64-
fml::RefPtr<fml::TaskRunner> p_raster_task_runner,
65-
fml::RefPtr<SkiaUnrefQueue> p_unref_queue);
68+
class ImageWrapper final : public ContextDestroyedListener {
69+
public:
70+
ImageWrapper(const GrBackendTexture& texture,
71+
sk_sp<GrDirectContext> context,
72+
fml::RefPtr<fml::TaskRunner> raster_task_runner,
73+
fml::RefPtr<SkiaUnrefQueue> unref_queue);
74+
75+
sk_sp<SkImage> CreateSkiaImage(const SkImageInfo& image_info);
76+
77+
const GrBackendTexture& texture() { return texture_; }
78+
79+
bool isTextureBacked();
6680

67-
sk_sp<SkImage> image;
68-
fml::RefPtr<fml::TaskRunner> raster_task_runner;
69-
fml::RefPtr<SkiaUnrefQueue> unref_queue;
81+
private:
82+
GrBackendTexture texture_;
83+
sk_sp<GrDirectContext> context_;
84+
fml::RefPtr<fml::TaskRunner> raster_task_runner_;
85+
fml::RefPtr<SkiaUnrefQueue> unref_queue_;
7086

7187
// |ContextDestroyedListener|
7288
void OnGrContextDestroyed() override;
7389
};
7490

75-
SkISize size_;
91+
const SkImageInfo image_info_;
7692
fml::RefPtr<fml::TaskRunner> raster_task_runner_;
7793
fml::RefPtr<SkiaUnrefQueue> unref_queue_;
7894
// Must be accessed using atomics.
7995
// TODO(dnfield): When c++20 is available use std::atomic<std::shared_ptr>
8096
std::shared_ptr<ImageWrapper> image_wrapper_;
8197
std::shared_ptr<TextureRegistry> texture_registry_;
98+
// May be used if this image is not texture backed.
99+
sk_sp<SkImage> image_;
82100
mutable std::mutex error_mutex_;
83101
std::optional<std::string> error_;
84102

85-
DlDeferredImageGPU(SkISize size,
103+
DlDeferredImageGPU(const SkImageInfo& image_info,
86104
fml::RefPtr<fml::TaskRunner> raster_task_runner,
87105
fml::RefPtr<SkiaUnrefQueue> unref_queue);
88106

lib/ui/painting/image_encoding.cc

Lines changed: 32 additions & 51 deletions
Original file line numberDiff line numberDiff line change
@@ -60,21 +60,6 @@ void InvokeDataCallback(std::unique_ptr<DartPersistentValue> callback,
6060
DartInvoke(callback->value(), {dart_data});
6161
}
6262

63-
static void ConvertGpuImageToRaster(
64-
sk_sp<DlImage> dl_image,
65-
std::function<void(sk_sp<SkImage>)> encode_task,
66-
fml::RefPtr<fml::TaskRunner> raster_task_runner) {
67-
fml::TaskRunner::RunNowOrPostTask(
68-
raster_task_runner, [dl_image, encode_task = std::move(encode_task)]() {
69-
auto image = dl_image->skia_image();
70-
if (image == nullptr) {
71-
encode_task(nullptr);
72-
return;
73-
}
74-
encode_task(image->makeRasterImage());
75-
});
76-
}
77-
7863
void ConvertImageToRaster(
7964
sk_sp<DlImage> dl_image,
8065
std::function<void(sk_sp<SkImage>)> encode_task,
@@ -83,42 +68,46 @@ void ConvertImageToRaster(
8368
fml::WeakPtr<GrDirectContext> resource_context,
8469
fml::WeakPtr<SnapshotDelegate> snapshot_delegate,
8570
const std::shared_ptr<const fml::SyncSwitch>& is_gpu_disabled_sync_switch) {
86-
auto image = dl_image->skia_image();
87-
88-
// Check validity of the image.
89-
if (image == nullptr) {
90-
FML_LOG(ERROR) << "Image was null.";
91-
encode_task(nullptr);
92-
return;
93-
}
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+
}
9481

95-
auto dimensions = image->dimensions();
82+
auto dimensions = image->dimensions();
9683

97-
if (dimensions.isEmpty()) {
98-
FML_LOG(ERROR) << "Image dimensions were empty.";
99-
encode_task(nullptr);
100-
return;
101-
}
84+
if (dimensions.isEmpty()) {
85+
FML_LOG(ERROR) << "Image dimensions were empty.";
86+
encode_task(nullptr);
87+
return;
88+
}
10289

103-
SkPixmap pixmap;
104-
if (image->peekPixels(&pixmap)) {
105-
// This is already a raster image.
106-
encode_task(image);
107-
return;
108-
}
90+
SkPixmap pixmap;
91+
if (image->peekPixels(&pixmap)) {
92+
// This is already a raster image.
93+
encode_task(image);
94+
return;
95+
}
10996

110-
if (sk_sp<SkImage> raster_image = image->makeRasterImage()) {
111-
// The image can be converted to a raster image.
112-
encode_task(raster_image);
113-
return;
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+
}
114102
}
115103

116104
// Cross-context images do not support makeRasterImage. Convert these images
117105
// by drawing them into a surface. This must be done on the raster thread
118106
// to prevent concurrent usage of the image on both the IO and raster threads.
119-
raster_task_runner->PostTask([image, encode_task = std::move(encode_task),
107+
raster_task_runner->PostTask([dl_image, encode_task = std::move(encode_task),
120108
resource_context, snapshot_delegate,
121109
io_task_runner, is_gpu_disabled_sync_switch]() {
110+
auto image = dl_image->skia_image();
122111
if (!snapshot_delegate) {
123112
io_task_runner->PostTask(
124113
[encode_task = std::move(encode_task)]() mutable {
@@ -244,17 +233,9 @@ void EncodeImageAndInvokeDataCallback(
244233
};
245234

246235
FML_DCHECK(image);
247-
switch (image->owning_context()) {
248-
case DlImage::OwningContext::kRaster:
249-
ConvertGpuImageToRaster(std::move(image), encode_task,
250-
raster_task_runner);
251-
break;
252-
case DlImage::OwningContext::kIO:
253-
ConvertImageToRaster(std::move(image), encode_task, raster_task_runner,
254-
io_task_runner, resource_context, snapshot_delegate,
255-
is_gpu_disabled_sync_switch);
256-
break;
257-
}
236+
ConvertImageToRaster(std::move(image), encode_task, raster_task_runner,
237+
io_task_runner, resource_context, snapshot_delegate,
238+
is_gpu_disabled_sync_switch);
258239
}
259240

260241
} // namespace

0 commit comments

Comments
 (0)