mirror of
				https://github.com/PabloMK7/citra.git
				synced 2025-10-31 05:40:04 +00:00 
			
		
		
		
	Merge pull request #5116 from zhaowenlan1779/cam-vsync
service/cam: Implement Vsync interrupt events
This commit is contained in:
		
						commit
						ad3c464e2d
					
				
					 5 changed files with 82 additions and 4 deletions
				
			
		|  | @ -60,6 +60,7 @@ void Module::PortConfig::Clear() { | ||||||
|     completion_event->Clear(); |     completion_event->Clear(); | ||||||
|     buffer_error_interrupt_event->Clear(); |     buffer_error_interrupt_event->Clear(); | ||||||
|     vsync_interrupt_event->Clear(); |     vsync_interrupt_event->Clear(); | ||||||
|  |     vsync_timings.clear(); | ||||||
|     is_receiving = false; |     is_receiving = false; | ||||||
|     is_active = false; |     is_active = false; | ||||||
|     is_pending_receiving = false; |     is_pending_receiving = false; | ||||||
|  | @ -133,6 +134,27 @@ void Module::CompletionEventCallBack(u64 port_id, s64) { | ||||||
|     port.completion_event->Signal(); |     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) { | void Module::StartReceiving(int port_id) { | ||||||
|     PortConfig& port = ports[port_id]; |     PortConfig& port = ports[port_id]; | ||||||
|     port.is_receiving = true; |     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].is_active = true; | ||||||
|     ports[port_id].camera_id = camera_id; |     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> | 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_busy = false; | ||||||
|                 } |                 } | ||||||
|                 cam->ports[i].is_active = false; |                 cam->ports[i].is_active = false; | ||||||
|  |                 cam->system.CoreTiming().UnscheduleEvent(cam->vsync_interrupt_event_callback, i); | ||||||
|             } |             } | ||||||
|             rb.Push(RESULT_SUCCESS); |             rb.Push(RESULT_SUCCESS); | ||||||
|         } else if (camera_select[0] && camera_select[1]) { |         } else if (camera_select[0] && camera_select[1]) { | ||||||
|  | @ -860,6 +886,34 @@ void Module::Interface::SynchronizeVsyncTiming(Kernel::HLERequestContext& ctx) { | ||||||
|                 camera_select1, camera_select2); |                 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) { | void Module::Interface::GetStereoCameraCalibrationData(Kernel::HLERequestContext& ctx) { | ||||||
|     IPC::RequestBuilder rb = IPC::RequestParser(ctx, 0x2B, 0, 0).MakeBuilder(17, 0); |     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( |     completion_event_callback = system.CoreTiming().RegisterEvent( | ||||||
|         "CAM::CompletionEventCallBack", |         "CAM::CompletionEventCallBack", | ||||||
|         [this](u64 userdata, s64 cycles_late) { CompletionEventCallBack(userdata, cycles_late); }); |         [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() { | Module::~Module() { | ||||||
|  |  | ||||||
|  | @ -5,6 +5,7 @@ | ||||||
| #pragma once | #pragma once | ||||||
| 
 | 
 | ||||||
| #include <array> | #include <array> | ||||||
|  | #include <deque> | ||||||
| #include <future> | #include <future> | ||||||
| #include <memory> | #include <memory> | ||||||
| #include <vector> | #include <vector> | ||||||
|  | @ -616,6 +617,21 @@ public: | ||||||
|          */ |          */ | ||||||
|         void SynchronizeVsyncTiming(Kernel::HLERequestContext& ctx); |         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 |          * Returns calibration data relating the outside cameras to each other, for use in AR | ||||||
|          * applications. |          * applications. | ||||||
|  | @ -716,6 +732,7 @@ public: | ||||||
| 
 | 
 | ||||||
| private: | private: | ||||||
|     void CompletionEventCallBack(u64 port_id, s64); |     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
 |     // Starts a receiving process on the specified port. This can only be called when is_busy = true
 | ||||||
|     // and is_receiving = false.
 |     // and is_receiving = false.
 | ||||||
|  | @ -744,7 +761,7 @@ private: | ||||||
|         std::unique_ptr<Camera::CameraInterface> impl; |         std::unique_ptr<Camera::CameraInterface> impl; | ||||||
|         std::array<ContextConfig, 2> contexts; |         std::array<ContextConfig, 2> contexts; | ||||||
|         int current_context{0}; |         int current_context{0}; | ||||||
|         FrameRate frame_rate{FrameRate::Rate_5}; |         FrameRate frame_rate{FrameRate::Rate_15}; | ||||||
|     }; |     }; | ||||||
| 
 | 
 | ||||||
|     struct PortConfig { |     struct PortConfig { | ||||||
|  | @ -773,6 +790,8 @@ private: | ||||||
|         std::shared_ptr<Kernel::Event> buffer_error_interrupt_event; |         std::shared_ptr<Kernel::Event> buffer_error_interrupt_event; | ||||||
|         std::shared_ptr<Kernel::Event> vsync_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.
 |         std::future<std::vector<u16>> capture_result; // will hold the received frame.
 | ||||||
|         Kernel::Process* dest_process{nullptr}; |         Kernel::Process* dest_process{nullptr}; | ||||||
|         VAddr dest{0};    // the destination address of the receiving process
 |         VAddr dest{0};    // the destination address of the receiving process
 | ||||||
|  | @ -787,6 +806,7 @@ private: | ||||||
|     std::array<CameraConfig, NumCameras> cameras; |     std::array<CameraConfig, NumCameras> cameras; | ||||||
|     std::array<PortConfig, 2> ports; |     std::array<PortConfig, 2> ports; | ||||||
|     Core::TimingEventType* completion_event_callback; |     Core::TimingEventType* completion_event_callback; | ||||||
|  |     Core::TimingEventType* vsync_interrupt_event_callback; | ||||||
|     std::atomic<bool> is_camera_reload_pending{false}; |     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"}, |         {0x00270140, nullptr, "SetAutoWhiteBalanceWindow"}, | ||||||
|         {0x00280080, nullptr, "SetNoiseFilter"}, |         {0x00280080, nullptr, "SetNoiseFilter"}, | ||||||
|         {0x00290080, &CAM_C::SynchronizeVsyncTiming, "SynchronizeVsyncTiming"}, |         {0x00290080, &CAM_C::SynchronizeVsyncTiming, "SynchronizeVsyncTiming"}, | ||||||
|         {0x002A0080, nullptr, "GetLatestVsyncTiming"}, |         {0x002A0080, &CAM_C::GetLatestVsyncTiming, "GetLatestVsyncTiming"}, | ||||||
|         {0x002B0000, &CAM_C::GetStereoCameraCalibrationData, "GetStereoCameraCalibrationData"}, |         {0x002B0000, &CAM_C::GetStereoCameraCalibrationData, "GetStereoCameraCalibrationData"}, | ||||||
|         {0x002C0400, nullptr, "SetStereoCameraCalibrationData"}, |         {0x002C0400, nullptr, "SetStereoCameraCalibrationData"}, | ||||||
|         {0x002D00C0, nullptr, "WriteRegisterI2c"}, |         {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"}, |         {0x00270140, nullptr, "SetAutoWhiteBalanceWindow"}, | ||||||
|         {0x00280080, nullptr, "SetNoiseFilter"}, |         {0x00280080, nullptr, "SetNoiseFilter"}, | ||||||
|         {0x00290080, &CAM_S::SynchronizeVsyncTiming, "SynchronizeVsyncTiming"}, |         {0x00290080, &CAM_S::SynchronizeVsyncTiming, "SynchronizeVsyncTiming"}, | ||||||
|         {0x002A0080, nullptr, "GetLatestVsyncTiming"}, |         {0x002A0080, &CAM_S::GetLatestVsyncTiming, "GetLatestVsyncTiming"}, | ||||||
|         {0x002B0000, &CAM_S::GetStereoCameraCalibrationData, "GetStereoCameraCalibrationData"}, |         {0x002B0000, &CAM_S::GetStereoCameraCalibrationData, "GetStereoCameraCalibrationData"}, | ||||||
|         {0x002C0400, nullptr, "SetStereoCameraCalibrationData"}, |         {0x002C0400, nullptr, "SetStereoCameraCalibrationData"}, | ||||||
|         {0x002D00C0, nullptr, "WriteRegisterI2c"}, |         {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"}, |         {0x00270140, nullptr, "SetAutoWhiteBalanceWindow"}, | ||||||
|         {0x00280080, nullptr, "SetNoiseFilter"}, |         {0x00280080, nullptr, "SetNoiseFilter"}, | ||||||
|         {0x00290080, &CAM_U::SynchronizeVsyncTiming, "SynchronizeVsyncTiming"}, |         {0x00290080, &CAM_U::SynchronizeVsyncTiming, "SynchronizeVsyncTiming"}, | ||||||
|         {0x002A0080, nullptr, "GetLatestVsyncTiming"}, |         {0x002A0080, &CAM_U::GetLatestVsyncTiming, "GetLatestVsyncTiming"}, | ||||||
|         {0x002B0000, &CAM_U::GetStereoCameraCalibrationData, "GetStereoCameraCalibrationData"}, |         {0x002B0000, &CAM_U::GetStereoCameraCalibrationData, "GetStereoCameraCalibrationData"}, | ||||||
|         {0x002C0400, nullptr, "SetStereoCameraCalibrationData"}, |         {0x002C0400, nullptr, "SetStereoCameraCalibrationData"}, | ||||||
|         {0x002D00C0, nullptr, "WriteRegisterI2c"}, |         {0x002D00C0, nullptr, "WriteRegisterI2c"}, | ||||||
|  |  | ||||||
		Loading…
	
	Add table
		Add a link
		
	
		Reference in a new issue