From e33fd247249edccb1149b9f0efc479bd0174e37b Mon Sep 17 00:00:00 2001 From: Erik Date: Thu, 3 Sep 2026 17:10:00 +0200 Subject: [PATCH] =?UTF-8?q?fix(render):=20#459=20=E2=80=94=20enable=20shad?= =?UTF-8?q?erDemoteToHelperInvocation,=20the=20feature=20the=20SPIR-V=201.?= =?UTF-8?q?6=20fragment=20modules=20declare?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The shader compiler targets Vulkan 1.3 / SPIR-V 1.6, where glslang lowers a fragment discard to OpDemoteToHelperInvocation; five committed modules (sky, mesh_detail, mesh_atmospheric, both directional-shadow cutouts) declare the capability, and vkCreateShaderModule reported VUID-VkShaderModuleCreateInfo-pCode-08740 twice per launch under the Khronos validation layer because the device never enabled the feature. The feature is core 1.3 (the device gate already requires 1.3), so it is read through the existing Vulkan13Features chain, enabled at device creation next to dynamicRendering/synchronization2/maintenance4, and gated as required in VulkanCapabilityRecord with its own failure text. Found by the first validation-layer self-gate of Campaign OVERHAUL v2 (S3 chunk 4 round 2); no register row, no behavior change on a conformant driver. Co-Authored-By: Claude Fable 5.1 --- .../Rendering/Gpu/Vk/VulkanCapabilityRecord.cs | 15 +++++++++++++++ src/AcDream.App/Rendering/Gpu/Vk/VulkanInterop.cs | 7 +++++++ 2 files changed, 22 insertions(+) diff --git a/src/AcDream.App/Rendering/Gpu/Vk/VulkanCapabilityRecord.cs b/src/AcDream.App/Rendering/Gpu/Vk/VulkanCapabilityRecord.cs index 5e9d5d42..e78874a0 100644 --- a/src/AcDream.App/Rendering/Gpu/Vk/VulkanCapabilityRecord.cs +++ b/src/AcDream.App/Rendering/Gpu/Vk/VulkanCapabilityRecord.cs @@ -84,6 +84,17 @@ internal sealed record VulkanDeviceFeatureSupport /// Relaxed shader interface rules for the dual-legal GLSL sources. public required bool Maintenance4 { get; init; } + /// + /// #459: the shader compiler targets Vulkan 1.3 / SPIR-V 1.6, where glslang + /// lowers every fragment discard to OpDemoteToHelperInvocation + /// (five committed modules declare the capability — sky, mesh_detail, + /// mesh_atmospheric and both directional-shadow cutout fragments). A module + /// that declares the capability without the feature enabled is invalid + /// usage (VUID-VkShaderModuleCreateInfo-pCode-08740), so the feature + /// is required and enabled, never optional. + /// + public required bool ShaderDemoteToHelperInvocation { get; init; } + /// /// Every feature present. The starting point for the forced-unsupported gate /// knob and for tests that assert one specific absence at a time. @@ -108,6 +119,7 @@ internal sealed record VulkanDeviceFeatureSupport DynamicRendering = true, Synchronization2 = true, Maintenance4 = true, + ShaderDemoteToHelperInvocation = true, }; /// @@ -139,6 +151,7 @@ internal sealed record VulkanDeviceFeatureSupport var n when Is(n, nameof(DynamicRendering)) => this with { DynamicRendering = false }, var n when Is(n, nameof(Synchronization2)) => this with { Synchronization2 = false }, var n when Is(n, nameof(Maintenance4)) => this with { Maintenance4 = false }, + var n when Is(n, nameof(ShaderDemoteToHelperInvocation)) => this with { ShaderDemoteToHelperInvocation = false }, _ => null, }; @@ -521,6 +534,8 @@ internal static class VulkanCapabilityRequirements failures.Add("synchronization2 is required; every barrier in the frame is a barrier2."); if (!features.Maintenance4) failures.Add("maintenance4 is required for the relaxed shader interface rules the shared GLSL relies on."); + if (!features.ShaderDemoteToHelperInvocation) + failures.Add("shaderDemoteToHelperInvocation is required; the SPIR-V 1.6 fragment modules lower discard to OpDemoteToHelperInvocation (#459)."); VulkanDeviceLimitSupport limits = capabilities.Limits; if (limits.MaxPushConstantsSize < GpuBindingModel.PushConstantBytes) diff --git a/src/AcDream.App/Rendering/Gpu/Vk/VulkanInterop.cs b/src/AcDream.App/Rendering/Gpu/Vk/VulkanInterop.cs index 3dae155b..5788a292 100644 --- a/src/AcDream.App/Rendering/Gpu/Vk/VulkanInterop.cs +++ b/src/AcDream.App/Rendering/Gpu/Vk/VulkanInterop.cs @@ -330,6 +330,7 @@ internal static unsafe class VulkanPhysicalDeviceInspector DynamicRendering = vulkan13.DynamicRendering, Synchronization2 = vulkan13.Synchronization2, Maintenance4 = vulkan13.Maintenance4, + ShaderDemoteToHelperInvocation = vulkan13.ShaderDemoteToHelperInvocation, }; } @@ -609,6 +610,12 @@ internal sealed unsafe class VulkanLogicalDeviceFactory DynamicRendering = true, Synchronization2 = true, Maintenance4 = true, + // #459: the SPIR-V 1.6 fragment modules declare + // DemoteToHelperInvocation (glslang's lowering of `discard` for a + // Vulkan 1.3 target); declaring it without the feature is invalid + // usage (VUID-VkShaderModuleCreateInfo-pCode-08740). Gated as + // required in VulkanCapabilityRecord, so this is never speculative. + ShaderDemoteToHelperInvocation = true, }; var vulkan12 = new PhysicalDeviceVulkan12Features {