[client] x11: make use of the x11 present extension for jitRender

This implementation is a bit dodgy and needs some work but is currently
functional. Consider this feature highly experiemental under X11.
This commit is contained in:
Geoffrey McRae 2021-08-02 14:46:21 +10:00
parent 037788f562
commit 891ee3e789
3 changed files with 122 additions and 10 deletions

View File

@ -9,6 +9,7 @@ pkg_check_modules(DISPLAYSERVER_X11 REQUIRED IMPORTED_TARGET
xscrnsaver xscrnsaver
xinerama xinerama
xcursor xcursor
xpresent
) )
add_library(displayserver_X11 STATIC add_library(displayserver_X11 STATIC

View File

@ -31,6 +31,7 @@
#include <X11/extensions/XInput2.h> #include <X11/extensions/XInput2.h>
#include <X11/extensions/scrnsaver.h> #include <X11/extensions/scrnsaver.h>
#include <X11/extensions/Xinerama.h> #include <X11/extensions/Xinerama.h>
#include <X11/extensions/Xpresent.h>
#include <X11/Xcursor/Xcursor.h> #include <X11/Xcursor/Xcursor.h>
#include <GL/glx.h> #include <GL/glx.h>
@ -45,6 +46,7 @@
#include "app.h" #include "app.h"
#include "common/debug.h" #include "common/debug.h"
#include "common/time.h" #include "common/time.h"
#include "common/event.h"
#include "util.h" #include "util.h"
#define _NET_WM_STATE_REMOVE 0 #define _NET_WM_STATE_REMOVE 0
@ -77,7 +79,32 @@ enum {
// forwards // forwards
static void x11SetFullscreen(bool fs); static void x11SetFullscreen(bool fs);
static int x11EventThread(void * unused); static int x11EventThread(void * unused);
static void x11GenericEvent(XGenericEventCookie *cookie); static void x11XInputEvent(XGenericEventCookie *cookie);
static void x11XPresentEvent(XGenericEventCookie *cookie);
static void x11DoPresent(void)
{
XPresentPixmap(
x11.display,
x11.window,
x11.presentPixmap,
x11.presentSerial++,
0, // valid
0, // update
-1, // x_off,
-1, // y_off,
0, // target_crtc
None, // wait_fence
None, // idle_fence
0, // options
0, // target_msc,
0, // divisor,
0, // remainder,
NULL, // notifies
0 // nnotifies
);
XFlush(x11.display);
}
static void x11Setup(void) static void x11Setup(void)
{ {
@ -487,15 +514,24 @@ static bool x11Init(const LG_DSInitParams params)
/* default to the square cursor */ /* default to the square cursor */
XDefineCursor(x11.display, x11.window, x11.cursors[LG_POINTER_SQUARE]); XDefineCursor(x11.display, x11.window, x11.cursors[LG_POINTER_SQUARE]);
x11.frameEvent = lgCreateEvent(true, 0);
x11.presentAvg = runningavg_new(1000);
XPresentQueryExtension(x11.display, &x11.xpresentOp, &event, &error);
x11.presentPixmap = XCreatePixmap(x11.display, x11.window, 1, 1, 24);
XPresentSelectInput(x11.display, x11.window,
PresentCompleteNotifyMask | PresentIdleNotifyMask);
XMapWindow(x11.display, x11.window); XMapWindow(x11.display, x11.window);
XFlush(x11.display); XFlush(x11.display);
if (!lgCreateThread("X11EventThread", x11EventThread, NULL, &x11.eventThread)) if (!lgCreateThread("X11EventThread", x11EventThread, NULL, &x11.eventThread))
{ {
DEBUG_ERROR("Failed to create the x11 event thread"); DEBUG_ERROR("Failed to create the x11 event thread");
return false; goto fail_window;
} }
x11DoPresent();
return true; return true;
fail_window: fail_window:
@ -513,11 +549,13 @@ static void x11Startup(void)
static void x11Shutdown(void) static void x11Shutdown(void)
{ {
lgSignalEvent(x11.frameEvent);
} }
static void x11Free(void) static void x11Free(void)
{ {
lgJoinThread(x11.eventThread, NULL); lgJoinThread(x11.eventThread, NULL);
lgFreeEvent(x11.frameEvent);
if (x11.window) if (x11.window)
XDestroyWindow(x11.display, x11.window); XDestroyWindow(x11.display, x11.window);
@ -667,9 +705,18 @@ static int x11EventThread(void * unused)
case GenericEvent: case GenericEvent:
{ {
XGenericEventCookie *cookie = (XGenericEventCookie*)&xe.xcookie; XGenericEventCookie *cookie = (XGenericEventCookie*)&xe.xcookie;
XGetEventData(x11.display, cookie); if (cookie->extension == x11.xinputOp)
x11GenericEvent(cookie); {
XFreeEventData(x11.display, cookie); XGetEventData(x11.display, cookie);
x11XInputEvent(cookie);
XFreeEventData(x11.display, cookie);
}
else if (cookie->extension == x11.xpresentOp)
{
XGetEventData(x11.display, cookie);
x11XPresentEvent(cookie);
XFreeEventData(x11.display, cookie);
}
break; break;
} }
@ -737,13 +784,10 @@ static int x11EventThread(void * unused)
return 0; return 0;
} }
static void x11GenericEvent(XGenericEventCookie *cookie) static void x11XInputEvent(XGenericEventCookie *cookie)
{ {
static int button_state = 0; static int button_state = 0;
if (cookie->extension != x11.xinputOp)
return;
switch(cookie->evtype) switch(cookie->evtype)
{ {
case XI_FocusIn: case XI_FocusIn:
@ -983,6 +1027,51 @@ static void x11GenericEvent(XGenericEventCookie *cookie)
} }
} }
#include <math.h>
static void x11XPresentEvent(XGenericEventCookie *cookie)
{
switch(cookie->evtype)
{
case PresentCompleteNotify:
{
lgSignalEvent(x11.frameEvent);
x11DoPresent();
#if 0
static uint64_t last = 0;
static uint64_t predict = 0;
XPresentCompleteNotifyEvent * ev =
(XPresentCompleteNotifyEvent *)cookie->data;
const int64_t err = (int64_t)predict - ev->ust;
if (last)
{
const uint64_t delta = ev->ust - last;
runningavg_push(x11.presentAvg, delta);
}
DEBUG_WARN("predict err %f", err / 1000.0f);
predict = (ev->ust + round(runningavg_calc(x11.presentAvg)));
last = ev->ust;
XFlush(x11.display);
#endif
break;
}
case PresentIdleNotify:
{
XPresentIdleNotifyEvent * ev =
(XPresentIdleNotifyEvent *)cookie->data;
(void)ev;
break;
}
}
}
#ifdef ENABLE_EGL #ifdef ENABLE_EGL
static EGLDisplay x11GetEGLDisplay(void) static EGLDisplay x11GetEGLDisplay(void)
{ {
@ -1056,6 +1145,16 @@ static void x11GLSwapBuffers(void)
} }
#endif #endif
static void x11WaitFrame(void)
{
lgWaitEvent(x11.frameEvent, TIMEOUT_INFINITE);
}
static void x11StopWaitFrame(void)
{
lgSignalEvent(x11.frameEvent);
}
static void x11GuestPointerUpdated(double x, double y, double localX, double localY) static void x11GuestPointerUpdated(double x, double y, double localX, double localY)
{ {
if (app_isCaptureMode() || !x11.entered) if (app_isCaptureMode() || !x11.entered)
@ -1332,6 +1431,8 @@ struct LG_DisplayServerOps LGDS_X11 =
.glSetSwapInterval = x11GLSetSwapInterval, .glSetSwapInterval = x11GLSetSwapInterval,
.glSwapBuffers = x11GLSwapBuffers, .glSwapBuffers = x11GLSwapBuffers,
#endif #endif
.waitFrame = x11WaitFrame,
.stopWaitFrame = x11StopWaitFrame,
.guestPointerUpdated = x11GuestPointerUpdated, .guestPointerUpdated = x11GuestPointerUpdated,
.setPointer = x11SetPointer, .setPointer = x11SetPointer,
.grabPointer = x11GrabPointer, .grabPointer = x11GrabPointer,

View File

@ -21,20 +21,30 @@
#ifndef _H_X11DS_X11_ #ifndef _H_X11DS_X11_
#define _H_X11DS_X11_ #define _H_X11DS_X11_
#include <stdatomic.h>
#include <X11/Xlib.h> #include <X11/Xlib.h>
#include <X11/Xatom.h> #include <X11/Xatom.h>
#include <X11/Xutil.h> #include <X11/Xutil.h>
#include <GL/glx.h>
#include "interface/displayserver.h" #include "interface/displayserver.h"
#include "common/thread.h" #include "common/thread.h"
#include "common/types.h" #include "common/types.h"
#include "common/runningavg.h"
struct X11DSState struct X11DSState
{ {
Display * display; Display * display;
Window window; Window window;
XVisualInfo * visual; XVisualInfo * visual;
int xinputOp; int xinputOp, xpresentOp;
uint32_t presentSerial;
Pixmap presentPixmap;
RunningAvg presentAvg;
LGEvent * frameEvent;
LGThread * eventThread; LGThread * eventThread;