Skip to content

vulkan: end the HDR UI layer's render pass when a shader is loaded - #19946

Merged
LibretroAdmin merged 2 commits into
libretro:masterfrom
Davey-Hughes:vulkan-hdr-ui-pass
Oct 30, 2026
Merged

LibretroAdmin merged 2 commits into
libretro:masterfrom
Davey-Hughes:vulkan-hdr-ui-pass

Conversation

@Davey-Hughes

Copy link
Copy Markdown
Contributor

With HDR on and a slang preset loaded, vulkan_frame() leaves the UI layer's render pass open whenever something is drawn over the game (menu, overlay, notification, statistics). The game pass ends the main pass and clears end_main_pass. The UI layer then begins sdr_render_pass on the off-screen buffer, and with end_main_pass still false nothing ends it. The HDR composite then records its barriers and begins its own render pass inside the open one.

This sets end_main_pass once that pass is begun, so the existing vkCmdEndRenderPass closes it. HDR without a shader and SDR with one already ended the pass and are unchanged.

Testing

No Android device here gives an HDR10 swapchain. An AYN Thor on Android 13 offers no HDR10 surface format, and RetroArch falls back to SDR there. So this was checked on Linux instead:

without this commit with it
HDR10, no shader clean clean
HDR10, 2-pass preset, applied twice VUID-vkCmdBeginRenderPass-renderpass once and VUID-vkCmdPipelineBarrier-None-07889 twice per frame with UI clean
HDR10, 2-pass preset, menu open same clean
HDR10, crt-gdv-mini-ultra alone same clean
scRGB, 2-pass preset same clean
SDR, 2-pass preset clean clean

The scRGB, SDR and single-pass runs without the commit were on 83edb80. The rest were run on this base, 770391e. GPU-assisted validation found nothing more. RADV draws these frames correctly either way, and with the commit the game and the menu still draw.

The four CI jobs that name vulkan.c (compile-matrix, samples-formats, samples-gfx, linux-vulkan-resize) pass locally, and vulkan.c builds clean with C89_BUILD=1.

Related Issues

#19699: on an Adreno 830 tablet (Android 16), Vulkan + HDR + any slang shader gives VK_ERROR_DEVICE_LOST. The touch overlay is on by default on Android, so every frame there takes this path. This is the likely cause, but it hasn't been confirmed on that device yet.

Davey-Hughes and others added 2 commits October 29, 2026 21:23
With HDR on and a shader preset loaded, the game pass ends the main
render pass and clears end_main_pass. When the menu, an overlay, a
message or a widget is drawn on top, the UI layer then begins
sdr_render_pass on the off-screen buffer, and with end_main_pass still
false nothing ends it. The composite that follows records its barriers
and begins the next render pass inside it, which Vulkan does not allow
(VUID-vkCmdBeginRenderPass-renderpass,
VUID-vkCmdPipelineBarrier-None-07889).

RADV draws these frames correctly anyway. On Android the touch overlay
is on by default, so every frame takes this path, and it is the likely
cause of the lost device in libretro#19699 (HDR plus any shader on an Adreno
tablet).
No CI lane ran the Vulkan driver with an HDR swapchain: lavapipe on X11
has no HDR10 surface format. So nothing saw the UI layer's render pass
left open under the composite whenever a shader preset and any UI met,
which the previous commit fixes.

samples/gfx/vulkan_hdr_ui_pass runs the shipping frontend from the
VULKAN_DEBUG=1 build on lavapipe under an Xvfb of depth 30, which gives
the surface a real 10-bit format. A layer, fake_hdr_layer.c, reports
that format a second time paired with HDR10_ST2084 and passes an HDR10
swapchain on in sRGB with the same format and images. The driver then
selects HDR10 and takes its whole HDR path; what it records is
unchanged.

The cases: a two-pass preset with the menu open, with the statistics,
and with an OSD message; the menu case again on the video thread; and
the controls, the preset with no UI and the menu with no preset. Each
must create an HDR10 swapchain and log the HDR game pass and composite
pass it is meant to take, so a run that fell back to SDR, or did not
draw the UI, fails rather than passing vacuously. Any validation error
fails a case.

Without the previous commit, the four preset-plus-UI cases fail with
VUID-vkCmdPipelineBarrier-None-07889 and
VUID-vkCmdBeginRenderPass-renderpass, the two errors in the report; the
controls pass either way. It runs in the Vulkan validation workflow's
harness job, which already builds the tree VULKAN_DEBUG=1.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01LBQPGctE3xjHw1i9kE5EzK
@LibretroAdmin
LibretroAdmin merged commit 3195d95 into libretro:master Oct 30, 2026
119 of 121 checks passed
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.

2 participants