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 | #include "flutter/flow/skia_gpu_object.h" |
6 | |
7 | #include "flutter/fml/message_loop.h" |
8 | #include "flutter/fml/synchronization/waitable_event.h" |
9 | #include "flutter/fml/task_runner.h" |
10 | #include "flutter/testing/thread_test.h" |
11 | #include "gtest/gtest.h" |
12 | #include "third_party/skia/include/core/SkRefCnt.h" |
13 | |
14 | #include <future> |
15 | |
16 | namespace flutter { |
17 | namespace testing { |
18 | |
19 | class TestSkObject : public SkRefCnt { |
20 | public: |
21 | TestSkObject(std::shared_ptr<fml::AutoResetWaitableEvent> latch, |
22 | fml::TaskQueueId* dtor_task_queue_id) |
23 | : latch_(latch), dtor_task_queue_id_(dtor_task_queue_id) {} |
24 | |
25 | ~TestSkObject() { |
26 | if (dtor_task_queue_id_) { |
27 | *dtor_task_queue_id_ = fml::MessageLoop::GetCurrentTaskQueueId(); |
28 | } |
29 | latch_->Signal(); |
30 | } |
31 | |
32 | private: |
33 | std::shared_ptr<fml::AutoResetWaitableEvent> latch_; |
34 | fml::TaskQueueId* dtor_task_queue_id_; |
35 | }; |
36 | |
37 | class SkiaGpuObjectTest : public ThreadTest { |
38 | public: |
39 | SkiaGpuObjectTest() |
40 | : unref_task_runner_(CreateNewThread()), |
41 | unref_queue_(fml::MakeRefCounted<SkiaUnrefQueue>( |
42 | unref_task_runner(), |
43 | fml::TimeDelta::FromSeconds(0))), |
44 | delayed_unref_queue_(fml::MakeRefCounted<SkiaUnrefQueue>( |
45 | unref_task_runner(), |
46 | fml::TimeDelta::FromSeconds(3))) { |
47 | // The unref queues must be created in the same thread of the |
48 | // unref_task_runner so the queue can access the same-thread-only WeakPtr of |
49 | // the GrContext constructed during the creation. |
50 | std::promise<bool> queuesCreated; |
51 | unref_task_runner_->PostTask([this, &queuesCreated]() { |
52 | unref_queue_ = fml::MakeRefCounted<SkiaUnrefQueue>( |
53 | unref_task_runner(), fml::TimeDelta::FromSeconds(0)); |
54 | delayed_unref_queue_ = fml::MakeRefCounted<SkiaUnrefQueue>( |
55 | unref_task_runner(), fml::TimeDelta::FromSeconds(3)); |
56 | queuesCreated.set_value(true); |
57 | }); |
58 | queuesCreated.get_future().wait(); |
59 | ::testing::FLAGS_gtest_death_test_style = "threadsafe" ; |
60 | } |
61 | |
62 | fml::RefPtr<fml::TaskRunner> unref_task_runner() { |
63 | return unref_task_runner_; |
64 | } |
65 | fml::RefPtr<SkiaUnrefQueue> unref_queue() { return unref_queue_; } |
66 | fml::RefPtr<SkiaUnrefQueue> delayed_unref_queue() { |
67 | return delayed_unref_queue_; |
68 | } |
69 | |
70 | private: |
71 | fml::RefPtr<fml::TaskRunner> unref_task_runner_; |
72 | fml::RefPtr<SkiaUnrefQueue> unref_queue_; |
73 | fml::RefPtr<SkiaUnrefQueue> delayed_unref_queue_; |
74 | }; |
75 | |
76 | TEST_F(SkiaGpuObjectTest, QueueSimple) { |
77 | std::shared_ptr<fml::AutoResetWaitableEvent> latch = |
78 | std::make_shared<fml::AutoResetWaitableEvent>(); |
79 | fml::TaskQueueId dtor_task_queue_id(0); |
80 | SkRefCnt* ref_object = new TestSkObject(latch, &dtor_task_queue_id); |
81 | |
82 | unref_queue()->Unref(ref_object); |
83 | latch->Wait(); |
84 | ASSERT_EQ(dtor_task_queue_id, unref_task_runner()->GetTaskQueueId()); |
85 | } |
86 | |
87 | TEST_F(SkiaGpuObjectTest, ObjectDestructor) { |
88 | std::shared_ptr<fml::AutoResetWaitableEvent> latch = |
89 | std::make_shared<fml::AutoResetWaitableEvent>(); |
90 | fml::TaskQueueId dtor_task_queue_id(0); |
91 | auto object = sk_make_sp<TestSkObject>(latch, &dtor_task_queue_id); |
92 | { |
93 | SkiaGPUObject<TestSkObject> sk_object(std::move(object), unref_queue()); |
94 | // Verify that the default SkiaGPUObject dtor queues and unref. |
95 | } |
96 | |
97 | latch->Wait(); |
98 | ASSERT_EQ(dtor_task_queue_id, unref_task_runner()->GetTaskQueueId()); |
99 | } |
100 | |
101 | TEST_F(SkiaGpuObjectTest, ObjectReset) { |
102 | std::shared_ptr<fml::AutoResetWaitableEvent> latch = |
103 | std::make_shared<fml::AutoResetWaitableEvent>(); |
104 | fml::TaskQueueId dtor_task_queue_id(0); |
105 | SkiaGPUObject<TestSkObject> sk_object( |
106 | sk_make_sp<TestSkObject>(latch, &dtor_task_queue_id), unref_queue()); |
107 | // Verify that explicitly resetting the GPU object queues and unref. |
108 | sk_object.reset(); |
109 | ASSERT_EQ(sk_object.get(), nullptr); |
110 | latch->Wait(); |
111 | ASSERT_EQ(dtor_task_queue_id, unref_task_runner()->GetTaskQueueId()); |
112 | } |
113 | |
114 | TEST_F(SkiaGpuObjectTest, ObjectResetTwice) { |
115 | std::shared_ptr<fml::AutoResetWaitableEvent> latch = |
116 | std::make_shared<fml::AutoResetWaitableEvent>(); |
117 | fml::TaskQueueId dtor_task_queue_id(0); |
118 | SkiaGPUObject<TestSkObject> sk_object( |
119 | sk_make_sp<TestSkObject>(latch, &dtor_task_queue_id), unref_queue()); |
120 | |
121 | sk_object.reset(); |
122 | ASSERT_EQ(sk_object.get(), nullptr); |
123 | sk_object.reset(); |
124 | ASSERT_EQ(sk_object.get(), nullptr); |
125 | |
126 | latch->Wait(); |
127 | ASSERT_EQ(dtor_task_queue_id, unref_task_runner()->GetTaskQueueId()); |
128 | } |
129 | |
130 | } // namespace testing |
131 | } // namespace flutter |
132 | |