Role of gl_IncomingRayFlagsEXT in GLSL Hit Shaders

The built-in variable gl_IncomingRayFlagsEXT provides hit shaders in the Vulkan ray tracing pipeline with read-only access to the flags set when a ray was launched. Defined by the GL_EXT_ray_tracing extension, this unsigned integer variable enables closest-hit and any-hit shaders to inspect the operational parameters of the active ray query. By communicating the ray's configuration from the caller directly to the hit stages, it allows shaders to modify their evaluation logic dynamically based on context.

Source and Availability

When a ray is dispatched using the traceRayEXT() call in a ray generation, closest-hit, or callable shader, the caller provides a bitmask of ray flags as one of the arguments. The hardware and driver propagate this flag bitmask down the ray traversal pipeline.

Inside the resulting hit shaders—specifically Any-Hit (AHIT) and Closest-Hit (CHIT)—this value is exposed as:

in uint gl_IncomingRayFlagsEXT;

It is also accessible in intersection and miss shaders, maintaining uniform access to the traversal context across the entire ray evaluation pipeline.

Core Roles in Hit Shaders

1. Context-Aware Shading

Hit shaders are often shared across multiple ray types, such as primary camera rays, reflection rays, and shadow rays. gl_IncomingRayFlagsEXT allows a single compiled shader to determine the caller's intent without requiring extra payload space.

For example, if a hit shader detects flags indicating a simple visibility test, it can bypass expensive lighting, texture fetches, or normal mapping calculations:

// Check if the ray was instructed to terminate on the first hit (common for shadow rays)
if ((gl_IncomingRayFlagsEXT & gl_RayFlagsTerminateOnFirstHitEXT) != 0u) {
    // Perform simplified calculations for visibility queries
    hitPayload.shadowFactor = 0.0;
    return;
}

2. Managing Geometry Opacity and Traversal

In any-hit shaders, geometry opacity must often be verified manually (such as evaluating alpha-tested foliage or fences). The shader can read gl_IncomingRayFlagsEXT to determine if flags like gl_RayFlagsOpaqueEXT or gl_RayFlagsNoOpaqueEXT were set upstream, allowing it to honor or override acceleration structure assumptions accordingly.

3. Handling Culling Behavior

While culling is typically performed fixed-function during traversal via flags such as:

  • gl_RayFlagsCullBackFacingTrianglesEXT
  • gl_RayFlagsCullFrontFacingTrianglesEXT
  • gl_RayFlagsCullOpaqueEXT
  • gl_RayFlagsCullNoOpaqueEXT

A hit shader can inspect these flags to resolve orientation-dependent shading effects, such as two-sided lighting or distinct inner/outer surface rendering logic when culling is explicitly disabled.

Common Ray Flag Bitmasks

The variable contains a bitwise combination of the ray control flags defined by the SPIR-V and Vulkan specifications, including:

  • gl_RayFlagsNoneEXT (0x0): Default traversal behavior.
  • gl_RayFlagsOpaqueEXT (0x1): Forces all geometry to be treated as opaque.
  • gl_RayFlagsNoOpaqueEXT (0x2): Forces any-hit shaders to run for all intersections.
  • gl_RayFlagsTerminateOnFirstHitEXT (0x4): Treats the first valid intersection as the final hit.
  • gl_RayFlagsSkipClosestHitShaderEXT (0x8): Prevents execution of the closest-hit shader upon termination.
  • gl_RayFlagsCullBackFacingTrianglesEXT (0x10): Discards back-facing hits.
  • gl_RayFlagsCullFrontFacingTrianglesEXT (0x20): Discards front-facing hits.

By providing direct visibility into these parameters, gl_IncomingRayFlagsEXT reduces ray payload overhead, promotes shader code reuse, and gives hit shaders the context needed to optimize rendering paths.