mirror of
				https://github.com/PabloMK7/citra.git
				synced 2025-10-30 21:30: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(); | ||||
|     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"}, | ||||
|  |  | |||
		Loading…
	
	Add table
		Add a link
		
	
		Reference in a new issue