Re: WHLSL Compatibility with HLSL

Miles,

Apologies, the HLSL semantics link/point is understood now. Please 
disregard my answer about this.

-Dzmitry

On 11/27/18 10:12 PM, Dzmitry Malyshau wrote:
>
> Hi Miles,
>
>
>>>
>>> Hi Myles,
>>>
>>> Thank you for sharing!
>>>
>>> Reading about the vast field of syntax features (preprocessor, array 
>>> syntax, call syntax, float literals, casts, etc) that raise 
>>> questions but ultimately not required to be specially handled by 
>>> WebGPU implementations only strengthens the point that human 
>>> writable format has different requirements from 
>>> implementation-digestable one,
>>>
>> I don’t understand this argument. SPIR-V has array syntax, float 
>> literals, and casts too.
>
>
> Well, the problem with HLSL is that there are different array syntaxes 
> possible, e.g. "float myArray[40]"  versus "float[40] myArray", while 
> SPIR-V has one and only syntax. Same for casts.
>
> For float literals, in SPIR-V there isn't a question whether exponent 
> notation needs to be supported.
>
>
>>> and one way or another we are approaching the point where some build 
>>> step is required before the actual authored shader source gets to 
>>> the backend.
>>>
>> We’re modifying WHLSL to accept existing HLSL programs. We’re not 
>> expecting web authors to run a build step to produce WHLSL from their 
>> HLSL source.
>
>
> On the last call we were elaborating about which side needs to run the 
> preprocessor. It's effectively a build step.
>
>
>>> > It appears that HLSL allows any arbitrary semantic for stage 
>>> in/out parameters. Around 30% of the corpus uses a semantic that 
>>> WHLSL doesn’t currently accept.
>>>
>>> In HLSL the semantic name is basically the "port to the outside". If 
>>> it's built-in, then the "outside" is the graphics/compute pipeline, 
>>> if it's user-defined, then it's the user code that can query the 
>>> names. I didn't realize this would be different for WHLSL.
>>>
>>>
>>
>> I don’t quite understand what you are describing. In any modern 3D 
>> graphics API, there is linkage between the graphics API and the 
>> inputs/outputs (MSL calls these [[ attribute(n) ]]) and between the 
>> vertex & fragment shaders (MSL calls these [[ user(n) ]]). When 
>> researching HLSL, I thought the list in the docs 
>> <https://docs.microsoft.com/en-us/windows/desktop/direct3dhlsl/dx-graphics-hlsl-semantics> was 
>> exhaustive, but it looks like it isn’t.
>
>
> This link is for DX9 semantics, which is long deprecated. In 
> non-compat (in the sense of DX9 compatibility) HLSL all the built-in 
> semantics starts with "SV_", and everything else is user defined. Does 
> WHLSL not have user-defined semantics?
>
>
>>> > There are a whole collection of variable modifiers that HLSL 
>>> sources use that WHLSL doesn’t accept. E.g. row_major float4x4 
>>> mvpMatrix;
>>>
>>> Is this on your radar?
>>>
>> Not quite sure what this question means. Yes?
>>>
>>> > HLSL has some hints about how the compiler should treat branches 
>>> and loops. They look like [ unroll ] for (…) and [ branch ] if ( …). 
>>> I don’t think these have semantic meaning so we can probably just 
>>> swallow them.
>>>
>>> I vaguely recall this to affect ERR_GRADIENT_FLOW**errors (aka 
>>> "Gradient operations can't occur inside loops with divergent flow 
>>> control."). So it may be more than just a hint.
>>>
>> Thanks for the tip; we’ll investigate this.
>>>
>>> Cheers,
>>>
>>> Dzmitry
>>>
>>> On 11/27/18 5:29 PM, Myles C. Maxfield wrote:
>>>> Over the past few days, I’ve collected a large corpus of HLSL files 
>>>> so we can determine what we need to do to be source-compatible with 
>>>> existing HLSL source.
>>>>
>>>> *The Corpus*
>>>>
>>>> I wrote a GitHub crawler which looked for repositories that had 
>>>> many HLSL files in them. I looked over the results of this crawler 
>>>> and hand-picked a few repositories that are from respectable 
>>>> sources. In total, we ended up with 2099 HLSL files.
>>>>
>>>> The list of repositories:
>>>>
>>>>   * Microsoft/DirectX-Graphics-Samples
>>>>   * vvvv/vvvv-sdk
>>>>       o Of limited use, because most of the source is written in
>>>>         another language (Effects) which includes HLSL snippets.
>>>>         GitHub classifies this as HLSL.
>>>>   * Unity-Technologies/ScriptableRenderPipeline
>>>>       o Of limited use, because most of the source is written in
>>>>         another language (Shaderlab) which includes HLSL snippets.
>>>>         GitHub classifies this as HLSL.
>>>>   * Microsoft/Windows-universal-samples
>>>>   * OGRECave/ogre
>>>>   * EpicGames/UnrealEngine
>>>>       o Of limited use, because most of the source is written in
>>>>         another language (Unreal Shader Format) which includes HLSL
>>>>         snippets. GitHub classifies this as HLSL.
>>>>   * ConfettiFX/The-Forge
>>>>   * AtomicGameEngine/AtomicGameEngine
>>>>   * NVIDIAGameWorks/D3DSamples
>>>>   * EpicGames/UnrealTournament
>>>>       o Of limited use, because most of the source is written in
>>>>         another language (Unreal Shader Format) which includes HLSL
>>>>         snippets. GitHub classifies this as HLSL.
>>>>   * urho3d/Urho3D
>>>>   * NVIDIAGameWorks/HairWorks
>>>>   * NVIDIAGameWorks/WaveWorks
>>>>       o Of limited use, because most of the source is written in
>>>>         another language (Effects) which includes HLSL snippets.
>>>>         GitHub classifies this as HLSL.
>>>>   * NVIDIAGameWorks/FleX
>>>>   * Unity-Technologies/PostProcessing
>>>>       o Of limited use, because most of the source is written in
>>>>         another language (Shaderlab) which includes HLSL snippets.
>>>>         GitHub classifies this as HLSL.
>>>>   * NVIDIAGameWorks/Falcor
>>>>   * NVIDIAGameWorks/FaceWorks
>>>>   * NVIDIAGameWorks/HBAOPlus
>>>>   * GPUOpen-LibrariesAndSDKs/GPUParticles11
>>>>   * NVIDIAGameWorks/VolumetricLighting
>>>>   * GPUOpen-Effects/ShadowFX
>>>>   * GPUOpen-LibrariesAndSDKs/LiquidVR
>>>>   * NVIDIAGameWorks/NvCloth
>>>>   * GPUOpen-Effects/DepthOfFieldFX
>>>>   * NVIDIAGameWorks/PhysX-3.4
>>>>   * GPUOpen-Effects/GeometryFX
>>>>   * GPUOpen-LibrariesAndSDKs/TiledLighting11
>>>>   * NVIDIAGameWorks/Flow
>>>>   * GPUOpen-LibrariesAndSDKs/ForwardPlus11
>>>>   * Microsoft/Win2D
>>>>   * GPUOpen-LibrariesAndSDKs/SSAA11
>>>>   * Microsoft/Win2D-Samples
>>>>   * PixarAnimationStudios/OpenSubdiv
>>>>
>>>> We could potentially figure out how to compile Effects, Shaderlab 
>>>> and Unreal Shader Format to HLSL (because that’s what their engines 
>>>> do). If we did this, we could grow the repository by 13% + 8% + 15% 
>>>> (respectively) = 36%. I didn’t want to get bogged down doing this, 
>>>> though.
>>>>
>>>> *Preprocessor*
>>>>
>>>> HLSL Source files make heavy use of the preprocessor. Each file 
>>>> includes an average of 9.61 uses of the preprocessor (lines that 
>>>> begin with “#”) and the preprocessor is used on average every 11.68 
>>>> lines.
>>>>
>>>> <Screen Shot 2018-11-13 at 1.03.53 PM.jpeg>
>>>>
>>>> As you can see above, most of the users of the preprocessor are not 
>>>> to include files, but are instead to enable / disable features. 
>>>> Therefore, this is a situation where compatibility with existing 
>>>> HLSL source is directly in conflict with simplicity of the language.
>>>>
>>>> I proceeded by running the corpus through the Microsoft HLSL 
>>>> preprocessor, and investigated the preprocessed files. My analysis 
>>>> is just based on the parsing stage of the language, not name 
>>>> resolution or type checking. Out-of-the-box, we parse 5.9% of the 
>>>> corpus.
>>>>
>>>> *Language Features*
>>>>
>>>> From investigating the source, I found some language features that 
>>>> HLSL depends on.
>>>>
>>>> In MSL, if you want to pass some data to your shader, you make a 
>>>> struct, and pass a reference to that struct as an argument of the 
>>>> main function. Then, in the main function, you reference the data 
>>>> by saying theReference.field. This approach is possible in HLSL, 
>>>> but there’s another more common way to do it. Instead of making a 
>>>> struct, you make a “cbuffer” which lists a set of fields, but those 
>>>> fields are treated as global variables. The cbuffer is given a 
>>>> “semantic” so the API can attach memory to back the cbuffer.
>>>>
>>>> cbuffer Camera : register(b0) // The API assigns memory to this 
>>>> block by using the “b0” handle
>>>> {
>>>>   float4x4 viewProjection;
>>>>   float4x4 projectionInv;
>>>>   float3 viewPos;
>>>> };
>>>>
>>>> Output main() {
>>>> output.foo = viewProjection; // viewProjection, projectionInv, and 
>>>> viewPos are in the global scope.
>>>> return output;
>>>> }
>>>>
>>>> About 1/3 of the files in the corpus use cbuffers.
>>>>
>>>> HLSL has two flavors of global variables:
>>>>
>>>>  1. Resources, like RWTexture2D<float2> dstTexture : register(u0);.
>>>>     These work just like entry point parameters, except they are in
>>>>     the global scope and therefore can be accessed from any
>>>>     function, without passing around a pointer to them.
>>>>  2. Literal data, like static const float convolutionWeights[] =
>>>>     {1, 2, 3};.
>>>>
>>>>
>>>> About 1/5 of the files in the corpus use global variables.
>>>>
>>>> HLSL supports default arguments in function parameters and 
>>>> cbuffers, so you can say void foo(int x = 3);. I would imagine 
>>>> specifying this would be tricky because we have to mention which 
>>>> variables and functions the initial value can refer to.
>>>>
>>>> Many files in the corpus use HLSL’s syntax for sampler literals, 
>>>> but those aren’t supported in SPIR-V, so I think we can safely 
>>>> ignore those. I don’t know what the SPIR-V Cross guys are doing 
>>>> about that.
>>>>
>>>> *New Syntax*
>>>>
>>>> There are lots of changes to the syntax of the language that 
>>>> shouldn’t have much of an effect on the language itself, but are 
>>>> required if we want to claim compatibility with lots of HLSL sources.
>>>>
>>>>   * Removing the entry point keywords (vertex, fragment, compute)
>>>>     is a requirement for any shader to compile. Instead, we should
>>>>     require that compilation of a WHLSL file state which function
>>>>     names are the entry points.
>>>>   * It appears that HLSL allows any arbitrary semantic for stage
>>>>     in/out parameters. Around 30% of the corpus uses a semantic
>>>>     that WHLSL doesn’t currently accept.
>>>>   * Some functions in the HLSL standard library use
>>>>     member-function-syntax, like texture.Sample(sampler, location)
>>>>     instead of Sample(texture, sampler, location).
>>>>   * There are a whole collection of variable modifiers that HLSL
>>>>     sources use that WHLSL doesn’t accept. E.g. row_major float4x4
>>>>     mvpMatrix;
>>>>   * HLSL has a few function modifiers like [ RootSignature(…stuff
>>>>     goes here…) ] void foo(…) { … } that are irrelevant for WebGPU.
>>>>     This includes information about the D3D root signature, but
>>>>     also things like how geometry shaders and tessellation work,
>>>>     which WebGPU doesn’t have.
>>>>   * HLSL arrays put the brackets after the variable name, like
>>>>     float myArray[40];
>>>>   * Arrays and structs can be initialized using brackets, like
>>>>     float myArray[3] = { 1.0, 2.0, 3.0 };
>>>>   * HLSL has some hints about how the compiler should treat
>>>>     branches and loops. They look like [ unroll ] for (…) and [
>>>>     branch ] if ( …). I don’t think these have semantic meaning so
>>>>     we can probably just swallow them.
>>>>   * HLSL uses C-style casts instead of C++-style casts. So, we need
>>>>     to support (float)x instead of float(x).
>>>>   * HLSL accepts float literals with exponents, like 1e-3.
>>>>   * Functions can be forward-declared in HLSL.
>>>>
>>>>
>>>> After doing all that, we get up to around 90% compatibility with 
>>>> parsing (not resolving names nor type checking) the HLSL corpus. 
>>>> The biggest wins are member-function syntax, allowing every 
>>>> semantic name, C-style casting, and C-style array syntax.
>>>>
>>>> —Myles
>>

Received on Wednesday, 28 November 2018 03:16:25 UTC