Merge pull request #5116 from zhaowenlan1779/cam-vsync
service/cam: Implement Vsync interrupt events
This commit is contained in:
		@@ -60,6 +60,7 @@ void Module::PortConfig::Clear() {
 | 
			
		||||
    completion_event->Clear();
 | 
			
		||||
    buffer_error_interrupt_event->Clear();
 | 
			
		||||
    vsync_interrupt_event->Clear();
 | 
			
		||||
    vsync_timings.clear();
 | 
			
		||||
    is_receiving = false;
 | 
			
		||||
    is_active = false;
 | 
			
		||||
    is_pending_receiving = false;
 | 
			
		||||
@@ -133,6 +134,27 @@ void Module::CompletionEventCallBack(u64 port_id, s64) {
 | 
			
		||||
    port.completion_event->Signal();
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static constexpr std::size_t MaxVsyncTimings = 5;
 | 
			
		||||
 | 
			
		||||
void Module::VsyncInterruptEventCallBack(u64 port_id, s64 cycles_late) {
 | 
			
		||||
    PortConfig& port = ports[port_id];
 | 
			
		||||
    const CameraConfig& camera = cameras[port.camera_id];
 | 
			
		||||
 | 
			
		||||
    if (!port.is_active) {
 | 
			
		||||
        return;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    port.vsync_timings.emplace_front(system.CoreTiming().GetGlobalTimeUs().count());
 | 
			
		||||
    if (port.vsync_timings.size() > MaxVsyncTimings) {
 | 
			
		||||
        port.vsync_timings.pop_back();
 | 
			
		||||
    }
 | 
			
		||||
    port.vsync_interrupt_event->Signal();
 | 
			
		||||
 | 
			
		||||
    system.CoreTiming().ScheduleEvent(
 | 
			
		||||
        msToCycles(LATENCY_BY_FRAME_RATE[static_cast<int>(camera.frame_rate)]) - cycles_late,
 | 
			
		||||
        vsync_interrupt_event_callback, port_id);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void Module::StartReceiving(int port_id) {
 | 
			
		||||
    PortConfig& port = ports[port_id];
 | 
			
		||||
    port.is_receiving = true;
 | 
			
		||||
@@ -173,6 +195,9 @@ void Module::ActivatePort(int port_id, int camera_id) {
 | 
			
		||||
    }
 | 
			
		||||
    ports[port_id].is_active = true;
 | 
			
		||||
    ports[port_id].camera_id = camera_id;
 | 
			
		||||
    system.CoreTiming().ScheduleEvent(
 | 
			
		||||
        msToCycles(LATENCY_BY_FRAME_RATE[static_cast<int>(cameras[camera_id].frame_rate)]),
 | 
			
		||||
        vsync_interrupt_event_callback, port_id);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
template <int max_index>
 | 
			
		||||
@@ -631,6 +656,7 @@ void Module::Interface::Activate(Kernel::HLERequestContext& ctx) {
 | 
			
		||||
                    cam->ports[i].is_busy = false;
 | 
			
		||||
                }
 | 
			
		||||
                cam->ports[i].is_active = false;
 | 
			
		||||
                cam->system.CoreTiming().UnscheduleEvent(cam->vsync_interrupt_event_callback, i);
 | 
			
		||||
            }
 | 
			
		||||
            rb.Push(RESULT_SUCCESS);
 | 
			
		||||
        } else if (camera_select[0] && camera_select[1]) {
 | 
			
		||||
@@ -860,6 +886,34 @@ void Module::Interface::SynchronizeVsyncTiming(Kernel::HLERequestContext& ctx) {
 | 
			
		||||
                camera_select1, camera_select2);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void Module::Interface::GetLatestVsyncTiming(Kernel::HLERequestContext& ctx) {
 | 
			
		||||
    IPC::RequestParser rp(ctx, 0x2A, 2, 0);
 | 
			
		||||
    const PortSet port_select(rp.Pop<u8>());
 | 
			
		||||
    const u32 count = rp.Pop<u32>();
 | 
			
		||||
 | 
			
		||||
    if (!port_select.IsSingle() || count > MaxVsyncTimings) {
 | 
			
		||||
        IPC::RequestBuilder rb = rp.MakeBuilder(1, 2);
 | 
			
		||||
        rb.Push(ERROR_OUT_OF_RANGE);
 | 
			
		||||
        rb.PushStaticBuffer({}, 0);
 | 
			
		||||
        return;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    IPC::RequestBuilder rb = rp.MakeBuilder(1, 2);
 | 
			
		||||
    rb.Push(RESULT_SUCCESS);
 | 
			
		||||
 | 
			
		||||
    const std::size_t port_id = port_select.m_val == 1 ? 0 : 1;
 | 
			
		||||
    std::vector<u8> out(count * sizeof(s64_le));
 | 
			
		||||
    std::size_t offset = 0;
 | 
			
		||||
    for (const s64_le timing : cam->ports[port_id].vsync_timings) {
 | 
			
		||||
        std::memcpy(out.data() + offset * sizeof(timing), &timing, sizeof(timing));
 | 
			
		||||
        offset++;
 | 
			
		||||
        if (offset >= count) {
 | 
			
		||||
            break;
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
    rb.PushStaticBuffer(out, 0);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void Module::Interface::GetStereoCameraCalibrationData(Kernel::HLERequestContext& ctx) {
 | 
			
		||||
    IPC::RequestBuilder rb = IPC::RequestParser(ctx, 0x2B, 0, 0).MakeBuilder(17, 0);
 | 
			
		||||
 | 
			
		||||
@@ -1032,6 +1086,10 @@ Module::Module(Core::System& system) : system(system) {
 | 
			
		||||
    completion_event_callback = system.CoreTiming().RegisterEvent(
 | 
			
		||||
        "CAM::CompletionEventCallBack",
 | 
			
		||||
        [this](u64 userdata, s64 cycles_late) { CompletionEventCallBack(userdata, cycles_late); });
 | 
			
		||||
    vsync_interrupt_event_callback = system.CoreTiming().RegisterEvent(
 | 
			
		||||
        "CAM::VsyncInterruptEventCallBack", [this](u64 userdata, s64 cycles_late) {
 | 
			
		||||
            VsyncInterruptEventCallBack(userdata, cycles_late);
 | 
			
		||||
        });
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
Module::~Module() {
 | 
			
		||||
 
 | 
			
		||||
@@ -5,6 +5,7 @@
 | 
			
		||||
#pragma once
 | 
			
		||||
 | 
			
		||||
#include <array>
 | 
			
		||||
#include <deque>
 | 
			
		||||
#include <future>
 | 
			
		||||
#include <memory>
 | 
			
		||||
#include <vector>
 | 
			
		||||
@@ -616,6 +617,21 @@ public:
 | 
			
		||||
         */
 | 
			
		||||
        void SynchronizeVsyncTiming(Kernel::HLERequestContext& ctx);
 | 
			
		||||
 | 
			
		||||
        /**
 | 
			
		||||
         * Gets the vsync timing record of the specified camera for the specified number of signals.
 | 
			
		||||
         *  Inputs:
 | 
			
		||||
         *      0: 0x002A0080
 | 
			
		||||
         *      1: Port
 | 
			
		||||
         *      2: Number of timings to get
 | 
			
		||||
         *      64: ((PastTimings * 8) << 14) | 2
 | 
			
		||||
         *      65: s64* TimingsOutput
 | 
			
		||||
         *  Outputs:
 | 
			
		||||
         *      0: 0x002A0042
 | 
			
		||||
         *      1: ResultCode
 | 
			
		||||
         *      2-3: Output static buffer
 | 
			
		||||
         */
 | 
			
		||||
        void GetLatestVsyncTiming(Kernel::HLERequestContext& ctx);
 | 
			
		||||
 | 
			
		||||
        /**
 | 
			
		||||
         * Returns calibration data relating the outside cameras to each other, for use in AR
 | 
			
		||||
         * applications.
 | 
			
		||||
@@ -716,6 +732,7 @@ public:
 | 
			
		||||
 | 
			
		||||
private:
 | 
			
		||||
    void CompletionEventCallBack(u64 port_id, s64);
 | 
			
		||||
    void VsyncInterruptEventCallBack(u64 port_id, s64 cycles_late);
 | 
			
		||||
 | 
			
		||||
    // Starts a receiving process on the specified port. This can only be called when is_busy = true
 | 
			
		||||
    // and is_receiving = false.
 | 
			
		||||
@@ -744,7 +761,7 @@ private:
 | 
			
		||||
        std::unique_ptr<Camera::CameraInterface> impl;
 | 
			
		||||
        std::array<ContextConfig, 2> contexts;
 | 
			
		||||
        int current_context{0};
 | 
			
		||||
        FrameRate frame_rate{FrameRate::Rate_5};
 | 
			
		||||
        FrameRate frame_rate{FrameRate::Rate_15};
 | 
			
		||||
    };
 | 
			
		||||
 | 
			
		||||
    struct PortConfig {
 | 
			
		||||
@@ -773,6 +790,8 @@ private:
 | 
			
		||||
        std::shared_ptr<Kernel::Event> buffer_error_interrupt_event;
 | 
			
		||||
        std::shared_ptr<Kernel::Event> vsync_interrupt_event;
 | 
			
		||||
 | 
			
		||||
        std::deque<s64> vsync_timings;
 | 
			
		||||
 | 
			
		||||
        std::future<std::vector<u16>> capture_result; // will hold the received frame.
 | 
			
		||||
        Kernel::Process* dest_process{nullptr};
 | 
			
		||||
        VAddr dest{0};    // the destination address of the receiving process
 | 
			
		||||
@@ -787,6 +806,7 @@ private:
 | 
			
		||||
    std::array<CameraConfig, NumCameras> cameras;
 | 
			
		||||
    std::array<PortConfig, 2> ports;
 | 
			
		||||
    Core::TimingEventType* completion_event_callback;
 | 
			
		||||
    Core::TimingEventType* vsync_interrupt_event_callback;
 | 
			
		||||
    std::atomic<bool> is_camera_reload_pending{false};
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
 
 | 
			
		||||
@@ -50,7 +50,7 @@ CAM_C::CAM_C(std::shared_ptr<Module> cam) : Module::Interface(std::move(cam), "c
 | 
			
		||||
        {0x00270140, nullptr, "SetAutoWhiteBalanceWindow"},
 | 
			
		||||
        {0x00280080, nullptr, "SetNoiseFilter"},
 | 
			
		||||
        {0x00290080, &CAM_C::SynchronizeVsyncTiming, "SynchronizeVsyncTiming"},
 | 
			
		||||
        {0x002A0080, nullptr, "GetLatestVsyncTiming"},
 | 
			
		||||
        {0x002A0080, &CAM_C::GetLatestVsyncTiming, "GetLatestVsyncTiming"},
 | 
			
		||||
        {0x002B0000, &CAM_C::GetStereoCameraCalibrationData, "GetStereoCameraCalibrationData"},
 | 
			
		||||
        {0x002C0400, nullptr, "SetStereoCameraCalibrationData"},
 | 
			
		||||
        {0x002D00C0, nullptr, "WriteRegisterI2c"},
 | 
			
		||||
 
 | 
			
		||||
@@ -50,7 +50,7 @@ CAM_S::CAM_S(std::shared_ptr<Module> cam) : Module::Interface(std::move(cam), "c
 | 
			
		||||
        {0x00270140, nullptr, "SetAutoWhiteBalanceWindow"},
 | 
			
		||||
        {0x00280080, nullptr, "SetNoiseFilter"},
 | 
			
		||||
        {0x00290080, &CAM_S::SynchronizeVsyncTiming, "SynchronizeVsyncTiming"},
 | 
			
		||||
        {0x002A0080, nullptr, "GetLatestVsyncTiming"},
 | 
			
		||||
        {0x002A0080, &CAM_S::GetLatestVsyncTiming, "GetLatestVsyncTiming"},
 | 
			
		||||
        {0x002B0000, &CAM_S::GetStereoCameraCalibrationData, "GetStereoCameraCalibrationData"},
 | 
			
		||||
        {0x002C0400, nullptr, "SetStereoCameraCalibrationData"},
 | 
			
		||||
        {0x002D00C0, nullptr, "WriteRegisterI2c"},
 | 
			
		||||
 
 | 
			
		||||
@@ -50,7 +50,7 @@ CAM_U::CAM_U(std::shared_ptr<Module> cam) : Module::Interface(std::move(cam), "c
 | 
			
		||||
        {0x00270140, nullptr, "SetAutoWhiteBalanceWindow"},
 | 
			
		||||
        {0x00280080, nullptr, "SetNoiseFilter"},
 | 
			
		||||
        {0x00290080, &CAM_U::SynchronizeVsyncTiming, "SynchronizeVsyncTiming"},
 | 
			
		||||
        {0x002A0080, nullptr, "GetLatestVsyncTiming"},
 | 
			
		||||
        {0x002A0080, &CAM_U::GetLatestVsyncTiming, "GetLatestVsyncTiming"},
 | 
			
		||||
        {0x002B0000, &CAM_U::GetStereoCameraCalibrationData, "GetStereoCameraCalibrationData"},
 | 
			
		||||
        {0x002C0400, nullptr, "SetStereoCameraCalibrationData"},
 | 
			
		||||
        {0x002D00C0, nullptr, "WriteRegisterI2c"},
 | 
			
		||||
 
 | 
			
		||||
		Reference in New Issue
	
	Block a user