Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
34 commits
Select commit Hold shift + click to select a range
c1fb4f3
feat: Direct Composition zero-copy path via ASurfaceControl + HWC ove…
Jun 27, 2026
d721771
fix: shortcut persistence + HUD indicator + diagnostic logging for Di…
Jun 27, 2026
d781226
fix: remove isDirectScanout gate + add throttled diagnostic logging f…
Jun 27, 2026
9ec2ec7
feat: vsync pacing via ASurfaceTransaction_setOnComplete (CPU/battery…
Jun 27, 2026
1341429
Merge pull request #1 from Vower2993/direct-composition-port
Vower2993 Jun 27, 2026
4187f12
feat: ADPF + hardware fence sync for DC — CPU boost + zero-poll frame…
Jun 28, 2026
0076fa5
chore: trigger CI
Jun 28, 2026
243c4da
chore: trigger CI for dc-adpf-fence branch
Jun 28, 2026
d06bd23
fix: remove junk line
Jun 28, 2026
3144f0a
merge: resolve conflicts, keep DC + ADPF + fence version
Jun 28, 2026
fa40ea7
fix: remove invalid SUSTAINED_PERFORMANCE_MODE wakelock constant
Jun 28, 2026
2c5032c
fix: FD leak — drain unconsumed fence FDs on DC fallback paths
Jun 28, 2026
48a46ad
fix: volatile dcLayerActive + hide on detach — dynamic DC indicator
Jun 28, 2026
1a3b4ee
feat: steps 3-5 — graphics preset reset, hardware pacing, Xiaomi zero…
Jun 29, 2026
a28acc7
perf: smoothed ADPF — rolling average + headroom bias + throttled rep…
Jun 29, 2026
57ff44f
feat: atomic submission gate — structural hardware pacing handshake
Jun 29, 2026
96abcd9
fix: skip nativeRenderFrame when no new content — eliminates 100% CPU…
Jun 29, 2026
81de88e
feat: event-driven render loop — decouple from Choreographer, strict …
Jun 29, 2026
c34dc9e
feat: frame floor pacing + input-driven cursor wake
Jun 29, 2026
9c5f8b8
chore: trigger CI
Jun 29, 2026
148e36a
fix: condvar wait + coalescing fix + input throttle — eliminate 100% CPU
Jun 29, 2026
c443ef0
feat: pure hardware fence sync + lockless input — final render loop r…
Jun 29, 2026
d065254
merge: sync upstream main, keep DC version of XServerDisplayActivity
Jun 29, 2026
08def53
fix: take upstream XServerDisplayActivity, re-apply DC lifecycle methods
Jun 29, 2026
536dba6
Merge branch 'main' into dc-adpf-fence
maxjivi05 Jun 29, 2026
f94d672
DC: fix NPE races, soft-boot release wait, device gating, and render …
maxjivi05 Jun 29, 2026
57ee468
DC: fix container/shortcut settings persistence
maxjivi05 Jun 29, 2026
4f062a8
DC: single-path fullscreen gating with hysteresis; keep recording whi…
maxjivi05 Jun 29, 2026
e3fd994
DC: decide before scene loop and skip Vulkan import of the game buffe…
maxjivi05 Jun 30, 2026
440bbd5
DC: revert release path to immediate ASurfaceControl_release (RedMagi…
maxjivi05 Jun 30, 2026
e489fbf
Merge branch 'main' into dc-adpf-fence
maxjivi05 Jun 30, 2026
4346131
Merge remote-tracking branch 'upstream/main' into pr584-update
maxjivi05 Jul 1, 2026
44e0207
DC: remove device soft-boot blocklist; gate on per-container toggle
maxjivi05 Jul 1, 2026
e954fba
DC: translate Direct Composition label to all locales; drop unused st…
maxjivi05 Jul 1, 2026
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions app/src/main/cpp/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -138,6 +138,7 @@ add_library(winlator SHARED
winlator/drawable.c
winlator/native_content_io.cpp
winlator/gpu_image.c
winlator/surface_compositor.c
winlator/sync_fence.c
winlator/sysvshared_memory.c
winlator/xconnector_epoll.c
Expand Down
574 changes: 574 additions & 0 deletions app/src/main/cpp/winlator/surface_compositor.c

Large diffs are not rendered by default.

11 changes: 11 additions & 0 deletions app/src/main/feature/library/GameSettings.kt
Original file line number Diff line number Diff line change
Expand Up @@ -513,6 +513,9 @@ class GameSettingsStateHolder {
val selectedStartupSelection = mutableIntStateOf(0)
val execArgs = mutableStateOf("")
val fullscreenStretched = mutableStateOf(false)
// Direct Composition (zero-copy AHB → SurfaceControl + HWC overlay).
// Per-container toggle; read once at activity startup. See Container.EXTRA_DIRECT_COMPOSITION.
val directComposition = mutableStateOf(false)

// Advanced - CPU
val cpuCount = mutableIntStateOf(Runtime.getRuntime().availableProcessors())
Expand Down Expand Up @@ -3661,6 +3664,14 @@ private fun AdvancedSection(
checked = state.fullscreenStretched.value,
onCheckedChange = { state.fullscreenStretched.value = it }
)

Spacer(Modifier.height(SettingItemGap))

SettingCheckbox(
label = stringResource(R.string.session_display_direct_composition),
checked = state.directComposition.value,
onCheckedChange = { state.directComposition.value = it }
)
}

Spacer(Modifier.height(SettingSectionGap))
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -422,6 +422,7 @@ class ContainerSettingsComposeDialog @JvmOverloads constructor(
}

state.fullscreenStretched.value = c?.isFullscreenStretched() ?: false
state.directComposition.value = c?.isDirectCompositionEnabled() ?: false

// Steam fields are shortcut-only in the UI; leave any existing steam
// state on the container untouched — saveSettings() skips them.
Expand Down Expand Up @@ -799,6 +800,7 @@ class ContainerSettingsComposeDialog @JvmOverloads constructor(
c.setWinComponents(wincomponents)
c.setDrives(drivesString)
c.setFullscreenStretched(state.fullscreenStretched.value)
c.setDirectCompositionEnabled(state.directComposition.value)
c.setInputType(finalInputType)
c.setExclusiveXInput(state.containerExclusiveInput.value)
c.setStartupSelection(startupSelection)
Expand Down Expand Up @@ -839,6 +841,10 @@ class ContainerSettingsComposeDialog @JvmOverloads constructor(
data.put("wincomponents", wincomponents)
data.put("drives", drivesString)
data.put("fullscreenStretched", state.fullscreenStretched.value)
val extraDataObj = data.optJSONObject("extraData") ?: org.json.JSONObject()
extraDataObj.put(Container.EXTRA_DIRECT_COMPOSITION, if (state.directComposition.value) "1" else "0")
extraDataObj.put("swapRB", if (state.selectedSurfaceEffect.intValue == 1) "1" else "0")
data.put("extraData", extraDataObj)
data.put("inputType", finalInputType)
data.put("exclusiveXInput", state.containerExclusiveInput.value)
data.put("startupSelection", startupSelection.toInt())
Expand All @@ -847,7 +853,6 @@ class ContainerSettingsComposeDialog @JvmOverloads constructor(
data.put("fexcoreVersion", fexcoreVersion)
data.put("fexcorePreset", fexcorePreset)
data.put("desktopTheme", desktopTheme)
data.put("swapRB", if (state.selectedSurfaceEffect.intValue == 1) "1" else "0")
data.put("wineVersion", selectedWineStr)
data.put("midiSoundFont", midiSoundFont)
data.put("lc_all", state.lcAll.value)
Expand Down
16 changes: 16 additions & 0 deletions app/src/main/feature/shortcuts/ShortcutSettingsComposeDialog.kt
Original file line number Diff line number Diff line change
Expand Up @@ -415,6 +415,14 @@ class ShortcutSettingsComposeDialog private constructor(
)
state.fullscreenStretched.value = fullscreenStretched == "1"

// Direct Composition (per-shortcut override of the container setting).
// Falls back to the container's value when the shortcut doesn't override.
val directComposition = getShortcutSetting(
Container.EXTRA_DIRECT_COMPOSITION,
if (container.isDirectCompositionEnabled()) "1" else "0"
)
state.directComposition.value = directComposition == "1"

// LC_ALL
state.lcAll.value = getShortcutSetting("lc_all", container.getLC_ALL())

Expand Down Expand Up @@ -1071,6 +1079,13 @@ class ShortcutSettingsComposeDialog private constructor(
if (container.isFullscreenStretched) "1" else "0"
)

// Direct Composition (per-shortcut override)
hasContainerOverride = hasContainerOverride or saveOverride(
Container.EXTRA_DIRECT_COMPOSITION,
if (state.directComposition.value) "1" else "0",
if (container.isDirectCompositionEnabled()) "1" else "0"
)

// Win components
val wincomponents = buildWinComponentsString()
hasContainerOverride =
Expand Down Expand Up @@ -2160,6 +2175,7 @@ class ShortcutSettingsComposeDialog private constructor(

state.lcAll.value = container.getLC_ALL()
state.fullscreenStretched.value = container.isFullscreenStretched
state.directComposition.value = container.isDirectCompositionEnabled()

val startupEntries = state.startupSelectionEntries.value
state.selectedStartupSelection.intValue = container.getStartupSelection().toInt()
Expand Down
1 change: 1 addition & 0 deletions app/src/main/res/values-da/strings.xml
Original file line number Diff line number Diff line change
Expand Up @@ -618,6 +618,7 @@ F.eks. <b>META</b> for <i>META-tast</i>, \n
<string name="session_display_frame_rate">Billedhastighed</string>
<string name="session_display_title">Skærm</string>
<string name="session_display_fullscreen_stretched">Aktiver fuldskærm (strakt)</string>
<string name="session_display_direct_composition">Direkte komposition (zero-copy)</string>
<string name="session_display_fps_label">FPS:</string>
<string name="session_display_renderer_label">Renderer:</string>
<string name="session_display_gpu_label">GPU:</string>
Expand Down
1 change: 1 addition & 0 deletions app/src/main/res/values-de/strings.xml
Original file line number Diff line number Diff line change
Expand Up @@ -618,6 +618,7 @@ Z. B. <b>META</b> für <i>Meta-Taste</i>, \n
<string name="session_display_frame_rate">Bildrate</string>
<string name="session_display_title">Anzeige</string>
<string name="session_display_fullscreen_stretched">Vollbild aktivieren (Gestreckt)</string>
<string name="session_display_direct_composition">Direkte Komposition (Zero-Copy)</string>
<string name="session_display_fps_label">FPS:</string>
<string name="session_display_renderer_label">Renderer:</string>
<string name="session_display_gpu_label">GPU:</string>
Expand Down
1 change: 1 addition & 0 deletions app/src/main/res/values-es/strings.xml
Original file line number Diff line number Diff line change
Expand Up @@ -618,6 +618,7 @@ Ej. <b>META</b> para la <i>tecla META</i>, \n
<string name="session_display_frame_rate">Tasa de fotogramas</string>
<string name="session_display_title">Pantalla</string>
<string name="session_display_fullscreen_stretched">Activar pantalla completa (estirada)</string>
<string name="session_display_direct_composition">Composición directa (sin copia)</string>
<string name="session_display_fps_label">FPS:</string>
<string name="session_display_renderer_label">Renderizador:</string>
<string name="session_display_gpu_label">GPU:</string>
Expand Down
1 change: 1 addition & 0 deletions app/src/main/res/values-fr/strings.xml
Original file line number Diff line number Diff line change
Expand Up @@ -618,6 +618,7 @@ Par ex. <b>META</b> pour la <i>touche META</i>, \n
<string name="session_display_frame_rate">Fréquence d\'images</string>
<string name="session_display_title">Affichage</string>
<string name="session_display_fullscreen_stretched">Activer le plein écran (étiré)</string>
<string name="session_display_direct_composition">Composition directe (zéro copie)</string>
<string name="session_display_fps_label">FPS :</string>
<string name="session_display_renderer_label">Moteur de rendu :</string>
<string name="session_display_gpu_label">GPU :</string>
Expand Down
1 change: 1 addition & 0 deletions app/src/main/res/values-hi/strings.xml
Original file line number Diff line number Diff line change
Expand Up @@ -730,6 +730,7 @@
<string name="session_display_frame_rate">फ़्रेम दर</string>
<string name="session_display_title">डिस्प्ले</string>
<string name="session_display_fullscreen_stretched">फ़ुलस्क्रीन सक्षम करें (खींचा हुआ)</string>
<string name="session_display_direct_composition">डायरेक्ट कंपोज़िशन (ज़ीरो-कॉपी)</string>
<string name="session_display_fps_label">FPS:</string>
<string name="session_display_renderer_label">Renderer:</string>
<string name="session_display_gpu_label">GPU:</string>
Expand Down
1 change: 1 addition & 0 deletions app/src/main/res/values-it/strings.xml
Original file line number Diff line number Diff line change
Expand Up @@ -618,6 +618,7 @@ Ad es. <b>META</b> per il <i>tasto META</i>, \n
<string name="session_display_frame_rate">Frequenza fotogrammi</string>
<string name="session_display_title">Display</string>
<string name="session_display_fullscreen_stretched">Abilita schermo intero (allungato)</string>
<string name="session_display_direct_composition">Composizione diretta (zero-copy)</string>
<string name="session_display_fps_label">FPS:</string>
<string name="session_display_renderer_label">Renderer:</string>
<string name="session_display_gpu_label">GPU:</string>
Expand Down
1 change: 1 addition & 0 deletions app/src/main/res/values-ko/strings.xml
Original file line number Diff line number Diff line change
Expand Up @@ -618,6 +618,7 @@
<string name="session_display_frame_rate">프레임 레이트</string>
<string name="session_display_title">디스플레이</string>
<string name="session_display_fullscreen_stretched">전체 화면 활성화 (늘림)</string>
<string name="session_display_direct_composition">다이렉트 컴포지션(제로 카피)</string>
<string name="session_display_fps_label">FPS:</string>
<string name="session_display_renderer_label">렌더러:</string>
<string name="session_display_gpu_label">GPU:</string>
Expand Down
1 change: 1 addition & 0 deletions app/src/main/res/values-pl/strings.xml
Original file line number Diff line number Diff line change
Expand Up @@ -624,6 +624,7 @@ Np. <b>META</b> dla <i>klawisza META</i>, \n
<string name="session_display_frame_rate">Częstotliwość klatek</string>
<string name="session_display_title">Wyświetlacz</string>
<string name="session_display_fullscreen_stretched">Włącz pełny ekran (rozciągnięty)</string>
<string name="session_display_direct_composition">Kompozycja bezpośrednia (zero-copy)</string>
<string name="session_display_fps_label">FPS:</string>
<string name="session_display_renderer_label">Renderer:</string>
<string name="session_display_gpu_label">GPU:</string>
Expand Down
1 change: 1 addition & 0 deletions app/src/main/res/values-pt-rBR/strings.xml
Original file line number Diff line number Diff line change
Expand Up @@ -618,6 +618,7 @@ Ex. <b>META</b> para <i>tecla META</i>, \n
<string name="session_display_frame_rate">Taxa de Quadros</string>
<string name="session_display_title">Tela</string>
<string name="session_display_fullscreen_stretched">Ativar Tela Cheia (Esticada)</string>
<string name="session_display_direct_composition">Composição direta (zero-copy)</string>
<string name="session_display_fps_label">FPS:</string>
<string name="session_display_renderer_label">Renderizador:</string>
<string name="session_display_gpu_label">GPU:</string>
Expand Down
1 change: 1 addition & 0 deletions app/src/main/res/values-ro/strings.xml
Original file line number Diff line number Diff line change
Expand Up @@ -618,6 +618,7 @@ De ex. <b>META</b> pentru <i>tasta META</i>, \n
<string name="session_display_frame_rate">Rata cadrelor</string>
<string name="session_display_title">Afisaj</string>
<string name="session_display_fullscreen_stretched">Activeaza ecran complet (intins)</string>
<string name="session_display_direct_composition">Compoziție directă (zero-copy)</string>
<string name="session_display_fps_label">FPS:</string>
<string name="session_display_renderer_label">Renderer:</string>
<string name="session_display_gpu_label">GPU:</string>
Expand Down
1 change: 1 addition & 0 deletions app/src/main/res/values-ru/strings.xml
Original file line number Diff line number Diff line change
Expand Up @@ -686,6 +686,7 @@
<string name="session_display_frame_rate">Частота кадров</string>
<string name="session_display_title">Экран</string>
<string name="session_display_fullscreen_stretched">Включить полноэкранный режим (растянутый)</string>
<string name="session_display_direct_composition">Прямая композиция (без копирования)</string>
<string name="session_display_fps_label">ФПС:</string>
<string name="session_display_renderer_label">Рендерер:</string>
<string name="session_display_gpu_label">GPU:</string>
Expand Down
1 change: 1 addition & 0 deletions app/src/main/res/values-uk/strings.xml
Original file line number Diff line number Diff line change
Expand Up @@ -624,6 +624,7 @@
<string name="session_display_frame_rate">Частота кадрів</string>
<string name="session_display_title">Дисплей</string>
<string name="session_display_fullscreen_stretched">Увімкнути повноекранний режим (розтягнутий)</string>
<string name="session_display_direct_composition">Пряма композиція (без копіювання)</string>
<string name="session_display_fps_label">FPS:</string>
<string name="session_display_renderer_label">Рендерер:</string>
<string name="session_display_gpu_label">GPU:</string>
Expand Down
1 change: 1 addition & 0 deletions app/src/main/res/values-zh-rCN/strings.xml
Original file line number Diff line number Diff line change
Expand Up @@ -618,6 +618,7 @@
<string name="session_display_frame_rate">帧率</string>
<string name="session_display_title">显示</string>
<string name="session_display_fullscreen_stretched">启用全屏(拉伸)</string>
<string name="session_display_direct_composition">直接合成(零拷贝)</string>
<string name="session_display_fps_label">FPS:</string>
<string name="session_display_renderer_label">渲染器:</string>
<string name="session_display_gpu_label">GPU:</string>
Expand Down
1 change: 1 addition & 0 deletions app/src/main/res/values-zh-rTW/strings.xml
Original file line number Diff line number Diff line change
Expand Up @@ -618,6 +618,7 @@
<string name="session_display_frame_rate">幀率</string>
<string name="session_display_title">顯示</string>
<string name="session_display_fullscreen_stretched">啟用全螢幕(拉伸)</string>
<string name="session_display_direct_composition">直接合成(零複製)</string>
<string name="session_display_fps_label">FPS:</string>
<string name="session_display_renderer_label">渲染器:</string>
<string name="session_display_gpu_label">GPU:</string>
Expand Down
1 change: 1 addition & 0 deletions app/src/main/res/values/strings.xml
Original file line number Diff line number Diff line change
Expand Up @@ -898,6 +898,7 @@ E.g. <b>META</b> for <i>META key</i>, \n
<string name="session_display_fps_label">FPS:</string>
<string name="session_display_renderer_label">Renderer:</string>
<string name="session_display_gpu_label">GPU:</string>
<string name="session_display_direct_composition">Direct Composition (zero-copy)</string>
<string name="session_display_ram_label">RAM:</string>
<string name="session_display_ram_usage_format">%1$s GB Used / %2$s Total</string>

Expand Down
37 changes: 37 additions & 0 deletions app/src/main/runtime/container/Container.java
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,27 @@ public class Container {
public static final String DEFAULT_GRAPHICSDRIVERCONFIG =
"vulkanVersion=1.3" + ";version=" + ";blacklistedExtensions=" + ";maxDeviceMemory=0" + ";presentMode=mailbox" + ";syncFrame=0" + ";disablePresentWait=1" + ";resourceType=auto" + ";bcnEmulation=auto" + ";bcnEmulationType=compute" + ";bcnEmulationCache=0" + ";gpuName=Device";
public static final String DEFAULT_DDRAWRAPPER = "none";

/**
* extraData JSON key for the per-container "Direct Composition" toggle.
* Stored as a string ("1"/"0") for symmetry with the rest of extraData.
* The setting is read at activity startup and applies for the whole
* session — it controls whether fullscreen drawables are pushed to a
* sibling Android SurfaceControl layer (zero-copy DPU scanout) instead of
* being composited by the VulkanRenderer. Changing it mid-game is not
* supported.
*
* <p>When enabled AND the device supports ASurfaceControl (API 29+) AND
* the device is not on the soft-boot blocklist (see SurfaceCompositor),
* the VulkanRenderer's per-frame hook extracts the AHardwareBuffer from
* the fullscreen direct-scanout candidate and hands it directly to
* SurfaceFlinger via ASurfaceTransaction_setBuffer. HWC promotes the
* layer to a DPU overlay plane — zero GPU compositing cost, zero buffer
* copy. This is the true zero-copy path.
*
* <p>When disabled (default), zero behavior change vs. pre-DC.
*/
public static final String EXTRA_DIRECT_COMPOSITION = "directComposition";
public static final String DEFAULT_WINCOMPONENTS = "direct3d=1,directsound=0,directmusic=0,directshow=0,directplay=0,xaudio=0,vcrun2010=1";
public static final String FALLBACK_WINCOMPONENTS = "direct3d=1,directsound=1,directmusic=1,directshow=1,directplay=1,xaudio=1,vcrun2010=1";
public static final String DEFAULT_DRIVES = "D:" + Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_DOWNLOADS).getAbsolutePath() + "F:" + Environment.getExternalStorageDirectory().getAbsolutePath();
Expand Down Expand Up @@ -299,6 +320,22 @@ public String getLanguage() {
return getExtra("containerLanguage", "english");
}

/**
* Whether this container should route fullscreen direct-scanout drawables
* to a sibling Android SurfaceControl layer (HWC overlay plane / DPU
* scanout) instead of having VulkanRenderer composite them. Default off.
*
* <p>Sampled once at activity startup and held for the session. Toggling
* has no effect on a running game; the user must relaunch the container.
*/
public boolean isDirectCompositionEnabled() {
return "1".equals(getExtra(EXTRA_DIRECT_COMPOSITION, "0"));
}

public void setDirectCompositionEnabled(boolean enabled) {
putExtra(EXTRA_DIRECT_COMPOSITION, enabled ? "1" : "0");
}

public String getExtra(String key) {
return getExtra(key, "");
}
Expand Down
Loading