[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:
Quantum
2021-05-11 16:49:39 -04:00
committed by Geoffrey McRae
parent f9a9953071
commit e70cfd84fb
14 changed files with 140 additions and 15 deletions

View File

@@ -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)

View File

@@ -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);

View File

@@ -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 =