Skip to content

Conversation

@xiaowei-guan
Copy link

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.
  /// 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;
  1. It uses Deprecated API
  // 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

…id change

FlutterOpenGLTexture and use deprecated api
Copy link
Member

@JSUYA JSUYA left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Sorry for the late review.
I left a comment. Please check it.

Comment on lines 145 to 186
auto it = impeller_gl_textures_.find(texture->name);
if (it != impeller_gl_textures_.end()) {
image = it->second;
} else {
impeller::TextureDescriptor desc;
desc.size = impeller::ISize(texture->width, texture->height);
desc.storage_mode = impeller::StorageMode::kDevicePrivate;
desc.format = impeller::PixelFormat::kR8G8B8A8UNormInt;
if (texture->target == GL_TEXTURE_EXTERNAL_OES) {
desc.type = impeller::TextureType::kTextureExternalOES;
} else {
desc.type = impeller::TextureType::kTexture2D;
}
return nullptr;
}

if (!image) {
// In case Skia rejects the image, call the release proc so that
// embedders can perform collection of intermediates.
if (texture->destruction_callback) {
texture->destruction_callback(texture->user_data);
impeller::ContextGLES& context =
impeller::ContextGLES::Cast(*aiks_context->GetContext());
impeller::HandleGLES handle = context.GetReactor()->CreateHandle(
impeller::HandleType::kTexture, texture->name);

image =
impeller::TextureGLES::WrapTexture(context.GetReactor(), desc, handle);
if (!image) {
// In case Skia rejects the image, call the release proc so that
// embedders can perform collection of intermediates.
if (texture->destruction_callback) {
texture->destruction_callback(texture->user_data);
}
FML_LOG(ERROR) << "Could not create external texture";
return nullptr;
}
FML_LOG(ERROR) << "Could not create external texture";
return nullptr;
}

if (texture->destruction_callback) {
texture->destruction_callback(texture->user_data);
}
image->SetCoordinateSystem(
impeller::TextureCoordinateSystem::kUploadFromHost);

return impeller::DlImageImpeller::Make(image);
}

sk_sp<DlImage> EmbedderExternalTextureGL::ResolveTextureImpellerSurface(
impeller::AiksContext* aiks_context,
std::unique_ptr<FlutterOpenGLTexture> texture) {
impeller::TextureDescriptor desc;
desc.size = impeller::ISize(texture->width, texture->height);
desc.storage_mode = impeller::StorageMode::kDevicePrivate;
desc.format = impeller::PixelFormat::kR8G8B8A8UNormInt;
desc.type = impeller::TextureType::kTextureExternalOES;
impeller::ContextGLES& context =
impeller::ContextGLES::Cast(*aiks_context->GetContext());
std::shared_ptr<impeller::TextureGLES> image =
std::make_shared<impeller::TextureGLES>(context.GetReactor(), desc);
image->MarkContentsInitialized();
image->SetCoordinateSystem(
impeller::TextureCoordinateSystem::kUploadFromHost);
if (!image->Bind()) {
if (texture->destruction_callback) {
texture->destruction_callback(texture->user_data);
}
FML_LOG(ERROR) << "Could not bind texture";
return nullptr;
}

if (!image) {
// In case Skia rejects the image, call the release proc so that
// embedders can perform collection of intermediates.
if (texture->destruction_callback) {
texture->destruction_callback(texture->user_data);
}
FML_LOG(ERROR) << "Could not create external texture";
return nullptr;
}

if (!texture->bind_callback(texture->user_data)) {
if (texture->destruction_callback) {
texture->destruction_callback(texture->user_data);
if (texture->destruction_callback &&
!context.GetReactor()->RegisterCleanupCallback(
handle,
[callback = texture->destruction_callback,
user_data = texture->user_data]() { callback(user_data); })) {
FML_LOG(ERROR) << "Could not register destruction callback";
return nullptr;
}
return nullptr;
}

if (texture->destruction_callback) {
texture->destruction_callback(texture->user_data);
impeller_gl_textures_[texture->name] = image;
Copy link
Member

@JSUYA JSUYA Jan 23, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@@ -138,6 +140,11 @@ sk_sp<DlImage> EmbedderExternalTextureGL::ResolveTextureImpeller(
     return nullptr;
   }

+  auto it = impeller_gl_textures_.find(texture->name);
+  if (it != impeller_gl_textures_.end()) {
+    std::shared_ptr<impeller::TextureGLES> image = it->second;
+    return impeller::DlImageImpeller::Make(image);
+  }
+
   impeller::TextureDescriptor desc;
   desc.size = impeller::ISize(texture->width, texture->height);

@@ -166,6 +173,8 @@ sk_sp<DlImage> EmbedderExternalTextureGL::ResolveTextureImpeller(
     return nullptr;
   }

+  impeller_gl_textures_[texture->name] = image;
+
   return impeller::DlImageImpeller::Make(image);
 }

If I understand correctly...
If you want to reuse a texture, we can minimize code diffs by immediately returning the image.
However, I have a few questions.

  • When will the images(textures) remaining in impeller_gl_textures_ be removed ?
  • Will calling impeller_gl_textures_.clear in OnTextureUnregistered() cause problems?
  • Will this cause problems if the texture size changes?

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

When will the images(textures) remaining in impeller_gl_textures_ be removed ?
==> Replace map with LRU cache, why use LRU cache

  1. If a FlutterOpenGLTexture has the same handle, we cannot immediately destroy impeller::TextureGLES, otherwise it will cause a black screen issue.
  2. If there are multiple different FlutterOpenGLTextures, excessive handles should be destroyed to avoid out-of-memory errors. This case does not exist on the Tizen platform.

Will calling impeller_gl_textures_.clear in OnTextureUnregistered() cause problems?
==>LRU cache will clear data when OnTextureUnregistered called.
Will this cause problems if the texture size changes?
==>LRU cache will update texture when texture size change.

Comment on lines 54 to 61
size_t i = 1u;
for (; i < kTextureMaxSize; i++) {
if (textures_[i].key == data.key) {
break;
}
}
for (auto j = i; j > 0; j--) {
textures_[j] = textures_[j - 1];
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

If the key is not found, textures_[6] will be accessed because i becomes kTextureMaxSize(6). If there is no scenario where the key is not found, there is no problem, but I recommend adding a check code(like RemoveTexture) to prevent a crash.

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yes,you are right. add a check code.

Comment on lines 38 to 40
auto result = textures_[i].value;
UpdateTexture(Data{.key = key_value,
.value = result,
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Do we need result? I think you can just pass textures_[i].value
.value = textures_[i].value,

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Done

if (!updated_image) {
textures_[0] = data;
}
UpdateTexture(data);
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

um... I may be misunderstanding, but you are looking for key and then looking for it again in UpdateTexture(). Shouldn't you just pass the idx?

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is because we need to consider another scenario: if the Texture's size changes, the corresponding width and height also need to be updated.
https://github.com/flutter-tizen/flutter/pull/23/changes#diff-c2fbc9e4861def16024ee77dc86670de2ab09742bdfd1cf83364b891df991c60R285-R289

if (texture_data.has_value() && size_change) {
    std::shared_ptr<impeller::TextureGLES> old_gles_texture =
        texture_data.value().value;
    old_gles_texture->Leak();
    std::shared_ptr<impeller::TextureGLES> new_gles_texture =
        CreateTextureGLES(aiks_context, texture.get());
    if (new_gles_texture) {
      texture_lru_.UpdateTexture(TextureLRU::Data{.key = texture->name,
                                                  .value = new_gles_texture,
                                                  .width = texture->width,
                                                  .height = texture->height});

public:
struct Data {
GLuint key = 0u;
std::shared_ptr<impeller::TextureGLES> value;
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

How about texture instead of value? I think it would be good more readability.

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Done

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Revert impeller render texture code for gles

2 participants