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
16namespace flutter {
17namespace testing {
18
19class 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
37class 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
76TEST_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
87TEST_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
101TEST_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
114TEST_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