Skip to content

Commit fcd10a6

Browse files
authored
[Tizen] Re-implemented render external texture gl for impeller to avoid change FlutterOpenGLTexture and use deprecated api (#26)
We have supported render external texture gl for Impeller flutter-tizen/engine#368 But this PR has two issues: 1. It modify FlutterOpenGLTexture, it added additional variables, not a good design. ```C++ /// The pixel data buffer. const uint8_t* buffer; /// The size of pixel buffer. size_t buffer_size; /// Callback invoked that the gpu surface texture start binding. BoolCallback bind_callback; /// The type of the texture. FlutterGLImpellerTextureType impeller_texture_type; ``` 2. It uses Deprecated API ```C++ // Deprecated: use BlitPass::AddCopy instead. [[nodiscard]] bool SetContents(const uint8_t* contents, size_t length, size_t slice = 0, bool is_opaque = false); ``` So I tried to revert offical PR to render external gl for impeller flutter/engine#56277 But this PR doesn't work on Tizen platform, I think This PR may not have been verified. To avoid change FlutterOpenGLTexture and use deprecated api, so I re-implemented render external texture gl for impeller based on this offical PR. Fix flutter-tizen/embedder#131 <!-- Thanks for filing a pull request! Reviewers are typically assigned within a week of filing a request. To learn more about code review, see our documentation on Tree Hygiene: https://github.com/flutter/flutter/blob/main/docs/contributing/Tree-hygiene.md --> *Replace this paragraph with a description of what this PR is changing or adding, and why. Consider including before/after screenshots.* *List which issues are fixed by this PR. You must list at least one issue. An issue is not required if the PR fixes something trivial like a typo.* *If you had to change anything in the [flutter/tests] repo, include a link to the migration guide as per the [breaking change policy].* ## Pre-launch Checklist - [ ] I read the [Contributor Guide] and followed the process outlined there for submitting PRs. - [ ] I read the [Tree Hygiene] wiki page, which explains my responsibilities. - [ ] I read and followed the [Flutter Style Guide], including [Features we expect every widget to implement]. - [ ] I signed the [CLA]. - [ ] I listed at least one issue that this PR fixes in the description above. - [ ] I updated/added relevant documentation (doc comments with `///`). - [ ] I added new tests to check the change I am making, or this PR is [test-exempt]. - [ ] I followed the [breaking change policy] and added [Data Driven Fixes] where supported. - [ ] All existing and new tests are passing. If you need help, consider asking for advice on the #hackers-new channel on [Discord]. **Note**: The Flutter team is currently trialing the use of [Gemini Code Assist for GitHub](https://developers.google.com/gemini-code-assist/docs/review-github-code). Comments from the `gemini-code-assist` bot should not be taken as authoritative feedback from the Flutter team. If you find its comments useful you can update your code accordingly, but if you are unsure or disagree with the feedback, please feel free to wait for a Flutter team member's review for guidance on which automated comments should be addressed. <!-- Links --> [Contributor Guide]: https://github.com/flutter/flutter/blob/main/docs/contributing/Tree-hygiene.md#overview [Tree Hygiene]: https://github.com/flutter/flutter/blob/main/docs/contributing/Tree-hygiene.md [test-exempt]: https://github.com/flutter/flutter/blob/main/docs/contributing/Tree-hygiene.md#tests [Flutter Style Guide]: https://github.com/flutter/flutter/blob/main/docs/contributing/Style-guide-for-Flutter-repo.md [Features we expect every widget to implement]: https://github.com/flutter/flutter/blob/main/docs/contributing/Style-guide-for-Flutter-repo.md#features-we-expect-every-widget-to-implement [CLA]: https://cla.developers.google.com/ [flutter/tests]: https://github.com/flutter/tests [breaking change policy]: https://github.com/flutter/flutter/blob/main/docs/contributing/Tree-hygiene.md#handling-breaking-changes [Discord]: https://github.com/flutter/flutter/blob/main/docs/contributing/Chat.md [Data Driven Fixes]: https://github.com/flutter/flutter/blob/main/docs/contributing/Data-driven-Fixes.md
1 parent bc84c63 commit fcd10a6

File tree

3 files changed

+199
-89
lines changed

3 files changed

+199
-89
lines changed

engine/src/flutter/shell/platform/embedder/embedder.h

Lines changed: 1 addition & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -405,7 +405,6 @@ typedef struct {
405405
} FlutterTransformation;
406406

407407
typedef void (*VoidCallback)(void* /* user data */);
408-
typedef bool (*BoolCallback)(void* /* user data */);
409408

410409
typedef enum {
411410
/// Specifies an OpenGL texture target type. Textures are specified using
@@ -513,13 +512,6 @@ typedef struct {
513512
uint32_t name;
514513
/// The texture format (example GL_RGBA8).
515514
uint32_t format;
516-
/// The pixel data buffer.
517-
const uint8_t* buffer;
518-
/// The size of pixel buffer.
519-
size_t buffer_size;
520-
/// Callback invoked that the gpu surface texture start binding.
521-
BoolCallback bind_callback;
522-
523515
/// User data to be returned on the invocation of the destruction callback.
524516
void* user_data;
525517
/// Callback invoked (on an engine managed thread) that asks the embedder to
@@ -613,6 +605,7 @@ typedef struct {
613605
uint32_t format;
614606
} FlutterOpenGLSurface;
615607

608+
typedef bool (*BoolCallback)(void* /* user data */);
616609
typedef FlutterTransformation (*TransformationCallback)(void* /* user data */);
617610
typedef uint32_t (*UIntCallback)(void* /* user data */);
618611
typedef bool (*SoftwareSurfacePresentCallback)(void* /* user data */,

engine/src/flutter/shell/platform/embedder/embedder_external_texture_gl.cc

Lines changed: 155 additions & 74 deletions
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,88 @@
2727

2828
namespace flutter {
2929

30+
std::optional<TextureLRU::Data> TextureLRU::FindTexture(
31+
std::optional<GLuint> key) {
32+
if (!key.has_value()) {
33+
return std::nullopt;
34+
}
35+
auto key_value = key.value();
36+
for (size_t i = 0u; i < kTextureMaxSize; i++) {
37+
if (textures_[i].key == key_value) {
38+
UpdateTexture(Data{.key = key_value,
39+
.texture = textures_[i].texture,
40+
.width = textures_[i].width,
41+
.height = textures_[i].height});
42+
return std::make_optional(textures_[i]);
43+
}
44+
}
45+
return std::nullopt;
46+
}
47+
48+
void TextureLRU::UpdateTexture(Data data) {
49+
if (textures_[0].key == data.key) {
50+
textures_[0] = data;
51+
return;
52+
}
53+
size_t i = 1u;
54+
for (; i < kTextureMaxSize; i++) {
55+
if (textures_[i].key == data.key) {
56+
break;
57+
}
58+
}
59+
60+
if (i == kTextureMaxSize) {
61+
return;
62+
}
63+
64+
for (auto j = i; j > 0; j--) {
65+
textures_[j] = textures_[j - 1];
66+
}
67+
textures_[0] = data;
68+
}
69+
70+
GLuint TextureLRU::AddTexture(Data data) {
71+
GLuint lru_key = textures_[kTextureMaxSize - 1].key;
72+
bool updated_image = false;
73+
for (size_t i = 0u; i < kTextureMaxSize; i++) {
74+
if (textures_[i].key == lru_key) {
75+
updated_image = true;
76+
textures_[i] = data;
77+
break;
78+
}
79+
}
80+
if (!updated_image) {
81+
textures_[0] = data;
82+
}
83+
UpdateTexture(data);
84+
return lru_key;
85+
}
86+
87+
void TextureLRU::Clear() {
88+
for (size_t i = 0u; i < kTextureMaxSize; i++) {
89+
textures_[i] = Data{.key = 0u, .texture = nullptr};
90+
}
91+
}
92+
93+
void TextureLRU::RemoveTexture(GLuint key) {
94+
size_t i = 0u;
95+
for (; i < kTextureMaxSize; i++) {
96+
if (textures_[i].key == key) {
97+
break;
98+
}
99+
}
100+
101+
if (i == kTextureMaxSize) {
102+
return;
103+
}
104+
105+
for (; i < kTextureMaxSize - 1; i++) {
106+
textures_[i] = textures_[i + 1];
107+
}
108+
109+
textures_[kTextureMaxSize - 1] = Data{.key = 0u, .texture = nullptr};
110+
}
111+
30112
EmbedderExternalTextureGL::EmbedderExternalTextureGL(
31113
int64_t texture_identifier,
32114
const ExternalTextureCallback& callback)
@@ -129,46 +211,27 @@ sk_sp<DlImage> EmbedderExternalTextureGL::ResolveTextureSkia(
129211
return DlImage::Make(std::move(image));
130212
}
131213

132-
sk_sp<DlImage> EmbedderExternalTextureGL::ResolveTextureImpeller(
133-
int64_t texture_id,
134-
impeller::AiksContext* aiks_context,
135-
const SkISize& size) {
136-
std::unique_ptr<FlutterOpenGLTexture> texture =
137-
external_texture_callback_(texture_id, size.width(), size.height());
138-
139-
if (!texture) {
140-
return nullptr;
141-
}
142-
143-
if (texture->bind_callback != nullptr) {
144-
return ResolveTextureImpellerSurface(aiks_context, std::move(texture));
145-
} else {
146-
return ResolveTextureImpellerPixelbuffer(aiks_context, std::move(texture));
147-
}
148-
}
149-
150-
sk_sp<DlImage> EmbedderExternalTextureGL::ResolveTextureImpellerPixelbuffer(
214+
std::shared_ptr<impeller::TextureGLES>
215+
EmbedderExternalTextureGL::CreateTextureGLES(
151216
impeller::AiksContext* aiks_context,
152-
std::unique_ptr<FlutterOpenGLTexture> texture) {
217+
FlutterOpenGLTexture* texture) {
153218
impeller::TextureDescriptor desc;
154219
desc.size = impeller::ISize(texture->width, texture->height);
155-
desc.type = impeller::TextureType::kTexture2D;
156220
desc.storage_mode = impeller::StorageMode::kDevicePrivate;
157221
desc.format = impeller::PixelFormat::kR8G8B8A8UNormInt;
222+
if (texture->target == GL_TEXTURE_EXTERNAL_OES) {
223+
desc.type = impeller::TextureType::kTextureExternalOES;
224+
} else {
225+
desc.type = impeller::TextureType::kTexture2D;
226+
}
158227
impeller::ContextGLES& context =
159228
impeller::ContextGLES::Cast(*aiks_context->GetContext());
160-
std::shared_ptr<impeller::TextureGLES> image =
161-
std::make_shared<impeller::TextureGLES>(context.GetReactor(), desc);
229+
impeller::HandleGLES handle = context.GetReactor()->CreateHandle(
230+
impeller::HandleType::kTexture, texture->name);
162231

163-
image->MarkContentsInitialized();
164-
if (!image->SetContents(texture->buffer, texture->buffer_size)) {
165-
if (texture->destruction_callback) {
166-
texture->destruction_callback(texture->user_data);
167-
}
168-
return nullptr;
169-
}
170-
171-
if (!image) {
232+
auto gles_texture =
233+
impeller::TextureGLES::WrapTexture(context.GetReactor(), desc, handle);
234+
if (!gles_texture) {
172235
// In case Skia rejects the image, call the release proc so that
173236
// embedders can perform collection of intermediates.
174237
if (texture->destruction_callback) {
@@ -178,58 +241,74 @@ sk_sp<DlImage> EmbedderExternalTextureGL::ResolveTextureImpellerPixelbuffer(
178241
return nullptr;
179242
}
180243

181-
if (texture->destruction_callback) {
182-
texture->destruction_callback(texture->user_data);
183-
}
244+
gles_texture->SetCoordinateSystem(
245+
impeller::TextureCoordinateSystem::kUploadFromHost);
184246

185-
return impeller::DlImageImpeller::Make(image);
247+
if (texture->destruction_callback &&
248+
!context.GetReactor()->RegisterCleanupCallback(
249+
handle,
250+
[callback = texture->destruction_callback,
251+
user_data = texture->user_data]() { callback(user_data); })) {
252+
FML_LOG(ERROR) << "Could not register destruction callback";
253+
return nullptr;
254+
}
255+
return gles_texture;
186256
}
187257

188-
sk_sp<DlImage> EmbedderExternalTextureGL::ResolveTextureImpellerSurface(
258+
sk_sp<DlImage> EmbedderExternalTextureGL::ResolveTextureImpeller(
259+
int64_t texture_id,
189260
impeller::AiksContext* aiks_context,
190-
std::unique_ptr<FlutterOpenGLTexture> texture) {
191-
impeller::TextureDescriptor desc;
192-
desc.size = impeller::ISize(texture->width, texture->height);
193-
desc.storage_mode = impeller::StorageMode::kDevicePrivate;
194-
desc.format = impeller::PixelFormat::kR8G8B8A8UNormInt;
195-
desc.type = impeller::TextureType::kTextureExternalOES;
196-
impeller::ContextGLES& context =
197-
impeller::ContextGLES::Cast(*aiks_context->GetContext());
198-
std::shared_ptr<impeller::TextureGLES> image =
199-
std::make_shared<impeller::TextureGLES>(context.GetReactor(), desc);
200-
image->MarkContentsInitialized();
201-
image->SetCoordinateSystem(
202-
impeller::TextureCoordinateSystem::kUploadFromHost);
203-
if (!image->Bind()) {
204-
if (texture->destruction_callback) {
205-
texture->destruction_callback(texture->user_data);
206-
}
207-
FML_LOG(ERROR) << "Could not bind texture";
208-
return nullptr;
209-
}
261+
const SkISize& size) {
262+
std::unique_ptr<FlutterOpenGLTexture> texture =
263+
external_texture_callback_(texture_id, size.width(), size.height());
210264

211-
if (!image) {
212-
// In case Skia rejects the image, call the release proc so that
213-
// embedders can perform collection of intermediates.
214-
if (texture->destruction_callback) {
215-
texture->destruction_callback(texture->user_data);
216-
}
217-
FML_LOG(ERROR) << "Could not create external texture";
265+
if (!texture) {
218266
return nullptr;
219267
}
220268

221-
if (!texture->bind_callback(texture->user_data)) {
222-
if (texture->destruction_callback) {
223-
texture->destruction_callback(texture->user_data);
224-
}
225-
return nullptr;
226-
}
269+
std::optional<TextureLRU::Data> texture_data =
270+
texture_lru_.FindTexture(texture->name);
271+
272+
bool size_change = false;
227273

228-
if (texture->destruction_callback) {
229-
texture->destruction_callback(texture->user_data);
274+
if (texture_data.has_value() &&
275+
(texture_data.value().width != texture->width ||
276+
texture_data.value().height != texture->height)) {
277+
size_change = true;
230278
}
231279

232-
return impeller::DlImageImpeller::Make(image);
280+
if (texture_data.has_value() && !size_change) {
281+
return impeller::DlImageImpeller::Make(texture_data.value().texture);
282+
} else if (texture_data.has_value() && size_change) {
283+
std::shared_ptr<impeller::TextureGLES> old_gles_texture =
284+
texture_data.value().texture;
285+
old_gles_texture->Leak();
286+
std::shared_ptr<impeller::TextureGLES> new_gles_texture =
287+
CreateTextureGLES(aiks_context, texture.get());
288+
if (new_gles_texture) {
289+
texture_lru_.UpdateTexture(TextureLRU::Data{.key = texture->name,
290+
.texture = new_gles_texture,
291+
.width = texture->width,
292+
.height = texture->height});
293+
294+
return impeller::DlImageImpeller::Make(new_gles_texture);
295+
} else {
296+
texture_lru_.RemoveTexture(texture->name);
297+
return nullptr;
298+
}
299+
} else {
300+
std::shared_ptr<impeller::TextureGLES> new_gles_texture =
301+
CreateTextureGLES(aiks_context, texture.get());
302+
if (new_gles_texture) {
303+
texture_lru_.AddTexture(TextureLRU::Data{.key = texture->name,
304+
.texture = new_gles_texture,
305+
.width = texture->width,
306+
.height = texture->height});
307+
return impeller::DlImageImpeller::Make(new_gles_texture);
308+
} else {
309+
return nullptr;
310+
}
311+
}
233312
}
234313

235314
// |flutter::Texture|
@@ -244,6 +323,8 @@ void EmbedderExternalTextureGL::MarkNewFrameAvailable() {
244323
}
245324

246325
// |flutter::Texture|
247-
void EmbedderExternalTextureGL::OnTextureUnregistered() {}
326+
void EmbedderExternalTextureGL::OnTextureUnregistered() {
327+
texture_lru_.Clear();
328+
}
248329

249330
} // namespace flutter

engine/src/flutter/shell/platform/embedder/embedder_external_texture_gl.h

Lines changed: 43 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -5,12 +5,52 @@
55
#ifndef FLUTTER_SHELL_PLATFORM_EMBEDDER_EMBEDDER_EXTERNAL_TEXTURE_GL_H_
66
#define FLUTTER_SHELL_PLATFORM_EMBEDDER_EMBEDDER_EXTERNAL_TEXTURE_GL_H_
77

8+
#include <list>
9+
#include <memory>
10+
#include <unordered_map>
811
#include "flutter/common/graphics/texture.h"
912
#include "flutter/fml/macros.h"
1013
#include "flutter/shell/platform/embedder/embedder.h"
14+
#include "impeller/renderer/backend/gles/texture_gles.h"
1115
#include "third_party/skia/include/core/SkSize.h"
1216

1317
namespace flutter {
18+
static constexpr size_t kTextureMaxSize = 6u;
19+
20+
class TextureLRU {
21+
public:
22+
struct Data {
23+
GLuint key = 0u;
24+
std::shared_ptr<impeller::TextureGLES> texture;
25+
size_t width = 0;
26+
size_t height = 0;
27+
};
28+
29+
TextureLRU() = default;
30+
31+
~TextureLRU() = default;
32+
33+
/// @brief Retrieve the Texture associated with the given [key], or nullptr.
34+
std::optional<Data> FindTexture(std::optional<GLuint> key);
35+
36+
/// @brief Add a new texture to the cache with a key, returning the key of the
37+
/// LRU entry that was removed.
38+
///
39+
/// The value may be `0`, in which case nothing was removed.
40+
GLuint AddTexture(Data data);
41+
42+
/// @brief Remove all entires from the image cache.
43+
void Clear();
44+
45+
/// @brief Remove a texture from the cache by key.
46+
void RemoveTexture(GLuint key);
47+
48+
/// @brief Marks [key] as the most recently used.
49+
void UpdateTexture(Data data);
50+
51+
private:
52+
std::array<Data, kTextureMaxSize> textures_;
53+
};
1454

1555
class EmbedderExternalTextureGL : public flutter::Texture {
1656
public:
@@ -25,7 +65,7 @@ class EmbedderExternalTextureGL : public flutter::Texture {
2565
private:
2666
const ExternalTextureCallback& external_texture_callback_;
2767
sk_sp<DlImage> last_image_;
28-
68+
TextureLRU texture_lru_ = TextureLRU();
2969
sk_sp<DlImage> ResolveTexture(int64_t texture_id,
3070
GrDirectContext* context,
3171
impeller::AiksContext* aiks_context,
@@ -39,13 +79,9 @@ class EmbedderExternalTextureGL : public flutter::Texture {
3979
impeller::AiksContext* aiks_context,
4080
const SkISize& size);
4181

42-
sk_sp<DlImage> ResolveTextureImpellerPixelbuffer(
43-
impeller::AiksContext* aiks_context,
44-
std::unique_ptr<FlutterOpenGLTexture> texture);
45-
46-
sk_sp<DlImage> ResolveTextureImpellerSurface(
82+
std::shared_ptr<impeller::TextureGLES> CreateTextureGLES(
4783
impeller::AiksContext* aiks_context,
48-
std::unique_ptr<FlutterOpenGLTexture> texture);
84+
FlutterOpenGLTexture* texture);
4985

5086
// |flutter::Texture|
5187
void Paint(PaintContext& context,

0 commit comments

Comments
 (0)