From e4062a6c909a4a31b2d65ee59268e718df572ab0 Mon Sep 17 00:00:00 2001 From: myT Date: Sat, 6 May 2017 22:01:14 +0200 Subject: [PATCH] reduced win32 raw mouse input latency and added cl_drawMouseLag --- changelog.txt | 2 ++ code/client/cl_input.cpp | 4 +++ code/client/cl_scrn.cpp | 35 ++++++++++++++++++++++++ code/client/client.h | 2 ++ code/qcommon/qcommon.h | 2 +- code/renderer/tr_main.cpp | 4 +++ code/renderer/tr_public.h | 6 +++-- code/win32/win_input.cpp | 56 +++++++++++++++------------------------ code/win32/win_local.h | 4 +-- code/win32/win_main.cpp | 5 ++-- 10 files changed, 78 insertions(+), 42 deletions(-) diff --git a/changelog.txt b/changelog.txt index 91cda14..fe8bcb1 100644 --- a/changelog.txt +++ b/changelog.txt @@ -56,6 +56,8 @@ fix: if requesting a resolution too high for the display, the image would be off chg: updated mouse input for better grab (de-)activation and fixed window dragging not working +chg: reduced raw mouse input latency and added cl_drawMouseLag + Linux: diff --git a/code/client/cl_input.cpp b/code/client/cl_input.cpp index 6abacfc..8e439ea 100644 --- a/code/client/cl_input.cpp +++ b/code/client/cl_input.cpp @@ -295,6 +295,7 @@ void CL_MouseEvent( int dx, int dy, int time ) VM_Call( cgvm, CG_MOUSE_EVENT, dx, dy ); cl.mouseDx[cl.mouseIndex] += dx; cl.mouseDy[cl.mouseIndex] += dy; + cl.mouseTime = time; } } @@ -454,6 +455,7 @@ static usercmd_t CL_CreateCmd() // get basic movement from mouse CL_MouseMove( &cmd ); + cl.userCmdTime = Sys_Milliseconds(); // get basic movement from joystick CL_JoystickMove( &cmd ); @@ -865,6 +867,8 @@ void CL_InitInput() Cmd_AddCommand ("+mlook", IN_MLookDown); Cmd_AddCommand ("-mlook", IN_MLookUp); + Cvar_Get( "cl_drawMouseLag", "0", 0 ); + m_speed = Cvar_Get( "m_speed", "8", CVAR_ARCHIVE ); m_accel = Cvar_Get( "m_accel", "0", CVAR_ARCHIVE ); m_limit = Cvar_Get( "m_limit", "0", CVAR_ARCHIVE ); diff --git a/code/client/cl_scrn.cpp b/code/client/cl_scrn.cpp index 26a0e98..293a602 100644 --- a/code/client/cl_scrn.cpp +++ b/code/client/cl_scrn.cpp @@ -215,6 +215,39 @@ void SCR_Init() /////////////////////////////////////////////////////////////// +static void SCR_DrawStats( float x, float y, float w, float h, int value ) +{ + if ( value < 0 || value >= 100 ) + SCR_DrawString( x, y, w, h, " ?", qfalse ); + else + SCR_DrawString( x, y, w, h, va( "%3d", value ), qfalse ); +} + + +static void SCR_DrawInputStats( int stats, float x, float y, float w, float h, const char* header ) +{ + SCR_DrawString( x, y, w, h, header, qfalse ); + x += 5.0f * w; + SCR_DrawStats( x, y, w, h, stats ); +} + + +static void SCR_DrawMouseInputLatencies() +{ + if ( !cls.cgameStarted || cls.state != CA_ACTIVE || + !Cvar_VariableIntegerValue( "cl_drawMouseLag" ) ) + return; + + float x = 10, y = 10, w = 16, h = 24; + SCR_AdjustFrom640( &x, &y, 0, 0 ); + SCR_DrawString( x, y, w, h, "mouse lag [ms]", qfalse ); + y += 30; + SCR_DrawInputStats( cl.userCmdTime - cl.mouseTime, x, y, w, h, "netw" ); + y += 30; + SCR_DrawInputStats( re_cameraMatrixTime - cl.mouseTime, x, y, w, h, "draw" ); +} + + // this will be called twice if rendering in stereo mode static void SCR_DrawScreenField( stereoFrame_t stereoFrame ) @@ -283,6 +316,8 @@ static void SCR_DrawScreenField( stereoFrame_t stereoFrame ) VM_Call( uivm, UI_REFRESH, cls.realtime ); } + SCR_DrawMouseInputLatencies(); + // console draws next Con_DrawConsole(); diff --git a/code/client/client.h b/code/client/client.h index 28a5646..4a6ae80 100644 --- a/code/client/client.h +++ b/code/client/client.h @@ -105,6 +105,7 @@ typedef struct { int mouseDx[2], mouseDy[2]; // added to by mouse events int mouseIndex; + int mouseTime; // when the last mouse input was sampled, for cl_drawMouseLag int joystickAxis[MAX_JOYSTICK_AXIS]; // set by joystick events // cgame communicates a few values to the client system @@ -116,6 +117,7 @@ typedef struct { usercmd_t cmds[CMD_BACKUP]; // each mesage will send several old cmds int cmdNumber; // incremented each frame, because multiple // frames may need to be packed into a single packet + int userCmdTime; // when the last usercmd_t was generated, for cl_drawMouseLag outPacket_t outPackets[PACKET_BACKUP]; // information about each packet we have sent out diff --git a/code/qcommon/qcommon.h b/code/qcommon/qcommon.h index 1df557a..e08e7fe 100644 --- a/code/qcommon/qcommon.h +++ b/code/qcommon/qcommon.h @@ -708,7 +708,7 @@ int Com_HashKey(char *string, int maxlen); int Com_Filter( const char* filter, const char* name ); int Com_FilterPath( const char* filter, const char* name ); int Com_RealTime(qtime_t *qtime); -qbool Com_SafeMode(); +qbool Com_SafeMode(); void Com_StartupVariable( const char *match ); // checks for and removes command line "+set var arg" constructs diff --git a/code/renderer/tr_main.cpp b/code/renderer/tr_main.cpp index c9d8a3b..e55439d 100644 --- a/code/renderer/tr_main.cpp +++ b/code/renderer/tr_main.cpp @@ -1272,6 +1272,9 @@ static void R_DebugGraphics() } +int re_cameraMatrixTime; + + // a view may be either the actual camera view, or a mirror / remote location void R_RenderView( const viewParms_t* parms ) @@ -1289,6 +1292,7 @@ void R_RenderView( const viewParms_t* parms ) int firstLitSurf = tr.refdef.numLitSurfs; // set viewParms.world + re_cameraMatrixTime = Sys_Milliseconds(); R_RotateForViewer(); R_SetupFrustum(); diff --git a/code/renderer/tr_public.h b/code/renderer/tr_public.h index 0075053..422f26e 100644 --- a/code/renderer/tr_public.h +++ b/code/renderer/tr_public.h @@ -158,8 +158,6 @@ typedef struct { qbool (*inPVS)( const vec3_t p1, const vec3_t p2 ); void (*TakeVideoFrame)( int h, int w, byte* captureBuffer, byte *encodeBuffer, qbool motionJpeg ); - // drakkar - void (*WindowFocus)(qbool focus); } refexport_t; // @@ -223,4 +221,8 @@ typedef struct { // if the module can't init to a valid rendering state, it will return NULL const refexport_t* GetRefAPI( const refimport_t* rimp ); + +extern int re_cameraMatrixTime; // when the final model-view matrix is computed, for cl_drawMouseLag + + #endif // __TR_PUBLIC_H diff --git a/code/win32/win_input.cpp b/code/win32/win_input.cpp index f52aed9..c7c6bb8 100644 --- a/code/win32/win_input.cpp +++ b/code/win32/win_input.cpp @@ -29,7 +29,6 @@ struct Mouse { virtual qbool Activate( qbool active ); virtual void OnWindowMoved() {} virtual void Shutdown() {} - virtual void Read( int* mx, int* my ) = 0; virtual qbool ProcessMessage( UINT msg, WPARAM wParam, LPARAM lParam ) { return qfalse; } // returns true if the event was handled Mouse() : active(qfalse), wheel(0) {} @@ -78,10 +77,7 @@ void Mouse::UpdateWheel( int delta ) struct rawmouse_t : public Mouse { virtual qbool Init(); virtual qbool Activate( qbool active ); - virtual void Read( int* mx, int* my ); virtual qbool ProcessMessage( UINT msg, WPARAM wParam, LPARAM lParam ); - - int x, y; }; static rawmouse_t rawmouse; @@ -109,14 +105,6 @@ qbool rawmouse_t::Activate( qbool active ) } -void rawmouse_t::Read( int* mx, int* my ) -{ - *mx = rawmouse.x; - *my = rawmouse.y; - rawmouse.x = rawmouse.y = 0; -} - - // MSDN says you have to always let DefWindowProc run for WM_INPUT // regardless of whether you process the message or not, so ALWAYS return false here @@ -138,8 +126,10 @@ qbool rawmouse_t::ProcessMessage( UINT msg, WPARAM wParam, LPARAM lParam ) if ( (ri.header.dwType != RIM_TYPEMOUSE) || (ri.data.mouse.usFlags != MOUSE_MOVE_RELATIVE) ) return qfalse; - rawmouse.x += ri.data.mouse.lLastX; - rawmouse.y += ri.data.mouse.lLastY; + const int dx = (int)ri.data.mouse.lLastX; + const int dy = (int)ri.data.mouse.lLastY; + if (dx != 0 || dy != 0) + Sys_QueEvent( g_wv.sysMsgTime, SE_MOUSE, dx, dy, 0, NULL ); if (!ri.data.mouse.usButtonFlags) // no button or wheel transitions return qfalse; @@ -173,12 +163,12 @@ qbool rawmouse_t::ProcessMessage( UINT msg, WPARAM wParam, LPARAM lParam ) struct winmouse_t : public Mouse { virtual qbool Activate( qbool active ); virtual void OnWindowMoved(); - virtual void Read( int* mx, int* my ); virtual qbool ProcessMessage( UINT msg, WPARAM wParam, LPARAM lParam ); void UpdateWindowCenter(); int window_center_x, window_center_y; + qbool active; }; static winmouse_t winmouse; @@ -197,9 +187,11 @@ void winmouse_t::UpdateWindowCenter() } -qbool winmouse_t::Activate(qbool active) +qbool winmouse_t::Activate( qbool _active ) { - if (!active) + active = _active; + + if (!_active) return qtrue; UpdateWindowCenter(); @@ -215,21 +207,23 @@ void winmouse_t::OnWindowMoved() } -void winmouse_t::Read( int* mx, int* my ) -{ - POINT p; - GetCursorPos( &p ); - *mx = p.x - window_center_x; - *my = p.y - window_center_y; - SetCursorPos( window_center_x, window_center_y ); -} - - qbool winmouse_t::ProcessMessage( UINT msg, WPARAM wParam, LPARAM lParam ) { + if ( !active ) + return qfalse; + #define QUEUE_WM_BUTTON( qbutton, mask ) \ Sys_QueEvent( g_wv.sysMsgTime, SE_KEY, qbutton, (wParam & mask), 0, NULL ); + POINT p; + GetCursorPos( &p ); + const int dx = p.x - window_center_x; + const int dy = p.y - window_center_y; + if (dx != 0 || dy != 0) { + Sys_QueEvent( g_wv.sysMsgTime, SE_MOUSE, dx, dy, 0, NULL ); + SetCursorPos( window_center_x, window_center_y ); + } + switch (msg) { case WM_LBUTTONDOWN: case WM_LBUTTONUP: @@ -408,14 +402,6 @@ void IN_Frame() } IN_Activate( qtrue ); - - int mx, my; - mouse->Read( &mx, &my ); - - if ( !mx && !my ) - return; - - Sys_QueEvent( 0, SE_MOUSE, mx, my, 0, NULL ); } diff --git a/code/win32/win_local.h b/code/win32/win_local.h index d0b694d..03022c8 100644 --- a/code/win32/win_local.h +++ b/code/win32/win_local.h @@ -63,8 +63,8 @@ typedef struct qbool isMinimized; // when we get a windows message, we store the time off - // so keyboard processing can know the exact time of an event - unsigned sysMsgTime; + // using Sys_Milliseconds + int sysMsgTime; RECT monitorRects[MAX_MONITOR_COUNT]; HMONITOR hMonitors[MAX_MONITOR_COUNT]; diff --git a/code/win32/win_main.cpp b/code/win32/win_main.cpp index 9999c23..0294271 100644 --- a/code/win32/win_main.cpp +++ b/code/win32/win_main.cpp @@ -35,7 +35,7 @@ Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA #include -WinVars_t g_wv; +WinVars_t g_wv; static qbool win_timePeriodActive = qfalse; @@ -471,7 +471,8 @@ sysEvent_t Sys_GetEvent() } // save the msg time, because wndprocs don't have access to the timestamp - g_wv.sysMsgTime = msg.time; + // msg.time seems to use values from GetTickCount + g_wv.sysMsgTime = Sys_Milliseconds(); TranslateMessage( &msg ); DispatchMessage( &msg );