New in D3D12 – DirectX Raytracing (DXR) now supports library subobjects
In the next update to Windows, codenamed 19H1, developers can specify DXR state subobjects inside a DXIL library. This provides an easier, flexible, and modular way of defining raytracing state, removing the need for repetitive boilerplate C++ code. This usability improvement was driven by feedback from early adopters of the API, so thanks to all those who took the time to share your experiences with us!
The D3D12RaytracingLibrarySubobjects sample illustrates using library subobjects in an application.
What are library subobjects?
Library subobjects are a way to configure raytracing pipeline state by defining subobjects directly within HLSL shader code. The following subobjects can be compiled from HLSL into a DXIL library:
A library subobject is identified by a string name, and can be exported from a library or existing collection in a similar fashion to how shaders are exported using D3D12_EXPORT_DESC. Library subobjects also support renaming while exporting from libraries or collections. Renaming can be used to avoid name collisions, and to promote subobject reuse.
This example shows how to define subobjects in HLSL:
GlobalRootSignature MyGlobalRootSignature =
"DescriptorTable(UAV(u0))," // Output texture
"SRV(t0)," // Acceleration structure
"CBV(b0)," // Scene constants
"DescriptorTable(SRV(t1, numDescriptors = 2))" // Static index and vertex buffers.
LocalRootSignature MyLocalRootSignature =
"RootConstants(num32BitConstants = 4, b1)" // Cube constants
TriangleHitGroup MyHitGroup =
"", // AnyHit
"MyClosestHitShader", // ClosestHit
"MyAnyHit", // AnyHit
"MyClosestHit", // ClosestHit
"MyIntersection" // Intersection
SubobjectToExportsAssociation MyLocalRootSignatureAssociation =
"MyLocalRootSignature", // Subobject name
"MyHitGroup;MyMissShader" // Exports association
RaytracingShaderConfig MyShaderConfig =
16, // Max payload size
8 // Max attribute size
RaytracingPipelineConfig MyPipelineConfig =
1 // Max trace recursion depth
StateObjectConfig MyStateObjectConfig =
Note that the subobject names used in an association subobject need not be defined within the same library or even collection, and can be imported from different libraries within same collection or a different collection altogether. In cases where a subobject definition is used from a different collection, the collection that provides the subobject definitions must use the state object config flag D3D12_STATE_OBJECT_FLAG_ALLOW_EXTERNAL_DEPENDENCIES_ON_LOCAL_DEFINITIONS, and the collection which depends on the external definitions of the subobject must specify the config flag D3D12_STATE_OBJECT_FLAG_ALLOW_LOCAL_DEPENDENCIES_ON_EXTERNAL_DEFINITIONS.
Subobject associations at library scope
(this section is included for completeness: most readers can probably ignore these details)
Library subobjects follow rules for default associations. An associable subobject (config or root signature subobject) becomes a candidate for implicit default association if it is the only subobject of its type defined in the library, and if it is not explicitly associated to any shader export. Use of default associable subobject can be explicitly specified by giving an empty list of shader exports in the SubobjectToExportsAssociation definition. Note that the scope of the defaults only applies to the shaders defined in the library. Also note that similar to non-explicit associations, the associable subobjects names specified in SubobjectToExportsAssociation need not be defined in the same library, and this definition can come from a different library or even different collection.
Subobject associations (i.e. config and root signature association between subobjects and shaders) defined at library scope have lower priority than the ones defined at collection or state object scope. This includes all explicit and default associations. For example, an explicit config or root signature association to a hit group defined at library scope can be overridden by an implicit default association at state object scope.
Subobject associations can be elevated to state object scope by using a SubobjectToExportsAssociation subobject at state object scope. This association will have equal priority to other state object scope associations, and the D3D12 runtime will report errors if multiple inconsistent associations are found for a given shader.
Creating Root Signatures from DXIL library bytecode
In DXR, if an application wants to use a global root signature in a DispatchRays() call then it must first bind the global root signature to the command list via SetComputeRootSignature(). For DXIL-defined global root signatures, the application must call SetComputeRootSignature() with an ID3D12RootSignature* that matches the DXIL-defined global root signature. To make this easier for developers, the D3D12 CreateRootSignature API has been updated to accept DXIL library bytecode and will create a root signature from the global root signature subobject defined in that DXIL library. The requirement here is that there should be only one global root signature defined in the DXIL library. The runtime and debug layer will report an error if this API is used with library bytecode having none or multiple global root signatures.
Similarly, the APIs D3D12CreateRootSignatureDeserializer and D3D12CreateVersionedRootSignatureDeserializer are updated to create root signature deserializers from library bytecode that defines one global root signature subobject.
Windows SDK version 18282 or higher is required for the DXC compiler update. OS version 18290 or higher is needed for runtime and debug layer binaries. Both are available today through the Windows Insider Program. PIX supports library subobjects as of version 1901.28. This feature does not require a driver update.