d3d12: Tessellation
This series enables GL_ARB_tessellation_shader
. The long series of compiler patches in the beginning is to get all of the tessellation uniqueness handled:
- D3D's hull shader must consist of two functions: the main shader which is run per vertex / control point, and a patch constant function which is run once, after all control points have been computed. The implications here are large:
- The DXIL backend only supported single-function shaders. The module emitter is updated to handle writing out multiple functions.
- GLSL's tess shaders are single-function. They expect the patch constants to be written by every control point. Some shader manipulation happens here to split things out. It seems to work okay. The algorithm here is to start by cloning the shader and then strip down the two copies differently. The main copy just has patch constant writing (
store_output
) removed, and then DCE is able to trim out all of the now-useless instructions. The patch constant copy is more complicated: any instruction that doesn't contribute to astore_output
is removed. Any side effects like image/SSBO writes should happen from the main shader anyway. However this isn't enough: the GLSL code can still usegl_InvocationID
since it's expecting to run the code per-vertex. So... we have to loop any code that depends on this, and then close the loops whenever abarrier
is encountered.- In order to actually detect when
gl_InvocationID
contributes to astore_output
vs just contributing to anif
that has no side effects, an upgrade tonir_opt_dead_cf
is needed to remove those deadif
blocks. I'll send this separately.
- In order to actually detect when
- Per-patch data sent between HS/DS is all kinds of special:
- It falls above the normal range of 64 for varying locations, so special bitfield handling is needed.
- It uses special DXIL intrinsics to read and write it.
- Worst of all, it has its own unique signature, separate from the input and output signatures, which (like input and output) needs to be present in 3 different ways in a DXIL module.
- The tessellation levels/factors are also unique sysvals, in that they're an array of
float
(meaning one per register) compared to afloat4
.
- HS and DS have their own metadata. In GLSL, most of this metadata is specified in the tess eval (domain) shader, with only the number of control points going from control -> eval being specified in the control shader. D3D is the opposite, where the hull shader specifies everything, and the domain shader needs to specify how many input control points are expected. The compiler requires the driver to fill out the
shader_info::tess
block for both hull and domain shaders.
After all the compiler patches, then the driver patches. Nothing too crazy:
- Handling linking between tess ctrl/eval shaders so that the metadata for the control shader can be filled out, and the patch varyings can be made to match identically.
- Control shaders are optional in GL, but required in D3D, so we add infrastructure to generate passthrough hull shaders.