NOTE: some links in this document are to internal documents that are not currently publically available. This file will be updated once they are published.
The Opacity Micromaps (OMM) feature allows DirectX Ray Tracing developers to allow ray-triangle hits to be trivially classified as miss or hit without having to invoke an any-hit shader.
This spec is narrowly focused on the HLSL compiler related aspects required to implement and test the feature from the compiler perspective. See the Opacity micromaps section in the Raytracing spec for more details on the overall feature and D3D runtime context.
There needs to be a way to enable OMM through subobjects in HLSL, equivalent
to D3D12_RAYTRACING_PIPELINE_FLAG_ALLOW_OPACITY_MICROMAPS
in the
API.
Additionally, the runtime allows instances to be tagged with
D3D12_RAYTRACING_INSTANCE_FLAG_FORCE_OMM_2_STATE
, but allowing this to be
specified at ray tracing time in a shader would provide flexibility for
developers.
A new RAYTRACING_PIPELINE_FLAG
is proposed to enable OMM in HLSL:
RAYTRACING_PIPELINE_FLAG_ALLOW_OPACITY_MICROMAPS
.
These flags are used in the Raytracing pipeline config1
subobject in HLSL.
A new RAY_FLAG
is proposed that allows ray tracing in shaders to force OMM
2-state for a particular trace: RAY_FLAG_FORCE_OMM_2_STATE
.
Add a built-in RAYTRACING_PIPELINE_FLAG_ALLOW_OPACITY_MICROMAPS
to the
RAYTRACING_PIPELINE_FLAG
flags in HLSL to enable OMM.
Add built-in RAY_FLAG_FORCE_OMM_2_STATE
to RAY_FLAG
flags in HLSL.
RAYTRACING_PIPELINE_FLAG
flags are used in the
Raytracing pipeline config1
subobject in HLSL. When RAYTRACING_PIPELINE_FLAG_ALLOW_OPACITY_MICROMAPS
is
used in the current pipeline configuration, the pipeline supports Opacity
Micromaps. If a triangle with an OMM is encountered during traversal with this
flag cleared, behavior is undefined. This flag should not be set if there are
no OMMs present, since it may incur a small penalty on traversal performance
overall. See the D3D12 flag definition for more details:
D3D12_RAYTRACING_PIPELINE_FLAG_ALLOW_OPACITY_MICROMAPS
.
Add a built-in RAY_FLAG_FORCE_OMM_2_STATE
flag to the RAY_FLAG
flags.
RAY_FLAG
flags are only meaningful when used in the RayFlags
parameter of
the TraceRay() or RayQuery::TraceRayInline()
intrinsic functions, or in the RAY_FLAGS
template argument of a
RayQuery object. When used with Opacity Micromaps
(RAYTRACING_PIPELINE_FLAG_ALLOW_OPACITY_MICROMAPS
or
D3D12_RAYTRACING_PIPELINE_FLAG_ALLOW_OPACITY_MICROMAPS
),
the raytracing pipeline will ignore the Unknown state and only consider the
Transparent/Opaque bit for all 4-state Opacity Micromaps encountered during
traversal. This flag has no effect if
D3D12_RAYTRACING_INSTANCE_FLAG_DISABLE_OMMS
is set on the instance, or if
Opacity Micromaps are globally not set, not allowed, or not supported.
If set, this flag will be present in the returned flags of the
RayFlags() intrinsic function.
In HLSL under DXC, these are defined as static const uint values:
static const uint RAYTRACING_PIPELINE_FLAG_ALLOW_OPACITY_MICROMAPS = 0x400;
static const uint RAY_FLAG_FORCE_OMM_2_STATE = 0x400;
Note: the fact that these flags have the same value is only a coincidence.
This adds no DXIL operations or metadata, it only adds a new flag value that may be used with existing DXIL operation parameters, returned by a DXIL operation.
The DXIL operations which either accept or return RayFlags
, and therefore may
accept or return the new RAY_FLAG_FORCE_OMM_2_STATE
are the following (along
with brief descriptions):
RayFlags
- returns ray flags currently in useTraceRay
- Trace a ray (with ray flags)AllocateRayQuery
- Creates a RayQuery and specifies the constant ray flagsRayQuery_TraceRayInline
- Trace a ray (with ray flags OR’d with the
RayQuery’s constant ray flags)When lowering to DXIL intrinsics, we will mask the flags using the legal mask for the shader target. This will prevent undefined behavior if invalid flags were specified and either warnings were ignored, or the flags were not a known constant value during semantic analysis.
In DxilConstants.h
, the RayFlag::ForceOMM2State
flag is added.
Propose adding ValidMask values for diagnostics and validation.
// Corresponds to RAY_FLAG_* in HLSL
enum class RayFlag : uint32_t {
...
ForceOMM2State = 0x400, // Force 2-state in Opacity Micromaps
ValidMask_1_8 = 0x3ff, // valid mask up through DXIL 1.8
ValidMask = 0x7ff, // current valid mask
};
This change is comaptible with the
SPV_EXT_opactity_micromap
extension, where the new flag is ForceOpacityMicromap2StateEXT
. It also,
coincidentally, has the same number value as ForceOMM2State
.
A warning diagnostic (default: warning) will be introduced and emitted when a reachable use of one of the new flags is encountered. A reachable use is one that is found by traversing AST from active entry and export functions, or from subobject declarations when compiling a library. Traversal will follow local function calls, as well as traversing referenced decls and initializers.
As an implementation detail, an attribute may be used on the new flag definitions, such as an existing Clang availability attribute or a new custom HLSL-specific attribute.
AST traversal from entry points will traverse DeclRefs and initializers to detect the use of the new ray flag. AST traversal will be added for subobject declarations on library targets to detect any use of the new pipeline flag.
This will have implications for uses of these flags outside of the intended targets. Since they are just uint values, it’s technically legal to refer to them elsewhere, so we will use a warning which defaults to warning rather than using DefaultError like we would for calls to unsupported intrinsic functions.
Proposed warning diagnostic:
"potential misuse of built-in constant %0 in shader model %1; introduced in shader model %2"
.
This new warning will have a new warning group to allow it to be targeted
easily for command-line override, such as hlsl-availability-constant
.When compiling a library with the
RaytracingPipelineFlags::AllowOpacityMicromaps
flag set in a
Raytracing pipeline config1 subobject,
a new DefaultError warning diagnostic will be added if the shader model is less
than 6.9. This will detect the case where the flag is not spelled out and
caught by AST traversal.
Current HLSL diagnostics in DXC do not verify RayFlags
values in any context.
TraceRay()
and RayQuery::TraceRayInline()
accept non-immediate values, but
the RayFlags
provided as a template argument to RayQuery
must be immediate.
In addition to the AST traversal detecting any explicit use of the new flag,
the same DefaultError warning diagnostic will be added to detect when the
new ray flag is used at the RayQuery
template argument, TraceRay()
, or
RayQuery::TraceRayInline()
(when it is immediate).
This can make use of the new ValidMask*
values.
Proposed DefaultError warning diagnostic:
"%select{RaytracingPipelineFlags|RayFlags}0 (0x%1) includes unsupported bits for shader model %2; valid mask: 0x%3"
.
This new warning will have a different warning group, such as
hlsl-availability
.See Issue RayQuery Template Diagnostics.
Validation will be added to ensure that the shader model is at least 6.9 when
the RaytracingPipelineFlags::AllowOpacityMicromaps
is used in a
Raytracing pipeline config1 subobject.
Proposed validation error diagnostic:
"RaytracingPipelineFlags in RaytracingPipelineConfig1 subobject '%0' specifies unknown flags (0x%1) for shader model %2; valid mask: 0x%3"
Three DXIL operations accept RayFlags
as input, but only one requires this
input to be immediate: AllocateRayQuery
.
Validation will be added to check the RayFlags
parameters for each applicable
DXIL operation, with an error emitted if the flags are constant, the new flag
is used, and the shader model is less than 6.9.
Proposed validation error diagnostic:
"RayFlags used in '%0' specifies unknown flags (0x%1) for shader model %2; valid mask: 0x%3"
Validation will also be added to ensure the flags are constant on input to
the AllocateRayQuery
DXIL operation.
Proposed validation error diagnostic:
"ConstRayFlags argument of AllocateRayQuery '%0' must be constant"
In the RDAT
data for the runtime, a new flag is added to the Flags
field
of the RaytracingPipelineConfig1
subobject type.
In DxilConstants.h
, the RaytracingPipelineFlags::AllowOpacityMicromaps
flag is added.
enum class RaytracingPipelineFlags : uint32_t {
...
ValidMask_1_8 = 0x300, // valid mask up through DXIL 1.8
AllowOpacityMicromaps = 0x400, // Allow Opacity Micromaps to be used
ValidMask = 0x700, // current valid mask
};
In RDAT_SubobjectTypes.inl
, the enum value is mapped and ValidMask updated.
RDAT_DXIL_ENUM_START(hlsl::DXIL::RaytracingPipelineFlags, uint32_t)
...
RDAT_ENUM_VALUE_NODEF(AllowOpacityMicromaps)
#if DEF_RDAT_ENUMS == DEF_RDAT_DUMP_IMPL
static_assert((unsigned)hlsl::DXIL::RaytracingPipelineFlags::ValidMask ==
0x700,
"otherwise, RDAT_DXIL_ENUM definition needs updating");
#endif
RDAT_ENUM_END()\
Any statically-determined use of RayFlag::ForceOMM2State
in a ray flags
parameter of the corresponding DXIL op will set the
RuntimeDataFunctionInfo::MinShaderTarget
shader model to a minimum of 6.9 for
the calling function. However, since RayFlags parameters are not required to be
an immediate constant for some of the intrinsics, dynamic usage of this flag
will not impact the shader model minimum.
Since RaytracingPipelineFlags::AllowOpacityMicromaps
is only interpreted in
the RaytracingPipelineConfig1
subobject, there is no fixed association with
any function, and no impact on the DXIL passed to the driver. Thus it has no
impact on any RuntimeDataFunctionInfo::MinShaderTarget
.
Since this flag may only be included in a shader model 6.9 library, the library
cannot be used on a device that doesn’t support shader model 6.9.
The use of RayFlag::ForceOMM2State
only requires Shader Model 6.9, since the
flag is ignored when OMM is not present or not supported.
Use of the RaytracingPipelineFlags::AllowOpacityMicromaps
flag will require
Shader Model 6.9. Additionally, the runtime will enforce the Opacity Micromaps
device feature support requirement if the subobject is used.
See Opacity Micromaps in the Raytracing spec for details.
RaytracingPipelineConfig1
subobject Flags
field.and
instruction masking of non-constant values, and for masking
off of a constant invalid flag when turning off the associated warnings.
These also verify that you can disable all the warning diagnostics.0x400
) in each applicable scenario.We will add diagnostics and validation for the use of the new flag in a DXR subobject when the shader model is less than 6.9.
We will add diagnostics and validation for RayFlag cases where they must be
constant (RayQuery template and AllocateRayQuery
DXIL op), or where they
happen to be constant. We will only check them against a mask for the shader
model, rather than checking for invalid combinations of valid flags.
We will add masking for generated DXIL in the compiler, but will not check that unknown values are masked in the DXIL validator.
We will not gate definitions of the flag by shader model, but will use a mechanism, such as availability attributes, to mark definitions as only being available in shader model 6.9. These diagnostics will be a warning by default, since it is legal to use the flag values in other contexts, but might indicate a mistaken usage. Diagnostics based on these will only be triggered when these definitions are reachable in the current compilation.
Some investigation is required to determine the approach for DXC to emit availability diagnostics for use of the new flag definitions themselves. We might use the built-in availability attribute, or use a new attribute, depending on practicalities in DXC.
Use of availability attributes for diagnostics will introduce changes in our current AST traversal that checks a few existing intrinsics. It will also require that we traverse subobject declarations when compiling a library. There may be an opportunity to replace some existing custom diagnostics in this path with the use of an availability attribute approach.
How should the RayQuery
ConstRayFlag
template argument be checked against
the valid mask in the compiler? We have a custom check for arguments such as
the dimensions passed to vector
and matrix
templates. It was suggested
that we might be able to implement this with some sort of static assert
instead. However, I’m concerned that this approach may unintentionally impact
unreachable uses of RayQuery
.