feat(texture): Tear down external textures on the render thread#182
Conversation
UnregisterTexture() previously destroyed the ExternalTexture (running glDeleteTextures) synchronously on the calling platform thread. That could race with an in-flight PopulateGLTexture() on the render thread and free the backing TBM buffer while the GPU still referenced it, causing heap corruption and "tbm_bo_free ... lock_cnt" crashes on the SW backend. - Add a completion-callback parameter to UnregisterTexture, plumbed through FlutterDesktopTextureRegistrarUnregisterExternalTexture, so callers learn when teardown has actually completed. - Add FlutterTizenEngine::PostRenderThreadTask(), a thin wrapper over the embedder API's PostRenderThreadTask. - UnregisterTexture now removes the texture from the map (blocking new lookups), then posts its destruction to the render thread. The engine runs that task only after any in-flight frame callback has completed, so it no longer races; glDeleteTextures runs on the thread that owns the GL context, and the completion callback fires only once teardown is done.
There was a problem hiding this comment.
Code Review
This pull request updates the texture unregistration process to defer the destruction of external textures and their GPU resources to the render thread using PostRenderThreadTask. Feedback indicates that if the engine is not running and the task is executed inline, calling OnMakeCurrent and UnregisterExternalTexture is unsafe due to a potentially destroyed GL context or null engine handle. A guard using engine->IsRunning() is suggested to prevent crashes.
Important
The consumer version of Gemini Code Assist on GitHub is being sunset. Starting June 18, 2026, new organization installations will be blocked, and all code review activity will officially cease on July 17, 2026.
For more details on the timeline and next steps, please review the Help Documentation.
The render-thread teardown task posted by UnregisterTexture() captures a raw renderer pointer. If the engine shuts down before the task runs, PostRenderThreadTask() runs it inline and the renderer may already be destroyed, so gl_renderer->OnMakeCurrent() could touch a dangling GL context/renderer. Guard the OnMakeCurrent() call with engine->IsRunning(). UnregisterExternalTexture() stays unconditional: it is null-safe at the embedder boundary (a torn-down engine handle just yields an error return) and is the registrar's core teardown step, so guarding it would skip the mandatory unregistration in the non-running case (and breaks the RegisterUnregisterTexture unit test, whose engine is never run). Also reflow the FlutterDesktopTextureRegistrarUnregisterExternalTexture call to satisfy clang-format.
dcdc1a5 to
b390e73
Compare
PostRenderThreadTask() ignored the embedder API's return value. If posting failed (e.g. engine shutdown began concurrently with the IsRunning() check), the heap-allocated task was never scheduled and never freed, and worse, the texture teardown/completion callback it carried would never run. Run the task inline when posting fails, mirroring the existing !engine_ fallback, instead of widening the API to return a bool that the sole caller couldn't act on any differently.
…rash Rework WebView::Dispose() to tear resources down safely: - Detach all engine callbacks (including the missing "policy,response,decide") and defer evas_object_del() until the embedder's UnregisterTexture completion callback, so the engine-owned TBM surfaces are not freed while a raster-thread frame is still reading them (flutter-tizen/embedder#182). - Add is_alive_/is_disposing_ guards so async callbacks arriving after disposal no longer touch the destroyed WebView. - On the Tizen 10.0 TV emulator (TV_PROFILE + x86_64), hide the stopped view instead of deleting it to avoid a SIGSEGV in chromium-efl's ~SelectionControllerEfl(); revert once the engine fix ships. Verified on the TV 10.0 emulator: example integration tests previously crashed on WebView disposal and now pass 19/19.
UnregisterTexture() previously destroyed the ExternalTexture (running glDeleteTextures) synchronously on the calling platform thread. That could race with an in-flight PopulateGLTexture() on the render thread and free the backing TBM buffer while the GPU still referenced it, causing heap corruption and "tbm_bo_free ... lock_cnt" crashes on the SW backend.