Skip to content

Commit 0c8c7c3

Browse files
committed
Optimize Xbox One FF effect handling
1 parent b6e886d commit 0c8c7c3

File tree

1 file changed

+26
-9
lines changed

1 file changed

+26
-9
lines changed

WinUHidDevs/WinUHidXOne.cpp

Lines changed: 26 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -210,7 +210,13 @@ DWORD WINAPI RumbleThreadProc(LPVOID lpParameter)
210210
{
211211
auto device = (PWINUHID_XONE_GAMEPAD)lpParameter;
212212

213-
Wrappers::HandleT<Wrappers::HandleTraits::HANDLENullTraits> timer{ CreateWaitableTimerW(NULL, TRUE, NULL) };
213+
//
214+
// Use a high resolution timer to ensure maximum effect timing accuracy. This timer
215+
// will only be set while a FF effect is playing on the device, so it won't impact
216+
// system power usage in any meaningful way.
217+
//
218+
Wrappers::HandleT<Wrappers::HandleTraits::HANDLENullTraits> timer{
219+
CreateWaitableTimerExW(NULL, NULL, CREATE_WAITABLE_TIMER_MANUAL_RESET | CREATE_WAITABLE_TIMER_HIGH_RESOLUTION, NULL) };
214220
if (!timer.IsValid()) {
215221
return GetLastError();
216222
}
@@ -258,14 +264,16 @@ DWORD WINAPI RumbleThreadProc(LPVOID lpParameter)
258264
//
259265
// Wait for the delay period before initiating the FF effect
260266
//
261-
dueTime.QuadPart = XONE_TIME_TO_FILETIME(outputReport.u.Delay);
262-
SetWaitableTimer(timer.Get(), &dueTime, 0, NULL, NULL, FALSE);
263-
result = WaitForMultipleObjects(ARRAYSIZE(objects), objects, FALSE, INFINITE);
264-
if (result == WAIT_OBJECT_0 || device->Stopping) {
265-
//
266-
// We got a new output report, so break and start over
267-
//
268-
break;
267+
if (outputReport.u.Delay != 0) {
268+
dueTime.QuadPart = XONE_TIME_TO_FILETIME(outputReport.u.Delay);
269+
SetWaitableTimer(timer.Get(), &dueTime, 0, NULL, NULL, FALSE);
270+
result = WaitForMultipleObjects(ARRAYSIZE(objects), objects, FALSE, INFINITE);
271+
if (result == WAIT_OBJECT_0 || device->Stopping) {
272+
//
273+
// We got a new output report, so break and start over
274+
//
275+
break;
276+
}
269277
}
270278

271279
//
@@ -277,6 +285,15 @@ DWORD WINAPI RumbleThreadProc(LPVOID lpParameter)
277285
// Wait for the duration period before stopping the FF effect
278286
//
279287
dueTime.QuadPart = XONE_TIME_TO_FILETIME(outputReport.u.Duration);
288+
if (outputReport.u.Delay == 0 && outputReport.u.Repeat != 0) {
289+
//
290+
// We specially handle the common case of repeats with no delay specified.
291+
// We can optimize the series of short waits and motor on/off cycles by
292+
// consolidating all the repeats into the initial wait.
293+
//
294+
dueTime.QuadPart += dueTime.QuadPart * outputReport.u.Repeat;
295+
outputReport.u.Repeat = 0;
296+
}
280297
SetWaitableTimer(timer.Get(), &dueTime, 0, NULL, NULL, FALSE);
281298
result = WaitForMultipleObjects(ARRAYSIZE(objects), objects, FALSE, INFINITE);
282299
if (result == WAIT_OBJECT_0 || device->Stopping) {

0 commit comments

Comments
 (0)