perf(android): low-latency decode overhaul — vendor keys, async loop, system tuning
android / android (push) Has been cancelled
apple / swift (push) Has been cancelled
apple / screenshots (push) Has been cancelled
arch / build-publish (push) Has been cancelled
ci / rust (push) Has been cancelled
ci / web (push) Has been cancelled
ci / docs-site (push) Has been cancelled
ci / bench (push) Has been cancelled
rpm / build-publish (44, fedora-44, punktfunk-fedora44-rpm) (push) Has been cancelled
deb / build-publish (push) Has been cancelled
decky / build-publish (push) Has been cancelled
docker / build-push (., web/Dockerfile, punktfunk-web) (push) Has been cancelled
docker / build-push (ci, ci/fedora-rpm.Dockerfile, punktfunk-fedora-rpm) (push) Has been cancelled
docker / build-push (ci, ci/rust-ci.Dockerfile, punktfunk-rust-ci) (push) Has been cancelled
docker / build-push (docs-site, docs-site/Dockerfile, punktfunk-docs) (push) Has been cancelled
docker / deploy-docs (push) Has been cancelled
docker / build-push (--build-arg FEDORA_VERSION=44, ci, ci/fedora-rpm.Dockerfile, punktfunk-fedora44-rpm) (push) Has been cancelled
rpm / build-publish (43, bazzite, punktfunk-fedora-rpm) (push) Successful in 9m21s
android / android (push) Has been cancelled
apple / swift (push) Has been cancelled
apple / screenshots (push) Has been cancelled
arch / build-publish (push) Has been cancelled
ci / rust (push) Has been cancelled
ci / web (push) Has been cancelled
ci / docs-site (push) Has been cancelled
ci / bench (push) Has been cancelled
rpm / build-publish (44, fedora-44, punktfunk-fedora44-rpm) (push) Has been cancelled
deb / build-publish (push) Has been cancelled
decky / build-publish (push) Has been cancelled
docker / build-push (., web/Dockerfile, punktfunk-web) (push) Has been cancelled
docker / build-push (ci, ci/fedora-rpm.Dockerfile, punktfunk-fedora-rpm) (push) Has been cancelled
docker / build-push (ci, ci/rust-ci.Dockerfile, punktfunk-rust-ci) (push) Has been cancelled
docker / build-push (docs-site, docs-site/Dockerfile, punktfunk-docs) (push) Has been cancelled
docker / deploy-docs (push) Has been cancelled
docker / build-push (--build-arg FEDORA_VERSION=44, ci, ci/fedora-rpm.Dockerfile, punktfunk-fedora44-rpm) (push) Has been cancelled
rpm / build-publish (43, bazzite, punktfunk-fedora-rpm) (push) Successful in 9m21s
Close the latency gap on the Android client with per-SoC decoder tuning, an event-driven decode loop, and full system integration. - Decoder selection: rank MediaCodecList decoders in Kotlin (hardware/vendor preferred, software avoided, FEATURE_LowLatency probed) and create the chosen one by name. Per-SoC low-latency keys gated on the codec-name prefix: Qualcomm picture-order + low-latency, Exynos (also Google Tensor), Amlogic, HiSilicon; MediaTek vdec-lowlatency set unconditionally. operating-rate = MAX (Qualcomm) vs priority = 0 (else) are mutually exclusive. NVIDIA/Rockchip/Realtek have no vendor key — covered by ranking + the standard low-latency key. - Async decode loop: AMediaCodec async-notify replaces the poll loop, presenting a decoded frame the instant it is ready instead of waiting out a poll interval. Behind USE_ASYNC_DECODE with the synchronous loop kept for A/B during bring-up. - System integration: Wi-Fi FULL_LOW_LATENCY lock and HDMI ALLM (setPreferMinimalPostProcessing) for the stream's lifetime; game_mode_config.xml opting out of OEM downscaling / FPS overrides. - Pipeline: boost the data-plane pump + audio thread priorities, AAudio usage=Game, DSCP marking on by default on Android, ADPF setPreferPowerEfficiency(false), and setFrameRateWithChangeStrategy(ALWAYS) to force the HDMI mode switch on TV. - lowLatencyMode master toggle (default on) as the escape hatch; the stats HUD now shows the resolved decoder name. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -28,6 +28,7 @@ type CreateSessionFn = unsafe extern "C" fn(*mut c_void, *const i32, usize, i64)
|
||||
type ReportFn = unsafe extern "C" fn(*mut c_void, i64) -> c_int;
|
||||
type UpdateTargetFn = unsafe extern "C" fn(*mut c_void, i64) -> c_int;
|
||||
type CloseFn = unsafe extern "C" fn(*mut c_void);
|
||||
type SetPreferPowerEfficiencyFn = unsafe extern "C" fn(*mut c_void, bool) -> c_int;
|
||||
|
||||
/// The entry points we use, resolved once from `libandroid.so`, plus the process-wide manager.
|
||||
struct Api {
|
||||
@@ -35,6 +36,9 @@ struct Api {
|
||||
report: ReportFn,
|
||||
update_target: UpdateTargetFn,
|
||||
close: CloseFn,
|
||||
/// `APerformanceHint_setPreferPowerEfficiency` — NDK **API 35**, so `Option`al even when the
|
||||
/// rest of ADPF resolved (a 33/34 device has the session API but not this one).
|
||||
set_prefer_power_efficiency: Option<SetPreferPowerEfficiencyFn>,
|
||||
manager: *mut c_void,
|
||||
}
|
||||
|
||||
@@ -70,11 +74,20 @@ fn resolve_api() -> Option<Api> {
|
||||
if manager.is_null() {
|
||||
return None;
|
||||
}
|
||||
// Optional (API 35): resolve if present, else `None` — the session still works without it.
|
||||
let set_prefer_power_efficiency =
|
||||
libc::dlsym(lib, c"APerformanceHint_setPreferPowerEfficiency".as_ptr());
|
||||
let set_prefer_power_efficiency = (!set_prefer_power_efficiency.is_null()).then(|| {
|
||||
std::mem::transmute::<*mut c_void, SetPreferPowerEfficiencyFn>(
|
||||
set_prefer_power_efficiency,
|
||||
)
|
||||
});
|
||||
Some(Api {
|
||||
create_session: std::mem::transmute::<*mut c_void, CreateSessionFn>(create_session),
|
||||
report: std::mem::transmute::<*mut c_void, ReportFn>(report),
|
||||
update_target: std::mem::transmute::<*mut c_void, UpdateTargetFn>(update_target),
|
||||
close: std::mem::transmute::<*mut c_void, CloseFn>(close),
|
||||
set_prefer_power_efficiency,
|
||||
manager,
|
||||
})
|
||||
}
|
||||
@@ -103,6 +116,13 @@ impl HintSession {
|
||||
if session.is_null() {
|
||||
return None;
|
||||
}
|
||||
// Tell the governor NOT to bias this session toward power efficiency (API 35+): our loop is
|
||||
// latency-critical, so we want it kept on fast cores at high clocks over battery savings.
|
||||
// Best-effort; absent below API 35.
|
||||
if let Some(f) = api.set_prefer_power_efficiency {
|
||||
// SAFETY: `session` is the live session just created; the fn takes it + a bool.
|
||||
unsafe { f(session, false) };
|
||||
}
|
||||
Some(Self { api, session })
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user