| // 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 <fidl/fuchsia.hardware.display/cpp/wire.h> |
| #include <fidl/fuchsia.hardware.display/cpp/wire_test_base.h> |
| #include <fuchsia/hardware/display/controller/c/banjo.h> |
| #include <lib/driver/testing/cpp/driver_runtime.h> |
| #include <lib/fdf/cpp/dispatcher.h> |
| #include <lib/fdf/dispatcher.h> |
| #include <lib/fidl/cpp/wire/client_base.h> |
| #include <lib/fidl/cpp/wire/wire_messaging.h> |
| #include <lib/sync/cpp/completion.h> |
| #include <zircon/errors.h> |
| |
| #include <array> |
| |
| #include <fbl/auto_lock.h> |
| #include <gtest/gtest.h> |
| |
| #include "src/graphics/display/drivers/coordinator/client-priority.h" |
| #include "src/graphics/display/drivers/coordinator/client.h" |
| #include "src/graphics/display/drivers/coordinator/controller.h" |
| #include "src/graphics/display/drivers/coordinator/engine-driver-client.h" |
| #include "src/graphics/display/lib/api-types-cpp/config-stamp.h" |
| #include "src/graphics/display/lib/api-types-cpp/display-id.h" |
| #include "src/lib/testing/predicates/status.h" |
| |
| namespace display { |
| |
| namespace { |
| |
| struct DispatcherAndShutdownCompletion { |
| fdf::SynchronizedDispatcher dispatcher; |
| std::shared_ptr<libsync::Completion> dispatcher_shutdown_completion; |
| }; |
| |
| DispatcherAndShutdownCompletion CreateDispatcherAndShutdownCompletionForTesting() { |
| auto shutdown_completion = std::make_shared<libsync::Completion>(); |
| zx::result<fdf::SynchronizedDispatcher> create_result = fdf::SynchronizedDispatcher::Create( |
| fdf::SynchronizedDispatcher::Options::kAllowSyncCalls, "display-test-dispatcher", |
| [shutdown_completion](fdf_dispatcher_t*) { shutdown_completion->Signal(); }); |
| ZX_ASSERT_MSG(create_result.is_ok(), "Failed to create dispatcher: %s", |
| create_result.status_string()); |
| return {.dispatcher = std::move(create_result).value(), |
| .dispatcher_shutdown_completion = std::move(shutdown_completion)}; |
| } |
| |
| } // namespace |
| |
| TEST(DisplayTest, ClientVSyncOk) { |
| fdf_testing::DriverRuntime driver_runtime; |
| |
| constexpr ConfigStamp kControllerStampValue(1); |
| constexpr ConfigStamp kClientStampValue(2); |
| |
| auto [client_end, server_end] = fidl::Endpoints<fuchsia_hardware_display::Coordinator>::Create(); |
| |
| auto [engine_client_end, engine_server_end] = |
| fdf::Endpoints<fuchsia_hardware_display_engine::Engine>::Create(); |
| auto engine_driver_client = std::make_unique<EngineDriverClient>(std::move(engine_client_end)); |
| |
| auto [dispatcher, shutdown_completion] = CreateDispatcherAndShutdownCompletionForTesting(); |
| Controller controller(std::move(engine_driver_client), dispatcher.borrow()); |
| |
| ClientProxy clientproxy(&controller, ClientPriority::kPrimary, ClientId(1), |
| std::move(server_end)); |
| clientproxy.EnableVsync(true); |
| fbl::AutoLock lock(controller.mtx()); |
| clientproxy.UpdateConfigStampMapping({ |
| .controller_stamp = kControllerStampValue, |
| .client_stamp = kClientStampValue, |
| }); |
| |
| EXPECT_OK(clientproxy.OnDisplayVsync(kInvalidDisplayId, 0, kControllerStampValue)); |
| |
| fidl::WireSyncClient client(std::move(client_end)); |
| |
| class EventHandler |
| : public fidl::testing::WireSyncEventHandlerTestBase<fuchsia_hardware_display::Coordinator> { |
| public: |
| explicit EventHandler(ConfigStamp expected_config_stamp) |
| : expected_config_stamp_(expected_config_stamp) {} |
| |
| void OnVsync(fidl::WireEvent<fuchsia_hardware_display::Coordinator::OnVsync>* event) override { |
| ConfigStamp applied_config_stamp = ToConfigStamp(event->applied_config_stamp); |
| if (applied_config_stamp == expected_config_stamp_) { |
| vsync_handled_ = true; |
| } |
| } |
| |
| void NotImplemented_(const std::string& name) override { FAIL() << "Unexpected " << name; } |
| |
| bool vsync_handled_ = false; |
| ConfigStamp expected_config_stamp_ = kInvalidConfigStamp; |
| }; |
| |
| EventHandler event_handler(kClientStampValue); |
| EXPECT_TRUE(client.HandleOneEvent(event_handler).ok()); |
| EXPECT_TRUE(event_handler.vsync_handled_); |
| |
| clientproxy.CloseTest(); |
| |
| dispatcher.ShutdownAsync(); |
| shutdown_completion->Wait(); |
| } |
| |
| TEST(DisplayTest, ClientVSynPeerClosed) { |
| fdf_testing::DriverRuntime driver_runtime; |
| |
| auto [client_end, server_end] = fidl::Endpoints<fuchsia_hardware_display::Coordinator>::Create(); |
| |
| auto [engine_client_end, engine_server_end] = |
| fdf::Endpoints<fuchsia_hardware_display_engine::Engine>::Create(); |
| auto engine_driver_client = std::make_unique<EngineDriverClient>(std::move(engine_client_end)); |
| |
| auto [dispatcher, shutdown_completion] = CreateDispatcherAndShutdownCompletionForTesting(); |
| Controller controller(std::move(engine_driver_client), dispatcher.borrow()); |
| |
| ClientProxy clientproxy(&controller, ClientPriority::kPrimary, ClientId(1), |
| std::move(server_end)); |
| clientproxy.EnableVsync(true); |
| fbl::AutoLock lock(controller.mtx()); |
| client_end.reset(); |
| EXPECT_OK(clientproxy.OnDisplayVsync(kInvalidDisplayId, 0, kInvalidConfigStamp)); |
| clientproxy.CloseTest(); |
| |
| dispatcher.ShutdownAsync(); |
| shutdown_completion->Wait(); |
| } |
| |
| TEST(DisplayTest, ClientVSyncNotSupported) { |
| fdf_testing::DriverRuntime driver_runtime; |
| |
| auto [client_end, server_end] = fidl::Endpoints<fuchsia_hardware_display::Coordinator>::Create(); |
| |
| auto [engine_client_end, engine_server_end] = |
| fdf::Endpoints<fuchsia_hardware_display_engine::Engine>::Create(); |
| auto engine_driver_client = std::make_unique<EngineDriverClient>(std::move(engine_client_end)); |
| |
| auto [dispatcher, shutdown_completion] = CreateDispatcherAndShutdownCompletionForTesting(); |
| Controller controller(std::move(engine_driver_client), dispatcher.borrow()); |
| |
| ClientProxy clientproxy(&controller, ClientPriority::kPrimary, ClientId(1), |
| std::move(server_end)); |
| fbl::AutoLock lock(controller.mtx()); |
| EXPECT_STATUS(ZX_ERR_NOT_SUPPORTED, |
| clientproxy.OnDisplayVsync(kInvalidDisplayId, 0, kInvalidConfigStamp)); |
| clientproxy.CloseTest(); |
| |
| dispatcher.ShutdownAsync(); |
| shutdown_completion->Wait(); |
| } |
| |
| TEST(DisplayTest, ClientMustDrainPendingStamps) { |
| fdf_testing::DriverRuntime driver_runtime; |
| |
| constexpr size_t kNumPendingStamps = 5; |
| constexpr std::array<uint64_t, kNumPendingStamps> kControllerStampValues = {1u, 2u, 3u, 4u, 5u}; |
| constexpr std::array<uint64_t, kNumPendingStamps> kClientStampValues = {2u, 3u, 4u, 5u, 6u}; |
| |
| auto [client_end, server_end] = fidl::Endpoints<fuchsia_hardware_display::Coordinator>::Create(); |
| |
| auto [engine_client_end, engine_server_end] = |
| fdf::Endpoints<fuchsia_hardware_display_engine::Engine>::Create(); |
| auto engine_driver_client = std::make_unique<EngineDriverClient>(std::move(engine_client_end)); |
| |
| auto [dispatcher, shutdown_completion] = CreateDispatcherAndShutdownCompletionForTesting(); |
| Controller controller(std::move(engine_driver_client), dispatcher.borrow()); |
| |
| ClientProxy clientproxy(&controller, ClientPriority::kPrimary, ClientId(1), |
| std::move(server_end)); |
| clientproxy.EnableVsync(false); |
| fbl::AutoLock lock(controller.mtx()); |
| for (size_t i = 0; i < kNumPendingStamps; i++) { |
| clientproxy.UpdateConfigStampMapping({ |
| .controller_stamp = ConfigStamp(kControllerStampValues[i]), |
| .client_stamp = ConfigStamp(kClientStampValues[i]), |
| }); |
| } |
| |
| EXPECT_STATUS( |
| ZX_ERR_NOT_SUPPORTED, |
| clientproxy.OnDisplayVsync(kInvalidDisplayId, 0, ConfigStamp(kControllerStampValues.back()))); |
| |
| // Even if Vsync is disabled, ClientProxy should always drain pending |
| // controller stamps. |
| EXPECT_EQ(clientproxy.pending_applied_config_stamps().size(), 1u); |
| EXPECT_EQ(clientproxy.pending_applied_config_stamps().front().controller_stamp, |
| ConfigStamp(kControllerStampValues.back())); |
| |
| clientproxy.CloseTest(); |
| |
| dispatcher.ShutdownAsync(); |
| shutdown_completion->Wait(); |
| } |
| |
| } // namespace display |