Skip to content

fix(vulkan): avoid stale dynamic UBO offsets for promoted inline constants - #809

Open
hzqst wants to merge 5 commits into
DiligentGraphics:masterfrom
hzqst:fix-promoted-ubo-dynamic-offsets
Open

hzqst wants to merge 5 commits into
DiligentGraphics:masterfrom
hzqst:fix-promoted-ubo-dynamic-offsets

Conversation

@hzqst

@hzqst hzqst commented Sep 28, 2026

Copy link
Copy Markdown
Contributor

Fixes #808.

Problem

A Vulkan inline constant resource promoted to push constants still occupies a dynamic UBO descriptor slot. Its fallback buffer is not mapped, but descriptor binding previously queried its dynamic offset anyway. If the buffer's recycled ID belonged to a mapped vertex buffer, that query could return a stale offset that violates minUniformBufferOffsetAlignment, producing VUID-vkCmdBindDescriptorSets-pDynamicOffsets-01971 even when GPU output is correct.

Fix

  • Read the current pipeline layout's PushConstantInfo during descriptor-set commitment.
  • Resolve the selected resource through the actually bound SRB cache, using the pipeline signature's descriptor-set and cache indices. This also handles SRBs created from a different compatible signature instance.
  • Pass that resource to WriteDynamicBufferOffsets and emit zero only for its unused fallback UBO.
  • Preserve the dynamic descriptor slot, offset count, and offset-change tracking. Ordinary dynamic UBOs, storage buffers, and inline constants using UBO emulation keep their normal offsets.

Re-evaluating the selection for the current pipeline is essential: the same SRB may alternate between push constants and UBO emulation.

Regression coverage

Adds two Vulkan cases in Tests/DiligentCoreAPITest/src/InlineConstantsTest.cpp:

  • InlineConstants.VulkanPromotedUBORecycledDynamicOffset
  • InlineConstants.VulkanPromotedUBOCompatibleSRB

Both establish a uniform-aligned mapped allocation anchor, then map a small vertex buffer and explicitly verify that its mapped-address difference from the anchor is not UBO-aligned. Releasing that buffer immediately before creating the inline constant signature makes its fallback UBO reuse the poisoned dynamic buffer ID. This avoids assuming a fresh context or a particular absolute heap offset. Devices whose vertex-buffer alignment already satisfies UBO alignment are explicitly skipped.

The first dispatch promotes B to push constants, leaving its recycled fallback UBO unmapped. Without the fix, descriptor binding reports VUID 01971. The existing GPU test environment enables Vulkan validation and converts unexpected validation errors into test failures; the tests do not allow or suppress this error.

Each case then alternates four dispatches between:

  1. B as push constants.
  2. A as push constants, with the same B SRB using UBO emulation.

Inline values and an ordinary dynamic UBO change between dispatches. GPU readback checks A, B, the ordinary UBO, and their combined result for every dispatch. This catches blanket offset-zeroing and incorrect handling of pipeline changes. The second case uses separate compatible signature instances for the PSOs and the bound B SRB, covering resolution through the bound cache.

Validation

Windows x64 Debug; RTX 5060, driver 610.88; Vulkan/Khronos validation 1.4.350:

  • Built DiligentCoreAPITest successfully.
  • Temporarily restored the original unconditional UBO offset-writing logic: 20/20 targeted case executions failed with VUID 01971 across 10 independent processes with randomized case order. The observed offset was 68 with a required alignment of 64. Explicit DXC reproduced the same error in both cases.
  • Restored the fix: the InlineConstants.* suite passed 11/11, including GPU readback and no validation errors.
  • Explicit DXC, randomized order, 10 repetitions: 20/20 targeted case executions passed, with no validation errors.
  • Final branch verification: InlineConstants.*:UpdateTextureFromBuffer.* passed 16/16; git diff --check passed.

Run from Tests/DiligentCoreAPITest/assets:

DiligentCoreAPITest.exe --mode=vk --gtest_filter=InlineConstants.VulkanPromotedUBO*
DiligentCoreAPITest.exe --mode=vk --shader_compiler=dxc --gtest_filter=InlineConstants.VulkanPromotedUBO* --gtest_repeat=10 --gtest_shuffle --gtest_random_seed=42

For repeated without-fix verification, launch separate processes: Khronos validation may stop reporting a repeated VUID after its duplicate-message limit is reached. The temporary negative-test backend changes are not included in this PR. Release, other GPUs, and other backends were not validated for this change.

hzqst and others added 3 commits September 28, 2026 15:46
…UBO offsets after buffer ID reuse. A fix need to be applied to `WriteDynamicBufferOffsets` to mitigate the issue.
Keep the existing upstream UpdateTexture implementation when fixing promoted inline constant offsets.

Co-Authored-By: Codex <codex@openai.com>
Seed a provably misaligned vertex allocation before recycling its dynamic buffer ID into an inline UBO. Cover compatible SRBs, pipeline-specific push constant selection, UBO emulation, and ordinary dynamic UBO updates with GPU readback and Vulkan validation.

Co-Authored-By: Codex <codex@openai.com>
hzqst and others added 2 commits September 28, 2026 16:19
Co-Authored-By: Codex <codex@openai.com>
Co-Authored-By: Codex <codex@openai.com>
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.

Vulkan: promoted inline constants can bind stale dynamic UBO offsets after buffer ID reuse

1 participant