[client] egl: use a lock for desktop damage to eliminate all races

There used to be a possible race when a bunch of rectangle is appended, but
the total count is not updated before it's read. Using a lock eliminates
all such races.
This commit is contained in:
Quantum 2021-08-01 04:24:55 -04:00 committed by Geoffrey McRae
parent f08e2ece93
commit 23c77e8508

View File

@ -104,7 +104,8 @@ struct Inst
bool hadOverlay; bool hadOverlay;
struct DesktopDamage desktopDamage[DESKTOP_DAMAGE_COUNT]; struct DesktopDamage desktopDamage[DESKTOP_DAMAGE_COUNT];
atomic_uint desktopDamageIdx; unsigned int desktopDamageIdx;
LG_Lock desktopDamageLock;
RingBuffer importTimings; RingBuffer importTimings;
GraphHandle importGraph; GraphHandle importGraph;
@ -182,16 +183,6 @@ static void egl_setup(void)
option_register(egl_options); option_register(egl_options);
} }
inline static struct DesktopDamage * currentDesktopDamage(struct Inst * this)
{
return this->desktopDamage + atomic_load(&this->desktopDamageIdx) % DESKTOP_DAMAGE_COUNT;
}
inline static struct DesktopDamage * finishDesktopDamage(struct Inst * this)
{
return this->desktopDamage + atomic_fetch_add(&this->desktopDamageIdx, 1) % DESKTOP_DAMAGE_COUNT;
}
static bool egl_create(void ** opaque, const LG_RendererParams params, bool * needsOpenGL) static bool egl_create(void ** opaque, const LG_RendererParams params, bool * needsOpenGL)
{ {
// check if EGL is even available // check if EGL is even available
@ -221,7 +212,7 @@ static bool egl_create(void ** opaque, const LG_RendererParams params, bool * ne
this->screenScaleY = 1.0f; this->screenScaleY = 1.0f;
this->uiScale = 1.0; this->uiScale = 1.0;
atomic_init(&this->desktopDamageIdx, 0); LG_LOCK_INIT(this->desktopDamageLock);
this->desktopDamage[0].count = -1; this->desktopDamage[0].count = -1;
this->importTimings = ringbuffer_new(256, sizeof(float)); this->importTimings = ringbuffer_new(256, sizeof(float));
@ -254,6 +245,7 @@ static void egl_deinitialize(void * opaque)
egl_damage_free (&this->damage); egl_damage_free (&this->damage);
LG_LOCK_FREE(this->lock); LG_LOCK_FREE(this->lock);
LG_LOCK_FREE(this->desktopDamageLock);
eglMakeCurrent(this->display, EGL_NO_SURFACE, EGL_NO_SURFACE, EGL_NO_CONTEXT); eglMakeCurrent(this->display, EGL_NO_SURFACE, EGL_NO_SURFACE, EGL_NO_CONTEXT);
@ -432,7 +424,9 @@ static void egl_on_resize(void * opaque, const int width, const int height, cons
egl_calc_mouse_state(this); egl_calc_mouse_state(this);
currentDesktopDamage(this)->count = -1; INTERLOCKED_SECTION(this->desktopDamageLock, {
this->desktopDamage[this->desktopDamageIdx].count = -1;
});
// this is needed to refresh the font atlas texture // this is needed to refresh the font atlas texture
ImGui_ImplOpenGL3_Shutdown(); ImGui_ImplOpenGL3_Shutdown();
@ -518,14 +512,16 @@ static bool egl_on_frame(void * opaque, const FrameBuffer * frame, int dmaFd,
this->start = true; this->start = true;
struct DesktopDamage * damage = currentDesktopDamage(this); INTERLOCKED_SECTION(this->desktopDamageLock, {
if (damage->count == -1 || damage->count + damageRectsCount >= KVMFR_MAX_DAMAGE_RECTS) struct DesktopDamage * damage = this->desktopDamage + this->desktopDamageIdx;
damage->count = -1; if (damage->count == -1 || damage->count + damageRectsCount >= KVMFR_MAX_DAMAGE_RECTS)
else damage->count = -1;
{ else
memcpy(damage->rects + damage->count, damageRects, damageRectsCount * sizeof(FrameDamageRect)); {
damage->count += damageRectsCount; memcpy(damage->rects + damage->count, damageRects, damageRectsCount * sizeof(FrameDamageRect));
} damage->count += damageRectsCount;
}
});
return true; return true;
} }
@ -821,7 +817,12 @@ static bool egl_render(void * opaque, LG_RendererRotate rotate, const bool newFr
bool hasOverlay = false; bool hasOverlay = false;
struct CursorState cursorState = { .visible = false }; struct CursorState cursorState = { .visible = false };
struct DesktopDamage * desktopDamage = finishDesktopDamage(this); struct DesktopDamage * desktopDamage;
INTERLOCKED_SECTION(this->desktopDamageLock, {
desktopDamage = this->desktopDamage + this->desktopDamageIdx;
this->desktopDamageIdx = (this->desktopDamageIdx + 1) % DESKTOP_DAMAGE_COUNT;
});
if (this->start) if (this->start)
{ {