Skip to content

AHB fix plus placed-memmory - #10

Merged
utkarshdalal merged 3 commits into
GameNative:wrapper-25from
abesmon:fix/pr-ahb-plus-placed
Aug 30, 2026
Merged

AHB fix plus placed-memmory#10
utkarshdalal merged 3 commits into
GameNative:wrapper-25from
abesmon:fix/pr-ahb-plus-placed

Conversation

@abesmon

Copy link
Copy Markdown
Contributor

TLDR: this one fixes AHB problems (very broken image) plus fixes black screen.

This fix primarely made for nintendo switch running android, but i've tryed to made it as much platform indepedent as i can. This Was heavily tested with dozens of A/B on my switch, but never tested on aby other devices, since i dont have one


Summary

This series fixes two independent omissions encountered when a direct Android
hardware-buffer swapchain is used together with the wrapper's emulated placed
memory maps:

  1. release exclusive direct-swapchain images to
    VK_QUEUE_FAMILY_FOREIGN_EXT before the Android consumer uses them;
  2. retain VkMemoryAllocateInfo::allocationSize in the wrapper memory object
    used by placed mappings.

The commits are kept separate so each invariant and its gating can be reviewed
independently.

1. Release direct AHardwareBuffer images

The Android hardware-buffer specification treats Android producers and
consumers as foreign devices for ownership transfer. Vulkan's queue-family
rules require explicit ownership transfer for external resources; without it,
reads by the second queue family have undefined contents even if memory
dependencies were otherwise expressed.

The first commit pre-records a release command for every usable queue family
and submits the matching command during present. It uses GENERAL as the
shared external layout and a generic memory-write source dependency because
WSI cannot know which application pipeline stage produced the image.

The behavioral change is structurally restricted to Android swapchain images
which are all of the following:

  • backed directly by an AHardwareBuffer (WSI_SWAPCHAIN_NO_BLIT);
  • created with VK_SHARING_MODE_EXCLUSIVE;
  • presented through this Android WSI path.

Concurrent images are excluded because legacy VkImageMemoryBarrier does not
permit the same foreign-family transfer for concurrent sharing, and blit
swapchains keep their existing presentation command path. There is no device,
vendor, application, or Switch-specific check.

Specification references:

2. Retain allocation size for placed mappings

wrapper_device_memory::alloc_size is already used to select the backing fd of
a multi-fd AHardwareBuffer and to resolve VK_WHOLE_SIZE, but the emulated
allocation path leaves it zero-initialized. That makes the first seekable
metadata fd look large enough and can produce a successful, truncated mapping.

The second commit stores the authoritative
VkMemoryAllocateInfo::allocationSize when that wrapper memory object is
created. This is a one-line bookkeeping fix. The existing control flow limits
it to the host-visible placed-allocation emulation path with
memoryMapPlaced/VK_EXT_map_memory_placed enabled. Imported, exported,
non-host-visible, and ordinary driver mappings keep their previous behavior.

This also matches the extension's model: VK_WHOLE_SIZE means the remainder of
the Vulkan allocation, and placed-map validity and reservation size are defined
using VkMemoryAllocateInfo::allocationSize.

Specification references:

Validation

Tested on an NVIDIA Tegra X1 Android device with the proprietary Vulkan ICD.
Every visual verdict below was checked on the physical display; exit status and
FPS were not used as corruption oracles.

Controlled A/B for AHardwareBuffer ownership, five runs per cell:

WorkloadParentWith release
Vulkan 64-bit0/5 correct5/5 correct
DX9 64-bit0/5 correct5/5 correct

Controlled production A/B for placed mapping, DX9 32-bit, five runs per arm:

BuildVisual resultSelected map size
assignment removed0/5 correct4096 bytes (metadata fd)
assignment present5/5 correct16777216 bytes (backing fd)

Final two-commit interaction smoke:

  • Vulkan 64-bit: correct image, exit 0;
  • DX9 64-bit: correct image, exit 0;
  • DX9 32-bit: correct image, exit 0;
  • instrumented last process recorded three 16 MiB placed maps, two direct
    no-blit swapchains, and six ownership-release barrier recordings.

For every evidence-producing run, the wrapper SHA in the container imagefs was
matched to the build artifact and a unique WRAPPER_LOG_FILE canary plus the
launcher's final guest environment confirmed that the intended binary and
configuration executed.

The direct AHardwareBuffer path exports exclusive swapchain images without releasing queue-family ownership to VK_QUEUE_FAMILY_FOREIGN_EXT. On drivers with private render-target layouts, an external importer can therefore observe unresolved or compressed contents.
Pre-record one release barrier per usable queue family and submit it with present. Use GENERAL as the shared layout and a generic memory-write source dependency because WSI cannot know how the application produced the image.
Restrict the change to exclusive, non-blit Android images: legacy VkImageMemoryBarrier does not permit FOREIGN_EXT transfers for concurrent images, and the image-blit path has separate presentation commands.
wrapper_device_memory::alloc_size is used to select the backing AHardwareBuffer fd and to resolve VK_WHOLE_SIZE, but it is left zero-initialized. With a multi-fd AHardwareBuffer this accepts the first seekable metadata fd even when it is smaller than the Vulkan allocation, producing a successful but truncated mapping.
Retain the authoritative VkMemoryAllocateInfo::allocationSize when the wrapper creates its placed-memory object. The change remains inside the existing host-visible VK_EXT_map_memory_placed allocation path; imported, exported, non-host-visible, and ordinary driver mappings are unchanged.
@utkarshdalal

Copy link
Copy Markdown
Contributor

Thanks, really solid work, the alloc_size fix is a clear bug fix

On the release barrier: it changes the present path for every device on the direct no-blit path, and on Adreno the PRESENT_SRC -> GENERAL transition may force UBWC decompression, which we can't easily verify across our device base. Could you gate the info->finish_create assignment in wsi_configure_android_image on driverID == VK_DRIVER_ID_NVIDIA_PROPRIETARY (plumbed through wsi_device)? Spec-wise the barrier is probably right everywhere, but I'd rather widen the allowlist as devices prove they need it than risk a fleet-wide regression. Also please drop the per-image "Recorded AHB ownership release barriers" log to debug level.

@abesmon

Copy link
Copy Markdown
ContributorAuthor

just for future generations: this is how bad release look like
IMG_9107

I think it could help somebody in future, if similar problem occur

Restrict the default AHB ownership release path to NVIDIA's proprietary driver to avoid changing direct no-blit presentation on unvalidated devices.\n\nAdd WRAPPER_AHB_OWNERSHIP_RELEASE as a tri-state override: unset follows the driver default, true opts other drivers in, and false provides a kill switch. Move the per-image success message to Mesa's debug logger.
@abesmon

abesmon commented Aug 30, 2026

Copy link
Copy Markdown
ContributorAuthor

@utkarshdalal i've pushed update with logs and ENV vars.

now its working this way:

WRAPPER_AHB_OWNERSHIP_RELEASEEffective policyVisual result
unsetNVIDIA default: enabledboth correct
falseforced disabledexpected artifacts in both
trueforced enabledboth correct

Sign up for freeto 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.

2 participants

@abesmon@utkarshdalal