State of HLSL: February 2025

Looking back, 2024 was a big year for HLSL. Shader Model 6.8 went retail, a Work Graphs Mesh Nodes Preview was released, the DXIL Validator was open sourced, DirectX announced plans to adopt SPIRV, and in news you probably missed: simple HLSL shaders compiled with Clang built from main, successfully ran on GPUs for the first time!

That last milestone probably mostly escaped notice, but it was a really huge achievement and I want to take some time to explore the state of HLSL in Clang to show some of the great things that we’re working on right under your nose that you might not be aware of.

Status of HLSL in Clang

Today we have a handful of extremely simple HLSL compute shaders that compile successfully in Clang. Clang supports the basic syntax and semantics of HLSL, a reasonable sampling of the HLSL intrinsic functions, and a couple basic resource types. Clang is not nearly ready for use by developers, but we’re a few weeks away from compiling compute shaders from an internal trove of production code.

Despite the early state of the compiler there are a few improvements over DXC that we can already demonstrate.

Addressing Design Bugs

DXC has a significant number of bugs that exist because either the design of HLSL or design decisions made during DXC’s implementation. In some cases, like the HLSL 202x Conforming Literals feature, we can fix the issue in DXC and implement the correct solution in Clang. In other cases, the fixes in DXC are very complicated and would require invasive changes to DXC.

For an example of the later case consider DXC issue #4871. This issue occurs because of problems in DXC’s design for implementing HLSL’s by-value calling convention. In Clang, we’ve prioritized full and accurate AST representations which enable us to handle these problems more robustly.

Improved diagnostics

HLSL has a lot of implicit behavior which it has carried from its origins as a domain-specific language. Users have found it useful to be aware of implicit behavior, like implicit conversions, since they can have a runtime performance impact. Unfortunately DXC doesn’t always have the ability to diagnose implicit conversions because they are not captured in the AST.

In the example below, Clang will warn about the implicit conversion of F from a float4 to an int4 and the implicit conversion on return of the int4 back to the float4. Meanwhile DXC will perform the conversions with no diagnostics.

void SillyTrunc(inout int4) {}

export float4 Trunc(float4 F) {
    SillyTrunc(F);
    return F;
}

Compiler Explorer

Language Server

Clang comes with a production implementation of Language Server Protocol which is used to power IDE tooling through a JSON-RPC interface that is widely adopted by a large number of code editors.

In our efforts to add HLSL support to Clang we’ve also gained a working LSP server with minimal investment. We plan to continue working on QoL improvements to make clangd’s HLSL support production ready, but even with our minimal investments we’re already seeing promising results!

Experimental Language Features

As we’re working on Clang we’re also not ripping out all of C++’s features. We’ve been leaving C++ features that we want to add to HLSL working in Clang. This simple shader utilizes both C++’s auto keyword and C++ lambdas. Clang can successfully compile this to valid DXIL!

RWBuffer<int4> In : register(u0);
RWBuffer<int4> Out : register(u1);

int reduceSum(int4 V) {
    auto R = [](int LHS, int RHS) -> int {
        return LHS + RHS;
    };
    return R(V.x, R(V.y, R(V.z, V.w)));
}

[numthreads(8,1,1)]
void main(uint GI : SV_GroupIndex) {
    Out[GI] = reduceSum(In[GI]).xxxx;
}

Compiler Explorer

Another frequently requested feature in HLSL is C++’s constexpr. In Clang, we’re using constexpr as a vital implementation tool to ensure constant evaluation of complex math operations. We’re extending constexpr support in Clang to include HLSL’s vector types and implicit conversions so that HLSL expressions can fully leverage the feature. For example the HLSL D3DCOLORtoUBYTE4 function is implemented as a constexpr:

constexpr vector<uint, 4> D3DCOLORtoUBYTE4(vector<float, 4> V) {
  return V.zyxw * 255.001953f;
}

This evaluation includes the implicit scalar to vector conversion and the evaluation of the vector constant expression.

Language Evolution

Something else that happened in 2024 that may have escaped notice was the first approved and implemented feature for the next version of HLSL.

HLSL 202x

The next version of HLSL is codenamed 202x, and it will serve as a bridge between DXC and Clang. We’re realistic that the two compilers will never be fully identical, but 202x will allow us to move DXC toward Clang and Clang toward DXC. This gives us the ability to deprecate some problematic features of HLSL during the compiler transition while providing a graceful path for users. We expect that shaders which compile successfully with HLSL 202x in DXC will compile successfully in Clang with little to no adjustment required.

The first feature added in HLSL 202x was 0017 Conforming Literals, which addressed a number of bugs in DXC that were caused by the complicated way DXC assigned types to integer and floating point literals.

HLSL 202y

In addition to planning our bridging release, we’ve also been planning our next feature release, codenamed 202y, which will be available only in Clang. We expect HLSL 202y will be a combination of new features and refinements of existing HLSL.

As an example, two likely HLSL 202y features are const non-static member functions, and non-member operator overloading. Both of these features require significant changes to how and when overload resolution occurs in HLSL. These features will necessitate adopting overload resolution rules more like C++, which will break source compatibility for some code.

Another feature that has been frequently requested is C++ constructors, which will require addressing our initialization list handling.

While we expect that these features will cause some disruption to existing HLSL codebases, we believe all of these features will deliver on highly demanded user requests, while improving the familiarity of HLSL. The disruptive refinements to the base language will also enable us to add other frequently requested features like union types, conversion operators, and access specifiers.

Public Design Process

One last big change that we were working on at the end of 2024 and are just getting rolling in 2025 is an expansion of our public language design process.

We’ve had difficulty ensuring that proposals move through the process smoothly. We also have found that we need a wide variety of input in order to maintain high quality for all our design specifications. To address both of these issues we’ve started hosting regular public design meetings.

This provides a tactical forum for us to coordinate shepherding proposals through the language evolution process, and it allows us to have a space to discuss changes with a wider audience of stakeholders. We’re optimistic that these public meetings will help us drive a more open and public collaboration to evolve HLSL.