mirror of
https://github.com/gnif/LookingGlass.git
synced 2025-08-06 10:44:01 +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:
@@ -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;
|
||||
}
|
||||
|
||||
|
||||
|
Reference in New Issue
Block a user