mirror of
https://github.com/gnif/LookingGlass.git
synced 2026-08-09 08:41:31 +00:00
[client] scheduler: qualify presentation feedback
Track cadence, interruption, and calibration wake reasons independently across X11 and Wayland. Feed phase correction back only when a pure cadence wake renders the exact frame that was queued at that wake. Propagate EGL swap results through the display-server boundary. Reject failed presentations and keep pending Wayland HDR descriptions inactive until the preceding surface commit succeeds.
This commit is contained in:
@@ -228,8 +228,11 @@ static const struct wp_image_description_v1_listener hdrImageDescListener =
|
|||||||
.ready2 = hdrImageDescReadyV2,
|
.ready2 = hdrImageDescReadyV2,
|
||||||
};
|
};
|
||||||
|
|
||||||
void waylandEGLSwapBuffers(EGLDisplay display, EGLSurface surface, const struct Rect * damage, int count)
|
bool waylandEGLSwapBuffers(EGLDisplay display, EGLSurface surface,
|
||||||
|
const struct Rect * damage, int count)
|
||||||
{
|
{
|
||||||
|
bool result = false;
|
||||||
|
|
||||||
// EGL presentation sends a batch of Wayland requests ending in a surface
|
// EGL presentation sends a batch of Wayland requests ending in a surface
|
||||||
// commit. A concurrent commit would apply a partial batch and, when explicit
|
// commit. A concurrent commit would apply a partial batch and, when explicit
|
||||||
// sync is active, omit one of the required acquire/release timeline points.
|
// sync is active, omit one of the required acquire/release timeline points.
|
||||||
@@ -248,8 +251,10 @@ void waylandEGLSwapBuffers(EGLDisplay display, EGLSurface surface, const struct
|
|||||||
|
|
||||||
waylandPresentationFrame();
|
waylandPresentationFrame();
|
||||||
applyHDRPending();
|
applyHDRPending();
|
||||||
swapWithDamage(&wlWm.swapWithDamage, display, surface, damage, count);
|
result = swapWithDamage(
|
||||||
activateReadyHDRImageDesc();
|
&wlWm.swapWithDamage, display, surface, damage, count);
|
||||||
|
if (result)
|
||||||
|
activateReadyHDRImageDesc();
|
||||||
});
|
});
|
||||||
|
|
||||||
if (wlWm.needsResize)
|
if (wlWm.needsResize)
|
||||||
@@ -305,6 +310,7 @@ void waylandEGLSwapBuffers(EGLDisplay display, EGLSurface surface, const struct
|
|||||||
}
|
}
|
||||||
|
|
||||||
wlWm.desktop->shellAckConfigureIfNeeded();
|
wlWm.desktop->shellAckConfigureIfNeeded();
|
||||||
|
return result;
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
@@ -750,6 +756,6 @@ void waylandGLSetSwapInterval(int interval)
|
|||||||
|
|
||||||
void waylandGLSwapBuffers(void)
|
void waylandGLSwapBuffers(void)
|
||||||
{
|
{
|
||||||
waylandEGLSwapBuffers(wlWm.glDisplay, wlWm.glSurface, NULL, 0);
|
(void)waylandEGLSwapBuffers(wlWm.glDisplay, wlWm.glSurface, NULL, 0);
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|||||||
@@ -267,7 +267,8 @@ struct WaylandDSState
|
|||||||
enum WaylandHDRPendingAction pendingHDRAction;
|
enum WaylandHDRPendingAction pendingHDRAction;
|
||||||
struct WaylandHDRParameters pendingHDR;
|
struct WaylandHDRParameters pendingHDR;
|
||||||
|
|
||||||
LGEvent * frameEvent;
|
_Atomic(unsigned) frameEventFlags;
|
||||||
|
LGEvent * frameEvent;
|
||||||
|
|
||||||
struct wl_list poll; // WaylandPoll::link
|
struct wl_list poll; // WaylandPoll::link
|
||||||
struct wl_list pollFree; // WaylandPoll::link
|
struct wl_list pollFree; // WaylandPoll::link
|
||||||
@@ -333,7 +334,8 @@ void waylandCursorScaleChange(void);
|
|||||||
#if defined(ENABLE_EGL) || defined(ENABLE_OPENGL)
|
#if defined(ENABLE_EGL) || defined(ENABLE_OPENGL)
|
||||||
bool waylandEGLInit(int w, int h);
|
bool waylandEGLInit(int w, int h);
|
||||||
EGLDisplay waylandGetEGLDisplay(void);
|
EGLDisplay waylandGetEGLDisplay(void);
|
||||||
void waylandEGLSwapBuffers(EGLDisplay display, EGLSurface surface, const struct Rect * damage, int count);
|
bool waylandEGLSwapBuffers(EGLDisplay display, EGLSurface surface,
|
||||||
|
const struct Rect * damage, int count);
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#ifdef ENABLE_EGL
|
#ifdef ENABLE_EGL
|
||||||
@@ -421,7 +423,7 @@ void waylandWindowFree(void);
|
|||||||
void waylandWindowUpdateScale(void);
|
void waylandWindowUpdateScale(void);
|
||||||
void waylandSetWindowSize(int x, int y);
|
void waylandSetWindowSize(int x, int y);
|
||||||
bool waylandIsValidPointerPos(int x, int y);
|
bool waylandIsValidPointerPos(int x, int y);
|
||||||
bool waylandWaitFrame(void);
|
LG_DSWaitFrameResult waylandWaitFrame(void);
|
||||||
void waylandSkipFrame(void);
|
void waylandSkipFrame(void);
|
||||||
void waylandStopWaitFrame(void);
|
void waylandStopWaitFrame(void);
|
||||||
void waylandNeedsResize(void);
|
void waylandNeedsResize(void);
|
||||||
|
|||||||
@@ -113,6 +113,13 @@ static const struct wl_surface_listener wlSurfaceListener = {
|
|||||||
.leave = wlSurfaceLeaveHandler,
|
.leave = wlSurfaceLeaveHandler,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
static void waylandSignalFrame(LG_DSWaitFrameResult result)
|
||||||
|
{
|
||||||
|
atomic_fetch_or_explicit(
|
||||||
|
&wlWm.frameEventFlags, result, memory_order_release);
|
||||||
|
lgSignalEvent(wlWm.frameEvent);
|
||||||
|
}
|
||||||
|
|
||||||
static void fractionalScalePreferredScale(void * data,
|
static void fractionalScalePreferredScale(void * data,
|
||||||
struct wp_fractional_scale_v1 * fractionalScale, uint32_t scale)
|
struct wp_fractional_scale_v1 * fractionalScale, uint32_t scale)
|
||||||
{
|
{
|
||||||
@@ -133,7 +140,7 @@ bool waylandWindowInit(const char * title, const char * appId, bool fullscreen,
|
|||||||
DEBUG_ERROR("Failed to initialize event for waitFrame");
|
DEBUG_ERROR("Failed to initialize event for waitFrame");
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
lgSignalEvent(wlWm.frameEvent);
|
waylandSignalFrame(LG_DS_WAIT_FRAME_INTERRUPTED);
|
||||||
|
|
||||||
if (!wlWm.compositor)
|
if (!wlWm.compositor)
|
||||||
{
|
{
|
||||||
@@ -220,7 +227,7 @@ bool waylandIsValidPointerPos(int x, int y)
|
|||||||
|
|
||||||
static void frameHandler(void * opaque, struct wl_callback * callback, unsigned int data)
|
static void frameHandler(void * opaque, struct wl_callback * callback, unsigned int data)
|
||||||
{
|
{
|
||||||
lgSignalEvent(wlWm.frameEvent);
|
waylandSignalFrame(LG_DS_WAIT_FRAME_CADENCE);
|
||||||
wl_callback_destroy(callback);
|
wl_callback_destroy(callback);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -228,9 +235,11 @@ static const struct wl_callback_listener frame_listener = {
|
|||||||
.done = frameHandler,
|
.done = frameHandler,
|
||||||
};
|
};
|
||||||
|
|
||||||
bool waylandWaitFrame(void)
|
LG_DSWaitFrameResult waylandWaitFrame(void)
|
||||||
{
|
{
|
||||||
lgWaitEvent(wlWm.frameEvent, TIMEOUT_INFINITE);
|
lgWaitEvent(wlWm.frameEvent, TIMEOUT_INFINITE);
|
||||||
|
const LG_DSWaitFrameResult result = atomic_exchange_explicit(
|
||||||
|
&wlWm.frameEventFlags, LG_DS_WAIT_FRAME_NONE, memory_order_acquire);
|
||||||
|
|
||||||
INTERLOCKED_SECTION(wlWm.surfaceLock,
|
INTERLOCKED_SECTION(wlWm.surfaceLock,
|
||||||
{
|
{
|
||||||
@@ -239,7 +248,7 @@ bool waylandWaitFrame(void)
|
|||||||
wl_callback_add_listener(callback, &frame_listener, NULL);
|
wl_callback_add_listener(callback, &frame_listener, NULL);
|
||||||
});
|
});
|
||||||
|
|
||||||
return false;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
void waylandSkipFrame(void)
|
void waylandSkipFrame(void)
|
||||||
@@ -253,5 +262,5 @@ void waylandSkipFrame(void)
|
|||||||
|
|
||||||
void waylandStopWaitFrame(void)
|
void waylandStopWaitFrame(void)
|
||||||
{
|
{
|
||||||
lgSignalEvent(wlWm.frameEvent);
|
waylandSignalFrame(LG_DS_WAIT_FRAME_INTERRUPTED);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -95,6 +95,13 @@ static void x11XPresentEvent(XGenericEventCookie *cookie);
|
|||||||
static void x11UpdateKeyboardGroup(void);
|
static void x11UpdateKeyboardGroup(void);
|
||||||
static void x11GrabPointer(void);
|
static void x11GrabPointer(void);
|
||||||
|
|
||||||
|
static void x11SignalFrame(LG_DSWaitFrameResult result)
|
||||||
|
{
|
||||||
|
atomic_fetch_or_explicit(
|
||||||
|
&x11.frameEventFlags, result, memory_order_release);
|
||||||
|
lgSignalEvent(x11.frameEvent);
|
||||||
|
}
|
||||||
|
|
||||||
static uint64_t x11ModePeriod(
|
static uint64_t x11ModePeriod(
|
||||||
const XRRScreenResources * resources, RRMode modeID)
|
const XRRScreenResources * resources, RRMode modeID)
|
||||||
{
|
{
|
||||||
@@ -849,7 +856,7 @@ static void x11Startup(void)
|
|||||||
static void x11Shutdown(void)
|
static void x11Shutdown(void)
|
||||||
{
|
{
|
||||||
if (x11.jitRender)
|
if (x11.jitRender)
|
||||||
lgSignalEvent(x11.frameEvent);
|
x11SignalFrame(LG_DS_WAIT_FRAME_INTERRUPTED);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void x11Free(void)
|
static void x11Free(void)
|
||||||
@@ -1595,7 +1602,7 @@ static void x11XPresentEvent(XGenericEventCookie *cookie)
|
|||||||
x11DoPresent(e->msc);
|
x11DoPresent(e->msc);
|
||||||
atomic_store(&x11.presentMsc, e->msc);
|
atomic_store(&x11.presentMsc, e->msc);
|
||||||
atomic_store(&x11.presentUst, e->ust);
|
atomic_store(&x11.presentUst, e->ust);
|
||||||
lgSignalEvent(x11.frameEvent);
|
x11SignalFrame(LG_DS_WAIT_FRAME_CADENCE);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -1645,14 +1652,14 @@ static EGLNativeWindowType x11GetEGLNativeWindow(void)
|
|||||||
return (EGLNativeWindowType)x11.window;
|
return (EGLNativeWindowType)x11.window;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void x11EGLSwapBuffers(EGLDisplay display, EGLSurface surface,
|
static bool x11EGLSwapBuffers(EGLDisplay display, EGLSurface surface,
|
||||||
const struct Rect * damage, int count)
|
const struct Rect * damage, int count)
|
||||||
{
|
{
|
||||||
static struct SwapWithDamageData data = {0};
|
static struct SwapWithDamageData data = {0};
|
||||||
if (!data.init)
|
if (!data.init)
|
||||||
swapWithDamageInit(&data, display);
|
swapWithDamageInit(&data, display);
|
||||||
|
|
||||||
swapWithDamage(&data, display, surface, damage, count);
|
return swapWithDamage(&data, display, surface, damage, count);
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
@@ -1692,10 +1699,17 @@ static void x11GLSwapBuffers(void)
|
|||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
static bool x11WaitFrame(void)
|
static LG_DSWaitFrameResult x11WaitFrame(void)
|
||||||
{
|
{
|
||||||
/* wait until we are woken up by the present event */
|
/* wait until we are woken up by the present event */
|
||||||
lgWaitEvent(x11.frameEvent, TIMEOUT_INFINITE);
|
lgWaitEvent(x11.frameEvent, TIMEOUT_INFINITE);
|
||||||
|
LG_DSWaitFrameResult result = atomic_exchange_explicit(
|
||||||
|
&x11.frameEventFlags, LG_DS_WAIT_FRAME_NONE, memory_order_acquire);
|
||||||
|
|
||||||
|
/* Interrupts carry no new presentation timestamp and must not perturb the
|
||||||
|
* calibration state. */
|
||||||
|
if (!(result & LG_DS_WAIT_FRAME_CADENCE))
|
||||||
|
return result;
|
||||||
|
|
||||||
#define WARMUP_TIME 3000000 //2s
|
#define WARMUP_TIME 3000000 //2s
|
||||||
#define CALIBRATION_COUNT 400
|
#define CALIBRATION_COUNT 400
|
||||||
@@ -1713,7 +1727,7 @@ static bool x11WaitFrame(void)
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (ust < expire)
|
if (ust < expire)
|
||||||
return false;
|
return result;
|
||||||
|
|
||||||
warmup = false;
|
warmup = false;
|
||||||
DEBUG_INFO("Warmup done, doing calibration...");
|
DEBUG_INFO("Warmup done, doing calibration...");
|
||||||
@@ -1831,14 +1845,14 @@ static bool x11WaitFrame(void)
|
|||||||
/* force rendering until we have finished calibration so we can take into
|
/* force rendering until we have finished calibration so we can take into
|
||||||
* account how long it takes for the scene to render */
|
* account how long it takes for the scene to render */
|
||||||
if (calibrate < CALIBRATION_COUNT)
|
if (calibrate < CALIBRATION_COUNT)
|
||||||
return true;
|
result |= LG_DS_WAIT_FRAME_FORCE_RENDER;
|
||||||
|
|
||||||
return false;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void x11StopWaitFrame(void)
|
static void x11StopWaitFrame(void)
|
||||||
{
|
{
|
||||||
lgSignalEvent(x11.frameEvent);
|
x11SignalFrame(LG_DS_WAIT_FRAME_INTERRUPTED);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void x11GuestPointerUpdated(double x, double y, double localX, double localY)
|
static void x11GuestPointerUpdated(double x, double y, double localX, double localY)
|
||||||
|
|||||||
@@ -81,6 +81,7 @@ struct X11DSState
|
|||||||
uint32_t presentSerial;
|
uint32_t presentSerial;
|
||||||
Pixmap presentPixmap;
|
Pixmap presentPixmap;
|
||||||
XserverRegion presentRegion;
|
XserverRegion presentRegion;
|
||||||
|
_Atomic(unsigned) frameEventFlags;
|
||||||
LGEvent * frameEvent;
|
LGEvent * frameEvent;
|
||||||
|
|
||||||
bool xrandrSupported;
|
bool xrandrSupported;
|
||||||
|
|||||||
@@ -103,7 +103,8 @@ bool app_getHDRDescFailed(void);
|
|||||||
#ifdef ENABLE_EGL
|
#ifdef ENABLE_EGL
|
||||||
EGLDisplay app_getEGLDisplay(void);
|
EGLDisplay app_getEGLDisplay(void);
|
||||||
EGLNativeWindowType app_getEGLNativeWindow(void);
|
EGLNativeWindowType app_getEGLNativeWindow(void);
|
||||||
void app_eglSwapBuffers(EGLDisplay display, EGLSurface surface, const struct Rect * damage, int count);
|
bool app_eglSwapBuffers(EGLDisplay display, EGLSurface surface,
|
||||||
|
const struct Rect * damage, int count);
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#ifdef ENABLE_OPENGL
|
#ifdef ENABLE_OPENGL
|
||||||
|
|||||||
@@ -35,7 +35,7 @@ struct SwapWithDamageData
|
|||||||
|
|
||||||
void swapWithDamageInit(struct SwapWithDamageData * data, EGLDisplay display);
|
void swapWithDamageInit(struct SwapWithDamageData * data, EGLDisplay display);
|
||||||
void swapWithDamageDisable(struct SwapWithDamageData * data);
|
void swapWithDamageDisable(struct SwapWithDamageData * data);
|
||||||
void swapWithDamage(struct SwapWithDamageData * data, EGLDisplay display, EGLSurface surface,
|
bool swapWithDamage(struct SwapWithDamageData * data, EGLDisplay display,
|
||||||
const struct Rect * damage, int count);
|
EGLSurface surface, const struct Rect * damage, int count);
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|||||||
@@ -103,6 +103,15 @@ typedef enum LG_DSPointer
|
|||||||
}
|
}
|
||||||
LG_DSPointer;
|
LG_DSPointer;
|
||||||
|
|
||||||
|
typedef enum LG_DSWaitFrameResult
|
||||||
|
{
|
||||||
|
LG_DS_WAIT_FRAME_NONE = 0,
|
||||||
|
LG_DS_WAIT_FRAME_CADENCE = 1 << 0,
|
||||||
|
LG_DS_WAIT_FRAME_INTERRUPTED = 1 << 1,
|
||||||
|
LG_DS_WAIT_FRAME_FORCE_RENDER = 1 << 2,
|
||||||
|
}
|
||||||
|
LG_DSWaitFrameResult;
|
||||||
|
|
||||||
#define LG_POINTER_COUNT (LG_POINTER_NOT_ALLOWED + 1)
|
#define LG_POINTER_COUNT (LG_POINTER_NOT_ALLOWED + 1)
|
||||||
|
|
||||||
typedef struct LG_DSInitParams
|
typedef struct LG_DSInitParams
|
||||||
@@ -171,7 +180,8 @@ struct LG_DisplayServerOps
|
|||||||
/* EGL support */
|
/* EGL support */
|
||||||
EGLDisplay (*getEGLDisplay)(void);
|
EGLDisplay (*getEGLDisplay)(void);
|
||||||
EGLNativeWindowType (*getEGLNativeWindow)(void);
|
EGLNativeWindowType (*getEGLNativeWindow)(void);
|
||||||
void (*eglSwapBuffers)(EGLDisplay display, EGLSurface surface, const struct Rect * damage, int count);
|
bool (*eglSwapBuffers)(EGLDisplay display, EGLSurface surface,
|
||||||
|
const struct Rect * damage, int count);
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#ifdef ENABLE_OPENGL
|
#ifdef ENABLE_OPENGL
|
||||||
@@ -184,11 +194,8 @@ struct LG_DisplayServerOps
|
|||||||
#endif
|
#endif
|
||||||
|
|
||||||
/* Waits for a good time to render the next frame in time for the next vblank.
|
/* Waits for a good time to render the next frame in time for the next vblank.
|
||||||
* This is optional and a display server may choose to not implement it.
|
* This is optional and a display server may choose to not implement it. */
|
||||||
*
|
LG_DSWaitFrameResult (*waitFrame)(void);
|
||||||
* return true to force the frame to be rendered, this is used by X11 for
|
|
||||||
* calibration */
|
|
||||||
bool (*waitFrame)(void);
|
|
||||||
|
|
||||||
/* This must be called when waitFrame returns, but no frame is actually rendered. */
|
/* This must be called when waitFrame returns, but no frame is actually rendered. */
|
||||||
void (*skipFrame)(void);
|
void (*skipFrame)(void);
|
||||||
|
|||||||
@@ -1689,13 +1689,17 @@ static bool egl_render(LG_Renderer * renderer, LG_RendererRotate rotate,
|
|||||||
const uint64_t composeEnd = nanotime();
|
const uint64_t composeEnd = nanotime();
|
||||||
timing->composeTime += composeEnd - postOverlayStart;
|
timing->composeTime += composeEnd - postOverlayStart;
|
||||||
|
|
||||||
const uint64_t swapStart = nanotime();
|
const uint64_t swapStart = nanotime();
|
||||||
app_eglSwapBuffers(this->display, this->surface, damage,
|
const bool swapResult = app_eglSwapBuffers(
|
||||||
|
this->display, this->surface, damage,
|
||||||
this->noSwapDamage ? 0 : damageIdx);
|
this->noSwapDamage ? 0 : damageIdx);
|
||||||
const uint64_t swapEnd = nanotime();
|
const uint64_t swapEnd = nanotime();
|
||||||
timing->swapTime = swapEnd - swapStart;
|
timing->swapTime = swapEnd - swapStart;
|
||||||
|
|
||||||
return true;
|
if (!swapResult)
|
||||||
|
DEBUG_ERROR("Failed to swap EGL buffers (eglError: 0x%x)", eglGetError());
|
||||||
|
|
||||||
|
return swapResult;
|
||||||
}
|
}
|
||||||
|
|
||||||
static bool egl_capture(LG_Renderer * renderer, LG_RendererCapture * capture)
|
static bool egl_capture(LG_Renderer * renderer, LG_RendererCapture * capture)
|
||||||
|
|||||||
@@ -838,9 +838,10 @@ EGLNativeWindowType app_getEGLNativeWindow(void)
|
|||||||
return g_state.ds->getEGLNativeWindow();
|
return g_state.ds->getEGLNativeWindow();
|
||||||
}
|
}
|
||||||
|
|
||||||
void app_eglSwapBuffers(EGLDisplay display, EGLSurface surface, const struct Rect * damage, int count)
|
bool app_eglSwapBuffers(EGLDisplay display, EGLSurface surface,
|
||||||
|
const struct Rect * damage, int count)
|
||||||
{
|
{
|
||||||
g_state.ds->eglSwapBuffers(display, surface, damage, count);
|
return g_state.ds->eglSwapBuffers(display, surface, damage, count);
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
|||||||
@@ -52,14 +52,11 @@ void swapWithDamageDisable(struct SwapWithDamageData * data)
|
|||||||
data->func = NULL;
|
data->func = NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
void swapWithDamage(struct SwapWithDamageData * data, EGLDisplay display, EGLSurface surface,
|
bool swapWithDamage(struct SwapWithDamageData * data, EGLDisplay display,
|
||||||
const struct Rect * damage, int count)
|
EGLSurface surface, const struct Rect * damage, int count)
|
||||||
{
|
{
|
||||||
if (!data->func || !count)
|
if (!data->func || !count)
|
||||||
{
|
return eglSwapBuffers(display, surface) == EGL_TRUE;
|
||||||
eglSwapBuffers(display, surface);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
EGLint rects[count * 4];
|
EGLint rects[count * 4];
|
||||||
for (int i = 0; i < count; ++i)
|
for (int i = 0; i < count; ++i)
|
||||||
@@ -69,5 +66,5 @@ void swapWithDamage(struct SwapWithDamageData * data, EGLDisplay display, EGLSur
|
|||||||
rects[i * 4 + 2] = damage[i].w;
|
rects[i * 4 + 2] = damage[i].w;
|
||||||
rects[i * 4 + 3] = damage[i].h;
|
rects[i * 4 + 3] = damage[i].h;
|
||||||
}
|
}
|
||||||
data->func(display, surface, rects, count);
|
return data->func(display, surface, rects, count) == EGL_TRUE;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -394,7 +394,8 @@ static void frameTimingFinishFrame(LG_RendererFrameToken token,
|
|||||||
}
|
}
|
||||||
|
|
||||||
static void frameTimingFinishRender(const LG_RendererFrameTiming * timing,
|
static void frameTimingFinishRender(const LG_RendererFrameTiming * timing,
|
||||||
uint64_t prepareStart, uint64_t prepareTime, uint64_t timestamp)
|
uint64_t prepareStart, uint64_t prepareTime, uint64_t timestamp,
|
||||||
|
LG_RendererFrameToken cadenceToken)
|
||||||
{
|
{
|
||||||
uint64_t feedbackFrameSerial = 0;
|
uint64_t feedbackFrameSerial = 0;
|
||||||
uint64_t feedbackQueueStart = 0;
|
uint64_t feedbackQueueStart = 0;
|
||||||
@@ -425,7 +426,8 @@ static void frameTimingFinishRender(const LG_RendererFrameTiming * timing,
|
|||||||
feedbackGeneration = record->scheduleGeneration;
|
feedbackGeneration = record->scheduleGeneration;
|
||||||
feedbackEpoch = record->scheduleEpoch;
|
feedbackEpoch = record->scheduleEpoch;
|
||||||
feedbackDeadline = record->scheduleDeadlineSerial;
|
feedbackDeadline = record->scheduleDeadlineSerial;
|
||||||
feedbackValid = record->phaseValid;
|
feedbackValid = record->phaseValid &&
|
||||||
|
timing->frameToken == cadenceToken;
|
||||||
feedbackQueueStart = record->queueStart;
|
feedbackQueueStart = record->queueStart;
|
||||||
|
|
||||||
if (unlikely(
|
if (unlikely(
|
||||||
@@ -640,9 +642,16 @@ static int renderThread(void * unused)
|
|||||||
|
|
||||||
while(likely(app_getState() != APP_STATE_SHUTDOWN))
|
while(likely(app_getState() != APP_STATE_SHUTDOWN))
|
||||||
{
|
{
|
||||||
|
LG_RendererFrameToken cadenceToken = LG_RENDERER_FRAME_TOKEN_NONE;
|
||||||
|
|
||||||
if (g_state.jitRender)
|
if (g_state.jitRender)
|
||||||
{
|
{
|
||||||
const bool forceRender = g_state.ds->waitFrame();
|
const LG_DSWaitFrameResult waitResult = g_state.ds->waitFrame();
|
||||||
|
const LG_RendererFrameToken queuedAtWake =
|
||||||
|
waitResult == LG_DS_WAIT_FRAME_CADENCE ?
|
||||||
|
frameTimingQueuedToken() : LG_RENDERER_FRAME_TOKEN_NONE;
|
||||||
|
const bool forceRender =
|
||||||
|
waitResult & LG_DS_WAIT_FRAME_FORCE_RENDER;
|
||||||
app_handleRenderEvent(microtime());
|
app_handleRenderEvent(microtime());
|
||||||
|
|
||||||
const uint64_t pending =
|
const uint64_t pending =
|
||||||
@@ -657,11 +666,9 @@ static int renderThread(void * unused)
|
|||||||
const bool overlayRender = overlayNeeded &&
|
const bool overlayRender = overlayNeeded &&
|
||||||
(!g_state.lastRenderTimeValid || !periodKnown ||
|
(!g_state.lastRenderTimeValid || !periodKnown ||
|
||||||
elapsed + outputPeriod >= g_state.overlayFrameTime);
|
elapsed + outputPeriod >= g_state.overlayFrameTime);
|
||||||
|
const bool clientWake = lgResetEvent(g_state.frameEvent);
|
||||||
|
|
||||||
if (!lgResetEvent(g_state.frameEvent)
|
if (!clientWake && !forceRender && !pending && !overlayRender)
|
||||||
&& !forceRender
|
|
||||||
&& !pending
|
|
||||||
&& !overlayRender)
|
|
||||||
{
|
{
|
||||||
if (g_state.ds->skipFrame)
|
if (g_state.ds->skipFrame)
|
||||||
g_state.ds->skipFrame();
|
g_state.ds->skipFrame();
|
||||||
@@ -669,7 +676,11 @@ static int renderThread(void * unused)
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (pending > 0)
|
if (pending > 0)
|
||||||
|
{
|
||||||
atomic_fetch_sub(&g_state.pendingCount, 1);
|
atomic_fetch_sub(&g_state.pendingCount, 1);
|
||||||
|
if (!clientWake)
|
||||||
|
cadenceToken = queuedAtWake;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
else if (g_params.fpsMin != 0)
|
else if (g_params.fpsMin != 0)
|
||||||
{
|
{
|
||||||
@@ -693,8 +704,10 @@ static int renderThread(void * unused)
|
|||||||
igGetStyle()->FontScaleMain = 1.0f / g_state.windowScale;
|
igGetStyle()->FontScaleMain = 1.0f / g_state.windowScale;
|
||||||
}
|
}
|
||||||
|
|
||||||
const bool fontDirty = atomic_exchange(&g_state.fontDirty, false);
|
const bool fontDirty = atomic_exchange(&g_state.fontDirty, false);
|
||||||
if (unlikely(fontDirty || g_state.fontScale != g_state.windowScale))
|
const bool fontUpdate = fontDirty ||
|
||||||
|
g_state.fontScale != g_state.windowScale;
|
||||||
|
if (unlikely(fontUpdate))
|
||||||
{
|
{
|
||||||
if (!util_buildUIFontAtlas(g_state.io->Fonts,
|
if (!util_buildUIFontAtlas(g_state.io->Fonts,
|
||||||
g_params.uiSize * g_state.windowScale, &g_state.fontLarge))
|
g_params.uiSize * g_state.windowScale, &g_state.fontLarge))
|
||||||
@@ -706,6 +719,9 @@ static int renderThread(void * unused)
|
|||||||
g_state.fontScale = g_state.windowScale;
|
g_state.fontScale = g_state.windowScale;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (unlikely(resize || fontUpdate))
|
||||||
|
cadenceToken = LG_RENDERER_FRAME_TOKEN_NONE;
|
||||||
|
|
||||||
if (unlikely(resize))
|
if (unlikely(resize))
|
||||||
{
|
{
|
||||||
if (g_state.lgr)
|
if (g_state.lgr)
|
||||||
@@ -721,11 +737,14 @@ static int renderThread(void * unused)
|
|||||||
|
|
||||||
renderQueue_process();
|
renderQueue_process();
|
||||||
|
|
||||||
const bool windowInvalid =
|
const bool windowInvalid =
|
||||||
atomic_exchange(&g_state.invalidateWindow, false);
|
atomic_exchange(&g_state.invalidateWindow, false);
|
||||||
const bool overlayFull = app_overlayNeedsFullRender();
|
const bool overlayFull = app_overlayNeedsFullRender();
|
||||||
const bool invalidate = windowInvalid || overlayFull;
|
const bool invalidate = windowInvalid || overlayFull;
|
||||||
const uint64_t prepareTime = nanotime() - prepareStart;
|
const uint64_t prepareTime = nanotime() - prepareStart;
|
||||||
|
|
||||||
|
if (unlikely(invalidate))
|
||||||
|
cadenceToken = LG_RENDERER_FRAME_TOKEN_NONE;
|
||||||
|
|
||||||
LG_RendererFrameTiming rendererTiming = {};
|
LG_RendererFrameTiming rendererTiming = {};
|
||||||
if (unlikely(!RENDERER(render, g_params.winRotate, frameTokenLimit,
|
if (unlikely(!RENDERER(render, g_params.winRotate, frameTokenLimit,
|
||||||
@@ -739,7 +758,8 @@ static int renderThread(void * unused)
|
|||||||
|
|
||||||
if (rendererTiming.frameToken != LG_RENDERER_FRAME_TOKEN_NONE)
|
if (rendererTiming.frameToken != LG_RENDERER_FRAME_TOKEN_NONE)
|
||||||
frameTimingFinishRender(
|
frameTimingFinishRender(
|
||||||
&rendererTiming, prepareStart, prepareTime, renderEnd);
|
&rendererTiming, prepareStart, prepareTime, renderEnd,
|
||||||
|
cadenceToken);
|
||||||
frameTimingPublishReady();
|
frameTimingPublishReady();
|
||||||
|
|
||||||
const uint64_t t = nanotime();
|
const uint64_t t = nanotime();
|
||||||
|
|||||||
Reference in New Issue
Block a user