HeapASRead renders a triangle, tracing half the frame with traceRayEXT and ray querying the other half, both reading the TLAS out of the descriptor heap, and checks the read-back pixels. The test runner runs it through the engine's normal path, so on NVIDIA it covers the rewrite too: an inherited CRAFTER_GRAPHICS_NO_AS_WORKAROUND is cleared, and the test checks the rewrite is on exactly where the driver needs it. HeapASRead --no-workaround is the check for a newer driver. Each path renders in its own child process with the rewrite off and validation off (GPU-assisted validation instruments the shaders), so a device loss on one doesn't hide the other. On 615.78.08 traceRayEXT still loses the device and the ray query renders nothing. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
51 lines
2.3 KiB
GLSL
51 lines
2.3 KiB
GLSL
//SPDX-License-Identifier: LGPL-3.0-only
|
|
//SPDX-FileCopyrightText: Copyright (C) 2026 Catcrafts®
|
|
|
|
#version 460
|
|
#extension GL_EXT_ray_tracing : enable
|
|
#extension GL_EXT_ray_query : enable
|
|
#extension GL_EXT_shader_image_load_formatted : enable
|
|
#extension GL_EXT_shader_explicit_arithmetic_types_int16 : enable
|
|
#extension GL_EXT_descriptor_heap : enable
|
|
#extension GL_EXT_nonuniform_qualifier : enable
|
|
|
|
// Reads the TLAS straight out of the descriptor heap through traceRayEXT and
|
|
// through an inline ray query: the two AS-read paths that lost the device on
|
|
// NVIDIA 610.43.02 (#7). `path` picks which: 0 traces the left half of the
|
|
// frame and ray queries the right half, 1 only traces, 2 only ray queries.
|
|
layout(constant_id = 0) const uint16_t bufferStart = 0us;
|
|
layout(constant_id = 1) const uint path = 0u;
|
|
layout(descriptor_heap) uniform accelerationStructureEXT topLevelAS[];
|
|
layout(descriptor_heap) uniform writeonly image2D image[];
|
|
|
|
layout(location = 0) rayPayloadEXT vec3 hitValue;
|
|
|
|
void main() {
|
|
uvec2 pixel = gl_LaunchIDEXT.xy;
|
|
uvec2 resolution = gl_LaunchSizeEXT.xy;
|
|
vec2 ndc = (vec2(pixel) + 0.5) / vec2(resolution) * 2.0 - 1.0;
|
|
|
|
// Same pinhole camera as examples/VulkanTriangle, facing +Z.
|
|
vec3 origin = vec3(0.0, 0.0, -300.0);
|
|
float aspect = float(resolution.x) / float(resolution.y);
|
|
float tanHalfFov = tan(radians(60.0) * 0.5);
|
|
vec3 direction = normalize(vec3(ndc.x * aspect * tanHalfFov, -ndc.y * tanHalfFov, 1.0));
|
|
|
|
bool trace = path == 1u || (path == 0u && pixel.x < resolution.x / 2);
|
|
vec3 colour;
|
|
if (trace) {
|
|
// Closest-hit writes green, miss writes grey.
|
|
traceRayEXT(topLevelAS[bufferStart], gl_RayFlagsNoneEXT, 0xff, 0, 0, 0,
|
|
origin, 0.001, direction, 10000.0, 0);
|
|
colour = hitValue;
|
|
} else {
|
|
rayQueryEXT query;
|
|
rayQueryInitializeEXT(query, topLevelAS[bufferStart], gl_RayFlagsOpaqueEXT, 0xff,
|
|
origin, 0.001, direction, 10000.0);
|
|
while (rayQueryProceedEXT(query)) {}
|
|
bool hit = rayQueryGetIntersectionTypeEXT(query, true) == gl_RayQueryCommittedIntersectionTriangleEXT;
|
|
// White for a hit, the miss shader's grey otherwise.
|
|
colour = hit ? vec3(1.0) : vec3(0.5);
|
|
}
|
|
imageStore(image[0], ivec2(pixel), vec4(colour, 1.0));
|
|
}
|