Skip to content

Commit 9d0ff07

Browse files
authored
Destroy textures on raster thread (#427)
* Destroy textures on raster thread Signed-off-by: Bari Rao <[email protected]> * Fix format Signed-off-by: Bari Rao <[email protected]> --------- Signed-off-by: Bari Rao <[email protected]>
1 parent 9dc1156 commit 9d0ff07

11 files changed

+219
-26
lines changed

src/flutter/fml/closure.h

+77
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,77 @@
1+
// Copyright 2013 The Flutter Authors. All rights reserved.
2+
// Use of this source code is governed by a BSD-style license that can be
3+
// found in the LICENSE file.
4+
5+
#ifndef FLUTTER_FML_CLOSURE_H_
6+
#define FLUTTER_FML_CLOSURE_H_
7+
8+
#include <functional>
9+
10+
#include "flutter/fml/macros.h"
11+
12+
namespace fml {
13+
14+
using closure = std::function<void()>;
15+
16+
//------------------------------------------------------------------------------
17+
/// @brief Wraps a closure that is invoked in the destructor unless
18+
/// released by the caller.
19+
///
20+
/// This is especially useful in dealing with APIs that return a
21+
/// resource by accepting ownership of a sub-resource and a closure
22+
/// that releases that resource. When such APIs are chained, each
23+
/// link in the chain must check that the next member in the chain
24+
/// has accepted the resource. If not, it must invoke the closure
25+
/// eagerly. Not doing this results in a resource leak in the
26+
/// erroneous case. Using this wrapper, the closure can be released
27+
/// once the next call in the chain has successfully accepted
28+
/// ownership of the resource. If not, the closure gets invoked
29+
/// automatically at the end of the scope. This covers the cases
30+
/// where there are early returns as well.
31+
///
32+
class ScopedCleanupClosure final {
33+
public:
34+
ScopedCleanupClosure() = default;
35+
36+
ScopedCleanupClosure(ScopedCleanupClosure&& other) {
37+
closure_ = other.Release();
38+
}
39+
40+
ScopedCleanupClosure& operator=(ScopedCleanupClosure&& other) {
41+
closure_ = other.Release();
42+
return *this;
43+
}
44+
45+
explicit ScopedCleanupClosure(const fml::closure& closure)
46+
: closure_(closure) {}
47+
48+
~ScopedCleanupClosure() { Reset(); }
49+
50+
fml::closure SetClosure(const fml::closure& closure) {
51+
auto old_closure = closure_;
52+
closure_ = closure;
53+
return old_closure;
54+
}
55+
56+
fml::closure Release() {
57+
fml::closure closure = closure_;
58+
closure_ = nullptr;
59+
return closure;
60+
}
61+
62+
void Reset() {
63+
if (closure_) {
64+
closure_();
65+
closure_ = nullptr;
66+
}
67+
}
68+
69+
private:
70+
fml::closure closure_;
71+
72+
FML_DISALLOW_COPY_AND_ASSIGN(ScopedCleanupClosure);
73+
};
74+
75+
} // namespace fml
76+
77+
#endif // FLUTTER_FML_CLOSURE_H_

src/flutter/fml/macros.h

+44
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,44 @@
1+
// Copyright 2013 The Flutter Authors. All rights reserved.
2+
// Use of this source code is governed by a BSD-style license that can be
3+
// found in the LICENSE file.
4+
5+
#ifndef FLUTTER_FML_MACROS_H_
6+
#define FLUTTER_FML_MACROS_H_
7+
8+
#ifndef FML_USED_ON_EMBEDDER
9+
10+
#define FML_EMBEDDER_ONLY [[deprecated]]
11+
12+
#else // FML_USED_ON_EMBEDDER
13+
14+
#define FML_EMBEDDER_ONLY
15+
16+
#endif // FML_USED_ON_EMBEDDER
17+
18+
#define FML_DISALLOW_COPY(TypeName) TypeName(const TypeName&) = delete
19+
20+
#define FML_DISALLOW_ASSIGN(TypeName) \
21+
TypeName& operator=(const TypeName&) = delete
22+
23+
#define FML_DISALLOW_MOVE(TypeName) \
24+
TypeName(TypeName&&) = delete; \
25+
TypeName& operator=(TypeName&&) = delete
26+
27+
#define FML_DISALLOW_COPY_AND_ASSIGN(TypeName) \
28+
TypeName(const TypeName&) = delete; \
29+
TypeName& operator=(const TypeName&) = delete
30+
31+
#define FML_DISALLOW_COPY_ASSIGN_AND_MOVE(TypeName) \
32+
TypeName(const TypeName&) = delete; \
33+
TypeName(TypeName&&) = delete; \
34+
TypeName& operator=(const TypeName&) = delete; \
35+
TypeName& operator=(TypeName&&) = delete
36+
37+
#define FML_DISALLOW_IMPLICIT_CONSTRUCTORS(TypeName) \
38+
TypeName() = delete; \
39+
FML_DISALLOW_COPY_ASSIGN_AND_MOVE(TypeName)
40+
41+
#define FML_FRIEND_TEST(test_case_name, test_name) \
42+
friend class test_case_name##_##test_name##_Test
43+
44+
#endif // FLUTTER_FML_MACROS_H_

src/flutter/shell/platform/common/client_wrapper/core_implementations.cc

+25-2
Original file line numberDiff line numberDiff line change
@@ -210,9 +210,32 @@ bool TextureRegistrarImpl::MarkTextureFrameAvailable(int64_t texture_id) {
210210
texture_registrar_ref_, texture_id);
211211
}
212212

213+
void TextureRegistrarImpl::UnregisterTexture(int64_t texture_id,
214+
std::function<void()> callback) {
215+
if (callback == nullptr) {
216+
FlutterDesktopTextureRegistrarUnregisterExternalTexture(
217+
texture_registrar_ref_, texture_id, nullptr, nullptr);
218+
return;
219+
}
220+
221+
struct Captures {
222+
std::function<void()> callback;
223+
};
224+
auto captures = new Captures();
225+
captures->callback = std::move(callback);
226+
FlutterDesktopTextureRegistrarUnregisterExternalTexture(
227+
texture_registrar_ref_, texture_id,
228+
[](void* opaque) {
229+
auto captures = reinterpret_cast<Captures*>(opaque);
230+
captures->callback();
231+
delete captures;
232+
},
233+
captures);
234+
}
235+
213236
bool TextureRegistrarImpl::UnregisterTexture(int64_t texture_id) {
214-
return FlutterDesktopTextureRegistrarUnregisterExternalTexture(
215-
texture_registrar_ref_, texture_id);
237+
UnregisterTexture(texture_id, nullptr);
238+
return true;
216239
}
217240

218241
} // namespace flutter

src/flutter/shell/platform/common/client_wrapper/include/flutter/texture_registrar.h

+7-2
Original file line numberDiff line numberDiff line change
@@ -128,8 +128,13 @@ class TextureRegistrar {
128128
// the callback that was provided upon creating the texture.
129129
virtual bool MarkTextureFrameAvailable(int64_t texture_id) = 0;
130130

131-
// Unregisters an existing Texture object.
132-
// Textures must not be unregistered while they're in use.
131+
// Asynchronously unregisters an existing texture object.
132+
// Upon completion, the optional |callback| gets invoked.
133+
virtual void UnregisterTexture(int64_t texture_id,
134+
std::function<void()> callback) = 0;
135+
136+
// Unregisters an existing texture object.
137+
// DEPRECATED: Use UnregisterTexture(texture_id, optional_callback) instead.
133138
virtual bool UnregisterTexture(int64_t texture_id) = 0;
134139
};
135140

src/flutter/shell/platform/common/client_wrapper/texture_registrar_impl.h

+4
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,10 @@ class TextureRegistrarImpl : public TextureRegistrar {
2727
// |flutter::TextureRegistrar|
2828
bool MarkTextureFrameAvailable(int64_t texture_id) override;
2929

30+
// |flutter::TextureRegistrar|
31+
void UnregisterTexture(int64_t texture_id,
32+
std::function<void()> callback) override;
33+
3034
// |flutter::TextureRegistrar|
3135
bool UnregisterTexture(int64_t texture_id) override;
3236

src/flutter/shell/platform/common/public/flutter_texture_registrar.h

+7-5
Original file line numberDiff line numberDiff line change
@@ -195,13 +195,15 @@ FLUTTER_EXPORT int64_t FlutterDesktopTextureRegistrarRegisterExternalTexture(
195195
FlutterDesktopTextureRegistrarRef texture_registrar,
196196
const FlutterDesktopTextureInfo* info);
197197

198-
// Unregisters an existing texture from the Flutter engine for a |texture_id|.
199-
// Returns true on success or false if the specified texture doesn't exist.
198+
// Asynchronously unregisters the texture identified by |texture_id| from the
199+
// Flutter engine.
200+
// An optional |callback| gets invoked upon completion.
200201
// This function can be called from any thread.
201-
// However, textures must not be unregistered while they're in use.
202-
FLUTTER_EXPORT bool FlutterDesktopTextureRegistrarUnregisterExternalTexture(
202+
FLUTTER_EXPORT void FlutterDesktopTextureRegistrarUnregisterExternalTexture(
203203
FlutterDesktopTextureRegistrarRef texture_registrar,
204-
int64_t texture_id);
204+
int64_t texture_id,
205+
void (*callback)(void* user_data),
206+
void* user_data);
205207

206208
// Marks that a new texture frame is available for a given |texture_id|.
207209
// Returns true on success or false if the specified texture doesn't exist.

src/flutter/shell/platform/linux_embedded/flutter_elinux.cc

+11-4
Original file line numberDiff line numberDiff line change
@@ -284,11 +284,18 @@ int64_t FlutterDesktopTextureRegistrarRegisterExternalTexture(
284284
->RegisterTexture(texture_info);
285285
}
286286

287-
bool FlutterDesktopTextureRegistrarUnregisterExternalTexture(
287+
void FlutterDesktopTextureRegistrarUnregisterExternalTexture(
288288
FlutterDesktopTextureRegistrarRef texture_registrar,
289-
int64_t texture_id) {
290-
return TextureRegistrarFromHandle(texture_registrar)
291-
->UnregisterTexture(texture_id);
289+
int64_t texture_id,
290+
void (*callback)(void* user_data),
291+
void* user_data) {
292+
auto registrar = TextureRegistrarFromHandle(texture_registrar);
293+
if (callback) {
294+
registrar->UnregisterTexture(
295+
texture_id, [callback, user_data]() { callback(user_data); });
296+
return;
297+
}
298+
registrar->UnregisterTexture(texture_id);
292299
}
293300

294301
bool FlutterDesktopTextureRegistrarMarkExternalTextureFrameAvailable(

src/flutter/shell/platform/linux_embedded/flutter_elinux_engine.cc

+20
Original file line numberDiff line numberDiff line change
@@ -425,6 +425,26 @@ bool FlutterELinuxEngine::MarkExternalTextureFrameAvailable(
425425
engine_, texture_id) == kSuccess);
426426
}
427427

428+
bool FlutterELinuxEngine::PostRasterThreadTask(fml::closure callback) {
429+
struct Captures {
430+
fml::closure callback;
431+
};
432+
auto captures = new Captures();
433+
captures->callback = std::move(callback);
434+
if (embedder_api_.PostRenderThreadTask(
435+
engine_,
436+
[](void* opaque) {
437+
auto captures = reinterpret_cast<Captures*>(opaque);
438+
captures->callback();
439+
delete captures;
440+
},
441+
captures) == kSuccess) {
442+
return true;
443+
}
444+
delete captures;
445+
return false;
446+
}
447+
428448
void FlutterELinuxEngine::OnVsync(uint64_t last_frame_time_nanos,
429449
uint64_t vsync_interval_time_nanos) {
430450
uint64_t current_time_nanos = embedder_api_.GetCurrentTime();

src/flutter/shell/platform/linux_embedded/flutter_elinux_engine.h

+3
Original file line numberDiff line numberDiff line change
@@ -120,6 +120,9 @@ class FlutterELinuxEngine {
120120
// given |texture_id|.
121121
bool MarkExternalTextureFrameAvailable(int64_t texture_id);
122122

123+
// Posts the given callback onto the raster thread.
124+
bool PostRasterThreadTask(fml::closure callback);
125+
123126
// Notifies the engine about the vsync event.
124127
void OnVsync(uint64_t last_frame_time_nanos,
125128
uint64_t vsync_interval_time_nanos);

src/flutter/shell/platform/linux_embedded/flutter_elinux_texture_registrar.cc

+19-11
Original file line numberDiff line numberDiff line change
@@ -72,20 +72,28 @@ int64_t FlutterELinuxTextureRegistrar::EmplaceTexture(
7272
return texture_id;
7373
}
7474

75-
bool FlutterELinuxTextureRegistrar::UnregisterTexture(int64_t texture_id) {
76-
{
77-
std::lock_guard<std::mutex> lock(map_mutex_);
78-
auto it = textures_.find(texture_id);
79-
if (it == textures_.end()) {
80-
return false;
81-
}
82-
textures_.erase(it);
83-
}
84-
75+
void FlutterELinuxTextureRegistrar::UnregisterTexture(int64_t texture_id,
76+
fml::closure callback) {
8577
engine_->task_runner()->RunNowOrPostTask([engine = engine_, texture_id]() {
8678
engine->UnregisterExternalTexture(texture_id);
8779
});
88-
return true;
80+
81+
bool posted = engine_->PostRasterThreadTask([this, texture_id, callback]() {
82+
{
83+
std::lock_guard<std::mutex> lock(map_mutex_);
84+
auto it = textures_.find(texture_id);
85+
if (it != textures_.end()) {
86+
textures_.erase(it);
87+
}
88+
}
89+
if (callback) {
90+
callback();
91+
}
92+
});
93+
94+
if (!posted && callback) {
95+
callback();
96+
}
8997
}
9098

9199
bool FlutterELinuxTextureRegistrar::MarkTextureFrameAvailable(

src/flutter/shell/platform/linux_embedded/flutter_elinux_texture_registrar.h

+2-2
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@
99
#include <mutex>
1010
#include <unordered_map>
1111

12+
#include "flutter/fml/closure.h"
1213
#include "flutter/shell/platform/common/public/flutter_texture_registrar.h"
1314
#include "flutter/shell/platform/linux_embedded/external_texture.h"
1415

@@ -28,8 +29,7 @@ class FlutterELinuxTextureRegistrar {
2829
int64_t RegisterTexture(const FlutterDesktopTextureInfo* texture_info);
2930

3031
// Attempts to unregister the texture identified by |texture_id|.
31-
// Returns true if the texture was successfully unregistered.
32-
bool UnregisterTexture(int64_t texture_id);
32+
void UnregisterTexture(int64_t texture_id, fml::closure callback = nullptr);
3333

3434
// Notifies the engine about a new frame being available.
3535
// Returns true on success.

0 commit comments

Comments
 (0)