{"id":5502,"date":"2021-12-08T14:38:28","date_gmt":"2021-12-08T22:38:28","guid":{"rendered":"https:\/\/devblogs.microsoft.com\/directx\/?p=5502"},"modified":"2022-01-28T13:23:12","modified_gmt":"2022-01-28T21:23:12","slug":"announcing-hlsl-2021","status":"publish","type":"post","link":"https:\/\/devblogs.microsoft.com\/directx\/announcing-hlsl-2021\/","title":{"rendered":"Announcing HLSL 2021"},"content":{"rendered":"<div>Today we are excited to announce the release of HLSL 2021! HLSL 2021 brings an assortment of new language features that we think will make shader authoring in HLSL more familiar and productive.<\/div>\n<div><\/div>\n<div><\/div>\n<div>Enabling HLSL 2021 is as easy as passing the `<span style=\"font-family: 'courier new', courier, monospace;\">-HV 2021<\/span>`, and you can immediately start enjoying all the new language features like:<\/div>\n<div><\/div>\n<ul>\n<li>Template functions and data types<\/li>\n<li>Overloadable operators for user defined data types<\/li>\n<li>Bitfield members for data types<\/li>\n<\/ul>\n<div>We intend to make HLSL 2021 the default language version in a future release after giving time for developers to test adopt and migrate code, and for us to perform more testing and integration. Once it is made the default you can use the `<span style=\"font-family: 'courier new', courier, monospace;\">-HV<\/span>` flag to specify an older language version if needed.<\/div>\n<div><\/div>\n<div><\/div>\n<div>There are also some other changes in HLSL 2021 that may have some more subtle or unexpected impact specifically:<\/div>\n<div><\/div>\n<ul>\n<li>Strict casting rules for user defined data types<\/li>\n<li>Logical operator short circuiting for scalar types<\/li>\n<li>C++ `<span style=\"font-family: 'courier new', courier, monospace;\">for<\/span>` loop scoping rules<\/li>\n<\/ul>\n<div>Let&#8217;s start by talking about some of the more subtle changes in HLSL 2021, then delve into all the fun new features!<\/div>\n<div><\/div>\n<h3>Strict Casting of User-defined Data Types<\/h3>\n<div>Prior to HLSL 2021, user defined data types with the same member layout would be treated as the same type and freely casted between. This behavior caused certain unintuitive errors and allowed some code to compile that may not have been as intended. For example given the following code:<\/div>\n<div><\/div>\n<div><\/div>\n<pre>struct LinearRGB {\r\n  float3 RGB;\r\n};\r\n\r\nstruct LinearYCoCg {\r\n  float3 YCoCg;\r\n};\r\n\r\nfloat GetLuma4(LinearRGB In) {\r\n  return In.RGB.g * 2.0 + In.RGB.r + In.RGB.b;\r\n}\r\n\r\nfloat GetLuma4(LinearYCoCg In) {\r\n  return In.YCoCg.x;\r\n}<\/pre>\n<div>In this example before HLSL 2021, any call to `<span style=\"font-family: 'courier new', courier, monospace;\">GetLuma4<\/span>` would be ambiguous because any object of type `<span style=\"font-family: 'courier new', courier, monospace;\">LinearYCoCg<\/span>` freely behaves as `<span style=\"font-family: 'courier new', courier, monospace;\">LinearRGB<\/span>`. With strict casting in HLSL 2021, these calls are unique and resolvable.<\/div>\n<div><\/div>\n<div><\/div>\n<div>This feature will cause some source code incompatibilities. For example, since the `<span style=\"font-family: 'courier new', courier, monospace;\">LinearRGB<\/span>` structure defined above will no longer implicitly convert to `<span style=\"font-family: 'courier new', courier, monospace;\">LinearYCoCg<\/span>` the following code compiles with previous language versions, but will not under HLSL 2021.<\/div>\n<div><\/div>\n<div><\/div>\n<pre>void Modify(inout LinearRGB V) {\r\n  V.RGB.x += 1;\r\n}\r\n\r\n[numthreads(64, 1, 1)]\r\nvoid main() {\r\n  LinearYCoCg V = {{0.0, 0.0, 0.0}};\r\n  Modify(V);\r\n}<\/pre>\n<div>You can workaround these failures by explicitly casting to the appropriate type, as in:<\/div>\n<div><\/div>\n<div><\/div>\n<pre>[numthreads(64, 1, 1)]\r\nvoid main() {\r\n  LinearYCoCg V = {{0.0, 0.0, 0.0}};\r\n  Modify((LinearRGB)V);\r\n}<\/pre>\n<h3>Logical Operator Short Circuiting<\/h3>\n<div>HLSL 2021 is introducing logical operator short circuiting behavior matching C. This means that if the first operand of a boolean `<span style=\"font-family: 'courier new', courier, monospace;\">&amp;&amp;<\/span>` is evaluated as `<span style=\"font-family: 'courier new', courier, monospace;\">false<\/span>`, the second operand will not be evaluated. Similarly, if the first operand of a boolean `<span style=\"font-family: 'courier new', courier, monospace;\">||<\/span>` is evaluated as `<span style=\"font-family: 'courier new', courier, monospace;\">true<\/span>` the second operand will not be evaluated. This can introduce behavior changes if the second operand performs a side-effecting operation. Take the following code:<\/div>\n<div><\/div>\n<div><\/div>\n<pre>struct Doggo {\r\n  bool isWagging;\r\n\r\n  bool wag() {\r\n  \u00a0 isWagging = !isWagging;\r\n  \u00a0 return !isWagging;\r\n  }\r\n\r\n  void bark() {\r\n  \u00a0 \/\/ woof!\r\n  }\r\n};\r\n\r\n[numthreads(1,1,1)]\r\nvoid main() {\r\n  Doggo Fido = {false};\r\n  for (int i = 0; i &lt; 10; ++i) {\r\n  \u00a0 if (Fido.isWagging &amp;&amp; Fido.wag())\r\n  \u00a0 \u00a0 Fido.bark();\r\n  }\r\n}<\/pre>\n<div><\/div>\n<div>In HLSL 2021, Fido&#8217;s wag and bark methods never get called. In HLSL pre-2021, wag gets called every time through the loop and bark gets called every other time through the loop.<\/div>\n<div><\/div>\n<div><\/div>\n<div>In addition to adding short circuiting behavior, in HLSL 2021 logical operators can only be used with scalar values. Prior to HLSL 2021, logical operators could be used with vector types to provide vector outputs like the code below:<\/div>\n<div><\/div>\n<pre>int3 X = {1, 1, 1};\r\nint3 Y = {0, 0, 0};\r\nbool3 Cond = X &amp;&amp; Y;\r\nbool3 Cond2 = X || Y;\r\nint3 Z = X ? 1 : 0;<\/pre>\n<div><\/div>\n<div>In HLSL 2021, this code will produce errors. If the old behavior is required the new `<span style=\"font-family: 'courier new', courier, monospace;\">and()<\/span>`, `<span style=\"font-family: 'courier new', courier, monospace;\">or()<\/span>`, and `<span style=\"font-family: 'courier new', courier, monospace;\">select()<\/span>` intrinsics can be applied as demonstrated below:<\/div>\n<div><\/div>\n<div><\/div>\n<pre>bool3 Cond = and(X, Y);\r\nbool3 Cond2 = or(X, Y);\r\nint3 Z = select(X, 1, 0);<\/pre>\n<div><\/div>\n<div>In cases where a single scalar evaluation is appropriate the `<span style=\"font-family: 'courier new', courier, monospace;\">any()<\/span>` intrinsic can be applied or an individual vector element can be used.<\/div>\n<div><\/div>\n<h3>C++ `<span style=\"font-family: 'courier new', courier, monospace;\">for<\/span>` Loop Scoping Rules<\/h3>\n<div>For compatibility with older versions of HLSL variables declared in the `<span style=\"font-family: 'courier new', courier, monospace;\">for<\/span>` statement of a `<span style=\"font-family: 'courier new', courier, monospace;\">for<\/span>` loop are attributed to the scope containing the `<span style=\"font-family: 'courier new', courier, monospace;\">for<\/span>` loop. This results in unexpected variable shadowing behavior. For example, in the code below the declaration of `<span style=\"font-family: 'courier new', courier, monospace;\">I<\/span>` in the `<span style=\"font-family: 'courier new', courier, monospace;\">for<\/span>` loop replaces the declaration of `<span style=\"font-family: 'courier new', courier, monospace;\">I<\/span>` outside the loop:<\/div>\n<div><\/div>\n<div><\/div>\n<pre>int I = 2;\r\nfor (int I = 0; I &lt; 10; ++I) {\r\n  \/\/ make pretty colors\r\n}\r\n\/\/ I == 10!!!<\/pre>\n<div>This behavior is a carry over from ANSI C, and was changed in C++ and C99.<\/div>\n<div><\/div>\n<div><\/div>\n<div>This change may cause code incompatibilities in your codebase. Code that declares variables in the `<span style=\"font-family: 'courier new', courier, monospace;\">for<\/span>` statement and expects the variables to be live after the end of the loop will no longer compile. Code that was relying on the old behavior can be fixed by hoisting the declaration out of the `<span style=\"font-family: 'courier new', courier, monospace;\">for<\/span>` statement.<\/div>\n<div><\/div>\n<h3>Template Functions and Data Types<\/h3>\n<div>HLSL 2021 adds support for C++-like templates for structs and functions. HLSL 2021 templates support full specializations, and template parameter inference when possible.<\/div>\n<div><\/div>\n<div><\/div>\n<div>Just as in C++, a template is declared using the `<span style=\"font-family: 'courier new', courier, monospace;\">template<\/span>` keyword and a template parameter list:<\/div>\n<div><\/div>\n<div><\/div>\n<pre>template&lt;typename T&gt;\r\nvoid increment(inout T X) {\r\n  X += 1;\r\n}<\/pre>\n<div>An explicit specialization can be declared using the `<span style=\"font-family: 'courier new', courier, monospace;\">template<\/span>` keyword with an empty parameter list:<\/div>\n<div><\/div>\n<div><\/div>\n<pre>template&lt;&gt;\r\nvoid increment(inout float3 X) {\r\n  X.x += 1.0;\r\n}<\/pre>\n<div>Partial template specializations are not supported at this time, but may be in a future release.<\/div>\n<div><\/div>\n<div><\/div>\n<div>Template functions are called using the normal syntax for function calls wherever the argument types allow for inferring the template parameters:<\/div>\n<div><\/div>\n<div><\/div>\n<pre>[numthreads(1,1,1)]\r\nvoid main() {\r\n  int X = 0;\r\n  int3 Y = {0,0,0};\r\n  float3 Z = {0.0,0.0,0.0};\r\n  increment(X);\r\n  increment(Y);\r\n  increment(Z);\r\n}<\/pre>\n<div>If a template parameter cannot be inferred by the input, HLSL templates follow C++ template rules and require parameters be specified at the call site:<\/div>\n<div><\/div>\n<div><\/div>\n<pre>template&lt;typename V, typename T&gt;\r\nV cast(T X) {\r\n  return (V)X;\r\n}\r\n\r\n[numthreads(1,1,1)]\r\nvoid main() {\r\n  int X = 1;\r\n  uint Y = cast&lt;uint&gt;(X);\r\n}<\/pre>\n<h3>Member Operator Overloading<\/h3>\n<div>HLSL 2021 is also extending programmers ability to create expressive custom data structures by enabling operator overloading on user defined data types. With HLSL 2021 you can override the arithmetic, bitwise, boolean, comparison, call, array subscript, and casting operators similar to how you would in C++.<\/div>\n<div><\/div>\n<div><\/div>\n<div>There are a few key differences from C++ that stem from HLSL not supporting reference and pointer types. Since operators cannot return references, some C++ operators do not make sense to override (address of `<span style=\"font-family: 'courier new', courier, monospace;\">&amp;<\/span>`, dereference `<span style=\"font-family: 'courier new', courier, monospace;\">*<\/span>` and pointer member `<span style=\"font-family: 'courier new', courier, monospace;\">-&gt;<\/span>` operators). This also means that operators that perform assignment (i.e. `<span style=\"font-family: 'courier new', courier, monospace;\">=<\/span>` or `<span style=\"font-family: 'courier new', courier, monospace;\">+=<\/span>`), and operators that generally return references to `<span style=\"font-family: 'courier new', courier, monospace;\">this<\/span>` (i.e. `<span style=\"font-family: 'courier new', courier, monospace;\">&lt;&lt;<\/span>` and `<span style=\"font-family: 'courier new', courier, monospace;\">&gt;&gt;<\/span>`) are not supported in HLSL 2021.<\/div>\n<div><\/div>\n<div><\/div>\n<div>Additionally since HLSL does not support dynamic memory allocation the `<span style=\"font-family: 'courier new', courier, monospace;\">new<\/span>` and `<span style=\"font-family: 'courier new', courier, monospace;\">delete<\/span>` operators cannot be overridden.<\/div>\n<div><\/div>\n<div><\/div>\n<div>The following code example demonstrates some of the ways that operators can be overloaded and used in HLSL 2021:<\/div>\n<div><\/div>\n<div><\/div>\n<pre>struct Pupper {\r\n  int Fur;\r\n\r\n  Pupper operator +(int MoarFur) {\r\n  \u00a0 Pupper Val = {Fur + MoarFur};\r\n  \u00a0 return Val;\r\n  }\r\n\r\n  bool operator &lt;=(int y){\r\n  \u00a0 return Fur &lt;= y;\r\n  }\r\n\r\n  operator bool() {\r\n  \u00a0 return Fur &gt; 50;\r\n  }\r\n};\r\n\r\n[numthreads(1, 1, 1)]\r\nvoid main(uint tidx : SV_DispatchThreadId) {\r\n  Pupper y = {0};\r\n  for (Pupper x = y; x &lt;= 100; x = x + 1) {\r\n  \u00a0 if ((bool)x)\r\n  \u00a0 \u00a0 y = y + 1;\r\n  }\r\n}<\/pre>\n<div>The full list of operators that can be overridden in HLSL 2021 are listed below.<\/div>\n<div>\n<table style=\"border-collapse: collapse; width: 100%; height: 116px;\">\n<tbody>\n<tr style=\"height: 30px;\">\n<td style=\"width: 50%; height: 30px;\">The arithmetic operators:<\/td>\n<td style=\"width: 50%; height: 30px;\">\u00a0`<span style=\"font-family: 'courier new', courier, monospace;\">+<\/span>`, `<span style=\"font-family: 'courier new', courier, monospace;\">&#8211;<\/span>`, `<span style=\"font-family: 'courier new', courier, monospace;\">*<\/span>`, `<span style=\"font-family: 'courier new', courier, monospace;\">\/<\/span>`, `<span style=\"font-family: 'courier new', courier, monospace;\">%<\/span>`<\/td>\n<\/tr>\n<tr style=\"height: 30px;\">\n<td style=\"width: 50%; height: 30px;\">The bitwise operators:<\/td>\n<td style=\"width: 50%; height: 30px;\">\u00a0`<span style=\"font-family: 'courier new', courier, monospace;\">&amp;<\/span>`, `<span style=\"font-family: 'courier new', courier, monospace;\">|<\/span>`, `<span style=\"font-family: 'courier new', courier, monospace;\">^<\/span>`<\/td>\n<\/tr>\n<tr style=\"height: 28px;\">\n<td style=\"width: 50%; height: 28px;\">Boolean and comparison operators:<\/td>\n<td style=\"width: 50%; height: 28px;\">\u00a0`<span style=\"font-family: 'courier new', courier, monospace;\">&amp;&amp;<\/span>`, `<span style=\"font-family: 'courier new', courier, monospace;\">||<\/span>`, `<span style=\"font-family: 'courier new', courier, monospace;\">!=<\/span>`, `<span style=\"font-family: 'courier new', courier, monospace;\">==<\/span>`, `<span style=\"font-family: 'courier new', courier, monospace;\">&lt;=<\/span>`, `<span style=\"font-family: 'courier new', courier, monospace;\">&gt;=<\/span>`, `<span style=\"font-family: 'courier new', courier, monospace;\">&lt;<\/span>`, `<span style=\"font-family: 'courier new', courier, monospace;\">&gt;<\/span>`<\/td>\n<\/tr>\n<tr style=\"height: 28px;\">\n<td style=\"width: 50%; height: 28px;\">Additional operators:<\/td>\n<td style=\"width: 50%; height: 28px;\">\u00a0call `<span style=\"font-family: 'courier new', courier, monospace;\">()<\/span>`, subscript `<span style=\"font-family: 'courier new', courier, monospace;\">[]<\/span>`, casts `<span style=\"font-family: 'courier new', courier, monospace;\">&lt;type&gt;<\/span>`.<\/td>\n<\/tr>\n<\/tbody>\n<\/table>\n<\/div>\n<p>&nbsp;<\/p>\n<h3>Bitfield Members in Data Types<\/h3>\n<div>In order to make it easier to utilize data structures from CPU code and provide more flexible integer sizes, HLSL 2021 has added bit field support for struct members. This allows specifying an arbitrary number of bits to use for an integer value inside a struct. Bit fields must be of an underlying integer type, but can be any number of bits less than the size of the specified type. With this syntax a 32-bit packed color could be represented as:<\/div>\n<div><\/div>\n<div><\/div>\n<pre>struct ColorRGBA {\r\n  uint R : 8;\r\n  uint G : 8;\r\n  uint B : 8;\r\n  uint A : 8;\r\n};<\/pre>\n<h3>Get Going!<\/h3>\n<div>We are very excited about all of these new features and we can&#8217;t wait to see what amazing things you do with them.<\/div>\n<div><\/div>\n<div><\/div>\n<div>All of these new features are available in the latest <a href=\"https:\/\/github.com\/microsoft\/DirectXShaderCompiler\/releases\/tag\/v1.6.2112\">DirectX Shader Compiler Release<\/a>, and should be backwards compatible to any DirectX 12 runtime.<\/div>\n<div><\/div>\n<div><\/div>\n<div>Special thanks to our partners at Google and AMD for their contributions to the HLSL 2021 release, and to our many users and contributors on GitHub.<\/div>\n<div><\/div>\n<div><\/div>\n<div>Please file any bugs you encounter with HLSL 2021 or HLSL generally against our <a href=\"https:\/\/github.com\/microsoft\/DirectXShaderCompiler\/\">GitHub project<\/a>.<\/div>\n<p>&nbsp;<\/p>\n","protected":false},"excerpt":{"rendered":"<p>Today we are excited to announce the release of HLSL 2021! HLSL 2021 brings an assortment of new language features that we think will make shader authoring in HLSL more familiar and productive. Enabling HLSL 2021 is as easy as passing the `-HV 2021`, and you can immediately start enjoying all the new language features [&hellip;]<\/p>\n","protected":false},"author":78222,"featured_media":5503,"comment_status":"open","ping_status":"closed","sticky":false,"template":"","format":"standard","meta":{"_acf_changed":false,"footnotes":""},"categories":[1],"tags":[],"class_list":["post-5502","post","type-post","status-publish","format-standard","has-post-thumbnail","hentry","category-directx"],"acf":[],"blog_post_summary":"<p>Today we are excited to announce the release of HLSL 2021! HLSL 2021 brings an assortment of new language features that we think will make shader authoring in HLSL more familiar and productive. Enabling HLSL 2021 is as easy as passing the `-HV 2021`, and you can immediately start enjoying all the new language features [&hellip;]<\/p>\n","_links":{"self":[{"href":"https:\/\/devblogs.microsoft.com\/directx\/wp-json\/wp\/v2\/posts\/5502","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/devblogs.microsoft.com\/directx\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/devblogs.microsoft.com\/directx\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/directx\/wp-json\/wp\/v2\/users\/78222"}],"replies":[{"embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/directx\/wp-json\/wp\/v2\/comments?post=5502"}],"version-history":[{"count":0,"href":"https:\/\/devblogs.microsoft.com\/directx\/wp-json\/wp\/v2\/posts\/5502\/revisions"}],"wp:featuredmedia":[{"embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/directx\/wp-json\/wp\/v2\/media\/5503"}],"wp:attachment":[{"href":"https:\/\/devblogs.microsoft.com\/directx\/wp-json\/wp\/v2\/media?parent=5502"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/directx\/wp-json\/wp\/v2\/categories?post=5502"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/directx\/wp-json\/wp\/v2\/tags?post=5502"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}