Skip to content
This repository was archived by the owner on Feb 25, 2025. It is now read-only.

Commit 44be8cd

Browse files
committed
Add a new test to verify that the resource context is destroyed in the task runner's thread
1 parent 4a2ea80 commit 44be8cd

File tree

5 files changed

+89
-79
lines changed

5 files changed

+89
-79
lines changed

ci/licenses_golden/licenses_flutter

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -170,7 +170,6 @@ FILE: ../../../flutter/flow/raster_cache_unittests.cc
170170
FILE: ../../../flutter/flow/rtree.cc
171171
FILE: ../../../flutter/flow/rtree.h
172172
FILE: ../../../flutter/flow/rtree_unittests.cc
173-
FILE: ../../../flutter/flow/skia_gpu_object.cc
174173
FILE: ../../../flutter/flow/skia_gpu_object.h
175174
FILE: ../../../flutter/flow/skia_gpu_object_unittests.cc
176175
FILE: ../../../flutter/flow/surface.cc

flow/BUILD.gn

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -64,7 +64,6 @@ source_set("flow") {
6464
"raster_cache_key.h",
6565
"rtree.cc",
6666
"rtree.h",
67-
"skia_gpu_object.cc",
6867
"skia_gpu_object.h",
6968
"surface.cc",
7069
"surface.h",

flow/skia_gpu_object.cc

Lines changed: 0 additions & 62 deletions
This file was deleted.

flow/skia_gpu_object.h

Lines changed: 57 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -11,25 +11,46 @@
1111
#include "flutter/fml/memory/ref_counted.h"
1212
#include "flutter/fml/memory/weak_ptr.h"
1313
#include "flutter/fml/task_runner.h"
14+
#include "flutter/fml/trace_event.h"
1415
#include "third_party/skia/include/core/SkRefCnt.h"
1516
#include "third_party/skia/include/gpu/GrDirectContext.h"
1617

1718
namespace flutter {
1819

1920
// A queue that holds Skia objects that must be destructed on the given task
2021
// runner.
21-
class SkiaUnrefQueue : public fml::RefCountedThreadSafe<SkiaUnrefQueue> {
22+
template <class T>
23+
class UnrefQueue : public fml::RefCountedThreadSafe<UnrefQueue<T>> {
2224
public:
23-
void Unref(SkRefCnt* object);
25+
using ResourceContext = T;
26+
27+
void Unref(SkRefCnt* object) {
28+
std::scoped_lock lock(mutex_);
29+
objects_.push_back(object);
30+
if (!drain_pending_) {
31+
drain_pending_ = true;
32+
task_runner_->PostDelayedTask(
33+
[strong = fml::Ref(this)]() { strong->Drain(); }, drain_delay_);
34+
}
35+
}
2436

2537
// Usually, the drain is called automatically. However, during IO manager
2638
// shutdown (when the platform side reference to the OpenGL context is about
2739
// to go away), we may need to pre-emptively drain the unref queue. It is the
2840
// responsibility of the caller to ensure that no further unrefs are queued
2941
// after this call.
30-
void Drain();
42+
void Drain() {
43+
TRACE_EVENT0("flutter", "SkiaUnrefQueue::Drain");
44+
std::deque<SkRefCnt*> skia_objects;
45+
{
46+
std::scoped_lock lock(mutex_);
47+
objects_.swap(skia_objects);
48+
drain_pending_ = false;
49+
}
50+
DoDrain(skia_objects, context_);
51+
}
3152

32-
void UpdateResourceContext(sk_sp<GrDirectContext> context) {
53+
void UpdateResourceContext(sk_sp<ResourceContext> context) {
3354
context_ = context;
3455
}
3556

@@ -39,25 +60,47 @@ class SkiaUnrefQueue : public fml::RefCountedThreadSafe<SkiaUnrefQueue> {
3960
std::mutex mutex_;
4061
std::deque<SkRefCnt*> objects_;
4162
bool drain_pending_;
42-
sk_sp<GrDirectContext> context_;
63+
sk_sp<ResourceContext> context_;
4364

4465
// The `GrDirectContext* context` is only used for signaling Skia to
4566
// performDeferredCleanup. It can be nullptr when such signaling is not needed
4667
// (e.g., in unit tests).
47-
SkiaUnrefQueue(fml::RefPtr<fml::TaskRunner> task_runner,
48-
fml::TimeDelta delay,
49-
sk_sp<GrDirectContext> context = nullptr);
50-
51-
~SkiaUnrefQueue();
68+
UnrefQueue(fml::RefPtr<fml::TaskRunner> task_runner,
69+
fml::TimeDelta delay,
70+
sk_sp<ResourceContext> context = nullptr)
71+
: task_runner_(std::move(task_runner)),
72+
drain_delay_(delay),
73+
drain_pending_(false),
74+
context_(context) {}
75+
76+
~UnrefQueue() {
77+
fml::TaskRunner::RunNowOrPostTask(
78+
task_runner_, [objects = std::move(objects_),
79+
context = std::move(context_)]() mutable {
80+
DoDrain(objects, context);
81+
context.reset();
82+
});
83+
}
5284

85+
// static
5386
static void DoDrain(const std::deque<SkRefCnt*>& skia_objects,
54-
sk_sp<GrDirectContext> context);
87+
sk_sp<ResourceContext> context) {
88+
for (SkRefCnt* skia_object : skia_objects) {
89+
skia_object->unref();
90+
}
91+
92+
if (context && skia_objects.size() > 0) {
93+
context->performDeferredCleanup(std::chrono::milliseconds(0));
94+
}
95+
}
5596

56-
FML_FRIEND_REF_COUNTED_THREAD_SAFE(SkiaUnrefQueue);
57-
FML_FRIEND_MAKE_REF_COUNTED(SkiaUnrefQueue);
58-
FML_DISALLOW_COPY_AND_ASSIGN(SkiaUnrefQueue);
97+
FML_FRIEND_REF_COUNTED_THREAD_SAFE(UnrefQueue);
98+
FML_FRIEND_MAKE_REF_COUNTED(UnrefQueue);
99+
FML_DISALLOW_COPY_AND_ASSIGN(UnrefQueue);
59100
};
60101

102+
using SkiaUnrefQueue = UnrefQueue<GrDirectContext>;
103+
61104
/// An object whose deallocation needs to be performed on an specific unref
62105
/// queue. The template argument U need to have a call operator that returns
63106
/// that unref queue.

flow/skia_gpu_object_unittests.cc

Lines changed: 32 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -22,7 +22,7 @@ class TestSkObject : public SkRefCnt {
2222
fml::TaskQueueId* dtor_task_queue_id)
2323
: latch_(latch), dtor_task_queue_id_(dtor_task_queue_id) {}
2424

25-
~TestSkObject() {
25+
virtual ~TestSkObject() {
2626
if (dtor_task_queue_id_) {
2727
*dtor_task_queue_id_ = fml::MessageLoop::GetCurrentTaskQueueId();
2828
}
@@ -34,6 +34,15 @@ class TestSkObject : public SkRefCnt {
3434
fml::TaskQueueId* dtor_task_queue_id_;
3535
};
3636

37+
class TestResourceContext : public TestSkObject {
38+
public:
39+
TestResourceContext(std::shared_ptr<fml::AutoResetWaitableEvent> latch,
40+
fml::TaskQueueId* dtor_task_queue_id)
41+
: TestSkObject(latch, dtor_task_queue_id) {}
42+
~TestResourceContext() = default;
43+
void performDeferredCleanup(std::chrono::milliseconds msNotUsed) {}
44+
};
45+
3746
class SkiaGpuObjectTest : public ThreadTest {
3847
public:
3948
SkiaGpuObjectTest()
@@ -127,5 +136,27 @@ TEST_F(SkiaGpuObjectTest, ObjectResetTwice) {
127136
ASSERT_EQ(dtor_task_queue_id, unref_task_runner()->GetTaskQueueId());
128137
}
129138

139+
TEST_F(SkiaGpuObjectTest, UnrefResourceContextInTaskRunnerThread) {
140+
std::shared_ptr<fml::AutoResetWaitableEvent> latch =
141+
std::make_shared<fml::AutoResetWaitableEvent>();
142+
fml::RefPtr<UnrefQueue<TestResourceContext>> unref_queue;
143+
fml::TaskQueueId dtor_task_queue_id(0);
144+
unref_task_runner()->PostTask([&]() mutable {
145+
auto resource_context =
146+
sk_make_sp<TestResourceContext>(latch, &dtor_task_queue_id);
147+
unref_queue = fml::MakeRefCounted<UnrefQueue<TestResourceContext>>(
148+
unref_task_runner(), fml::TimeDelta::FromSeconds(0), resource_context);
149+
latch->Signal();
150+
});
151+
latch->Wait();
152+
153+
// Delete the unref queue, it will schedule a task to unref the resource
154+
// context in the task runner's thread.
155+
unref_queue = nullptr;
156+
latch->Wait();
157+
// Verify that the resource context was destroyed in the task runner's thread.
158+
ASSERT_EQ(dtor_task_queue_id, unref_task_runner()->GetTaskQueueId());
159+
}
160+
130161
} // namespace testing
131162
} // namespace flutter

0 commit comments

Comments
 (0)