Skip to content

d3d12: Tessellation

Jesse Natalie requested to merge jenatali/mesa:d3d12-tess into main

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 a store_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 use gl_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 a barrier is encountered.
      • In order to actually detect when gl_InvocationID contributes to a store_output vs just contributing to an if that has no side effects, an upgrade to nir_opt_dead_cf is needed to remove those dead if blocks. I'll send this separately.
  • 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 a float4.
  • 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.
Edited by Jesse Natalie

Merge request reports