Fixed and updated model 0 and model 1 for framegen with clean-room re… - #8
Open
utkarshdalal wants to merge 2 commits into
Open
Fixed and updated model 0 and model 1 for framegen with clean-room re…#8utkarshdalal wants to merge 2 commits into
utkarshdalal wants to merge 2 commits into
Conversation
teldommm
pushed a commit
to teldommm/bionic-fg
that referenced
this pull request
Jul 29, 2026
…ndroid wrapper ICDs (Winlator/Turnip) (xXJSONDeruloXx#6) * fix(manifest): declare disable_environment so implicit-layer loaders don't skip the layer The Vulkan spec requires an implicit layer manifest to declare BOTH enable_environment and disable_environment. With only enable_environment, strict loaders (e.g. the glibc Khronos loader used inside Winlator-style wrapper-ICD setups) reject the layer at manifest-parse time: Layer "VK_LAYER_BIONIC_framegen" doesn't contain required layer object disable_environment in the manifest JSON file, skipping this layer Add disable_environment (BIONIC_FG_DISABLE=1) to satisfy the spec so the layer is actually discovered and loaded. * feat: single-device mode + layer-dispatch routing for Android wrapper ICDs Makes the frame-gen layer work on Android Winlator-style wrapper ICDs (wrapper_icd -> Turnip via adrenotools), where the original standalone second-device design hangs/crashes. Changes: - Single-device FramegenContext: run interpolation on the application's OWN VkDevice (vk::Device::wrap of the app instance/physical/device/queue) instead of spinning a second VkInstance+VkDevice and doing cross-device AHB sharing. The two-device path deadlocked on this stack (compute submit / queue-wait across distinct wrapper-ICD instances never completes). JNI standalone path keeps the original Device::create(). - Route physical-device queries through the layer's device/instance dispatch (memPropsFn from nextGIPA) instead of global vkXxx symbols. Global calls with chain-level handles from inside a layer can be rejected as invalid (the same hazard CreateDevice already guards against), which was crashing AHB import (vkGetPhysicalDeviceMemoryProperties). - Bound the present-path fence waits (UINT64_MAX -> 250ms) at all three wait sites: on a timeout, present the real frame (no hang); after 2 consecutive timeouts, disable framegen for that swapchain so the app runs full speed instead of stuttering into an ANR. - Remove two *instance* extensions (VK_KHR_external_memory_capabilities, VK_KHR_get_physical_device_properties2) wrongly listed in the device-ext array kRequiredDeviceExts[]; they always reported 'Device ext not available' (harmless, filtered before vkCreateDevice, but misleading). - Add an optional fps_limit (conf.toml key / BIONIC_FG_FPS_LIMIT env, 0=off, 10..200): paces the application's real present calls so on-screen FPS = limit x multiplier; generated frames bypass the pacer. Works in passthrough too. Verified on-device (Adreno 750, Turnip, DXVK 2.4.1): 2x/3x/4x frame gen and the fps limiter all working, no hangs. * fix(layer): track copy and generated-frame fence timeouts separately Addresses review: the shared fenceTimeouts counter was reset on every copy- fence success, before the generated-frame fence waits. At 2x a single generated timeout bumped it to 1, then the next frame's successful copy reset it to 0, so the disable-after-two-timeouts behaviour could never trigger for generated frames. Split into copyFenceTimeouts / genFenceTimeouts, each reset only when a fence of its own type signals; framegen is disabled once either reaches the threshold. * feat(layer): split sync-incompatibility timeout from generated-frame cadence deadline Addresses review (250ms arbitrary / could mis-fire on a legitimately slow frame; the generated-frame skip is really hang-recovery): - Replace the fixed 250ms wait with a generous sync-incompatibility timeout scaled off the frame budget (4x base interval, clamped 200ms..1s) when an fps limit is set, else a 500ms fallback. Bounded waits always return so ANR can't happen regardless; the timeout only governs how long before a never-signaling path is judged stuck. - Raise the consecutive-timeout disable threshold 2 -> 6 so transient slow frames (shader compilation, queue backlog) don't permanently disable framegen. - Give generated frames a separate, shorter cadence deadline (~2x the target output interval = 1s/(base*mult)) when an fps limit is set: a frame that misses it is skipped to hold pace and is NOT counted as a sync failure; only a timeout at the full sync bound counts toward disabling. * feat(layer): review follow-ups — self-describing fps cap, variance-aware cadence, opt-in derive/even-pace Addresses PR xXJSONDeruloXx#6 review threads: - C (fps_limit:211 / xXJSONDeruloXx#8): split fps_limit_enabled bool from the remembered fps_limit value so conf.toml is self-describing; respect any positive value (10-200 is a frontend convenience, no longer clamped in the layer). Back-compat: a config without fps_limit_enabled treats fps_limit>0 as enabled. - B/derive (1093): the budget-derived sync-incompatibility timeout is now opt-in (derive_sync_timeout, default off -> fixed 500ms fallback) since deriving at init is unreliable. - B/cadence (1334): generated-frame deadline is now variance-aware — derived from a measured base-interval EWMA (a cap is a ceiling, not a perf promise) with a 1.5x tolerance band, so a slightly-late frame is still presented and only a big overrun is skipped to hold pace. - D (1200): opt-in even_pace flag spaces generated presents across the base interval at 1s/(base*mult); off by default. - E (manifest:17): document that disable_environment is loader-required for implicit layers and not a second toggle. * fix(layer): make sync-failure force-disable sticky vs conf hot-reload A swapchain auto-disabled after kMaxFenceTimeouts stored the kill in conf.enabled, which the hot-reload path overwrites wholesale from the file (st.conf = newConf). So any conf.toml touch — notably the in-game flow-scale slider — silently re-armed framegen on a present path already proven sync-incompatible with the ICD. Split the runtime kill into a sticky SwapState::framegenForceDisabled that hot-reload never clears; the QueuePresent gate honours it, and the clean re-attempt point stays a swapchain recreate (fresh SwapState defaults it false). Answers PR xXJSONDeruloXx#6 review thread on layer.cpp:1093 (within-session recovery).
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
…write (#1)