diff --git a/src/steamcompmgr.cpp b/src/steamcompmgr.cpp index c42a962..b0af81d 100644 --- a/src/steamcompmgr.cpp +++ b/src/steamcompmgr.cpp @@ -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(); diff --git a/src/vblankmanager.cpp b/src/vblankmanager.cpp index bdc7f19..066a233 100644 --- a/src/vblankmanager.cpp +++ b/src/vblankmanager.cpp @@ -5,8 +5,9 @@ #include #include -#include "X11/Xlib.h" -#include "assert.h" +#include +#include +#include #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 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 ) diff --git a/src/vblankmanager.hpp b/src/vblankmanager.hpp index cba96c0..9ad0a9f 100644 --- a/src/vblankmanager.hpp +++ b/src/vblankmanager.hpp @@ -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 );