DirectXShaderCompiler
DirectXShaderCompiler copied to clipboard
Annotate entry points inside HLSL source code
Hello !
Currently to compile a shader one needs to specify both the entry point and the shader stage to the compiler:
- if
myshader.hlsl
contains several entry points (typical use case: one fore VS, one for PS), then the file must be compiled several times. The redundant work is not a lot for tiny shaders but for big, auto-generated shaders this overhead can become non-negligible - more importantly, this means that a shader source file is not sufficient in itself, to be compiled we also need to store somewhere a list of
(entry_point, shader_stage)
, requiring the shader author to manually fill it. Not having such a structure means creating a coupling between shader creation and shader compilation.
I think it is better to directly specify the entry points inside the HLSL source. The best solution I see is to add an attribute to the entry points like that: [entry("<stage>")]
(or any variation deemed more pleasant obviously).
// some HLSL code...
[entry("vertex")]
float4 simple_projection(float4 pos : SV_Position) : SV_Position
{
// ...
}
// more code...
[entry("pixel")]
float4 nice_color(float4 pos : SV_Position): SV_Target
{
// ...
}
The compiler API would be something like Compile(filename, shader_model, options)
returning an array of (bytecode, entry_name, shader_stage)
. This can be done in a backward-compatible fashion. The results for a source with N entry points is N bytecode objects, as if the compiler was called N times.
I really want this and I can try to implement it if you want.
There is already a supported attribute for DXIL library targets, like: [shader("pixel")]
, for identifying the entry functions in a library.
The missing piece is producing an array of normal (non-library) compiled shaders from each of the entries exposed in the library. That step could be accomplished with a small utility that introspects a compiled DXIL library and performs a Link operation for each entry point found, producing an array of outputs, either through a collection in a C++ API, or for a command line utility, perhaps a series of output files in a target directory, using some naming convention to include the shader entry name and target profile.
So the outline for the utility would be:
- Probably outside the utility: compile to a library profile (
lib_6_*
, depending on the desired shader model). - In the utility, load a DXIL Library binary, which was compiled in a previous step to a library profile.
- Using IDxcLinker,
RegisterLibrary
this library with the interface. - Using reflection, discover the names and shader targets of the entry points available to link from the library.
- Link() each entry point found to the corresponding target profile constructed by combining the shader kind and major/minor version obtained through reflection.
Regarding reflection: Use IDxcUtils::CreateReflection()
to create reflection using the ID3D12LibraryReflection
interface. Iterate through functions (using GetFunctionByIndex()
), use GetDesc()
on each function to get the Name
and decode the Version
token for the shader kind (GetVersionShaderType()
in DxilContainer.h
- high 16-bits map to ``D3D12_SHADER_VERSION_TYPEfrom
d3d12shader.h). Skip functions that are
ShaderKind::Library` - these are exported library functions, not shader entry points.