Let a container serve both D8VK and Zink on a pre-1.2 ICD - #13
Merged
Conversation
A global WRAPPER_VK_VERSION can be necessary for one compatibility layer while exposing that same raised version changes another engine's feature-query ABI beyond what the base driver accepts. Add a generic override selected by exact VkApplicationInfo engine name through WRAPPER_ENGINE_NAME and WRAPPER_ENGINE_VK_VERSION. Both variables must be present, so existing behavior is unchanged by default. Exact matching avoids silently catching unrelated engines.
Lower the Vulkan 1.3 commands needed by legacy consumers to supported extension or Vulkan 1.2 paths, and add an opt-in imageless-framebuffer compatibility path. Keep both compatibility layers disabled unless explicitly requested, and only expose them when the base driver lacks the native capability.
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.
Two control points and one emulation. All off by default — with no
environment set, this changes nothing for any driver.
Motivation
Newer D8VK calls Vulkan 1.3 core entry points. On a Vulkan 1.1 ICD those function
pointers do not exist, and calling one surfaced in 32-bit Wine as an assertion in
loader_thunks.crather than a useful Vulkan error. A container can report ahigher core version, but then the wrapper must actually lower the calls that
version implies.
The catch: raising the reported version raises it for every client, and Zink
changes ABI at Vulkan 1.2. Above it, it requests features through the
VkPhysicalDeviceVulkan12Features/Vulkan13Featuresaggregates instead of theextension feature structs an older ICD understands — and
process_pnext_chaindrops an aggregate the base driver is too old to have. So the moment D3D8 works,
OpenGL stops.
That is why these ship together: raising the version for D8VK is what creates the
need for a per-engine version control point, and reporting 1.1 to Zink is what
makes it ask for
VK_KHR_imageless_framebufferas an extension the driver lacks.Technical basis
Vulkan 1.3 promoted
VK_KHR_synchronization2(vkQueueSubmit2),VK_EXT_extended_dynamic_stateand…state2, andVK_KHR_dynamic_rendering.Vulkan 1.2 promoted
VK_KHR_imageless_framebuffer.See the promotion table.
A promoted entry point is only guaranteed where the core version is. The 1.1-era
ICD here still exposes the pre-promotion EXT entry points, so the lowering
enables the EXT names by name and routes core calls to them; where no EXT
equivalent exists (
vkQueueSubmit2), it translates to the legacy operation.Before / after
vkQueueSubmit2VK_ERROR_FEATURE_NOT_PRESENTWhy this shape
The wrapper decides nothing; the container operator does. This ends a chain of
narrowing guesses — an earlier revision inspected
driverIDand picked a versionitself, a later one hardcoded a zink-named variable, this one removes the
guessing:
Both variables are required, so an unset knob is identical to the code being
absent. The match is an exact
strcmp, not a substring, so no unrelated engineis silently caught and no engine is named in the code — the Zink case is one
instantiation, not the mechanism.
That is also the whole platform-safety argument: there is no default to regress.
The diff was audited hunk by hunk for this, and three places that ran regardless
of the knobs were brought behind them — the
pNextunlink of the imagelessfeature (keyed on the driver's extension list, it would have stripped a
legitimate request on a 1.2 driver supporting the feature as core), the
command-buffer walk in
ResetCommandPool, and the per-view hash insert inCreateImageView.Flags, including for non-NVIDIA
Nothing is driver-gated. Any driver hitting the same gaps can opt in.
WRAPPER_EMULATE_VULKAN_1_3=1WRAPPER_ENGINE_NAME+WRAPPER_ENGINE_VK_VERSIONWRAPPER_EMULATE_IMAGELESS_FRAMEBUFFER=1VK_KHR_imageless_framebufferand the driver lacks it.The Tegra configuration, as a worked example:
Note the escaped space.
WRAPPER_ENGINE_NAMEis an exact match and Zink'sengine name is
mesa zink; in a launcher whose environment field isspace-separated, writing it unescaped silently yields
WRAPPER_ENGINE_NAME=mesaand the override never fires. Each control point logswhen it engages, which is how to confirm it took:
Evidence
Switch v1, Tegra X1, NVIDIA proprietary 111.0.0 (Vulkan 1.1). Necessity was
measured by toggling one binary — an unset knob equals the commit being absent,
so this removes build variance. Removing each in turn: D3D8 drops to a blank
window at 3 FPS; Balatro goes black at 0 FPS; Balatro exits at
CreateGraphicsPipelines. For the first, diffing enabled device extensionsbetween arms shows exactly
VK_EXT_extended_dynamic_stateand…state2.No regression elsewhere: 21-point render matrix, three passes, against the
preceding upstream build — 21/21, and D3D9/D3D10/D3D11 unmoved in both bitnesses.
Limitations
QueueSubmit2lowering forwardspNextinto alegacy
VkSubmitInfowithout proof that sync2-only chains are filtered orabsent; dynamic-rendering lowering has no full depth/stencil resolve; colour
attachments are capped at eight. It is a shim for the calls D8VK makes.
why nothing is on by default.