Skip to content

Commit

Permalink
Initial WGSL support (shader-slang#5006)
Browse files Browse the repository at this point in the history
* Add WGSL as a target

This is required for shader-slang#4807.

* C-like emitter: Allow the function header emission to be overloaded

WGSL-style function headers are pretty different from normal C-style headers:

Normal C-style headers:
 ReturnType Func(...)
 void VoidFunc(...)

WGSL-style headers:
  fn Func(...) -> ReturnType
  fn VoidFunc(...)

This change allows the header style to be overloaded, in order to accomodate WGSL-style
headers as required to resolve issue shader-slang#4807, but retains normal C-style headers as the
default implementation.

[1] https://www.w3.org/TR/WGSL/#function-declaration-sec

* C-like emitter: Allow emission of switch case selectors to be overloaded

The C-like emitter will emit code like this:

    switch(a.x)
    {

    case 0:
    case 1:
    {
       ...
    } break;

    ...

    }

This is not allowed in WGSL. Instead, selectors for cases that share a body must [1] be
separated by commas, like this:

    switch(a.x)
    {

    case 0, 1:
    {
       ...
    } break;

    ...

    }

To prepare for addressing issue shader-slang#4807, this patch makes the emission of switch case
selectors overloadable.

[1] https://www.w3.org/TR/WGSL/#syntax-case_selectors

* C-like emitter: Support WGSL-style declarations

This patch helps to address issue 4807.

C-like languages declare variables like this:
i32 a;

WGSL declares variables like this:
var a : i32

The patch introduces overloads so that the forthcoming WGSL emitter can output WGSL-style
declarations, which helps to resolve shader-slang#4807.

* C-like emitter: Support overloading of declarators

Unlike C-like languages, WGSL does not support the following types at the syntax level,
via declarators:
- arrays
- pointers
- references

For this reason, this patch introduces support for overloading the declarator emitter,
in order to help address issue shader-slang#4807.

C-like languages:
int a[3]; // Array-ness of type is mixed into the "declarator"

WGSL:
var a : array<int, 3>; // Array-ness of type is part of the... type_specifier!

* C-like emitter: Allow struct declaration separator to be overridden

C-like languages use ';' as a separator, and languages like e.g. WGSL use ','.
This change prepares for addressing issue shader-slang#4807.

* C-like emitter: Allow overriding of whether pointer-like syntax is necessary

Things like e.g. structured buffers map to "ptr-to-array" in WGSL, but ptr-typed
expressions don't always need C-style pointer-like syntax.
Therefore, make it overrideable whether or not such syntax is emitted in various cases in
order to address shader-slang#4807.

* C-like emitter: Emit parenthesis to avoid warning about & and + precedence

This helps with shader-slang#4807 because WGSL compilers (e.g. Tint) treat absence of parenthesis as
an error.

* C-like emitter: Add hook for emitting struct field attributes

WGSL requires @align attributes to specify explicit field alignment in certain cases.
Thus, this patch prepares for addressing shader-slang#4807.

* C-like emitter: Add hook for emitting global param types

Declarations of structured buffers map to global array declarations in WGSL.
However, in all other cases such as when structured buffers are used in operands, their
types map to *ptr*-to-array.
This patch makes it possible for the WGSL back-end to say that structured buffers
generally map to "ptr-to-array" types, but still have a special case of just "array" when
declaring the global shader parameter.

Thus, this patch helps with addressing shader-slang#4807.

* IR lowering: Use std140 for WGSL uniform buffers

This patch just cuts out some logic that prevented std140 to be chosen for WGSL uniform
buffers.

Note that WGSL buffers in the uniform address space is not quite std140, but for now it's
close enough to avoid compile issues.

Later on, a custom layout should be created for WGSL uniform buffers.
When that's done, this change will be revisited, but for now it helps to resolve shader-slang#4807.

* Don't emit line directives in WGSL by default

WGSL does not support line directives [1].
The plan currently seems to be to instead support source-map [2].
This is part of addressing issue shader-slang#4807.

[1] gpuweb/gpuweb#606
[2] https://github.com/mozilla/source-map

* WGSL IR legalization: Map SV's

The implementation closely follows the cooresponding one for Metal.

Supported:
- DispatchThreadID
- GroupID
- GroupThreadID
- GroupThreadID

Unsupported:
- GSInstanceID

This is not complete, but it helps to address shader-slang#4807.

* WGSL emitter: Add support for basic language constructs

A lot of the basics are added in order to generate correct WGSL code for basic Slang language constructs.
This addresses issue shader-slang#4807.

This adds support for at least the following:
- statments
 - if statements
 - ternary operator
 - while statement
 - for statements
 - variable declarations
 - switch statements
  - Note: Slang may emit non-constant case expressions, see issue 4834
- literals
 - integer literals
  - u?int[16|32|64]_t
  - float and half literals
  - bool literals
  - vector literals and splatting (e.g 1.xxx)
- function definitions
- assignments
 - +=, *=, /=
 - array assignments
 - vector assignments/updates
  - swizzles of other vectors
  - from matrix rows ('m[i]' notation)
  - from matrix cols (using swizzle notation, e.g 'm._11_12_13')
 - matrix assignments/updates
  - to rows ('m[i]' notation)
  - to cols (using swizzle notation, e.g 'm._11_12_13')
- declarations
 - arrays

[1] https://www.w3.org/TR/WGSL/#syntax-switch_body

* Add some WGSL capabilities

This patch registers some WGSL capabilities required to pass many of the initial compute
shader compile tests.
Many capabilities still remain to be added -- this is just an initial set to help resolve
issue shader-slang#4807.

- asint
- min and max
- cos and sin
- all and any

* WGSL and C-like emitters: Add hack to bitcast case expression

In WGSL, the switch condition and case types must match.
https://www.w3.org/TR/WGSL/#switch-statement

Slang currently allows these types to mismatch, as pointed out in shader-slang#4921.

Issue shader-slang#4921 should eventually be addressed in the front-end by a patch like [1].
However, at the moment that would break Falcor tests.
Thus, this patch temporarily works around the issue in the WGSL emitter only in order to
help resolve shader-slang#4807.

In the future, the Falcor tests should be fixed, this patch should be dropped and [1]
should be merged instead.

[1] a32156e
  • Loading branch information
aleino-nv authored Sep 9, 2024
1 parent 110d82f commit 170558c
Show file tree
Hide file tree
Showing 22 changed files with 1,630 additions and 56 deletions.
2 changes: 2 additions & 0 deletions include/slang.h
Original file line number Diff line number Diff line change
Expand Up @@ -603,6 +603,7 @@ extern "C"
SLANG_METAL_LIB, ///< Metal library
SLANG_METAL_LIB_ASM, ///< Metal library assembly
SLANG_HOST_SHARED_LIBRARY, ///< A shared library/Dll for host code (for hosting CPU/OS)
SLANG_WGSL, ///< WebGPU shading language
SLANG_TARGET_COUNT_OF,
};

Expand Down Expand Up @@ -735,6 +736,7 @@ extern "C"
SLANG_SOURCE_LANGUAGE_CUDA,
SLANG_SOURCE_LANGUAGE_SPIRV,
SLANG_SOURCE_LANGUAGE_METAL,
SLANG_SOURCE_LANGUAGE_WGSL,
SLANG_SOURCE_LANGUAGE_COUNT_OF,
};

Expand Down
3 changes: 3 additions & 0 deletions source/compiler-core/slang-artifact-desc-util.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -197,6 +197,7 @@ SLANG_HIERARCHICAL_ENUM(ArtifactKind, SLANG_ARTIFACT_KIND, SLANG_ARTIFACT_KIND_E
x(CUDA, Source) \
x(Metal, Source) \
x(Slang, Source) \
x(WGSL, Source) \
x(KernelLike, Base) \
x(DXIL, KernelLike) \
x(DXBC, KernelLike) \
Expand Down Expand Up @@ -288,6 +289,7 @@ SLANG_HIERARCHICAL_ENUM(ArtifactStyle, SLANG_ARTIFACT_STYLE, SLANG_ARTIFACT_STYL
case SLANG_METAL: return Desc::make(Kind::Source, Payload::Metal, Style::Kernel, 0);
case SLANG_METAL_LIB: return Desc::make(Kind::Executable, Payload::MetalAIR, Style::Kernel, 0);
case SLANG_METAL_LIB_ASM: return Desc::make(Kind::Assembly, Payload::MetalAIR, Style::Kernel, 0);
case SLANG_WGSL: return Desc::make(Kind::Source, Payload::WGSL, Style::Kernel, 0);
default: break;
}

Expand Down Expand Up @@ -330,6 +332,7 @@ SLANG_HIERARCHICAL_ENUM(ArtifactStyle, SLANG_ARTIFACT_STYLE, SLANG_ARTIFACT_STYL
case Payload::Cpp: return (desc.style == Style::Host) ? SLANG_HOST_CPP_SOURCE : SLANG_CPP_SOURCE;
case Payload::CUDA: return SLANG_CUDA_SOURCE;
case Payload::Metal: return SLANG_METAL;
case Payload::WGSL: return SLANG_WGSL;
default: break;
}
break;
Expand Down
1 change: 1 addition & 0 deletions source/compiler-core/slang-artifact.h
Original file line number Diff line number Diff line change
Expand Up @@ -143,6 +143,7 @@ enum class ArtifactPayload : uint8_t
CUDA, ///< CUDA source
Metal, ///< Metal source
Slang, ///< Slang source
WGSL, ///< WGSL source

KernelLike, ///< GPU Kernel like

Expand Down
1 change: 1 addition & 0 deletions source/core/slang-type-text-util.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -63,6 +63,7 @@ static const TypeTextUtil::CompileTargetInfo s_compileTargetInfos[] =
{ SLANG_METAL, "metal", "metal", "Metal shader source" },
{ SLANG_METAL_LIB, "metallib", "metallib", "Metal Library Bytecode" },
{ SLANG_METAL_LIB_ASM, "metallib-asm" "metallib-asm", "Metal Library Bytecode assembly" },
{ SLANG_WGSL, "wgsl", "wgsl", "WebGPU shading language source" },
};

static const NamesDescriptionValue s_languageInfos[] =
Expand Down
1 change: 1 addition & 0 deletions source/slang-record-replay/util/emum-to-string.h
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,7 @@ namespace SlangRecord
CASE(SLANG_METAL_LIB);
CASE(SLANG_METAL_LIB_ASM);
CASE(SLANG_HOST_SHARED_LIBRARY);
CASE(SLANG_WGSL);
CASE(SLANG_TARGET_COUNT_OF);
default:
Slang::StringBuilder str;
Expand Down
29 changes: 20 additions & 9 deletions source/slang/hlsl.meta.slang
Original file line number Diff line number Diff line change
Expand Up @@ -5668,7 +5668,7 @@ vector<T,N> acosh(vector<T,N> x)
// Test if all components are non-zero (HLSL SM 1.0)
__generic<T : __BuiltinType>
[__readNone]
[require(cpp_cuda_glsl_hlsl_metal_spirv)]
[require(cpp_cuda_glsl_hlsl_metal_spirv_wgsl)]
bool all(T x)
{
__target_switch
Expand All @@ -5679,6 +5679,8 @@ bool all(T x)
__intrinsic_asm "all";
case metal:
__intrinsic_asm "all";
case wgsl:
__intrinsic_asm "all";
case spirv:
let zero = __default<T>();
if (__isInt<T>())
Expand Down Expand Up @@ -5806,7 +5808,7 @@ int3 WorkgroupSize();

__generic<T : __BuiltinType>
[__readNone]
[require(cpp_cuda_glsl_hlsl_metal_spirv)]
[require(cpp_cuda_glsl_hlsl_metal_spirv_wgsl)]
bool any(T x)
{
__target_switch
Expand All @@ -5817,6 +5819,8 @@ bool any(T x)
__intrinsic_asm "any";
case metal:
__intrinsic_asm "any";
case wgsl:
__intrinsic_asm "any";
case spirv:
let zero = __default<T>();
if (__isInt<T>())
Expand Down Expand Up @@ -6142,7 +6146,7 @@ vector<T,N> asinh(vector<T,N> x)
// Reinterpret bits as an int (HLSL SM 4.0)

[__readNone]
[require(cpp_cuda_glsl_hlsl_metal_spirv, shader5_sm_4_0)]
[require(cpp_cuda_glsl_hlsl_metal_spirv_wgsl, shader5_sm_4_0)]
int asint(float x)
{
__target_switch
Expand All @@ -6152,6 +6156,7 @@ int asint(float x)
case glsl: __intrinsic_asm "floatBitsToInt";
case hlsl: __intrinsic_asm "asint";
case metal: __intrinsic_asm "as_type<$TR>($0)";
case wgsl: __intrinsic_asm "bitcast<$TR>($0)";
case spirv: return spirv_asm {
OpBitcast $$int result $x
};
Expand Down Expand Up @@ -6285,7 +6290,7 @@ void asuint(double value, out uint lowbits, out uint highbits)
// Reinterpret bits as a uint (HLSL SM 4.0)

[__readNone]
[require(cpp_cuda_glsl_hlsl_metal_spirv, shader5_sm_4_0)]
[require(cpp_cuda_glsl_hlsl_metal_spirv_wgsl, shader5_sm_4_0)]
uint asuint(float x)
{
__target_switch
Expand All @@ -6295,6 +6300,7 @@ uint asuint(float x)
case glsl: __intrinsic_asm "floatBitsToUint";
case hlsl: __intrinsic_asm "asuint";
case metal: __intrinsic_asm "as_type<$TR>($0)";
case wgsl: __intrinsic_asm "bitcast<$TR>($0)";
case spirv: return spirv_asm {
OpBitcast $$uint result $x
};
Expand Down Expand Up @@ -7025,7 +7031,7 @@ void clip(matrix<T,N,M> x)
// Cosine
__generic<T : __BuiltinFloatingPointType>
[__readNone]
[require(cpp_cuda_glsl_hlsl_metal_spirv, sm_4_0_version)]
[require(cpp_cuda_glsl_hlsl_metal_spirv_wgsl, sm_4_0_version)]
T cos(T x)
{
__target_switch
Expand All @@ -7035,6 +7041,7 @@ T cos(T x)
case glsl: __intrinsic_asm "cos";
case hlsl: __intrinsic_asm "cos";
case metal: __intrinsic_asm "cos";
case wgsl: __intrinsic_asm "cos";
case spirv: return spirv_asm {
OpExtInst $$T result glsl450 Cos $x
};
Expand Down Expand Up @@ -10427,7 +10434,7 @@ matrix<T, N, M> mad(matrix<T, N, M> mvalue, matrix<T, N, M> avalue, matrix<T, N,
// maximum
__generic<T : __BuiltinIntegerType>
[__readNone]
[require(cpp_cuda_glsl_hlsl_metal_spirv, sm_4_0_version)]
[require(cpp_cuda_glsl_hlsl_metal_spirv_wgsl, sm_4_0_version)]
T max(T x, T y)
{
// Note: a stdlib implementation of `max` (or `min`) will require splitting
Expand All @@ -10440,6 +10447,7 @@ T max(T x, T y)
case hlsl: __intrinsic_asm "max";
case glsl: __intrinsic_asm "max";
case metal: __intrinsic_asm "max";
case wgsl: __intrinsic_asm "max";
case cuda: __intrinsic_asm "$P_max($0, $1)";
case cpp: __intrinsic_asm "$P_max($0, $1)";
case spirv:
Expand Down Expand Up @@ -10656,14 +10664,15 @@ vector<T,N> fmax3(vector<T,N> x, vector<T,N> y, vector<T,N> z)
// minimum
__generic<T : __BuiltinIntegerType>
[__readNone]
[require(cpp_cuda_glsl_hlsl_metal_spirv, sm_4_0_version)]
[require(cpp_cuda_glsl_hlsl_metal_spirv_wgsl, sm_4_0_version)]
T min(T x, T y)
{
__target_switch
{
case hlsl:
case glsl:
case metal:
case wgsl:
__intrinsic_asm "min";
case cuda:
case cpp:
Expand Down Expand Up @@ -11103,13 +11112,14 @@ T mul(vector<T, N> x, vector<T, N> y)
// vector-matrix
__generic<T : __BuiltinFloatingPointType, let N : int, let M : int>
[__readNone]
[require(cpp_cuda_glsl_hlsl_metal_spirv, sm_4_0_version)]
[require(cpp_cuda_glsl_hlsl_metal_spirv_wgsl, sm_4_0_version)]
vector<T, M> mul(vector<T, N> left, matrix<T, N, M> right)
{
__target_switch
{
case glsl: __intrinsic_asm "($1 * $0)";
case metal: __intrinsic_asm "($1 * $0)";
case wgsl: __intrinsic_asm "($1 * $0)";
case hlsl: __intrinsic_asm "mul";
case spirv: return spirv_asm {
OpMatrixTimesVector $$vector<T, M> result $right $left
Expand Down Expand Up @@ -12166,7 +12176,7 @@ matrix<int, N, M> sign(matrix<T, N, M> x)

__generic<T : __BuiltinFloatingPointType>
[__readNone]
[require(cpp_cuda_glsl_hlsl_metal_spirv, sm_4_0_version)]
[require(cpp_cuda_glsl_hlsl_metal_spirv_wgsl, sm_4_0_version)]
T sin(T x)
{
__target_switch
Expand All @@ -12176,6 +12186,7 @@ T sin(T x)
case glsl: __intrinsic_asm "sin";
case hlsl: __intrinsic_asm "sin";
case metal: __intrinsic_asm "sin";
case wgsl: __intrinsic_asm "sin";
case spirv: return spirv_asm {
OpExtInst $$T result glsl450 Sin $x
};
Expand Down
15 changes: 12 additions & 3 deletions source/slang/slang-capabilities.capdef
Original file line number Diff line number Diff line change
Expand Up @@ -111,6 +111,10 @@ def metal : target + textualTarget;
/// [Target]
def spirv : target;

/// Represents the WebGPU shading language code generation target.
/// [Target]
def wgsl : target + textualTarget;

// Capabilities that stand for target SPIR-V versions for the GLSL backend.
// These are not compilation targets. We will convert `_spirv_*` to `glsl_spirv_*` during compilation.

Expand Down Expand Up @@ -228,15 +232,15 @@ def _cuda_sm_9_0 : _cuda_sm_8_0;

/// All code-gen targets
/// [Compound]
alias any_target = hlsl | metal | glsl | c | cpp | cuda | spirv;
alias any_target = hlsl | metal | glsl | c | cpp | cuda | spirv | wgsl;

/// All non-asm code-gen targets
/// [Compound]
alias any_textual_target = hlsl | metal | glsl | c | cpp | cuda;
alias any_textual_target = hlsl | metal | glsl | c | cpp | cuda | wgsl;

/// All slang-gfx compatible code-gen targets
/// [Compound]
alias any_gfx_target = hlsl | metal | glsl | spirv;
alias any_gfx_target = hlsl | metal | glsl | spirv | wgsl;

/// All "cpp syntax" code-gen targets
/// [Compound]
Expand Down Expand Up @@ -266,6 +270,10 @@ alias cpp_cuda_glsl_hlsl_spirv = cpp | cuda | glsl | hlsl | spirv;
/// [Compound]
alias cpp_cuda_glsl_hlsl_metal_spirv = cpp | cuda | glsl | hlsl | metal | spirv;

/// CPP, CUDA, GLSL, HLSL, Metal, SPIRV and WGSL code-gen targets
/// [Compound]
alias cpp_cuda_glsl_hlsl_metal_spirv_wgsl = cpp | cuda | glsl | hlsl | metal | spirv | wgsl;

/// CPP, CUDA, and HLSL code-gen targets
/// [Compound]
alias cpp_cuda_hlsl = cpp | cuda | hlsl;
Expand Down Expand Up @@ -1178,6 +1186,7 @@ alias sm_4_0_version = _sm_4_0
| spirv_1_0
| _cuda_sm_2_0
| metal
| wgsl
| cpp
;

Expand Down
1 change: 1 addition & 0 deletions source/slang/slang-compiler.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1715,6 +1715,7 @@ namespace Slang
case CodeGenTarget::PyTorchCppBinding:
case CodeGenTarget::CSource:
case CodeGenTarget::Metal:
case CodeGenTarget::WGSL:
{
RefPtr<ExtensionTracker> extensionTracker = _newExtensionTracker(target);

Expand Down
1 change: 1 addition & 0 deletions source/slang/slang-compiler.h
Original file line number Diff line number Diff line change
Expand Up @@ -94,6 +94,7 @@ namespace Slang
Metal = SLANG_METAL,
MetalLib = SLANG_METAL_LIB,
MetalLibAssembly = SLANG_METAL_LIB_ASM,
WGSL = SLANG_WGSL,
CountOf = SLANG_TARGET_COUNT_OF,
};

Expand Down
4 changes: 4 additions & 0 deletions source/slang/slang-doc-markdown-writer.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -483,6 +483,10 @@ static DocMarkdownWriter::Requirement _getRequirementFromTargetToken(const Token
{
return Requirement{ CodeGenTarget::Metal, targetName };
}
else if (isCapabilityDerivedFrom(targetCap, CapabilityAtom::wgsl))
{
return Requirement{ CodeGenTarget::WGSL, targetName };
}
return Requirement{ CodeGenTarget::Unknown, String() };
}

Expand Down
Loading

0 comments on commit 170558c

Please sign in to comment.