Skip to content

win32u: Don't override vendor and device IDs that don't match a fixup - #368

Open
djdisodo wants to merge 1 commit into
ValveSoftware:proton_11.0from
slopization:proton_11.0_vkid
Open

djdisodo wants to merge 1 commit into
ValveSoftware:proton_11.0from
slopization:proton_11.0_vkid

Conversation

@djdisodo

Copy link
Copy Markdown

fixup_device_id_vulkan() passes the ids through struct pci_id so the existing fixup can match them, but then copies the struct back unconditionally. The wider Vulkan value is narrowed to 16 bits on the way in, which is harmless while it is only used for matching, and becomes a silent identity change once it is published again.

On hardware whose Vulkan IDs don't fit in 16 bits this rewrites the reported identity, e.g. Qualcomm's 0x43050a01 becomes 0x00000a01.

Vulkan expects the application to validate cached pipeline data against the device: VkPipelineCacheHeaderVersionOne stores the vendor ID, device ID and pipelineCacheUUID of the device that produced it, and data whose header does not match is meant to be discarded. With the reported IDs altered, such an application discards its cache and recompiles every pipeline on each run.

This was observed with Unity - a 2021.3.34f1 reference build and a shipping 2021.3.34f5 title both compare all four header fields and log "Vulkan PSO: Invalid vulkan pipeline cache header, skipping save to disk" - but the check follows directly from the header layout and is not specific to that engine.

The WINE_HIDE_*_GPU options only deal with 16-bit PCI identities, so the narrowing is lossless wherever they can apply; writing the values back only when the fixup matched confines it to those cases.

fixup_device_id_vulkan() passes the ids through struct pci_id so the
existing fixup can match them, but then copies the struct back
unconditionally.  The wider Vulkan value is narrowed to 16 bits on the
way in, which is harmless while it is only used for matching, and
becomes a silent identity change once it is published again.

On hardware whose Vulkan IDs don't fit in 16 bits this rewrites the
reported identity, e.g. Qualcomm's 0x43050a01 becomes 0x00000a01.

Vulkan expects the application to validate cached pipeline data against
the device: VkPipelineCacheHeaderVersionOne stores the vendor ID, device
ID and pipelineCacheUUID of the device that produced it, and data whose
header does not match is meant to be discarded.  With the reported IDs
altered, such an application discards its cache and recompiles every
pipeline on each run.

This was observed with Unity - a 2021.3.34f1 reference build and a
shipping 2021.3.34f5 title both compare all four header fields and log
"Vulkan PSO: Invalid vulkan pipeline cache header, skipping save to
disk" - but the check follows directly from the header layout and is not
specific to that engine.

The WINE_HIDE_*_GPU options only deal with 16-bit PCI identities, so the
narrowing is lossless wherever they can apply; writing the values back
only when the fixup matched confines it to those cases.

Signed-off-by: sodo <djdisodo@gmail.com>
@djdisodo

Copy link
Copy Markdown
Author

there are more things that might break shader caching

A. Legacy properties path skips the override — fix

win32u_vkGetPhysicalDeviceProperties() returns host values unmasked when the instance
lacks VK_KHR_get_physical_device_properties2; ...Properties2 masks them. Same device,
two identities, depending on the entry point.

    physical_device->instance->p_vkGetPhysicalDeviceProperties( ..., properties );
    fixup_device_id_vulkan( &properties->vendorID, &properties->deviceID );
    return;

B. UUID/LUID structures

get_physical_device_properties2() uses the real deviceUUID to derive the Windows
LUID and node mask. A substituted UUID breaks that mapping and desynchronises the
cache header's UUID, with no way to repair either

C. Pipeline cache header

The header carries the driver's real ids and UUID; the properties report the masked ones,
so any validating application discards its cache every run.

Coherent masking needs rewrite-on-read and restore-on-write — the driver validates
initialData itself, so a one-way rewrite makes caches silently useless rather than
merely inconsistent. That is editing driver-owned data and breaks on driver changes.

with the override active, caches cannot be reused.

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