mirror of
https://github.com/cemu-project/DS4Windows.git
synced 2024-12-27 00:51:48 +01:00
Reduced input lag by implementing overlapped IO and changing threading
This commit is contained in:
parent
0dd442f813
commit
5dbc193351
@ -121,6 +121,7 @@ namespace DS4Windows
|
||||
private byte[] accel = new byte[6];
|
||||
private byte[] gyro = new byte[6];
|
||||
private byte[] inputReport;
|
||||
private byte[] inputReport2;
|
||||
private byte[] btInputReport = null;
|
||||
private byte[] outputReportBuffer, outputReport;
|
||||
private readonly DS4Touchpad touchpad = null;
|
||||
@ -134,6 +135,8 @@ namespace DS4Windows
|
||||
public DateTime lastActive = DateTime.UtcNow;
|
||||
public DateTime firstActive = DateTime.UtcNow;
|
||||
private bool charging;
|
||||
// Use large value for worst case scenario
|
||||
private static int readStreamTimeout = 100;
|
||||
public event EventHandler<EventArgs> Report = null;
|
||||
public event EventHandler<EventArgs> Removal = null;
|
||||
|
||||
@ -221,6 +224,7 @@ namespace DS4Windows
|
||||
if (conType == ConnectionType.USB)
|
||||
{
|
||||
inputReport = new byte[64];
|
||||
inputReport2 = new byte[64];
|
||||
outputReport = new byte[hDevice.Capabilities.OutputReportByteLength];
|
||||
outputReportBuffer = new byte[hDevice.Capabilities.OutputReportByteLength];
|
||||
}
|
||||
@ -244,7 +248,13 @@ namespace DS4Windows
|
||||
ds4Output = new Thread(performDs4Output);
|
||||
ds4Output.Priority = ThreadPriority.Highest;
|
||||
ds4Output.Name = "DS4 Output thread: " + Mac;
|
||||
ds4Output.Start();
|
||||
if (conType == ConnectionType.BT)
|
||||
{
|
||||
// Only use the output thread for Bluetooth connections.
|
||||
// USB will utilize overlapped IO instead.
|
||||
ds4Output.Start();
|
||||
}
|
||||
|
||||
ds4Input = new Thread(performDs4Input);
|
||||
ds4Input.Priority = ThreadPriority.Highest;
|
||||
ds4Input.Name = "DS4 Input thread: " + Mac;
|
||||
@ -273,7 +283,7 @@ namespace DS4Windows
|
||||
|
||||
private void StopOutputUpdate()
|
||||
{
|
||||
if (ds4Output.ThreadState != System.Threading.ThreadState.Stopped || ds4Output.ThreadState != System.Threading.ThreadState.Aborted)
|
||||
if (ds4Output.ThreadState != System.Threading.ThreadState.Unstarted || ds4Output.ThreadState != System.Threading.ThreadState.Stopped || ds4Output.ThreadState != System.Threading.ThreadState.Aborted)
|
||||
{
|
||||
try
|
||||
{
|
||||
@ -295,7 +305,7 @@ namespace DS4Windows
|
||||
}
|
||||
else
|
||||
{
|
||||
return hDevice.WriteOutputReportViaInterrupt(outputReport, 8);
|
||||
return hDevice.WriteAsyncOutputReportViaInterrupt(outputReport);
|
||||
}
|
||||
}
|
||||
|
||||
@ -303,10 +313,12 @@ namespace DS4Windows
|
||||
{
|
||||
lock (outputReport)
|
||||
{
|
||||
int lastError = 0;
|
||||
//int lastError = 0;
|
||||
while (true)
|
||||
{
|
||||
if (writeOutput())
|
||||
Monitor.Wait(outputReport);
|
||||
writeOutput();
|
||||
/*if (writeOutput())
|
||||
{
|
||||
lastError = 0;
|
||||
if (testRumble.IsRumbleSet()) // repeat test rumbles periodically; rumble has auto-shut-off in the DS4 firmware
|
||||
@ -323,6 +335,7 @@ namespace DS4Windows
|
||||
lastError = thisError;
|
||||
}
|
||||
}
|
||||
*/
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -374,7 +387,8 @@ namespace DS4Windows
|
||||
readTimeout.Enabled = true;
|
||||
if (conType != ConnectionType.USB)
|
||||
{
|
||||
HidDevice.ReadStatus res = hDevice.ReadFile(btInputReport);
|
||||
//HidDevice.ReadStatus res = hDevice.ReadFile(btInputReport);
|
||||
HidDevice.ReadStatus res = hDevice.ReadAsyncWithFileStream(btInputReport, readStreamTimeout);
|
||||
readTimeout.Enabled = false;
|
||||
if (res == HidDevice.ReadStatus.Success)
|
||||
{
|
||||
@ -394,7 +408,8 @@ namespace DS4Windows
|
||||
}
|
||||
else
|
||||
{
|
||||
HidDevice.ReadStatus res = hDevice.ReadFile(inputReport);
|
||||
//HidDevice.ReadStatus res = hDevice.ReadFile(inputReport);
|
||||
HidDevice.ReadStatus res = hDevice.ReadAsyncWithFileStream(inputReport2, readStreamTimeout);
|
||||
readTimeout.Enabled = false;
|
||||
if (res != HidDevice.ReadStatus.Success)
|
||||
{
|
||||
@ -405,6 +420,10 @@ namespace DS4Windows
|
||||
Removal(this, EventArgs.Empty);
|
||||
return;
|
||||
}
|
||||
else
|
||||
{
|
||||
Array.Copy(inputReport2, 0, inputReport, 0, inputReport.Length);
|
||||
}
|
||||
}
|
||||
if (ConnectionType == ConnectionType.BT && btInputReport[0] != 0x11)
|
||||
{
|
||||
@ -517,7 +536,12 @@ namespace DS4Windows
|
||||
// XXX fix initialization ordering so the null checks all go away
|
||||
if (Report != null)
|
||||
Report(this, EventArgs.Empty);
|
||||
sendOutputReport(false);
|
||||
bool syncWriteReport = true;
|
||||
if (conType == ConnectionType.BT)
|
||||
{
|
||||
syncWriteReport = false;
|
||||
}
|
||||
sendOutputReport(syncWriteReport);
|
||||
if (!string.IsNullOrEmpty(error))
|
||||
error = string.Empty;
|
||||
if (!string.IsNullOrEmpty(currerror))
|
||||
|
@ -202,10 +202,9 @@ namespace DS4Windows
|
||||
if (safeReadHandle == null)
|
||||
safeReadHandle = OpenHandle(_devicePath, true);
|
||||
if (fileStream == null && !safeReadHandle.IsInvalid)
|
||||
fileStream = new FileStream(safeReadHandle, FileAccess.ReadWrite, inputBuffer.Length, false);
|
||||
fileStream = new FileStream(safeReadHandle, FileAccess.ReadWrite, inputBuffer.Length, true);
|
||||
if (!safeReadHandle.IsInvalid && fileStream.CanRead)
|
||||
{
|
||||
|
||||
Task<ReadStatus> readFileTask = new Task<ReadStatus>(() => ReadWithFileStreamTask(inputBuffer));
|
||||
readFileTask.Start();
|
||||
bool success = readFileTask.Wait(timeout);
|
||||
@ -245,6 +244,46 @@ namespace DS4Windows
|
||||
|
||||
|
||||
|
||||
return ReadStatus.ReadError;
|
||||
}
|
||||
|
||||
public ReadStatus ReadAsyncWithFileStream(byte[] inputBuffer, int timeout)
|
||||
{
|
||||
try
|
||||
{
|
||||
if (safeReadHandle == null)
|
||||
safeReadHandle = OpenHandle(_devicePath, true);
|
||||
if (fileStream == null && !safeReadHandle.IsInvalid)
|
||||
fileStream = new FileStream(safeReadHandle, FileAccess.ReadWrite, inputBuffer.Length, true);
|
||||
if (!safeReadHandle.IsInvalid && fileStream.CanRead)
|
||||
{
|
||||
|
||||
Task<int> readTask = fileStream.ReadAsync(inputBuffer, 0, inputBuffer.Length);
|
||||
readTask.Wait(timeout);
|
||||
if (readTask.Result > 0)
|
||||
{
|
||||
return ReadStatus.Success;
|
||||
}
|
||||
else
|
||||
{
|
||||
return ReadStatus.NoDataRead;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
if (e is AggregateException)
|
||||
{
|
||||
Console.WriteLine(e.Message);
|
||||
return ReadStatus.WaitFail;
|
||||
}
|
||||
else
|
||||
{
|
||||
return ReadStatus.ReadError;
|
||||
}
|
||||
}
|
||||
|
||||
return ReadStatus.ReadError;
|
||||
}
|
||||
|
||||
@ -285,7 +324,7 @@ namespace DS4Windows
|
||||
}
|
||||
if (fileStream == null && !safeReadHandle.IsInvalid)
|
||||
{
|
||||
fileStream = new FileStream(safeReadHandle, FileAccess.ReadWrite, outputBuffer.Length, false);
|
||||
fileStream = new FileStream(safeReadHandle, FileAccess.ReadWrite, outputBuffer.Length, true);
|
||||
}
|
||||
if (fileStream != null && fileStream.CanWrite && !safeReadHandle.IsInvalid)
|
||||
{
|
||||
@ -304,6 +343,36 @@ namespace DS4Windows
|
||||
|
||||
}
|
||||
|
||||
public bool WriteAsyncOutputReportViaInterrupt(byte[] outputBuffer)
|
||||
{
|
||||
try
|
||||
{
|
||||
if (safeReadHandle == null)
|
||||
{
|
||||
safeReadHandle = OpenHandle(_devicePath, true);
|
||||
}
|
||||
if (fileStream == null && !safeReadHandle.IsInvalid)
|
||||
{
|
||||
fileStream = new FileStream(safeReadHandle, FileAccess.ReadWrite, outputBuffer.Length, true);
|
||||
}
|
||||
if (fileStream != null && fileStream.CanWrite && !safeReadHandle.IsInvalid)
|
||||
{
|
||||
Task writeTask = fileStream.WriteAsync(outputBuffer, 0, outputBuffer.Length);
|
||||
//fileStream.Write(outputBuffer, 0, outputBuffer.Length);
|
||||
return true;
|
||||
}
|
||||
else
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
catch (Exception)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
private SafeFileHandle OpenHandle(String devicePathName, Boolean isExclusive)
|
||||
{
|
||||
SafeFileHandle hidHandle;
|
||||
@ -312,11 +381,11 @@ namespace DS4Windows
|
||||
{
|
||||
if (isExclusive)
|
||||
{
|
||||
hidHandle = NativeMethods.CreateFile(devicePathName, NativeMethods.GENERIC_READ | NativeMethods.GENERIC_WRITE, 0, IntPtr.Zero, NativeMethods.OpenExisting, 0x20000000 | 0x80000000, 0);
|
||||
hidHandle = NativeMethods.CreateFile(devicePathName, NativeMethods.GENERIC_READ | NativeMethods.GENERIC_WRITE, 0, IntPtr.Zero, NativeMethods.OpenExisting, 0x20000000 | 0x80000000 | NativeMethods.FILE_FLAG_OVERLAPPED, 0);
|
||||
}
|
||||
else
|
||||
{
|
||||
hidHandle = NativeMethods.CreateFile(devicePathName, NativeMethods.GENERIC_READ | NativeMethods.GENERIC_WRITE, NativeMethods.FILE_SHARE_READ | NativeMethods.FILE_SHARE_WRITE, IntPtr.Zero, NativeMethods.OpenExisting, 0x20000000 | 0x80000000, 0);
|
||||
hidHandle = NativeMethods.CreateFile(devicePathName, NativeMethods.GENERIC_READ | NativeMethods.GENERIC_WRITE, NativeMethods.FILE_SHARE_READ | NativeMethods.FILE_SHARE_WRITE, IntPtr.Zero, NativeMethods.OpenExisting, 0x20000000 | 0x80000000 | NativeMethods.FILE_FLAG_OVERLAPPED, 0);
|
||||
}
|
||||
}
|
||||
catch (Exception)
|
||||
|
Loading…
Reference in New Issue
Block a user