mirror of
				https://github.com/PabloMK7/citra.git
				synced 2025-10-30 21:30:04 +00:00 
			
		
		
		
	HID: manages updating itself using correct ticks
This commit is contained in:
		
							parent
							
								
									16a3f9e393
								
							
						
					
					
						commit
						3c333c53f1
					
				
					 3 changed files with 90 additions and 59 deletions
				
			
		|  | @ -35,6 +35,15 @@ static u32 next_gyroscope_index; | |||
| static int enable_accelerometer_count = 0; // positive means enabled
 | ||||
| static int enable_gyroscope_count = 0;     // positive means enabled
 | ||||
| 
 | ||||
| static int pad_update_event; | ||||
| static int accelerometer_update_event; | ||||
| static int gyroscope_update_event; | ||||
| 
 | ||||
| // Updating period for each HID device. These empirical values are measured from a 11.2 3DS.
 | ||||
| constexpr u64 pad_update_ticks = 268123480ull / 234; | ||||
| constexpr u64 accelerometer_update_ticks = 268123480ull / 104; | ||||
| constexpr u64 gyroscope_update_ticks = 268123480ull / 101; | ||||
| 
 | ||||
| static PadState GetCirclePadDirectionState(s16 circle_pad_x, s16 circle_pad_y) { | ||||
|     // 30 degree and 60 degree are angular thresholds for directions
 | ||||
|     constexpr float TAN30 = 0.577350269f; | ||||
|  | @ -65,14 +74,9 @@ static PadState GetCirclePadDirectionState(s16 circle_pad_x, s16 circle_pad_y) { | |||
|     return state; | ||||
| } | ||||
| 
 | ||||
| void Update() { | ||||
| static void UpdatePadCallback(u64 userdata, int cycles_late) { | ||||
|     SharedMem* mem = reinterpret_cast<SharedMem*>(shared_mem->GetPointer()); | ||||
| 
 | ||||
|     if (mem == nullptr) { | ||||
|         LOG_DEBUG(Service_HID, "Cannot update HID prior to mapping shared memory!"); | ||||
|         return; | ||||
|     } | ||||
| 
 | ||||
|     PadState state = VideoCore::g_emu_window->GetPadState(); | ||||
| 
 | ||||
|     // Get current circle pad position and update circle pad direction
 | ||||
|  | @ -131,59 +135,68 @@ void Update() { | |||
|     event_pad_or_touch_1->Signal(); | ||||
|     event_pad_or_touch_2->Signal(); | ||||
| 
 | ||||
|     // Update accelerometer
 | ||||
|     if (enable_accelerometer_count > 0) { | ||||
|         mem->accelerometer.index = next_accelerometer_index; | ||||
|         next_accelerometer_index = | ||||
|             (next_accelerometer_index + 1) % mem->accelerometer.entries.size(); | ||||
|     // Reschedule recurrent event
 | ||||
|     CoreTiming::ScheduleEvent(pad_update_ticks - cycles_late, pad_update_event); | ||||
| } | ||||
| 
 | ||||
|         AccelerometerDataEntry& accelerometer_entry = | ||||
|             mem->accelerometer.entries[mem->accelerometer.index]; | ||||
|         std::tie(accelerometer_entry.x, accelerometer_entry.y, accelerometer_entry.z) = | ||||
|             VideoCore::g_emu_window->GetAccelerometerState(); | ||||
| static void UpdateAccelerometerCallback(u64 userdata, int cycles_late) { | ||||
|     SharedMem* mem = reinterpret_cast<SharedMem*>(shared_mem->GetPointer()); | ||||
| 
 | ||||
|         // Make up "raw" entry
 | ||||
|         // TODO(wwylele):
 | ||||
|         // From hardware testing, the raw_entry values are approximately,
 | ||||
|         // but not exactly, as twice as corresponding entries (or with a minus sign).
 | ||||
|         // It may caused by system calibration to the accelerometer.
 | ||||
|         // Figure out how it works, or, if no game reads raw_entry,
 | ||||
|         // the following three lines can be removed and leave raw_entry unimplemented.
 | ||||
|         mem->accelerometer.raw_entry.x = -2 * accelerometer_entry.x; | ||||
|         mem->accelerometer.raw_entry.z = 2 * accelerometer_entry.y; | ||||
|         mem->accelerometer.raw_entry.y = -2 * accelerometer_entry.z; | ||||
|     mem->accelerometer.index = next_accelerometer_index; | ||||
|     next_accelerometer_index = (next_accelerometer_index + 1) % mem->accelerometer.entries.size(); | ||||
| 
 | ||||
|         // If we just updated index 0, provide a new timestamp
 | ||||
|         if (mem->accelerometer.index == 0) { | ||||
|             mem->accelerometer.index_reset_ticks_previous = mem->accelerometer.index_reset_ticks; | ||||
|             mem->accelerometer.index_reset_ticks = (s64)CoreTiming::GetTicks(); | ||||
|         } | ||||
|     AccelerometerDataEntry& accelerometer_entry = | ||||
|         mem->accelerometer.entries[mem->accelerometer.index]; | ||||
|     std::tie(accelerometer_entry.x, accelerometer_entry.y, accelerometer_entry.z) = | ||||
|         VideoCore::g_emu_window->GetAccelerometerState(); | ||||
| 
 | ||||
|         event_accelerometer->Signal(); | ||||
|     // Make up "raw" entry
 | ||||
|     // TODO(wwylele):
 | ||||
|     // From hardware testing, the raw_entry values are approximately, but not exactly, as twice as
 | ||||
|     // corresponding entries (or with a minus sign). It may caused by system calibration to the
 | ||||
|     // accelerometer. Figure out how it works, or, if no game reads raw_entry, the following three
 | ||||
|     // lines can be removed and leave raw_entry unimplemented.
 | ||||
|     mem->accelerometer.raw_entry.x = -2 * accelerometer_entry.x; | ||||
|     mem->accelerometer.raw_entry.z = 2 * accelerometer_entry.y; | ||||
|     mem->accelerometer.raw_entry.y = -2 * accelerometer_entry.z; | ||||
| 
 | ||||
|     // If we just updated index 0, provide a new timestamp
 | ||||
|     if (mem->accelerometer.index == 0) { | ||||
|         mem->accelerometer.index_reset_ticks_previous = mem->accelerometer.index_reset_ticks; | ||||
|         mem->accelerometer.index_reset_ticks = (s64)CoreTiming::GetTicks(); | ||||
|     } | ||||
| 
 | ||||
|     // Update gyroscope
 | ||||
|     if (enable_gyroscope_count > 0) { | ||||
|         mem->gyroscope.index = next_gyroscope_index; | ||||
|         next_gyroscope_index = (next_gyroscope_index + 1) % mem->gyroscope.entries.size(); | ||||
|     event_accelerometer->Signal(); | ||||
| 
 | ||||
|         GyroscopeDataEntry& gyroscope_entry = mem->gyroscope.entries[mem->gyroscope.index]; | ||||
|         std::tie(gyroscope_entry.x, gyroscope_entry.y, gyroscope_entry.z) = | ||||
|             VideoCore::g_emu_window->GetGyroscopeState(); | ||||
|     // Reschedule recurrent event
 | ||||
|     CoreTiming::ScheduleEvent(accelerometer_update_ticks - cycles_late, accelerometer_update_event); | ||||
| } | ||||
| 
 | ||||
|         // Make up "raw" entry
 | ||||
|         mem->gyroscope.raw_entry.x = gyroscope_entry.x; | ||||
|         mem->gyroscope.raw_entry.z = -gyroscope_entry.y; | ||||
|         mem->gyroscope.raw_entry.y = gyroscope_entry.z; | ||||
| static void UpdateGyroscopeCallback(u64 userdata, int cycles_late) { | ||||
|     SharedMem* mem = reinterpret_cast<SharedMem*>(shared_mem->GetPointer()); | ||||
| 
 | ||||
|         // If we just updated index 0, provide a new timestamp
 | ||||
|         if (mem->gyroscope.index == 0) { | ||||
|             mem->gyroscope.index_reset_ticks_previous = mem->gyroscope.index_reset_ticks; | ||||
|             mem->gyroscope.index_reset_ticks = (s64)CoreTiming::GetTicks(); | ||||
|         } | ||||
|     mem->gyroscope.index = next_gyroscope_index; | ||||
|     next_gyroscope_index = (next_gyroscope_index + 1) % mem->gyroscope.entries.size(); | ||||
| 
 | ||||
|         event_gyroscope->Signal(); | ||||
|     GyroscopeDataEntry& gyroscope_entry = mem->gyroscope.entries[mem->gyroscope.index]; | ||||
|     std::tie(gyroscope_entry.x, gyroscope_entry.y, gyroscope_entry.z) = | ||||
|         VideoCore::g_emu_window->GetGyroscopeState(); | ||||
| 
 | ||||
|     // Make up "raw" entry
 | ||||
|     mem->gyroscope.raw_entry.x = gyroscope_entry.x; | ||||
|     mem->gyroscope.raw_entry.z = -gyroscope_entry.y; | ||||
|     mem->gyroscope.raw_entry.y = gyroscope_entry.z; | ||||
| 
 | ||||
|     // If we just updated index 0, provide a new timestamp
 | ||||
|     if (mem->gyroscope.index == 0) { | ||||
|         mem->gyroscope.index_reset_ticks_previous = mem->gyroscope.index_reset_ticks; | ||||
|         mem->gyroscope.index_reset_ticks = (s64)CoreTiming::GetTicks(); | ||||
|     } | ||||
| 
 | ||||
|     event_gyroscope->Signal(); | ||||
| 
 | ||||
|     // Reschedule recurrent event
 | ||||
|     CoreTiming::ScheduleEvent(gyroscope_update_ticks - cycles_late, gyroscope_update_event); | ||||
| } | ||||
| 
 | ||||
| void GetIPCHandles(Service::Interface* self) { | ||||
|  | @ -204,7 +217,11 @@ void EnableAccelerometer(Service::Interface* self) { | |||
|     u32* cmd_buff = Kernel::GetCommandBuffer(); | ||||
| 
 | ||||
|     ++enable_accelerometer_count; | ||||
|     event_accelerometer->Signal(); | ||||
| 
 | ||||
|     // Schedules the accelerometer update event if the accelerometer was just enabled
 | ||||
|     if (enable_accelerometer_count == 1) { | ||||
|         CoreTiming::ScheduleEvent(accelerometer_update_ticks, accelerometer_update_event); | ||||
|     } | ||||
| 
 | ||||
|     cmd_buff[1] = RESULT_SUCCESS.raw; | ||||
| 
 | ||||
|  | @ -215,7 +232,11 @@ void DisableAccelerometer(Service::Interface* self) { | |||
|     u32* cmd_buff = Kernel::GetCommandBuffer(); | ||||
| 
 | ||||
|     --enable_accelerometer_count; | ||||
|     event_accelerometer->Signal(); | ||||
| 
 | ||||
|     // Unschedules the accelerometer update event if the accelerometer was just disabled
 | ||||
|     if (enable_accelerometer_count == 0) { | ||||
|         CoreTiming::UnscheduleEvent(accelerometer_update_event, 0); | ||||
|     } | ||||
| 
 | ||||
|     cmd_buff[1] = RESULT_SUCCESS.raw; | ||||
| 
 | ||||
|  | @ -226,7 +247,11 @@ void EnableGyroscopeLow(Service::Interface* self) { | |||
|     u32* cmd_buff = Kernel::GetCommandBuffer(); | ||||
| 
 | ||||
|     ++enable_gyroscope_count; | ||||
|     event_gyroscope->Signal(); | ||||
| 
 | ||||
|     // Schedules the gyroscope update event if the gyroscope was just enabled
 | ||||
|     if (enable_gyroscope_count == 1) { | ||||
|         CoreTiming::ScheduleEvent(gyroscope_update_ticks, gyroscope_update_event); | ||||
|     } | ||||
| 
 | ||||
|     cmd_buff[1] = RESULT_SUCCESS.raw; | ||||
| 
 | ||||
|  | @ -237,7 +262,11 @@ void DisableGyroscopeLow(Service::Interface* self) { | |||
|     u32* cmd_buff = Kernel::GetCommandBuffer(); | ||||
| 
 | ||||
|     --enable_gyroscope_count; | ||||
|     event_gyroscope->Signal(); | ||||
| 
 | ||||
|     // Unschedules the gyroscope update event if the gyroscope was just disabled
 | ||||
|     if (enable_gyroscope_count == 0) { | ||||
|         CoreTiming::UnscheduleEvent(gyroscope_update_event, 0); | ||||
|     } | ||||
| 
 | ||||
|     cmd_buff[1] = RESULT_SUCCESS.raw; | ||||
| 
 | ||||
|  | @ -298,6 +327,15 @@ void Init() { | |||
|     event_accelerometer = Event::Create(ResetType::OneShot, "HID:EventAccelerometer"); | ||||
|     event_gyroscope = Event::Create(ResetType::OneShot, "HID:EventGyroscope"); | ||||
|     event_debug_pad = Event::Create(ResetType::OneShot, "HID:EventDebugPad"); | ||||
| 
 | ||||
|     // Register update callbacks
 | ||||
|     pad_update_event = CoreTiming::RegisterEvent("HID::UpdatePadCallback", UpdatePadCallback); | ||||
|     accelerometer_update_event = | ||||
|         CoreTiming::RegisterEvent("HID::UpdateAccelerometerCallback", UpdateAccelerometerCallback); | ||||
|     gyroscope_update_event = | ||||
|         CoreTiming::RegisterEvent("HID::UpdateGyroscopeCallback", UpdateGyroscopeCallback); | ||||
| 
 | ||||
|     CoreTiming::ScheduleEvent(pad_update_ticks, pad_update_event); | ||||
| } | ||||
| 
 | ||||
| void Shutdown() { | ||||
|  |  | |||
|  | @ -296,9 +296,6 @@ void GetGyroscopeLowRawToDpsCoefficient(Service::Interface* self); | |||
|  */ | ||||
| void GetGyroscopeLowCalibrateParam(Service::Interface* self); | ||||
| 
 | ||||
| /// Checks for user input updates
 | ||||
| void Update(); | ||||
| 
 | ||||
| /// Initialize HID service
 | ||||
| void Init(); | ||||
| 
 | ||||
|  |  | |||
|  | @ -15,7 +15,6 @@ | |||
| #include "common/vector_math.h" | ||||
| #include "core/core_timing.h" | ||||
| #include "core/hle/service/gsp_gpu.h" | ||||
| #include "core/hle/service/hid/hid.h" | ||||
| #include "core/hw/gpu.h" | ||||
| #include "core/hw/hw.h" | ||||
| #include "core/memory.h" | ||||
|  | @ -551,9 +550,6 @@ static void VBlankCallback(u64 userdata, int cycles_late) { | |||
|     Service::GSP::SignalInterrupt(Service::GSP::InterruptId::PDC0); | ||||
|     Service::GSP::SignalInterrupt(Service::GSP::InterruptId::PDC1); | ||||
| 
 | ||||
|     // Check for user input updates
 | ||||
|     Service::HID::Update(); | ||||
| 
 | ||||
|     if (!Settings::values.use_vsync && Settings::values.toggle_framelimit) { | ||||
|         FrameLimiter(); | ||||
|     } | ||||
|  |  | |||
		Loading…
	
	Add table
		Add a link
		
	
		Reference in a new issue