[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
xinerama
xcursor
xpresent
)
add_library(displayserver_X11 STATIC

View File

@ -31,6 +31,7 @@
#include <X11/extensions/XInput2.h>
#include <X11/extensions/scrnsaver.h>
#include <X11/extensions/Xinerama.h>
#include <X11/extensions/Xpresent.h>
#include <X11/Xcursor/Xcursor.h>
#include <GL/glx.h>
@ -45,6 +46,7 @@
#include "app.h"
#include "common/debug.h"
#include "common/time.h"
#include "common/event.h"
#include "util.h"
#define _NET_WM_STATE_REMOVE 0
@ -77,7 +79,32 @@ enum {
// forwards
static void x11SetFullscreen(bool fs);
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)
{
@ -487,15 +514,24 @@ static bool x11Init(const LG_DSInitParams params)
/* default to the square cursor */
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);
XFlush(x11.display);
if (!lgCreateThread("X11EventThread", x11EventThread, NULL, &x11.eventThread))
{
DEBUG_ERROR("Failed to create the x11 event thread");
return false;
goto fail_window;
}
x11DoPresent();
return true;
fail_window:
@ -513,11 +549,13 @@ static void x11Startup(void)
static void x11Shutdown(void)
{
lgSignalEvent(x11.frameEvent);
}
static void x11Free(void)
{
lgJoinThread(x11.eventThread, NULL);
lgFreeEvent(x11.frameEvent);
if (x11.window)
XDestroyWindow(x11.display, x11.window);
@ -667,9 +705,18 @@ static int x11EventThread(void * unused)
case GenericEvent:
{
XGenericEventCookie *cookie = (XGenericEventCookie*)&xe.xcookie;
XGetEventData(x11.display, cookie);
x11GenericEvent(cookie);
XFreeEventData(x11.display, cookie);
if (cookie->extension == x11.xinputOp)
{
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;
}
@ -737,13 +784,10 @@ static int x11EventThread(void * unused)
return 0;
}
static void x11GenericEvent(XGenericEventCookie *cookie)
static void x11XInputEvent(XGenericEventCookie *cookie)
{
static int button_state = 0;
if (cookie->extension != x11.xinputOp)
return;
switch(cookie->evtype)
{
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
static EGLDisplay x11GetEGLDisplay(void)
{
@ -1056,6 +1145,16 @@ static void x11GLSwapBuffers(void)
}
#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)
{
if (app_isCaptureMode() || !x11.entered)
@ -1332,6 +1431,8 @@ struct LG_DisplayServerOps LGDS_X11 =
.glSetSwapInterval = x11GLSetSwapInterval,
.glSwapBuffers = x11GLSwapBuffers,
#endif
.waitFrame = x11WaitFrame,
.stopWaitFrame = x11StopWaitFrame,
.guestPointerUpdated = x11GuestPointerUpdated,
.setPointer = x11SetPointer,
.grabPointer = x11GrabPointer,

View File

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