blob: b7a6a08244a35da423cb58279ab8687582cdf459 [file] [log] [blame]
// Copyright 2019 The Fuchsia 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 <lib/async/default.h>
#include <lib/async/time.h>
#include <lib/gtest/test_loop_fixture.h>
#include <zircon/syscalls.h>
#include <unordered_set>
#include <gtest/gtest.h>
#include "src/ui/scenic/lib/display/display_manager.h"
#include "src/ui/scenic/lib/display/tests/mock_display_controller.h"
#include "src/ui/scenic/lib/gfx/swapchain/display_swapchain.h"
namespace scenic_impl {
namespace gfx {
namespace test {
namespace {
struct ChannelPair {
zx::channel server;
zx::channel client;
};
ChannelPair CreateChannelPair() {
ChannelPair c;
FX_CHECK(ZX_OK == zx::channel::create(0, &c.server, &c.client));
return c;
}
} // namespace
class DisplaySwapchainMockTest : public gtest::TestLoopFixture {
public:
// |testing::Test|
void SetUp() override {
TestLoopFixture::SetUp();
async_set_default_dispatcher(dispatcher());
sysmem_ = std::make_unique<Sysmem>();
display_manager_ = std::make_unique<display::DisplayManager>([]() {});
}
// |testing::Test|
void TearDown() override {
display_manager_.reset();
sysmem_.reset();
TestLoopFixture::TearDown();
}
std::unique_ptr<DisplaySwapchain> CreateSwapchain(display::Display* display) {
auto swapchain = std::make_unique<DisplaySwapchain>(
sysmem_.get(), display_manager_->default_display_controller(),
display_manager_->default_display_controller_listener(), display, /*escher*/ nullptr);
display_manager_->default_display_controller_listener()->SetOnVsyncCallback(
fit::bind_member(swapchain.get(), &DisplaySwapchain::OnVsync));
return swapchain;
}
display::DisplayManager* display_manager() { return display_manager_.get(); }
display::Display* display() { return display_manager()->default_display(); }
private:
std::unique_ptr<Sysmem> sysmem_;
std::unique_ptr<display::DisplayManager> display_manager_;
};
TEST_F(DisplaySwapchainMockTest, AcknowledgeVsync) {
const uint64_t kDisplayId = 0;
const uint32_t kDisplayWidth = 1024;
const uint32_t kDisplayHeight = 768;
const size_t kTotalVsync = 10;
const size_t kAcknowledgeRate = 5;
std::unordered_set<uint64_t> cookies_sent;
size_t num_vsync_swapchain_received = 0;
size_t num_vsync_acknowledgement = 0;
auto controller_channel = CreateChannelPair();
auto device_channel = CreateChannelPair();
display_manager()->BindDefaultDisplayController(
fidl::InterfaceHandle<fuchsia::hardware::display::Controller>(
std::move(controller_channel.client)),
std::move(device_channel.client));
display_manager()->SetDefaultDisplayForTests(
std::make_shared<display::Display>(kDisplayId, kDisplayWidth, kDisplayHeight));
display::test::MockDisplayController mock_display_controller;
mock_display_controller.Bind(std::move(device_channel.server),
std::move(controller_channel.server));
mock_display_controller.set_acknowledge_vsync_fn(
[&cookies_sent, &num_vsync_acknowledgement](uint64_t cookie) {
ASSERT_TRUE(cookies_sent.find(cookie) != cookies_sent.end());
++num_vsync_acknowledgement;
});
auto swapchain = CreateSwapchain(display());
swapchain->RegisterVsyncListener([&num_vsync_swapchain_received](zx::time vsync_timestamp) {
++num_vsync_swapchain_received;
});
for (size_t vsync_id = 1; vsync_id <= kTotalVsync; vsync_id++) {
// We only require acknowledgement for every |kAcknowledgeRate| Vsync IDs.
uint64_t cookie = (vsync_id % kAcknowledgeRate == 0) ? vsync_id : 0;
test_loop().AdvanceTimeByEpsilon();
mock_display_controller.events().OnVsync(kDisplayId, /* timestamp */ test_loop().Now().get(),
/* images */ {}, cookie);
if (cookie) {
cookies_sent.insert(cookie);
}
// Display controller should handle the incoming Vsync message.
EXPECT_TRUE(RunLoopUntilIdle());
}
EXPECT_EQ(num_vsync_swapchain_received, kTotalVsync);
EXPECT_EQ(num_vsync_acknowledgement, kTotalVsync / kAcknowledgeRate);
}
} // namespace test
} // namespace gfx
} // namespace scenic_impl