mirror of
https://github.com/flutter/flutter.git
synced 2026-02-20 02:29:02 +08:00
There are two issues in the test as written: * There is a race on the first check to dtor_task_queue_id which might be encountered if the calling thread is de-scheduled and the unref queue manages to collect the object before the end of the scope. * Two threads were owning a shared object but we relied on the object to be collected on the unref queue.
132 lines
4.4 KiB
C++
132 lines
4.4 KiB
C++
// Copyright 2013 The Flutter Authors. All rights reserved.
|
|
// Use of this source code is governed by a BSD-style license that can be
|
|
// found in the LICENSE file.
|
|
|
|
#include "flutter/flow/skia_gpu_object.h"
|
|
|
|
#include "flutter/fml/message_loop.h"
|
|
#include "flutter/fml/synchronization/waitable_event.h"
|
|
#include "flutter/fml/task_runner.h"
|
|
#include "flutter/testing/thread_test.h"
|
|
#include "gtest/gtest.h"
|
|
#include "third_party/skia/include/core/SkRefCnt.h"
|
|
|
|
#include <future>
|
|
|
|
namespace flutter {
|
|
namespace testing {
|
|
|
|
class TestSkObject : public SkRefCnt {
|
|
public:
|
|
TestSkObject(std::shared_ptr<fml::AutoResetWaitableEvent> latch,
|
|
fml::TaskQueueId* dtor_task_queue_id)
|
|
: latch_(latch), dtor_task_queue_id_(dtor_task_queue_id) {}
|
|
|
|
~TestSkObject() {
|
|
if (dtor_task_queue_id_) {
|
|
*dtor_task_queue_id_ = fml::MessageLoop::GetCurrentTaskQueueId();
|
|
}
|
|
latch_->Signal();
|
|
}
|
|
|
|
private:
|
|
std::shared_ptr<fml::AutoResetWaitableEvent> latch_;
|
|
fml::TaskQueueId* dtor_task_queue_id_;
|
|
};
|
|
|
|
class SkiaGpuObjectTest : public ThreadTest {
|
|
public:
|
|
SkiaGpuObjectTest()
|
|
: unref_task_runner_(CreateNewThread()),
|
|
unref_queue_(fml::MakeRefCounted<SkiaUnrefQueue>(
|
|
unref_task_runner(),
|
|
fml::TimeDelta::FromSeconds(0))),
|
|
delayed_unref_queue_(fml::MakeRefCounted<SkiaUnrefQueue>(
|
|
unref_task_runner(),
|
|
fml::TimeDelta::FromSeconds(3))) {
|
|
// The unref queues must be created in the same thread of the
|
|
// unref_task_runner so the queue can access the same-thread-only WeakPtr of
|
|
// the GrContext constructed during the creation.
|
|
std::promise<bool> queuesCreated;
|
|
unref_task_runner_->PostTask([this, &queuesCreated]() {
|
|
unref_queue_ = fml::MakeRefCounted<SkiaUnrefQueue>(
|
|
unref_task_runner(), fml::TimeDelta::FromSeconds(0));
|
|
delayed_unref_queue_ = fml::MakeRefCounted<SkiaUnrefQueue>(
|
|
unref_task_runner(), fml::TimeDelta::FromSeconds(3));
|
|
queuesCreated.set_value(true);
|
|
});
|
|
queuesCreated.get_future().wait();
|
|
::testing::FLAGS_gtest_death_test_style = "threadsafe";
|
|
}
|
|
|
|
fml::RefPtr<fml::TaskRunner> unref_task_runner() {
|
|
return unref_task_runner_;
|
|
}
|
|
fml::RefPtr<SkiaUnrefQueue> unref_queue() { return unref_queue_; }
|
|
fml::RefPtr<SkiaUnrefQueue> delayed_unref_queue() {
|
|
return delayed_unref_queue_;
|
|
}
|
|
|
|
private:
|
|
fml::RefPtr<fml::TaskRunner> unref_task_runner_;
|
|
fml::RefPtr<SkiaUnrefQueue> unref_queue_;
|
|
fml::RefPtr<SkiaUnrefQueue> delayed_unref_queue_;
|
|
};
|
|
|
|
TEST_F(SkiaGpuObjectTest, QueueSimple) {
|
|
std::shared_ptr<fml::AutoResetWaitableEvent> latch =
|
|
std::make_shared<fml::AutoResetWaitableEvent>();
|
|
fml::TaskQueueId dtor_task_queue_id(0);
|
|
SkRefCnt* ref_object = new TestSkObject(latch, &dtor_task_queue_id);
|
|
|
|
unref_queue()->Unref(ref_object);
|
|
latch->Wait();
|
|
ASSERT_EQ(dtor_task_queue_id, unref_task_runner()->GetTaskQueueId());
|
|
}
|
|
|
|
TEST_F(SkiaGpuObjectTest, ObjectDestructor) {
|
|
std::shared_ptr<fml::AutoResetWaitableEvent> latch =
|
|
std::make_shared<fml::AutoResetWaitableEvent>();
|
|
fml::TaskQueueId dtor_task_queue_id(0);
|
|
auto object = sk_make_sp<TestSkObject>(latch, &dtor_task_queue_id);
|
|
{
|
|
SkiaGPUObject<TestSkObject> sk_object(std::move(object), unref_queue());
|
|
// Verify that the default SkiaGPUObject dtor queues and unref.
|
|
}
|
|
|
|
latch->Wait();
|
|
ASSERT_EQ(dtor_task_queue_id, unref_task_runner()->GetTaskQueueId());
|
|
}
|
|
|
|
TEST_F(SkiaGpuObjectTest, ObjectReset) {
|
|
std::shared_ptr<fml::AutoResetWaitableEvent> latch =
|
|
std::make_shared<fml::AutoResetWaitableEvent>();
|
|
fml::TaskQueueId dtor_task_queue_id(0);
|
|
SkiaGPUObject<TestSkObject> sk_object(
|
|
sk_make_sp<TestSkObject>(latch, &dtor_task_queue_id), unref_queue());
|
|
// Verify that explicitly resetting the GPU object queues and unref.
|
|
sk_object.reset();
|
|
ASSERT_EQ(sk_object.get(), nullptr);
|
|
latch->Wait();
|
|
ASSERT_EQ(dtor_task_queue_id, unref_task_runner()->GetTaskQueueId());
|
|
}
|
|
|
|
TEST_F(SkiaGpuObjectTest, ObjectResetTwice) {
|
|
std::shared_ptr<fml::AutoResetWaitableEvent> latch =
|
|
std::make_shared<fml::AutoResetWaitableEvent>();
|
|
fml::TaskQueueId dtor_task_queue_id(0);
|
|
SkiaGPUObject<TestSkObject> sk_object(
|
|
sk_make_sp<TestSkObject>(latch, &dtor_task_queue_id), unref_queue());
|
|
|
|
sk_object.reset();
|
|
ASSERT_EQ(sk_object.get(), nullptr);
|
|
sk_object.reset();
|
|
ASSERT_EQ(sk_object.get(), nullptr);
|
|
|
|
latch->Wait();
|
|
ASSERT_EQ(dtor_task_queue_id, unref_task_runner()->GetTaskQueueId());
|
|
}
|
|
|
|
} // namespace testing
|
|
} // namespace flutter
|