Skip to content

Request UBWC-compressed swapchain buffers on Adreno - #3

Open
Leb-Sun wants to merge 17 commits into
mainfrom
ubwc-swapchain-usage
Open

Request UBWC-compressed swapchain buffers on Adreno#3
Leb-Sun wants to merge 17 commits into
mainfrom
ubwc-swapchain-usage

Conversation

@Leb-Sun

@Leb-Sun Leb-Sun commented Aug 5, 2026

Copy link
Copy Markdown
Owner

Stacked on #2 (aimapper backend) so a build from this branch carries both fixes. #2 stays clean for possible upstreaming; this one is deliberately vendor-specific and is not.

Evidence

Paired same-session SurfaceFlinger captures on an A840, GameSpace frame generation ON / upscaling OFF, -b driver both runs:

system Adreno driver : usage 0x10000b00   12852 KiB   compressed: true
Turnip               : usage 0x00000b00   12768 KiB   compressed: false
                             ^^^^^^^^^

12768 KiB is 1216x2688x4 exactly — linear, no metadata. 12852 KiB is that plus the UBWC metadata plane. Stable across all 3 samples in both runs. Every other buffer on the device carries 0x10000000; only Turnip's swapchain buffer lacks it.

Layer state is byte-identical between the two runs — same dataspace=0x10810000, same composition=DEVICE (2). The buffer is the entire difference.

0x10000000 is Qualcomm's private "allocate UBWC" gralloc usage bit. Mesa sets no vendor usage bits anywhere today (vk_android.c knows only HW_RENDER and HW_TEXTURE), so Turnip has never asked for compression and gralloc had no reason to grant it.

Why not the standard route

VK_EXT_image_compression_control is the vendor-neutral mechanism, and vk_android.c:317 has a TODO pointing at it. It does not help: that extension exists for an application to request compression, and WinNative/DXVK never will. The blob does not wait to be asked — it compresses by default. Matching that is a driver default, not an app-facing option.

Gating

0x10000000 lives in AIDL BufferUsage's VENDOR_MASK (bits 28-31), so it means whatever each vendor decides. This build only ever contains freedreno (-Dvulkan-drivers=freedreno), so the bit can only be emitted from Turnip's own ANDROID_native_buffer entry points. Both are covered, since which one Android 16 calls is not established.

A better long-term gate is the detected gralloc vendor — the aimapper backend from #2 already knows it loaded mapper.qti.so. Worth doing if this proves out; not worth the plumbing before we know the bit helps.

Unproven

  • The frame-gen hypothesis is untested. UBWC-vs-linear is the only meaningful difference left, and the bandwidth argument is coherent (interpolation reads two frames per output frame where upscaling reads one; UBWC roughly halves that). "Only remaining difference" is not "cause".
  • Forcing UBWC may break formats that cannot be compressed. Gralloc should reject or ignore rather than misrender, but that is not verified on this device. Normal gameplay with all GameSpace features off is the check.

3 lines of code; the rest of the diff is comment. Patch is idempotent and aborts rather than writing a broken tree if the #define anchor drifts while a use still applies.

Leb-Sun added 4 commits August 4, 2026 02:31
Upstream hardcodes tu_autotune_algorithm=prefer_sysmem for DXVK/vkd3d, which
is an unconditional early return collecting no metrics -- on A8xx it disables
tiled rendering outright, leaving 18MB of GMEM unused. That default suits parts
with 1-3MB of GMEM, not A840.

The eco variant defaults A8xx to the adaptive bandwidth autotuner, logs the
GMEM budget under TU_DEBUG=startup, and exposes TU_ECO_DEPTH_CACHE_KB and
TU_ECO_GMEM_BW_NUM so the GMEM trade can be swept on-device rather than
costing a build per value. All changes are A8xx-gated.

TU_ECO_DEPTH_CACHE_KB accepts only 64/128/192/256: the CCU depth cache is
described both by a fraction enum (which programs RB_CCU_CACHE_CNTL) and by a
byte size (which drives the GMEM offset maths), and the two must agree or the
hardware writes cache lines over tile memory. Confirmed on an A840 --
gmem_size=18874368, usable=16564224, 674 blocks; 192 KB yields 690 blocks,
enough to fit a tile-aligned 1080p colour+depth pass in one tile instead of two.

CI gains a variants input for partial builds and a publish input defaulting to
false, so screening builds produce artifacts without tagging a release. The
patch-drift check greps case-sensitively; case-insensitive matched clang's
ordinary "warning:" output and fired on every build.
@Leb-Sun
Leb-Sun force-pushed the ubwc-swapchain-usage branch from 014aa4c to 64fde8b Compare August 5, 2026 16:32
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant