mirror of
https://github.com/Droid-Deck/DroidDeck.git
synced 2026-11-11 19:11:08 +00:00
Merge branch 'main' into fix/mangoapp-drm-listing
This commit is contained in:
8 files changed
+45
-9
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 */
|
||||
|
||||
@@ -144,6 +144,7 @@ class MainActivity : ComponentActivity() {
|
||||
private var directAudio by mutableStateOf(false)
|
||||
private var clientDirectAudio by mutableStateOf(false)
|
||||
private var forceFullscreen by mutableStateOf(true)
|
||||
private var stretch16x9 by mutableStateOf(false)
|
||||
private var launcherFullscreen by mutableStateOf(true)
|
||||
private var storeEnabled by mutableStateOf(false)
|
||||
private var appImagesEnabled by mutableStateOf(false)
|
||||
@@ -958,6 +959,7 @@ class MainActivity : ComponentActivity() {
|
||||
directAudio = if (mode == SessionService.MODE_STEAM) directAudio else null,
|
||||
clientDirectAudio = clientDirectAudio,
|
||||
forceFullscreen = if (mode == SessionService.MODE_STEAM) forceFullscreen else null,
|
||||
stretch16x9 = if (mode == SessionService.MODE_STEAM) stretch16x9 else null,
|
||||
mic = if (mode == SessionService.MODE_STEAM) mic else null,
|
||||
renderer = if (mode == SessionService.MODE_DESKTOP) renderer else null,
|
||||
gameStorage = if (mode == SessionService.MODE_STEAM) gameStorage else null,
|
||||
@@ -993,6 +995,7 @@ class MainActivity : ComponentActivity() {
|
||||
onDirectAudio = { on -> SessionPrefs.setDirectAudio(this, on); directAudio = on },
|
||||
onClientDirectAudio = { on -> SessionPrefs.setClientDirectAudio(this, on); clientDirectAudio = on },
|
||||
onForceFullscreen = { on -> SessionPrefs.setForceFullscreen(this, on); forceFullscreen = on },
|
||||
onStretch16x9 = { on -> SessionPrefs.setStretch16x9(this, on); stretch16x9 = on },
|
||||
onMic = { on ->
|
||||
SessionPrefs.setMicEnabled(this, on)
|
||||
mic = on
|
||||
@@ -1119,6 +1122,7 @@ class MainActivity : ComponentActivity() {
|
||||
directAudio = SessionPrefs.directAudio(this)
|
||||
clientDirectAudio = SessionPrefs.clientDirectAudio(this)
|
||||
forceFullscreen = SessionPrefs.forceFullscreen(this)
|
||||
stretch16x9 = SessionPrefs.stretch16x9(this)
|
||||
mic = SessionPrefs.micEnabled(this)
|
||||
renderer = SessionPrefs.desktopRenderer(this)
|
||||
gameStorage = SessionPrefs.gameStorage(this)
|
||||
|
||||
@@ -157,6 +157,7 @@ object DeviceReport {
|
||||
k("Guest host name", SessionPrefs.guestHostname(context))
|
||||
k("DirectAudio for games", SessionPrefs.directAudio(context))
|
||||
k("Stretch games to fill", SessionPrefs.forceFullscreen(context))
|
||||
k("Stretch 16:9 to panel", SessionPrefs.stretch16x9(context))
|
||||
k("Client audio", if (SessionPrefs.clientDirectAudio(context)) "DirectAudio" else "classic")
|
||||
k("Microphone", SessionPrefs.micEnabled(context))
|
||||
k("On-screen controls", SessionPrefs.oscMode(context))
|
||||
|
||||
@@ -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))
|
||||
}
|
||||
}
|
||||
|
||||
@@ -184,6 +184,12 @@ object SessionPrefs {
|
||||
writeForceFullscreenFlag(context)
|
||||
}
|
||||
|
||||
fun stretch16x9(context: Context): Boolean = prefs(context).getBoolean("stretch16x9", false)
|
||||
|
||||
fun setStretch16x9(context: Context, on: Boolean) {
|
||||
prefs(context).edit().putBoolean("stretch16x9", on).apply()
|
||||
}
|
||||
|
||||
/**
|
||||
* The same choice as a file the running session watches, so the drawer can change it live:
|
||||
* the session hands every change to gamescope, which reads GAMESCOPE_FORCE_WINDOWS_FULLSCREEN
|
||||
|
||||
@@ -540,6 +540,7 @@ class SessionService : Service() {
|
||||
if (steamHere) guest.add("BL_STEAM_CHANNEL=" + SessionPrefs.steamChannel(this))
|
||||
if (SessionState.mode == MODE_STEAM) {
|
||||
guest.add("BL_GAMESCOPE_FORCE_FULLSCREEN=" + (if (SessionPrefs.forceFullscreen(this)) "1" else "0"))
|
||||
guest.add("BL_GAMESCOPE_STRETCH_16X9=" + (if (SessionPrefs.stretch16x9(this)) "1" else "0"))
|
||||
SessionPrefs.writeForceFullscreenFlag(this)
|
||||
}
|
||||
// Proton's own gate for its xalia helper (its `proton` script reads this, and sets
|
||||
|
||||
@@ -68,6 +68,7 @@ class ModeSettings(
|
||||
val fexPreset: String? = null,
|
||||
/** Steam only: games are stretched to fill the screen (null = not a Steam page). */
|
||||
val forceFullscreen: Boolean? = null,
|
||||
val stretch16x9: Boolean? = null,
|
||||
/** Steam only: the client branch forced on the command line. */
|
||||
val steamChannel: String? = null,
|
||||
/** Steam only: enable the SteamOS client interface and its performance controls. */
|
||||
@@ -117,6 +118,7 @@ class ModeSettingsActions(
|
||||
val onPickGameStorageFolder: () -> Unit = {},
|
||||
val onFexPreset: (String) -> Unit = {},
|
||||
val onForceFullscreen: (Boolean) -> Unit = {},
|
||||
val onStretch16x9: (Boolean) -> Unit = {},
|
||||
val onSteamChannel: (String) -> Unit = {},
|
||||
val onSteamDeckMode: (Boolean) -> Unit = {},
|
||||
val onMangoapp: (Boolean) -> Unit = {},
|
||||
@@ -361,6 +363,11 @@ fun ModeSettingsPage(s: ModeSettings, a: ModeSettingsActions) {
|
||||
"Keeps games that resize their own window (FlatOut) full screen. Turn it off if a game shows up small in a corner (Quake 3). Applies next session.",
|
||||
s.forceFullscreen, onChange = a.onForceFullscreen,
|
||||
)
|
||||
if (s.stretch16x9 != null) ToggleRow(
|
||||
host, "stretch169", "Stretch 16:9 games to a narrower screen",
|
||||
"On a screen squarer than 16:9 (a foldable's inner panel), games render at 16:9 and are stretched to fill it: no bars, slightly wider-looking. Applies next session.",
|
||||
s.stretch16x9, onChange = a.onStretch16x9,
|
||||
)
|
||||
}
|
||||
if (steam && s.directAudio != null && s.mic != null) SettingsGroup("Audio") {
|
||||
ToggleRow(host, "da", "DirectAudio for games", "Bypasses PulseAudio for lower latency in games.", s.directAudio, onChange = a.onDirectAudio)
|
||||
|
||||
@@ -140,7 +140,16 @@ if [ -z "${BL_INSIDE:-}" ]; then
|
||||
fi
|
||||
width=${BL_WIDTH:-1280}
|
||||
height=${BL_HEIGHT:-720}
|
||||
args=(--backend wayland --expose-wayland -f -W "$width" -H "$height" -w "$width" -h "$height")
|
||||
nested=$width
|
||||
if [ "$mode" = steam ] && [ "${BL_GAMESCOPE_STRETCH_16X9:-0}" = 1 ]; then
|
||||
wide=$(( (height * 16 + 4) / 9 / 2 * 2 ))
|
||||
if [ "$wide" -gt "$width" ]; then
|
||||
nested=$wide
|
||||
echo "== gamescope: games at ${nested}x${height} stretched to the ${width}x${height} output"
|
||||
fi
|
||||
fi
|
||||
args=(--backend wayland --expose-wayland -f -W "$width" -H "$height" -w "$nested" -h "$height")
|
||||
[ "$nested" != "$width" ] && args+=(-S stretch)
|
||||
# -r is what gamescope advertises as the refresh rate, and what a game reads as the display's.
|
||||
# Left unset it defaults to 60, so a 120 Hz panel offers only 60 Hz in game settings. The FPS
|
||||
# limiter wins when it is on (it is a deliberate cap); otherwise use the panel's own rate.
|
||||
|
||||
Reference in new issue
Block a user