-
Notifications
You must be signed in to change notification settings - Fork 2
[Tizen] Re-implemented render external texture gl for impeller to avoid change FlutterOpenGLTexture and use deprecated api #22
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: flutter-3.38.3
Are you sure you want to change the base?
Conversation
The offical PR doesn't work
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Pull request overview
This PR re-implements external texture rendering for Impeller on Tizen to address two critical design issues: (1) avoiding modifications to the public FlutterOpenGLTexture API by removing added fields (buffer, buffer_size, bind_callback), and (2) eliminating the use of deprecated SetContents API in favor of TextureGLES::WrapTexture.
Key changes:
- Removed buffer management fields from FlutterOpenGLTexture struct
- Replaced ResolveTextureImpellerPixelbuffer and ResolveTextureImpellerSurface with a unified CreateImpellerTexture approach using WrapTexture
- Added texture change detection via IsExternalTextureChanged to cache and reuse texture objects
Reviewed changes
Copilot reviewed 3 out of 3 changed files in this pull request and generated 7 comments.
| File | Description |
|---|---|
| embedder.h | Removed buffer-related fields and bind_callback from FlutterOpenGLTexture; moved BoolCallback typedef after FlutterOpenGLSurface definition |
| embedder_external_texture_gl.h | Added texture_image_ and desc_ members for caching; replaced two Impeller resolution methods with IsExternalTextureChanged and CreateImpellerTexture |
| embedder_external_texture_gl.cc | Implemented texture caching with change detection; replaced deprecated SetContents with WrapTexture API; added cleanup callback registration |
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
| if (texture_image_ == nullptr) { | ||
| texture_image_ = CreateImpellerTexture(aiks_context, texture.get()); | ||
| } else { | ||
| if (IsExternalTextureChanged(texture.get())) { | ||
| texture_image_.reset(); | ||
| texture_image_ = CreateImpellerTexture(aiks_context, texture.get()); | ||
| } | ||
| return nullptr; | ||
| } |
Copilot
AI
Jan 8, 2026
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
When the texture hasn't changed (IsExternalTextureChanged returns false at line 235), the code doesn't call the destruction_callback for the newly obtained texture object. The external_texture_callback_ returns a new FlutterOpenGLTexture object each time it's called (line 216-217), and each of these objects may have associated embedder resources that need to be cleaned up via the destruction_callback.
Without calling the destruction_callback for unchanged textures, embedder resources associated with these texture objects will leak on every frame where the texture hasn't changed.
| bool EmbedderExternalTextureGL::IsExternalTextureChanged( | ||
| FlutterOpenGLTexture* texture) { | ||
| if (static_cast<int64_t>(texture->width) != desc_.size.width || | ||
| static_cast<int64_t>(texture->height) != desc_.size.height) { | ||
| return true; | ||
| } | ||
| auto handle = texture_image_->GetGLHandle(); | ||
| if (!handle.has_value()) { | ||
| return true; | ||
| } | ||
|
|
||
| if (handle.value() != texture->name) { | ||
| return true; | ||
| } | ||
| return false; | ||
| } |
Copilot
AI
Jan 8, 2026
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The IsExternalTextureChanged function assumes texture_image_ is non-null, but it's called inside ResolveTextureImpeller after checking if texture_image_ is nullptr on line 232. However, this check could fail if texture_image_ is not null but GetGLHandle() returns no value. In such cases, line 138 accesses texture_image_->GetGLHandle() which could be called on a null or invalid texture_image_.
Additionally, this function is called at line 235 where texture_image_ is guaranteed to be non-null due to the else clause, but there's no guard against texture_image_ being in an invalid state.
| if (static_cast<int64_t>(texture->width) != desc_.size.width || | ||
| static_cast<int64_t>(texture->height) != desc_.size.height) { | ||
| return true; |
Copilot
AI
Jan 8, 2026
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The member variable desc_ is being used to store texture state for comparison in IsExternalTextureChanged, but it's not properly initialized before the first call. On the first invocation where texture_image_ is nullptr (line 232), CreateImpellerTexture is called which sets desc_ at line 165. However, if IsExternalTextureChanged is called when texture_image_ is non-null but desc_ hasn't been initialized from a previous successful CreateImpellerTexture call, the comparison will use uninitialized values.
While this may work in practice because desc_ is initialized during CreateImpellerTexture, the logic is fragile and relies on implicit ordering assumptions.
engine/src/flutter/shell/platform/embedder/embedder_external_texture_gl.cc
Outdated
Show resolved
Hide resolved
| 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 for texture: " | ||
| << texture->name; | ||
| // Clean up the texture since we couldn't register the callback | ||
| texture_image.reset(); | ||
| return nullptr; | ||
| } |
Copilot
AI
Jan 8, 2026
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
When RegisterCleanupCallback fails (line 198), the code resets texture_image but doesn't explicitly call the destruction_callback for the current texture. The destruction_callback needs to be invoked to allow the embedder to clean up resources immediately when the cleanup callback registration fails. Without this, embedder resources associated with the texture parameter may leak.
engine/src/flutter/shell/platform/embedder/embedder_external_texture_gl.cc
Outdated
Show resolved
Hide resolved
| // Validate texture parameters | ||
| if (size.width() <= 0 || size.height() <= 0) { | ||
| FML_LOG(ERROR) << "Invalid texture size: " << size.width() << "x" | ||
| << size.height(); | ||
| return nullptr; | ||
| } |
Copilot
AI
Jan 8, 2026
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The validation of texture size occurs after fetching the texture from external_texture_callback_ (line 216), but before using it. If this validation fails, the destruction_callback for the texture object won't be called, leading to a resource leak. The texture object should have its destruction_callback invoked before returning.
1.Add validation for texture dimensions(width/height > 0) 2.Add validation for texture name. 3.Add datailed error logging.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Pull request overview
Copilot reviewed 3 out of 3 changed files in this pull request and generated 5 comments.
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
engine/src/flutter/shell/platform/embedder/embedder_external_texture_gl.h
Outdated
Show resolved
Hide resolved
engine/src/flutter/shell/platform/embedder/embedder_external_texture_gl.cc
Show resolved
Hide resolved
| sk_sp<DlImage> EmbedderExternalTextureGL::ResolveTextureImpeller( | ||
| int64_t texture_id, | ||
| impeller::AiksContext* aiks_context, | ||
| const SkISize& size) { | ||
| std::unique_ptr<FlutterOpenGLTexture> texture = | ||
| external_texture_callback_(texture_id, size.width(), size.height()); | ||
|
|
||
| if (!texture) { | ||
| FML_LOG(ERROR) << "External texture callback returned null for texture_id: " | ||
| << texture_id; | ||
| return nullptr; | ||
| } | ||
|
|
||
| if (!texture->bind_callback(texture->user_data)) { | ||
| if (texture->destruction_callback) { | ||
| texture->destruction_callback(texture->user_data); | ||
| } | ||
| if (!ValidateTextureParameters(texture.get(), size)) { | ||
| return nullptr; | ||
| } | ||
|
|
||
| if (texture->destruction_callback) { | ||
| texture->destruction_callback(texture->user_data); | ||
| if (!texture_image_) { | ||
| texture_image_ = CreateImpellerTexture(aiks_context, texture.get()); | ||
| } else { | ||
| if (IsExternalTextureChanged(texture.get(), desc_)) { | ||
| texture_image_.reset(); | ||
| texture_image_ = CreateImpellerTexture(aiks_context, texture.get()); | ||
| } | ||
| } | ||
|
|
||
| if (texture_image_ == nullptr) { | ||
| FML_LOG(ERROR) << "Failed to create Impeller texture for texture_id: " | ||
| << texture_id; | ||
| return nullptr; | ||
| } | ||
|
|
||
| return impeller::DlImageImpeller::Make(image); | ||
| return impeller::DlImageImpeller::Make(texture_image_); | ||
| } |
Copilot
AI
Jan 9, 2026
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
There's a lifecycle management issue with the destruction callbacks. Every call to ResolveTextureImpeller invokes external_texture_callback_ which returns a new FlutterOpenGLTexture object (line 230-231). If the texture hasn't changed and texture_image_ is reused (lines 245-250), the destruction_callback from the newly returned texture is never invoked - it goes out of scope when the unique_ptr is destroyed at the end of the function. This means the embedder's cleanup code won't be called for that texture instance. The destruction callback should be invoked for each FlutterOpenGLTexture returned by the callback, regardless of whether texture_image_ is reused or recreated.
engine/src/flutter/shell/platform/embedder/embedder_external_texture_gl.cc
Show resolved
Hide resolved
| bool EmbedderExternalTextureGL::IsExternalTextureChanged( | ||
| FlutterOpenGLTexture* texture, | ||
| impeller::TextureDescriptor& desc) { | ||
| if (static_cast<int64_t>(texture->width) != desc.size.width || | ||
| static_cast<int64_t>(texture->height) != desc.size.height) { | ||
| return true; | ||
| } | ||
|
|
||
| if (!texture) { | ||
| return nullptr; | ||
| auto handle = texture_image_->GetGLHandle(); | ||
| if (!handle.has_value()) { | ||
| return true; | ||
| } | ||
|
|
||
| if (texture->bind_callback != nullptr) { | ||
| return ResolveTextureImpellerSurface(aiks_context, std::move(texture)); | ||
| } else { | ||
| return ResolveTextureImpellerPixelbuffer(aiks_context, std::move(texture)); | ||
| if (handle.value() != texture->name) { | ||
| return true; | ||
| } | ||
|
|
Copilot
AI
Jan 9, 2026
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The IsExternalTextureChanged method takes a desc parameter but this appears to be the stored desc_ member variable based on the call at line 246. The method signature would be clearer if it didn't take the desc parameter since it's using the member variable desc_ stored from previous calls. Alternatively, if the intent is to compare against a provided descriptor, the parameter name should be different (e.g., previous_desc or stored_desc) to clarify what's being compared.
7e690e0 to
e3ef7ce
Compare
1.Add validateTextureParmeters help method to reduce code dulication.
We have supported render external texture gl for Impeller
flutter-tizen/engine#368
But this PR has two issues:
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