- From: Dzmitry Malyshau <dmalyshau@mozilla.com>
- Date: Tue, 27 Nov 2018 22:12:48 -0500
- To: "Myles C. Maxfield" <mmaxfield@apple.com>
- Cc: public-gpu@w3.org
- Message-ID: <1e6d355d-906a-19a5-22be-153e9bfcc3fa@mozilla.com>
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:13:13 UTC