mirror of
https://github.com/gnif/LookingGlass.git
synced 2024-11-10 00:28:20 +00:00
[client] egl: use eglSwapBuffersWithDamageKHR for cursor-only updates
Instead of damaging the entire surface when rendering a cursor move, we can use the EGL_KHR_swap_buffers_with_damage extension to only damage the part of the window covered by the cursor. This should reduce the cursor movement latency on Wayland.
This commit is contained in:
parent
f9a9953071
commit
e70cfd84fb
@ -254,7 +254,7 @@ static EGLNativeWindowType sdlGetEGLNativeWindow(void)
|
||||
}
|
||||
}
|
||||
|
||||
static void sdlEGLSwapBuffers(EGLDisplay display, EGLSurface surface)
|
||||
static void sdlEGLSwapBuffers(EGLDisplay display, EGLSurface surface, const struct Rect * damage, int count)
|
||||
{
|
||||
eglSwapBuffers(display, surface);
|
||||
}
|
||||
|
@ -41,6 +41,7 @@ bool waylandEGLInit(int w, int h)
|
||||
DEBUG_ERROR("Failed to create EGL window");
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
@ -68,9 +69,51 @@ EGLDisplay waylandGetEGLDisplay(void)
|
||||
return eglGetDisplay(native);
|
||||
}
|
||||
|
||||
void waylandEGLSwapBuffers(EGLDisplay display, EGLSurface surface)
|
||||
void waylandEGLSwapBuffers(EGLDisplay display, EGLSurface surface, const struct Rect * damage, int count)
|
||||
{
|
||||
eglSwapBuffers(display, surface);
|
||||
if (!wlWm.eglSwapWithDamageInit)
|
||||
{
|
||||
const char *exts = eglQueryString(display, EGL_EXTENSIONS);
|
||||
wlWm.eglSwapWithDamageInit = true;
|
||||
if (wl_proxy_get_version((struct wl_proxy *) wlWm.surface) < 4)
|
||||
DEBUG_INFO("Swapping buffers with damage: not supported, need wl_compositor v4");
|
||||
else if (strstr(exts, "EGL_KHR_swap_buffers_with_damage") && g_egl_dynProcs.eglSwapBuffersWithDamageKHR)
|
||||
{
|
||||
wlWm.eglSwapWithDamage = g_egl_dynProcs.eglSwapBuffersWithDamageKHR;
|
||||
DEBUG_INFO("Using EGL_KHR_swap_buffers_with_damage");
|
||||
}
|
||||
else if (strstr(exts, "EGL_EXT_swap_buffers_with_damage") && g_egl_dynProcs.eglSwapBuffersWithDamageEXT)
|
||||
{
|
||||
wlWm.eglSwapWithDamage = g_egl_dynProcs.eglSwapBuffersWithDamageEXT;
|
||||
DEBUG_INFO("Using EGL_EXT_swap_buffers_with_damage");
|
||||
}
|
||||
else
|
||||
DEBUG_INFO("Swapping buffers with damage: not supported");
|
||||
}
|
||||
|
||||
if (wlWm.eglSwapWithDamage && count)
|
||||
{
|
||||
if (count * 4 > wlWm.eglDamageRectCount)
|
||||
{
|
||||
free(wlWm.eglDamageRects);
|
||||
wlWm.eglDamageRects = malloc(sizeof(EGLint) * count * 4);
|
||||
if (!wlWm.eglDamageRects)
|
||||
DEBUG_FATAL("Out of memory");
|
||||
wlWm.eglDamageRectCount = count * 4;
|
||||
}
|
||||
|
||||
for (int i = 0; i < count; ++i)
|
||||
{
|
||||
wlWm.eglDamageRects[i*4+0] = damage[i].x;
|
||||
wlWm.eglDamageRects[i*4+1] = damage[i].y;
|
||||
wlWm.eglDamageRects[i*4+2] = damage[i].w;
|
||||
wlWm.eglDamageRects[i*4+3] = damage[i].h;
|
||||
}
|
||||
|
||||
wlWm.eglSwapWithDamage(display, surface, wlWm.eglDamageRects, count);
|
||||
}
|
||||
else
|
||||
eglSwapBuffers(display, surface);
|
||||
|
||||
if (wlWm.needsResize)
|
||||
{
|
||||
@ -169,6 +212,6 @@ void waylandGLSetSwapInterval(int interval)
|
||||
|
||||
void waylandGLSwapBuffers(void)
|
||||
{
|
||||
waylandEGLSwapBuffers(wlWm.glDisplay, wlWm.glSurface);
|
||||
waylandEGLSwapBuffers(wlWm.glDisplay, wlWm.glSurface, NULL, 0);
|
||||
}
|
||||
#endif
|
||||
|
@ -37,7 +37,9 @@ static void registryGlobalHandler(void * data, struct wl_registry * registry,
|
||||
else if (!strcmp(interface, wl_shm_interface.name))
|
||||
wlWm.shm = wl_registry_bind(wlWm.registry, name, &wl_shm_interface, 1);
|
||||
else if (!strcmp(interface, wl_compositor_interface.name) && version >= 3)
|
||||
wlWm.compositor = wl_registry_bind(wlWm.registry, name, &wl_compositor_interface, 3);
|
||||
wlWm.compositor = wl_registry_bind(wlWm.registry, name,
|
||||
// we only need v3 to run, but v4 can use eglSwapBuffersWithDamageKHR
|
||||
&wl_compositor_interface, version > 4 ? 4 : version);
|
||||
#ifndef ENABLE_LIBDECOR
|
||||
else if (!strcmp(interface, xdg_wm_base_interface.name))
|
||||
wlWm.xdgWmBase = wl_registry_bind(wlWm.registry, name, &xdg_wm_base_interface, 1);
|
||||
|
@ -29,6 +29,7 @@ Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
# include <EGL/eglext.h>
|
||||
#endif
|
||||
|
||||
#include "egl_dynprocs.h"
|
||||
#include "common/locking.h"
|
||||
#include "common/countedbuffer.h"
|
||||
#include "interface/displayserver.h"
|
||||
@ -66,6 +67,13 @@ struct SurfaceOutput
|
||||
struct wl_list link;
|
||||
};
|
||||
|
||||
enum EGLSwapWithDamageState {
|
||||
SWAP_WITH_DAMAGE_UNKNOWN,
|
||||
SWAP_WITH_DAMAGE_UNSUPPORTED,
|
||||
SWAP_WITH_DAMAGE_KHR,
|
||||
SWAP_WITH_DAMAGE_EXT,
|
||||
};
|
||||
|
||||
struct WaylandDSState
|
||||
{
|
||||
bool pointerGrabbed;
|
||||
@ -88,8 +96,12 @@ struct WaylandDSState
|
||||
bool warpSupport;
|
||||
double cursorX, cursorY;
|
||||
|
||||
#ifdef ENABLE_EGL
|
||||
#if defined(ENABLE_EGL) || defined(ENABLE_OPENGL)
|
||||
struct wl_egl_window * eglWindow;
|
||||
bool eglSwapWithDamageInit;
|
||||
eglSwapBuffersWithDamageKHR_t eglSwapWithDamage;
|
||||
EGLint * eglDamageRects;
|
||||
int eglDamageRectCount;
|
||||
#endif
|
||||
|
||||
#ifdef ENABLE_OPENGL
|
||||
@ -197,7 +209,7 @@ void waylandShowPointer(bool show);
|
||||
#if defined(ENABLE_EGL) || defined(ENABLE_OPENGL)
|
||||
bool waylandEGLInit(int w, int h);
|
||||
EGLDisplay waylandGetEGLDisplay(void);
|
||||
void waylandEGLSwapBuffers(EGLDisplay display, EGLSurface surface);
|
||||
void waylandEGLSwapBuffers(EGLDisplay display, EGLSurface surface, const struct Rect * damage, int count);
|
||||
#endif
|
||||
|
||||
#ifdef ENABLE_EGL
|
||||
|
@ -114,5 +114,3 @@ bool waylandIsValidPointerPos(int x, int y)
|
||||
{
|
||||
return x >= 0 && x < wlWm.width && y >= 0 && y < wlWm.height;
|
||||
}
|
||||
|
||||
|
||||
|
@ -930,7 +930,7 @@ static EGLNativeWindowType x11GetEGLNativeWindow(void)
|
||||
return (EGLNativeWindowType)x11.window;
|
||||
}
|
||||
|
||||
static void x11EGLSwapBuffers(EGLDisplay display, EGLSurface surface)
|
||||
static void x11EGLSwapBuffers(EGLDisplay display, EGLSurface surface, const struct Rect * damage, int count)
|
||||
{
|
||||
eglSwapBuffers(display, surface);
|
||||
}
|
||||
|
@ -66,7 +66,7 @@ bool app_getProp(LG_DSProperty prop, void * ret);
|
||||
#ifdef ENABLE_EGL
|
||||
EGLDisplay app_getEGLDisplay(void);
|
||||
EGLNativeWindowType app_getEGLNativeWindow(void);
|
||||
void app_eglSwapBuffers(EGLDisplay display, EGLSurface surface);
|
||||
void app_eglSwapBuffers(EGLDisplay display, EGLSurface surface, const struct Rect * damage, int count);
|
||||
#endif
|
||||
|
||||
#ifdef ENABLE_OPENGL
|
||||
|
@ -17,6 +17,8 @@ this program; if not, write to the Free Software Foundation, Inc., 59 Temple
|
||||
Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
*/
|
||||
|
||||
#ifndef _H_LG_EGL_DYNPROCS_
|
||||
#define _H_LG_EGL_DYNPROCS_
|
||||
#ifdef ENABLE_EGL
|
||||
|
||||
#include <EGL/egl.h>
|
||||
@ -24,6 +26,8 @@ Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
|
||||
typedef EGLDisplay (*eglGetPlatformDisplayEXT_t)(EGLenum platform,
|
||||
void *native_display, const EGLint *attrib_list);
|
||||
typedef void (*eglSwapBuffersWithDamageKHR_t)(EGLDisplay dpy,
|
||||
EGLSurface surface, const EGLint *rects, EGLint n_rects);
|
||||
typedef void (*glEGLImageTargetTexture2DOES_t)(GLenum target,
|
||||
GLeglImageOES image);
|
||||
|
||||
@ -31,6 +35,8 @@ struct EGLDynProcs
|
||||
{
|
||||
eglGetPlatformDisplayEXT_t eglGetPlatformDisplay;
|
||||
eglGetPlatformDisplayEXT_t eglGetPlatformDisplayEXT;
|
||||
eglSwapBuffersWithDamageKHR_t eglSwapBuffersWithDamageKHR;
|
||||
eglSwapBuffersWithDamageKHR_t eglSwapBuffersWithDamageEXT;
|
||||
glEGLImageTargetTexture2DOES_t glEGLImageTargetTexture2DOES;
|
||||
};
|
||||
|
||||
@ -41,3 +47,5 @@ void egl_dynProcsInit(void);
|
||||
#else
|
||||
#define egl_dynProcsInit(...)
|
||||
#endif
|
||||
|
||||
#endif // _H_LG_EGL_DYNPROCS_
|
||||
|
@ -22,6 +22,7 @@ Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
|
||||
#include <stdbool.h>
|
||||
#include <EGL/egl.h>
|
||||
#include "common/types.h"
|
||||
|
||||
typedef enum LG_ClipboardData
|
||||
{
|
||||
@ -115,7 +116,7 @@ struct LG_DisplayServerOps
|
||||
/* EGL support */
|
||||
EGLDisplay (*getEGLDisplay)(void);
|
||||
EGLNativeWindowType (*getEGLNativeWindow)(void);
|
||||
void (*eglSwapBuffers)(EGLDisplay display, EGLSurface surface);
|
||||
void (*eglSwapBuffers)(EGLDisplay display, EGLSurface surface, const struct Rect * damage, int count);
|
||||
#endif
|
||||
|
||||
#ifdef ENABLE_OPENGL
|
||||
|
@ -215,6 +215,16 @@ void egl_cursor_set_state(EGL_Cursor * cursor, const bool visible, const float x
|
||||
cursor->y = y;
|
||||
}
|
||||
|
||||
struct CursorState egl_cursor_get_state(EGL_Cursor * cursor, int width, int height) {
|
||||
return (struct CursorState) {
|
||||
.visible = cursor->visible,
|
||||
.rect.x = (cursor->x * width + width) / 2,
|
||||
.rect.y = (-cursor->y * height + height) / 2 - cursor->h * height,
|
||||
.rect.w = cursor->w * width + 2,
|
||||
.rect.h = cursor->h * height + 2,
|
||||
};
|
||||
}
|
||||
|
||||
void egl_cursor_render(EGL_Cursor * cursor, LG_RendererRotate rotate)
|
||||
{
|
||||
if (!cursor->visible)
|
||||
|
@ -25,6 +25,11 @@ Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
|
||||
typedef struct EGL_Cursor EGL_Cursor;
|
||||
|
||||
struct CursorState {
|
||||
bool visible;
|
||||
struct Rect rect;
|
||||
};
|
||||
|
||||
bool egl_cursor_init(EGL_Cursor ** cursor);
|
||||
void egl_cursor_free(EGL_Cursor ** cursor);
|
||||
|
||||
@ -41,4 +46,6 @@ void egl_cursor_set_size(EGL_Cursor * cursor, const float x, const float y);
|
||||
void egl_cursor_set_state(EGL_Cursor * cursor, const bool visible,
|
||||
const float x, const float y);
|
||||
|
||||
struct CursorState egl_cursor_get_state(EGL_Cursor * cursor, int width, int height);
|
||||
|
||||
void egl_cursor_render(EGL_Cursor * cursor, LG_RendererRotate rotate);
|
||||
|
@ -106,6 +106,9 @@ struct Inst
|
||||
unsigned fontSize;
|
||||
LG_FontObj helpFontObj;
|
||||
unsigned helpFontSize;
|
||||
|
||||
bool cursorLastValid;
|
||||
struct CursorState cursorLast;
|
||||
};
|
||||
|
||||
static struct Option egl_options[] =
|
||||
@ -472,6 +475,8 @@ void egl_on_resize(void * opaque, const int width, const int height, const doubl
|
||||
egl_calc_mouse_state(this);
|
||||
egl_update_font(this);
|
||||
egl_update_help_font(this);
|
||||
|
||||
this->cursorLastValid = false;
|
||||
}
|
||||
|
||||
bool egl_on_mouse_shape(void * opaque, const LG_RendererCursor cursor,
|
||||
@ -545,6 +550,7 @@ bool egl_on_frame(void * opaque, const FrameBuffer * frame, int dmaFd)
|
||||
}
|
||||
|
||||
this->start = true;
|
||||
this->cursorLastValid = false;
|
||||
return true;
|
||||
}
|
||||
|
||||
@ -581,12 +587,14 @@ void egl_on_alert(void * opaque, const LG_MsgAlert alert, const char * message,
|
||||
}
|
||||
|
||||
this->showAlert = true;
|
||||
this->cursorLastValid = false;
|
||||
}
|
||||
|
||||
void egl_on_help(void * opaque, const char * message)
|
||||
{
|
||||
struct Inst * this = (struct Inst *)opaque;
|
||||
egl_help_set_text(this->help, message);
|
||||
this->cursorLastValid = false;
|
||||
}
|
||||
|
||||
void egl_on_show_fps(void * opaque, bool showFPS)
|
||||
@ -767,6 +775,10 @@ bool egl_render(void * opaque, LG_RendererRotate rotate)
|
||||
glClearColor(0.0f, 0.0f, 0.0f, 1.0f);
|
||||
glClear(GL_COLOR_BUFFER_BIT);
|
||||
|
||||
bool hasLastCursor = this->cursorLastValid;
|
||||
bool cursorRendered = false;
|
||||
struct CursorState cursorState;
|
||||
|
||||
if (this->start && egl_desktop_render(this->desktop,
|
||||
this->translateX, this->translateY,
|
||||
this->scaleX , this->scaleY ,
|
||||
@ -780,6 +792,8 @@ bool egl_render(void * opaque, LG_RendererRotate rotate)
|
||||
this->waitDone = true;
|
||||
}
|
||||
|
||||
cursorRendered = true;
|
||||
cursorState = egl_cursor_get_state(this->cursor, this->width, this->height);
|
||||
egl_cursor_render(this->cursor,
|
||||
(this->format.rotate + rotate) % LG_ROTATE_MAX);
|
||||
}
|
||||
@ -819,14 +833,39 @@ bool egl_render(void * opaque, LG_RendererRotate rotate)
|
||||
close = true;
|
||||
|
||||
if (close)
|
||||
{
|
||||
this->showAlert = false;
|
||||
this->cursorLastValid = false;
|
||||
}
|
||||
else
|
||||
egl_alert_render(this->alert, this->screenScaleX, this->screenScaleY);
|
||||
}
|
||||
|
||||
struct Rect damage[2];
|
||||
int damageIdx = 0;
|
||||
|
||||
if (this->waitDone)
|
||||
{
|
||||
if (cursorRendered && hasLastCursor)
|
||||
{
|
||||
if (this->cursorLast.visible)
|
||||
damage[damageIdx++] = this->cursorLast.rect;
|
||||
|
||||
if (cursorState.visible)
|
||||
damage[damageIdx++] = cursorState.rect;
|
||||
|
||||
this->cursorLast = cursorState;
|
||||
}
|
||||
else if (cursorRendered)
|
||||
{
|
||||
this->cursorLast = cursorState;
|
||||
this->cursorLastValid = true;
|
||||
}
|
||||
}
|
||||
|
||||
egl_fps_render(this->fps, this->screenScaleX, this->screenScaleY);
|
||||
egl_help_render(this->help, this->screenScaleX, this->screenScaleY);
|
||||
app_eglSwapBuffers(this->display, this->surface);
|
||||
app_eglSwapBuffers(this->display, this->surface, damage, damageIdx);
|
||||
return true;
|
||||
}
|
||||
|
||||
@ -834,6 +873,7 @@ void egl_update_fps(void * opaque, const float avgUPS, const float avgFPS)
|
||||
{
|
||||
struct Inst * this = (struct Inst *)opaque;
|
||||
egl_fps_update(this->fps, avgUPS, avgFPS);
|
||||
this->cursorLastValid = false;
|
||||
}
|
||||
|
||||
struct LG_Renderer LGR_EGL =
|
||||
|
@ -448,9 +448,9 @@ EGLNativeWindowType app_getEGLNativeWindow(void)
|
||||
return g_state.ds->getEGLNativeWindow();
|
||||
}
|
||||
|
||||
void app_eglSwapBuffers(EGLDisplay display, EGLSurface surface)
|
||||
void app_eglSwapBuffers(EGLDisplay display, EGLSurface surface, const struct Rect * damage, int count)
|
||||
{
|
||||
g_state.ds->eglSwapBuffers(display, surface);
|
||||
g_state.ds->eglSwapBuffers(display, surface, damage, count);
|
||||
}
|
||||
#endif
|
||||
|
||||
|
@ -31,6 +31,10 @@ void egl_dynProcsInit(void)
|
||||
eglGetProcAddress("eglGetPlatformDisplayEXT");
|
||||
g_egl_dynProcs.glEGLImageTargetTexture2DOES = (glEGLImageTargetTexture2DOES_t)
|
||||
eglGetProcAddress("glEGLImageTargetTexture2DOES");
|
||||
g_egl_dynProcs.eglSwapBuffersWithDamageKHR = (eglSwapBuffersWithDamageKHR_t)
|
||||
eglGetProcAddress("eglSwapBuffersWithDamageKHR");
|
||||
g_egl_dynProcs.eglSwapBuffersWithDamageEXT = (eglSwapBuffersWithDamageKHR_t)
|
||||
eglGetProcAddress("eglSwapBuffersWithDamageEXT");
|
||||
};
|
||||
|
||||
#endif
|
||||
|
Loading…
Reference in New Issue
Block a user