Closed chaoticbob closed 3 months ago
The way Slang compiler is architected is that we will always compile user code to platform-neutral Slang IR modules in-dependent of the final code generation target, and then specialize the IR to each target after linking.
This means that our front-end has no assumption or knowledge of the code gen target, and it cannot evaluate anything at parsing/type checking time that is target-dependent.
In function bodies, we already have __target_switch
that can deal with target-dependent code.
What is being asked is what should we do for the global scope.
I think this should be handled by the capability system. We can allow the user to do:
struct MyType
{
[target_specific(metal)] int metalOnlyField;
}
And the compiler can implement the behavior that such fields declared with require
is only available and defined for metal
, and attempting to use metalOnlyField
from a function intended for other targets is a type error.
In the meanwhile, the user can always choose to define those macros themselves if they know what target they are compiling for. It is just that we cannot provide a builtin __spirv__
macro due to the compiler design.
Got it! Thanks for the explanation, Yong.
Just looked at __target_switch
and it makes sense for any shader that's authored as Slang source. The syntax style is new to me and will take a bit to get used to, but from first reading it seems able to achieve similar things to the platform macro blocks. I do think the documentation could use some additional wording for anyone coming to look for a solution on how to customize behavior in function bodies for different targets.
For the case
statements, do the values just correspond to the arg values passed to -target
or is there a different mappings that users should be aware of?
Since the compiler can't support the macros due to architecture, we can address the issue through guidance per your suggestion of user defined macros.
For the very first example, you can use the command line argument to control the macro.
struct ParamDesc {
int Value;
};
#if defined(__spirv__)
[[vk::push_constant]]
#endif
ConstantBuffer<ParamDesc> Params : register(b1);
float4 main(float4 P : SV_POSITION) : SV_TARGET
{
return float4(Params.Value, 0, 0, 1);
}
In the command-line argument, you can use -D__spirv__
in your example above.
slangc.exe source.slang -target spirv -D__spirv__ -entry main -stage fragment
For the case statements, do the values just correspond to the arg values passed to -target or is there a different mappings that users should be aware of?
For the case
statements you may pass almost any capabilities from the Slang capabilities system to target specific feature sets
case GLSL_450:
will only be targeted if a user compiles code with equal to or greater than GLSL450 capabilities.For most users, case glsl:
case spirv:
case hlsl:
default:
will be enough.
For examples, hlsl.meta.slang
and glsl.meta.slang
is a good reference for how to use __target_switch
.
@ArielG-NV Just for completeness, will there also be a Metal target as well? Something like metal
?
@chaoticbob Yes, the metal
capability is already defined.
there already is a metal
target
the targets:
cpp
, metal
, glsl
, hlsl
, spirv
, cuda
Thanks. Closing this issue, will follow with @bmillsNV and @swoods-nv about documentation.
In some cases, it would be useful to have a preprocessor macro for targets to allow custom handling for the target's platform.
For example, when compiling to SPIRV, it would be useful to have
__spirv__
to add attribute decorations to resource declarations:For the above case, not all compilers can handle attribute decorations and ignore unknown ones. FXC fails with a syntax error if the surrounding
#if defined
is removed:Another example is when using mesh shaders, there's some functionality differences between Apple GPUs and PC GPUs that users may wish to custom handle:
Besides having
__spirv__
to maintain compatibility with DXC, I don't have recommendations on what the preprocessor macros should be for the targets.