| Index: gpu/ipc/service/gpu_vsync_provider_unittest_win.cc
|
| diff --git a/gpu/ipc/service/gpu_vsync_provider_unittest_win.cc b/gpu/ipc/service/gpu_vsync_provider_unittest_win.cc
|
| index 2b96b4a493c80cd660f54c29283f334efc06b8cf..4e4eaafcea83780fd6b8860c54ad99427b3e8d9b 100644
|
| --- a/gpu/ipc/service/gpu_vsync_provider_unittest_win.cc
|
| +++ b/gpu/ipc/service/gpu_vsync_provider_unittest_win.cc
|
| @@ -2,18 +2,137 @@
|
| // Use of this source code is governed by a BSD-style license that can be
|
| // found in the LICENSE file.
|
|
|
| -#include "gpu/ipc/service/gpu_vsync_provider.h"
|
| +#include "gpu/ipc/service/gpu_vsync_provider_win.h"
|
|
|
| #include <memory>
|
|
|
| #include "base/bind.h"
|
| #include "base/synchronization/lock.h"
|
| #include "base/synchronization/waitable_event.h"
|
| +#include "base/threading/thread.h"
|
| +#include "gpu/ipc/common/gpu_messages.h"
|
| +#include "ipc/ipc_channel.h"
|
| +#include "ipc/ipc_message_macros.h"
|
| +#include "ipc/message_filter.h"
|
| #include "testing/gtest/include/gtest/gtest.h"
|
| #include "ui/base/win/hidden_window.h"
|
|
|
| namespace gpu {
|
|
|
| +namespace {
|
| +
|
| +class FakeChannel : public base::Thread, public IPC::Channel {
|
| + public:
|
| + explicit FakeChannel(const gfx::VSyncProvider::UpdateVSyncCallback& callback)
|
| + : base::Thread("io"),
|
| + callback_(callback),
|
| + io_done_event_(base::WaitableEvent::ResetPolicy::AUTOMATIC,
|
| + base::WaitableEvent::InitialState::NOT_SIGNALED) {}
|
| +
|
| + ~FakeChannel() override {
|
| + task_runner()->PostTask(FROM_HERE,
|
| + base::Bind(&FakeChannel::RemoveFilterOnIOThread,
|
| + base::Unretained(this)));
|
| + io_done_event_.Wait();
|
| + Stop();
|
| + }
|
| +
|
| + void SetNeedsVSync(bool needs_vsync) {
|
| + task_runner()->PostTask(FROM_HERE,
|
| + base::Bind(&FakeChannel::SetNeedsVSyncOnIOThread,
|
| + base::Unretained(this), needs_vsync));
|
| + io_done_event_.Wait();
|
| + }
|
| +
|
| + void AddFilter(IPC::MessageFilter* message_filter) {
|
| + message_filter_ = message_filter;
|
| +
|
| + // Start the thread.
|
| + Start();
|
| +
|
| + task_runner()->PostTask(
|
| + FROM_HERE,
|
| + base::Bind(&FakeChannel::AddFilterOnIOThread, base::Unretained(this)));
|
| + io_done_event_.Wait();
|
| + }
|
| +
|
| + // IPC::Channel implementation
|
| + bool Send(IPC::Message* msg) override {
|
| + IPC_BEGIN_MESSAGE_MAP(FakeChannel, *msg)
|
| + IPC_MESSAGE_HANDLER(GpuCommandBufferMsg_UpdateVSyncParameters,
|
| + OnUpdateVSyncParameters);
|
| + IPC_MESSAGE_UNHANDLED(return false)
|
| + IPC_END_MESSAGE_MAP()
|
| + return true;
|
| + }
|
| +
|
| + bool Connect() override {
|
| + NOTREACHED();
|
| + return false;
|
| + }
|
| +
|
| + void Close() override { NOTREACHED(); }
|
| +
|
| + private:
|
| + void SetNeedsVSyncOnIOThread(bool needs_vsync) {
|
| + GpuCommandBufferMsg_SetNeedsVSync msg(0, needs_vsync);
|
| + message_filter_->OnMessageReceived(msg);
|
| + io_done_event_.Signal();
|
| + }
|
| +
|
| + void AddFilterOnIOThread() {
|
| + message_filter_->OnFilterAdded(this);
|
| + io_done_event_.Signal();
|
| + }
|
| +
|
| + void RemoveFilterOnIOThread() {
|
| + message_filter_->OnFilterRemoved();
|
| + io_done_event_.Signal();
|
| + }
|
| +
|
| + void OnUpdateVSyncParameters(base::TimeTicks timestamp,
|
| + base::TimeDelta interval) {
|
| + callback_.Run(timestamp, interval);
|
| + }
|
| +
|
| + gfx::VSyncProvider::UpdateVSyncCallback callback_;
|
| + base::WaitableEvent io_done_event_;
|
| +
|
| + scoped_refptr<IPC::MessageFilter> message_filter_;
|
| +
|
| + DISALLOW_COPY_AND_ASSIGN(FakeChannel);
|
| +};
|
| +
|
| +class FakeDelegate : public ImageTransportSurfaceDelegate,
|
| + public base::SupportsWeakPtr<FakeDelegate> {
|
| + public:
|
| + explicit FakeDelegate(FakeChannel* channel) : channel_(channel) {}
|
| +
|
| + void DidCreateAcceleratedSurfaceChildWindow(
|
| + SurfaceHandle parent_window,
|
| + SurfaceHandle child_window) override {}
|
| + void DidSwapBuffersComplete(SwapBuffersCompleteParams params) override {}
|
| + const gles2::FeatureInfo* GetFeatureInfo() const override { return nullptr; }
|
| + void SetLatencyInfoCallback(const LatencyInfoCallback& callback) override {}
|
| + void UpdateVSyncParameters(base::TimeTicks timebase,
|
| + base::TimeDelta interval) override {
|
| + // This shouldn't be called by GpuVSyncProviderWin
|
| + NOTREACHED();
|
| + }
|
| +
|
| + void AddFilter(IPC::MessageFilter* message_filter) override {
|
| + channel_->AddFilter(message_filter);
|
| + }
|
| +
|
| + int32_t GetRouteID() const override { return 0; }
|
| +
|
| + private:
|
| + FakeChannel* channel_;
|
| + DISALLOW_COPY_AND_ASSIGN(FakeDelegate);
|
| +};
|
| +
|
| +} // namespace
|
| +
|
| class GpuVSyncProviderTest : public testing::Test {
|
| public:
|
| GpuVSyncProviderTest()
|
| @@ -21,17 +140,16 @@ class GpuVSyncProviderTest : public testing::Test {
|
| base::WaitableEvent::InitialState::NOT_SIGNALED) {}
|
| ~GpuVSyncProviderTest() override {}
|
|
|
| - void SetUp() override {}
|
| + void SetUp() override {
|
| + channel_.reset(new FakeChannel(
|
| + base::Bind(&GpuVSyncProviderTest::OnVSync, base::Unretained(this))));
|
| + delegate_.reset(new FakeDelegate(channel_.get()));
|
| + provider_.reset(
|
| + new GpuVSyncProviderWin(delegate_->AsWeakPtr(), ui::GetHiddenWindow()));
|
| + }
|
|
|
| void TearDown() override {}
|
|
|
| - void OnVSync(base::TimeTicks timestamp) {
|
| - // This is called on VSync worker thread.
|
| - base::AutoLock lock(lock_);
|
| - if (++vsync_count_ == 3)
|
| - vsync_event_.Signal();
|
| - }
|
| -
|
| int vsync_count() {
|
| base::AutoLock lock(lock_);
|
| return vsync_count_;
|
| @@ -42,20 +160,36 @@ class GpuVSyncProviderTest : public testing::Test {
|
| vsync_count_ = 0;
|
| }
|
|
|
| + void set_vsync_stop_count(int value) { vsync_stop_count_ = value; }
|
| +
|
| + void SetNeedsVSync(bool needs_vsync) { channel_->SetNeedsVSync(needs_vsync); }
|
| +
|
| protected:
|
| base::WaitableEvent vsync_event_;
|
|
|
| private:
|
| + void OnVSync(base::TimeTicks timestamp, base::TimeDelta interval) {
|
| + // This is called on VSync worker thread.
|
| + EXPECT_GT(timestamp, previous_vsync_timestamp_);
|
| + previous_vsync_timestamp_ = timestamp;
|
| +
|
| + base::AutoLock lock(lock_);
|
| + if (++vsync_count_ == vsync_stop_count_)
|
| + vsync_event_.Signal();
|
| + }
|
| +
|
| base::Lock lock_;
|
| int vsync_count_ = 0;
|
| + int vsync_stop_count_ = 0;
|
| + base::TimeTicks previous_vsync_timestamp_;
|
| + std::unique_ptr<FakeChannel> channel_;
|
| + std::unique_ptr<FakeDelegate> delegate_;
|
| + std::unique_ptr<GpuVSyncProviderWin> provider_;
|
| };
|
|
|
| +// Tests that VSync signal production is controlled by SetNeedsVSync.
|
| TEST_F(GpuVSyncProviderTest, VSyncSignalTest) {
|
| - SurfaceHandle window = ui::GetHiddenWindow();
|
| -
|
| - std::unique_ptr<GpuVSyncProvider> provider = GpuVSyncProvider::Create(
|
| - base::Bind(&GpuVSyncProviderTest::OnVSync, base::Unretained(this)),
|
| - window);
|
| + set_vsync_stop_count(3);
|
|
|
| constexpr base::TimeDelta wait_timeout =
|
| base::TimeDelta::FromMilliseconds(300);
|
| @@ -65,11 +199,11 @@ TEST_F(GpuVSyncProviderTest, VSyncSignalTest) {
|
| EXPECT_FALSE(wait_result);
|
| EXPECT_EQ(0, vsync_count());
|
|
|
| - provider->EnableVSync(true);
|
| + SetNeedsVSync(true);
|
|
|
| vsync_event_.Wait();
|
|
|
| - provider->EnableVSync(false);
|
| + SetNeedsVSync(false);
|
|
|
| // Verify that VSync callbacks stop coming after disabling.
|
| // Please note that it might still be possible for one
|
| @@ -81,4 +215,13 @@ TEST_F(GpuVSyncProviderTest, VSyncSignalTest) {
|
| EXPECT_FALSE(wait_result);
|
| }
|
|
|
| +// Verifies that VSync timestamp is monotonic.
|
| +TEST_F(GpuVSyncProviderTest, VSyncMonotonicTimestampTest) {
|
| + set_vsync_stop_count(60);
|
| + SetNeedsVSync(true);
|
| + // Make sure this doesn't run for longer than 1 second in case VSync
|
| + // callbacks are slowed by running multiple tests in parallel.
|
| + vsync_event_.TimedWait(base::TimeDelta::FromMilliseconds(1000));
|
| +}
|
| +
|
| } // namespace gpu
|
|
|