Stop using X11 events for vblankmanager
Instead, use a pipe. Check if the pipe is readable in the steamcompmgr event loop. This avoids a roundtrip through the X11 server. Closes: https://github.com/Plagman/gamescope/issues/201
This commit is contained in:
parent
d8dacddaea
commit
470756029d
3 changed files with 85 additions and 54 deletions
|
@ -3066,7 +3066,7 @@ spawn_client( char **argv )
|
|||
}
|
||||
|
||||
static void
|
||||
dispatch_x11( Display *dpy, MouseCursor *cursor, bool *vblank )
|
||||
dispatch_x11( Display *dpy, MouseCursor *cursor )
|
||||
{
|
||||
do {
|
||||
XEvent ev;
|
||||
|
@ -3153,26 +3153,6 @@ dispatch_x11( Display *dpy, MouseCursor *cursor, bool *vblank )
|
|||
break;
|
||||
case ClientMessage:
|
||||
handle_client_message(dpy, &ev.xclient);
|
||||
|
||||
if ( ev.xclient.data.l[0] == 24 && ev.xclient.data.l[1] == 8 )
|
||||
{
|
||||
// Decode the split up vblanktime... Sign-extend nonsense...
|
||||
uint64_t vblanktime = (uint64_t(uint32_t(ev.xclient.data.l[2])) << 32) |
|
||||
uint64_t(uint32_t(ev.xclient.data.l[3]));
|
||||
uint64_t vblankreceived = get_time_in_nanos();
|
||||
uint64_t diff = vblankreceived - vblanktime;
|
||||
|
||||
// give it 1 ms of slack.. maybe too long
|
||||
if ( diff > 1'000'000ul )
|
||||
{
|
||||
gpuvis_trace_printf( "ignored stale vblank" );
|
||||
}
|
||||
else
|
||||
{
|
||||
gpuvis_trace_printf( "got vblank" );
|
||||
*vblank = true;
|
||||
}
|
||||
}
|
||||
break;
|
||||
case LeaveNotify:
|
||||
if (ev.xcrossing.window == currentInputFocusWindow)
|
||||
|
@ -3203,9 +3183,49 @@ dispatch_x11( Display *dpy, MouseCursor *cursor, bool *vblank )
|
|||
}
|
||||
break;
|
||||
}
|
||||
} while (QLength (dpy));
|
||||
XFlush(dpy);
|
||||
} while (XPending (dpy));
|
||||
}
|
||||
|
||||
static bool
|
||||
dispatch_vblank( int fd )
|
||||
{
|
||||
bool vblank = false;
|
||||
for (;;)
|
||||
{
|
||||
uint64_t vblanktime = 0;
|
||||
ssize_t ret = read( fd, &vblanktime, sizeof( vblanktime ) );
|
||||
if ( ret < 0 )
|
||||
{
|
||||
if ( errno == EAGAIN )
|
||||
break;
|
||||
|
||||
perror( "steamcompmgr: dispatch_vblank: read failed" );
|
||||
break;
|
||||
}
|
||||
|
||||
uint64_t diff = get_time_in_nanos() - vblanktime;
|
||||
|
||||
// give it 1 ms of slack.. maybe too long
|
||||
if ( diff > 1'000'000ul )
|
||||
{
|
||||
gpuvis_trace_printf( "ignored stale vblank" );
|
||||
}
|
||||
else
|
||||
{
|
||||
gpuvis_trace_printf( "got vblank" );
|
||||
vblank = true;
|
||||
}
|
||||
}
|
||||
return vblank;
|
||||
}
|
||||
|
||||
enum event_type {
|
||||
EVENT_X11,
|
||||
EVENT_VBLANK,
|
||||
EVENT_COUNT // keep last
|
||||
};
|
||||
|
||||
void
|
||||
steamcompmgr_main (int argc, char **argv)
|
||||
{
|
||||
|
@ -3380,7 +3400,8 @@ steamcompmgr_main (int argc, char **argv)
|
|||
allDamage = None;
|
||||
clipChanged = True;
|
||||
|
||||
vblank_init();
|
||||
int vblankFD = vblank_init();
|
||||
assert( vblankFD >= 0 );
|
||||
|
||||
currentOutputWidth = g_nOutputWidth;
|
||||
currentOutputHeight = g_nOutputHeight;
|
||||
|
@ -3436,9 +3457,15 @@ steamcompmgr_main (int argc, char **argv)
|
|||
std::thread imageWaitThread( imageWaitThreadMain );
|
||||
imageWaitThread.detach();
|
||||
|
||||
struct pollfd x11_pollfd = {
|
||||
.fd = XConnectionNumber(dpy),
|
||||
.events = POLLIN,
|
||||
struct pollfd pollfds[] = {
|
||||
[ EVENT_X11 ] = {
|
||||
.fd = XConnectionNumber( dpy ),
|
||||
.events = POLLIN,
|
||||
},
|
||||
[ EVENT_VBLANK ] = {
|
||||
.fd = vblankFD,
|
||||
.events = POLLIN,
|
||||
},
|
||||
};
|
||||
|
||||
for (;;)
|
||||
|
@ -3446,7 +3473,7 @@ steamcompmgr_main (int argc, char **argv)
|
|||
focusDirty = False;
|
||||
bool vblank = false;
|
||||
|
||||
if ( poll( &x11_pollfd, 1, -1 ) < 0)
|
||||
if ( poll( pollfds, EVENT_COUNT, -1 ) < 0)
|
||||
{
|
||||
if ( errno == EAGAIN )
|
||||
continue;
|
||||
|
@ -3455,15 +3482,21 @@ steamcompmgr_main (int argc, char **argv)
|
|||
break;
|
||||
}
|
||||
|
||||
if ( x11_pollfd.revents & POLLHUP )
|
||||
if ( pollfds[ EVENT_X11 ].revents & POLLHUP )
|
||||
{
|
||||
fprintf( stderr, "Lost connection to the X11 server\n" );
|
||||
break;
|
||||
}
|
||||
|
||||
if ( x11_pollfd.revents & POLLIN )
|
||||
assert( !( pollfds[ EVENT_VBLANK ].revents & POLLHUP ) );
|
||||
|
||||
if ( pollfds[ EVENT_X11 ].revents & POLLIN )
|
||||
{
|
||||
dispatch_x11( dpy, cursor.get(), &vblank );
|
||||
dispatch_x11( dpy, cursor.get() );
|
||||
}
|
||||
if ( pollfds[ EVENT_VBLANK ].revents & POLLIN )
|
||||
{
|
||||
vblank = dispatch_vblank( vblankFD );
|
||||
}
|
||||
|
||||
if ( run == false )
|
||||
|
@ -3527,7 +3560,6 @@ steamcompmgr_main (int argc, char **argv)
|
|||
if (fadeOutWindow.id)
|
||||
{
|
||||
XSendEvent(dpy, ourWindow, True, SubstructureRedirectMask, &nudgeEvent);
|
||||
XFlush(dpy);
|
||||
}
|
||||
|
||||
cursor->updatePosition();
|
||||
|
|
|
@ -5,8 +5,9 @@
|
|||
#include <chrono>
|
||||
#include <atomic>
|
||||
|
||||
#include "X11/Xlib.h"
|
||||
#include "assert.h"
|
||||
#include <assert.h>
|
||||
#include <fcntl.h>
|
||||
#include <unistd.h>
|
||||
|
||||
#include "gpuvis_trace_utils.h"
|
||||
|
||||
|
@ -15,7 +16,7 @@
|
|||
#include "wlserver.hpp"
|
||||
#include "main.hpp"
|
||||
|
||||
static Display *g_nestedDpy;
|
||||
static int g_vblankPipe[2];
|
||||
|
||||
std::atomic<uint64_t> g_lastVblank;
|
||||
|
||||
|
@ -42,38 +43,36 @@ void vblankThreadRun( void )
|
|||
|
||||
// give the time of vblank to steamcompmgr
|
||||
uint64_t vblanktime = get_time_in_nanos();
|
||||
XEvent repaintMsg = {};
|
||||
repaintMsg.xclient.type = ClientMessage;
|
||||
repaintMsg.xclient.window = DefaultRootWindow( g_nestedDpy );
|
||||
repaintMsg.xclient.format = 32;
|
||||
repaintMsg.xclient.data.l[0] = 24;
|
||||
repaintMsg.xclient.data.l[1] = 8;
|
||||
// Although these are longs which are 64-bit, something funky goes on
|
||||
// that stops us from encoding more than 32-bits in each element.
|
||||
// This matches the format above which is "32".
|
||||
repaintMsg.xclient.data.l[2] = uint32_t(vblanktime >> 32);
|
||||
repaintMsg.xclient.data.l[3] = uint32_t(vblanktime & 0xFFFFFFFF);
|
||||
|
||||
// send a message to nudge it out of its event loop
|
||||
XSendEvent( g_nestedDpy , DefaultRootWindow( g_nestedDpy ), True, SubstructureRedirectMask, &repaintMsg);
|
||||
XFlush( g_nestedDpy );
|
||||
|
||||
gpuvis_trace_printf( "sent vblank" );
|
||||
ssize_t ret = write( g_vblankPipe[ 1 ], &vblanktime, sizeof( vblanktime ) );
|
||||
if ( ret <= 0 )
|
||||
{
|
||||
perror( "vblankmanager: write failed" );
|
||||
}
|
||||
else
|
||||
{
|
||||
gpuvis_trace_printf( "sent vblank" );
|
||||
}
|
||||
|
||||
// Get on the other side of it now
|
||||
sleep_for_nanos( g_uVblankDrawBufferNS + 1'000'000 );
|
||||
}
|
||||
}
|
||||
|
||||
void vblank_init( void )
|
||||
int vblank_init( void )
|
||||
{
|
||||
g_nestedDpy = XOpenDisplay( wlserver_get_nested_display_name() );
|
||||
assert( g_nestedDpy != nullptr );
|
||||
if ( pipe2( g_vblankPipe, O_CLOEXEC | O_NONBLOCK ) != 0 )
|
||||
{
|
||||
perror( "vblankmanager: pipe failed" );
|
||||
return -1;
|
||||
}
|
||||
|
||||
g_lastVblank = get_time_in_nanos();
|
||||
|
||||
std::thread vblankThread( vblankThreadRun );
|
||||
vblankThread.detach();
|
||||
|
||||
return g_vblankPipe[ 0 ];
|
||||
}
|
||||
|
||||
void vblank_mark_possible_vblank( void )
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
// Try to figure out when vblank is and notify steamcompmgr to render some time before it
|
||||
|
||||
void vblank_init( void );
|
||||
int vblank_init( void );
|
||||
|
||||
void vblank_mark_possible_vblank( void );
|
||||
|
|
Loading…
Reference in a new issue