mirror of
https://github.com/Droid-Deck/DroidDeck.git
synced 2026-11-12 11:31:08 +00:00
Clock frame generation by the game's frames
With frame generation on, a scene drawn for another window (Steam's overlay) went into the engine as a game frame. Adaptive counted it as source rate and planned against that (36 base for a game capped at 30), and a fixed multiplier gave it present slots while game frames were dropped (26 -> 51 at 2x). Such a change now waits for the game's next frame. The HUD's base rate is the game window's own frames, as Steam's overlay counts them, instead of the compositor's scene rate.
This commit is contained in:
1 parent
6ae5940f0d
commit
cd284ca59a
2 files changed
+16
-8
No files matched your search
@@ -750,6 +750,8 @@ static void take_shm(struct surface *s, struct wl_shm_buffer *shm, struct wl_res
|
||||
static struct surface *g_hud_surface;
|
||||
/* When the HUD's window last presented a frame (now_ns), to let a replacement take over. */
|
||||
static int64_t g_hud_last_ns;
|
||||
/* That window committed a frame the screen has not drawn yet. */
|
||||
static int g_hud_fresh;
|
||||
extern void banner_on_game_surface(const char *window, const char *gpu); /* window NULL = gone */
|
||||
extern void banner_on_game_frame(void);
|
||||
/* The program behind that window: its Linux pid (the Wayland client's credentials) and executable name
|
||||
@@ -852,7 +854,7 @@ static void take_dmabuf(struct surface *s, struct dmabuf_buffer *b, struct wl_re
|
||||
* Asking whether the compositor could import it, as this used to, is a question about the
|
||||
* copy path and not about whether a frame happened: a game whose buffers go straight to
|
||||
* the display layer draws on screen while the counter sat at 0.0 fps and 1000.0 ms. */
|
||||
if (s == g_hud_surface) { g_hud_last_ns = now_ns(); banner_on_game_frame(); }
|
||||
if (s == g_hud_surface) { g_hud_last_ns = now_ns(); g_hud_fresh = 1; banner_on_game_frame(); }
|
||||
}
|
||||
|
||||
/* ---- hooks for ahb_swapchain.c (zero-copy layers) */
|
||||
@@ -2021,6 +2023,7 @@ static void render_scene(void) {
|
||||
int copy = 0; /* this scene went through the screen swapchain (the perf line's "copy") */
|
||||
|
||||
g_dirty = 0;
|
||||
g_hud_fresh = 0;
|
||||
g_hdr_unimported = NULL; /* found again while the scene is built (HDR gate open only) */
|
||||
wl_list_for_each(s, &g_surfaces, link) s->drawn = 0;
|
||||
scene_size(&w, &h);
|
||||
@@ -2236,6 +2239,13 @@ static void schedule_render(void) {
|
||||
wl_event_source_timer_update(g_fallback_timer, 8);
|
||||
}
|
||||
|
||||
/* With frame generation on, every scene is the engine's next source frame, so one drawn for
|
||||
* another window (Steam's overlay) counted as a game frame and took its present slots. Such a
|
||||
* change waits for the game's next frame, unless the game has been still for 100 ms. */
|
||||
static int scene_waits_for_game(int64_t now) {
|
||||
return g_hud_surface && !g_hud_fresh && now - g_hud_last_ns < 100000000LL && vkp_framegen_active();
|
||||
}
|
||||
|
||||
/* A screen refresh (Choreographer tick): draw the newest state once. */
|
||||
static void on_vsync(int64_t frame_time_ns) {
|
||||
int64_t now = now_ns();
|
||||
@@ -2251,7 +2261,7 @@ static void on_vsync(int64_t frame_time_ns) {
|
||||
if (vkp_apply_window_request()) g_dirty = 1;
|
||||
/* A screen-effect setting changed (JNI, any thread): redraw so it shows on a static scene too. */
|
||||
if (vkp_effects_sync()) g_dirty = 1;
|
||||
if (g_dirty) render_scene();
|
||||
if (g_dirty && !scene_waits_for_game(now)) render_scene();
|
||||
}
|
||||
|
||||
/* ------------------------------------------------------------------ wl_seat */
|
||||
|
||||
@@ -21,8 +21,9 @@ import java.util.concurrent.atomic.AtomicInteger
|
||||
* is on, what the screen is actually being shown - "60 → 118 fps" is the proof that the engine
|
||||
* is doing something, and "FG starting" or a reason is the proof that it is not.
|
||||
*
|
||||
* The base rate is counted here from the compositor's per-frame callback, so it is right with or
|
||||
* without an engine. The presented rate comes from the engine's own telemetry while it generates.
|
||||
* The base rate is the game window's own frames, counted here from the compositor's per-frame
|
||||
* callback with or without an engine - what Steam's overlay counts too. The presented rate comes
|
||||
* from the engine's telemetry while it generates.
|
||||
*/
|
||||
class PerfHud(context: Context) {
|
||||
/** Empty when the HUD is off or not yet started. */
|
||||
@@ -99,10 +100,7 @@ class PerfHud(context: Context) {
|
||||
return when {
|
||||
problem == 1 -> context.getString(R.string.hud_fg_unsupported, name)
|
||||
problem == 2 -> context.getString(R.string.hud_fg_failed, name)
|
||||
stats != null && stats[3] > 1f -> {
|
||||
val source = if (stats[2] > 1f) stats[2] else base
|
||||
String.format(Locale.US, "%s %.0f → %.0f fps", label, source, stats[3])
|
||||
}
|
||||
stats != null && stats[3] > 1f -> String.format(Locale.US, "%s %.0f → %.0f fps", label, base, stats[3])
|
||||
else -> context.getString(R.string.hud_fg_starting, label, fps(base))
|
||||
}
|
||||
}
|
||||
|
||||
Reference in new issue
Block a user