blob: c2799fe0ffcc26b01c66aeb19bf17ffff7d0b052 [file] [log] [blame]
// Copyright 2024 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.
#ifndef SRC_GRAPHICS_DISPLAY_DRIVERS_AMLOGIC_DISPLAY_VSYNC_RECEIVER_H_
#define SRC_GRAPHICS_DISPLAY_DRIVERS_AMLOGIC_DISPLAY_VSYNC_RECEIVER_H_
#include <fidl/fuchsia.hardware.platform.device/cpp/wire.h>
#include <lib/async/cpp/irq.h>
#include <lib/ddk/device.h>
#include <lib/fit/function.h>
#include <lib/zx/interrupt.h>
#include <lib/zx/result.h>
#include <lib/zx/time.h>
#include <threads.h>
#include <zircon/syscalls/port.h>
#include <cstddef>
#include <memory>
#include <fbl/mutex.h>
#include "src/graphics/display/lib/driver-framework-migration-utils/dispatcher/dispatcher-factory.h"
#include "src/graphics/display/lib/driver-framework-migration-utils/dispatcher/dispatcher.h"
namespace amlogic_display {
// Receives Vertical Sync (Vsync) interrupts triggered by the display engine
// indicating that the display engine finishes presenting a frame to the
// display device.
class VsyncReceiver {
public:
// Internal state size for the function called when a Vsync interrupt is
// triggered.
static constexpr size_t kOnVsyncTargetSize = 16;
// The type of the function called when a Vsync interrupt is triggered.
using VsyncHandler = fit::inline_function<void(zx::time timestamp), kOnVsyncTargetSize>;
// Factory method intended for production use.
// Creates a VsyncReceiver that is receiving Vsync interrupts.
//
// `platform_device` must be valid.
//
// `on_vsync` is called when the display engine finishes presenting a frame
// to the display device and triggers a Vsync interrupt. Must be non-null.
static zx::result<std::unique_ptr<VsyncReceiver>> Create(
display::DispatcherFactory& dispatcher_factory,
fidl::UnownedClientEnd<fuchsia_hardware_platform_device::Device> platform_device,
VsyncHandler on_vsync);
// Production code should prefer the factory method `Create()`.
//
// `irq_handler_dispatcher` must not be empty.
// `vsync_irq` must be valid.
// `on_vsync` must be non-null.
explicit VsyncReceiver(zx::interrupt vsync_irq, VsyncHandler on_vsync,
std::unique_ptr<display::Dispatcher> irq_handler_dispatcher);
VsyncReceiver(const VsyncReceiver&) = delete;
VsyncReceiver& operator=(const VsyncReceiver&) = delete;
~VsyncReceiver();
// If `receiving` is true, starts receiving Vsync interrupts; otherwise, stops
// receiving Vsync interrupts.
//
// This method is idempotent.
zx::result<> SetReceivingState(bool receiving);
private:
// Start receiving Vsync interrupts.
//
// The VsyncReceiver must not be receiving Vsync interrupts before it's
// called.
zx::result<> Start();
// Stop receiving Vsync interrupts.
//
// Unhandled Vysnc interrupts queued in the dispatcher will be canceled.
//
// The VsyncReceiver must be receiving Vsync interrupts before it's called.
zx::result<> Stop();
void OnVsync(zx::time timestamp);
void InterruptHandler(async_dispatcher_t* dispatcher, async::IrqBase* irq, zx_status_t status,
const zx_packet_interrupt_t* interrupt);
const zx::interrupt vsync_irq_;
const VsyncHandler on_vsync_;
bool is_receiving_ = false;
// The `irq_handler_dispatcher_` and `irq_handler_` are constant between
// Init() and instance destruction. Only accessed on the threads used for
// class initialization and destruction.
std::unique_ptr<display::Dispatcher> irq_handler_dispatcher_;
async::IrqMethod<VsyncReceiver, &VsyncReceiver::InterruptHandler> irq_handler_{this};
};
} // namespace amlogic_display
#endif // SRC_GRAPHICS_DISPLAY_DRIVERS_AMLOGIC_DISPLAY_VSYNC_RECEIVER_H_