HLSL Compilation Targets: lib_6_6 vs cs_6_6
Modern DirectX Shader Compiler (DXC) relies on compilation targets to
determine how High-Level Shader Language (HLSL) code is validated,
optimized, and packaged for the GPU. Stage-specific profiles such as
cs_6_6 compile isolated, single-entry-point programs for
specific pipeline stages like compute shaders, whereas library profiles
like lib_6_6 generate modular, multi-entry shader libraries
essential for modern features such as DirectX Raytracing (DXR) and Work
Graphs. Understanding the architectural differences between these target
profiles is vital for structuring HLSL code bases, managing linking, and
optimizing GPU pipeline state objects.
Stage-Specific Targets: cs_6_6
The cs_6_6 compilation target represents a dedicated
compute shader compiled under Shader Model 6.6. When targeting
cs_6_6, DXC expects a monolithic program with a single,
explicitly defined entry point function that includes the
[numthreads(x, y, z)] attribute.
Because the compiler knows the exact entry point and execution context during compilation, it performs aggressive whole-program optimizations. Any functions, variables, or resource bindings that are unreachable from the declared entry point are treated as dead code and stripped from the final DXIL (DirectX Intermediate Language) binary. The resulting output is a self-contained shader blob ready to be passed directly into a traditional Compute Pipeline State Object (PSO).
Library Targets: lib_6_6
The lib_6_6 target compiles HLSL code into a reusable
code library rather than an isolated, monolithic stage. Introduced
primarily to support DXR and later extended to features like Work
Graphs, library targets do not enforce a single entry point or a fixed
pipeline stage.
A single lib_6_6 binary can contain:
- Multiple entry points of various types (e.g.,
[shader("raygeneration")],[shader("closesthit")],[shader("compute")],[shader("node")]). - Standalone helper functions exported for linking with other shaders at runtime.
- Shared type definitions and resource declarations.
Instead of stripping unreferenced functions, DXC preserves all exported public functions and their symbol tables within the DXIL binary. This allows the DirectX 12 runtime and the graphics driver to link these functions dynamically when assembling a State Object (such as a Raytracing Pipeline State Object or an Executable Graph).
Key Architectural Differences
Entry Point Requirements:
cs_6_6requires exactly one compute entry point specified via the compiler command line (e.g.,-E CSMain).lib_6_6does not use the-Eflag to target a single function; instead, entry points are declared inside the HLSL source using the[shader("...")]attribute.Dead Code Elimination: In
cs_6_6, dead code elimination is global and definitive; uncalled functions are removed. Inlib_6_6, exported functions are retained regardless of whether they reference each other, keeping the library flexible for external linkage at the cost of requiring the driver to perform final dead-code elimination when building the pipeline state.Pipeline State Object Integration: A
cs_6_6blob is supplied directly to a standardD3D12_COMPUTE_PIPELINE_STATE_DESC. Conversely, alib_6_6container must be wrapped inside aD3D12_STATE_OBJECT_DESC, where the application explicitly defines which entry points, hit groups, or subobjects are exposed to the driver.Resource Binding Semantics: While
cs_6_6resolves all root signatures and resource registers at compile-time for a fixed compute context,lib_6_6supports both local and global root signatures, enabling localized resource binding per raytracing shader or node function.
Choosing Between Targets
Use cs_6_6 for traditional, standalone compute workloads
where performance requires compile-time symbol resolution and standard
compute pipeline state caching. Use lib_6_6 whenever
developing for DirectX Raytracing, Work Graphs, dynamic shader linking,
or when packaging multiple related entry points into a single compiled
artifact to simplify asset management.