2727
2828namespace 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+
30112EmbedderExternalTextureGL::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
0 commit comments