[client] ds: refactor common EGL swap with damage logic

This commit creates a new utility library, eglutil.h, which contains code
to detect and use EGL_KHR_swap_buffers_with_damage or its EXT equivalent.

This logic used to be duplicated between the X11 and Wayland display servers,
which is not ideal.
This commit is contained in:
Quantum 2021-07-19 04:01:19 -04:00 committed by Geoffrey McRae
parent a8d4668c4d
commit 0cbc529640
6 changed files with 129 additions and 77 deletions

View File

@ -119,6 +119,7 @@ set(SOURCES
src/clipboard.c
src/kb.c
src/egl_dynprocs.c
src/eglutil.c
)
# Force cimgui to build as a static library.

View File

@ -32,6 +32,7 @@
#if defined(ENABLE_EGL) || defined(ENABLE_OPENGL)
#include "egl_dynprocs.h"
#include "eglutil.h"
bool waylandEGLInit(int w, int h)
{
@ -71,53 +72,19 @@ EGLDisplay waylandGetEGLDisplay(void)
void waylandEGLSwapBuffers(EGLDisplay display, EGLSurface surface, const struct Rect * damage, int count)
{
if (!wlWm.eglSwapWithDamageInit)
if (!wlWm.swapWithDamage.init)
{
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 (util_hasGLExt(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 (util_hasGLExt(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");
swapWithDamageDisable(&wlWm.swapWithDamage);
}
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;
swapWithDamageInit(&wlWm.swapWithDamage, display);
}
waylandPresentationFrame();
wlWm.eglSwapWithDamage(display, surface, wlWm.eglDamageRects, count);
}
else
{
waylandPresentationFrame();
eglSwapBuffers(display, surface);
}
swapWithDamage(&wlWm.swapWithDamage, display, surface, damage, count);
if (wlWm.needsResize)
{

View File

@ -27,6 +27,7 @@
# include <wayland-egl.h>
# include <EGL/egl.h>
# include <EGL/eglext.h>
# include "eglutil.h"
#endif
#include "app.h"
@ -101,10 +102,7 @@ struct WaylandDSState
#if defined(ENABLE_EGL) || defined(ENABLE_OPENGL)
struct wl_egl_window * eglWindow;
bool eglSwapWithDamageInit;
eglSwapBuffersWithDamageKHR_t eglSwapWithDamage;
EGLint * eglDamageRects;
int eglDamageRectCount;
struct SwapWithDamageData swapWithDamage;
#endif
#ifdef ENABLE_OPENGL

View File

@ -38,6 +38,7 @@
#ifdef ENABLE_EGL
#include <EGL/eglext.h>
#include "egl_dynprocs.h"
#include "eglutil.h"
#endif
#include "app.h"
@ -943,40 +944,11 @@ static EGLNativeWindowType x11GetEGLNativeWindow(void)
static void x11EGLSwapBuffers(EGLDisplay display, EGLSurface surface,
const struct Rect * damage, int count)
{
static bool detectDone = false;
static eglSwapBuffersWithDamageKHR_t swapWithDamage = NULL;
static struct SwapWithDamageData data = {0};
if (!data.init)
swapWithDamageInit(&data, display);
if (!detectDone)
{
const char *exts = eglQueryString(display, EGL_EXTENSIONS);
DEBUG_INFO("%s", exts);
if (util_hasGLExt(exts, "EGL_KHR_swap_buffers_with_damage"))
swapWithDamage = g_egl_dynProcs.eglSwapBuffersWithDamageKHR;
else if (util_hasGLExt(exts, "EGL_EXT_swap_buffers_with_damage"))
swapWithDamage = g_egl_dynProcs.eglSwapBuffersWithDamageEXT;
if (swapWithDamage)
DEBUG_INFO("Using eglSwapBuffersWithDamage");
detectDone = true;
}
if (swapWithDamage && count)
{
EGLint rects[count*4];
EGLint *p = rects;
for(int i = 0; i < count; ++i, p += 4)
{
p[0] = damage[i].x;
p[1] = damage[i].y;
p[2] = damage[i].w;
p[3] = damage[i].h;
}
swapWithDamage(display, surface, rects, count);
}
else
eglSwapBuffers(display, surface);
swapWithDamage(&data, display, surface, damage, count);
}
#endif

41
client/include/eglutil.h Normal file
View File

@ -0,0 +1,41 @@
/**
* Looking Glass
* Copyright (C) 2017-2021 The Looking Glass Authors
* https://looking-glass.io
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License as published by the Free
* Software Foundation; either version 2 of the License, or (at your option)
* any later version.
*
* This program is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
* more details.
*
* You should have received a copy of the GNU General Public License along
* with this program; if not, write to the Free Software Foundation, Inc., 59
* Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
#ifndef _H_LG_GLUTIL_
#define _H_LG_GLUTIL_
#include <stdbool.h>
#include <EGL/egl.h>
#include "common/types.h"
#include "egl_dynprocs.h"
struct SwapWithDamageData
{
bool init;
eglSwapBuffersWithDamageKHR_t func;
};
void swapWithDamageInit(struct SwapWithDamageData * data, EGLDisplay display);
void swapWithDamageDisable(struct SwapWithDamageData * data);
void swapWithDamage(struct SwapWithDamageData * data, EGLDisplay display, EGLSurface surface,
const struct Rect * damage, int count);
#endif

73
client/src/eglutil.c Normal file
View File

@ -0,0 +1,73 @@
/**
* Looking Glass
* Copyright (C) 2017-2021 The Looking Glass Authors
* https://looking-glass.io
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License as published by the Free
* Software Foundation; either version 2 of the License, or (at your option)
* any later version.
*
* This program is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
* more details.
*
* You should have received a copy of the GNU General Public License along
* with this program; if not, write to the Free Software Foundation, Inc., 59
* Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
#include "eglutil.h"
#include "common/debug.h"
#include "egl_dynprocs.h"
#include "util.h"
void swapWithDamageInit(struct SwapWithDamageData * data, EGLDisplay display)
{
const char *exts = eglQueryString(display, EGL_EXTENSIONS);
data->init = true;
if (util_hasGLExt(exts, "EGL_KHR_swap_buffers_with_damage") && g_egl_dynProcs.eglSwapBuffersWithDamageKHR)
{
data->func = g_egl_dynProcs.eglSwapBuffersWithDamageKHR;
DEBUG_INFO("Using EGL_KHR_swap_buffers_with_damage");
}
else if (util_hasGLExt(exts, "EGL_EXT_swap_buffers_with_damage") && g_egl_dynProcs.eglSwapBuffersWithDamageEXT)
{
data->func = g_egl_dynProcs.eglSwapBuffersWithDamageEXT;
DEBUG_INFO("Using EGL_EXT_swap_buffers_with_damage");
}
else
{
data->func = NULL;
DEBUG_INFO("Swapping buffers with damage: not supported");
}
}
void swapWithDamageDisable(struct SwapWithDamageData * data)
{
data->init = false;
data->func = NULL;
}
void swapWithDamage(struct SwapWithDamageData * data, EGLDisplay display, EGLSurface surface,
const struct Rect * damage, int count)
{
if (!data->func || !count)
{
eglSwapBuffers(display, surface);
return;
}
EGLint rects[count * 4];
for (int i = 0; i < count; ++i)
{
rects[i * 4 + 0] = damage[i].x;
rects[i * 4 + 1] = damage[i].y;
rects[i * 4 + 2] = damage[i].w;
rects[i * 4 + 3] = damage[i].h;
}
data->func(display, surface, rects, count);
}