|
4 | 4 |
|
5 | 5 | #include "flutter_tizen_texture_registrar.h" |
6 | 6 |
|
7 | | -#include <iostream> |
| 7 | +#include <memory> |
8 | 8 | #include <mutex> |
9 | 9 |
|
10 | 10 | #include "flutter/shell/platform/tizen/external_texture.h" |
11 | 11 | #include "flutter/shell/platform/tizen/external_texture_surface_egl.h" |
12 | 12 | #include "flutter/shell/platform/tizen/flutter_tizen_engine.h" |
13 | 13 | #include "flutter/shell/platform/tizen/logger.h" |
| 14 | +#include "flutter/shell/platform/tizen/tizen_renderer_gl.h" |
14 | 15 |
|
15 | 16 | namespace flutter { |
16 | 17 |
|
@@ -67,16 +68,66 @@ int64_t FlutterTizenTextureRegistrar::RegisterTexture( |
67 | 68 | return texture_id; |
68 | 69 | } |
69 | 70 |
|
70 | | -bool FlutterTizenTextureRegistrar::UnregisterTexture(int64_t texture_id) { |
| 71 | +bool FlutterTizenTextureRegistrar::UnregisterTexture(int64_t texture_id, |
| 72 | + void (*callback)(void*), |
| 73 | + void* user_data) { |
| 74 | + std::unique_ptr<ExternalTexture> texture; |
71 | 75 | { |
72 | 76 | std::lock_guard<std::mutex> lock(map_mutex_); |
73 | 77 | auto iter = textures_.find(texture_id); |
74 | 78 | if (iter == textures_.end()) { |
75 | 79 | return false; |
76 | 80 | } |
| 81 | + // Remove from the map first so no *new* PopulateGLTexture() lookup can |
| 82 | + // find this texture. A PopulateGLTexture() already in flight on the render |
| 83 | + // thread may still hold a raw pointer to it (it drops map_mutex_ before |
| 84 | + // using the texture), so destruction is deferred to a render-thread task |
| 85 | + // below. |
| 86 | + texture = std::move(iter->second); |
77 | 87 | textures_.erase(iter); |
78 | 88 | } |
79 | | - return engine_->UnregisterExternalTexture(texture_id); |
| 89 | + |
| 90 | + // Destroy the texture on the render thread rather than here on the calling |
| 91 | + // (platform) thread. The engine runs this task only after any in-flight |
| 92 | + // frame callback on the render thread has completed, so it cannot race with |
| 93 | + // a PopulateGLTexture() that is still reading this texture. Tearing it down |
| 94 | + // on the platform thread instead would let the backing TBM buffer be freed |
| 95 | + // while the render thread still has it mapped/referenced -> heap corruption |
| 96 | + // and the "tbm_bo_free ... lock_cnt" crash. Running on the render thread |
| 97 | + // also puts glDeleteTextures on the thread that owns the GL context. |
| 98 | + // |
| 99 | + // The completion |callback| (used by webview_flutter_lwe to free its TBM |
| 100 | + // buffer pool) is likewise invoked only after the render thread is done with |
| 101 | + // the texture, giving the plugin a correct "safe to free" signal. |
| 102 | + FlutterTizenEngine* engine = engine_; |
| 103 | + auto* gl_renderer = dynamic_cast<TizenRendererGL*>(engine->renderer()); |
| 104 | + // shared_ptr (not unique_ptr): PostRenderThreadTask takes a copyable |
| 105 | + // std::function, so the captured owner must be copyable. |
| 106 | + std::shared_ptr<ExternalTexture> tex(std::move(texture)); |
| 107 | + engine->PostRenderThreadTask( |
| 108 | + [engine, gl_renderer, texture_id, tex, callback, user_data]() mutable { |
| 109 | + // On the render thread, make the render context current so |
| 110 | + // glDeleteTextures in the texture's destructor targets the correct |
| 111 | + // context (the engine does not guarantee a current context when |
| 112 | + // running posted tasks). |
| 113 | + // |
| 114 | + // If the engine has shut down between PostRenderThreadTask() being |
| 115 | + // called and this task running, PostRenderThreadTask() runs the task |
| 116 | + // inline and the renderer may already be destroyed, so skip |
| 117 | + // OnMakeCurrent() to avoid touching a dangling GL context/renderer. |
| 118 | + // UnregisterExternalTexture() stays unconditional: it is null-safe at |
| 119 | + // the embedder boundary (a torn-down engine handle just yields an |
| 120 | + // error) and is the registrar's core teardown step. |
| 121 | + if (engine->IsRunning() && gl_renderer) { |
| 122 | + gl_renderer->OnMakeCurrent(); |
| 123 | + } |
| 124 | + tex.reset(); |
| 125 | + engine->UnregisterExternalTexture(texture_id); |
| 126 | + if (callback) { |
| 127 | + callback(user_data); |
| 128 | + } |
| 129 | + }); |
| 130 | + return true; |
80 | 131 | } |
81 | 132 |
|
82 | 133 | bool FlutterTizenTextureRegistrar::MarkTextureFrameAvailable( |
|
0 commit comments