这是indexloc提供的服务,不要输入任何密码
Skip to content

Position: Directly ingest SPIR-V, and not a human-writable shading language #44

@kainino0x

Description

@kainino0x

Revision R1: 2018-01-01
Revision R2: 2018-01-03

WebGPU should directly ingest SPIR-V, and it should not ingest a human-writable shading language. [R2] The WebGPU group should bless HLSL and fully maintain a complete development path to enable development with HLSL.

Ease of SPIR-V ingestion

SPIR-V is a smaller and simpler implementation and verification target than any human-writable shading language.

  • Ingesting SPIR-V instead of a shading language removes substantial amounts of code from the WebGPU implementation, such as a preprocessor and (text) parser.

  • It eliminates code for language-level concepts like identifiers and expression trees, and all string processing, from the translator frontend and validator.

  • During the development of WebGL, hundreds of bugs and edge cases have been encountered which are exclusive to the ingestion of a human-writable shading language. Note that these can not be dismissed as simply bugs in the browser's shader translator; these types of bugs are inherent to ingesting a text-based language. Ingesting SPIR-V categorically eliminates bugs in these areas (example bugs provided):

    • String-related operations: parsing, tokens, identifiers (bug), literals (bug, bug) - including needing to enforce a maximum identifier length (bug) in the specification to avoid implementation-specific limits
    • Scoping and identifier namespacing/collisions (bug, bug)
    • Abstract syntax trees - including needing to enforce a maximum tree depth/size/complexity (bug, bug) in the specification to avoid implementation-specific limits
    • The preprocessor (bug, bug) - another entire language layered on top
    • Weak typing (bug, bug) - implicit type conversions and type inference
    • Implicit qualifiers and other optional syntax (bug, bug)
    • Other error-prone high-level language features, like initializers (bug, bug), vec/mat destructuring (bug), etc.

    This bug list, curated from the ANGLE and Chromium repositories, illustrates the classes of bugs that have been encountered during the development of the WebGL shading language specification, and which would be categorically eliminated by ingesting only the SPIR-V binary format.

  • Ingesting SPIR-V does add a few new concepts:

    • Parsing of a simple binary format - much simpler to parse than HLSL/GLSL
    • Control flow graph and single static assignment form
      • CFGs are simpler than ASTs and much easier to operate on.
      • SSA forms are simpler and much easier to operate on.
      • Code transformations and analyses are much easier to apply to CFG/SSA, which is why modern compilers use them internally. (Examples: bounds checks, bounds check elision, injecting temporary values and computations, constant propagation, dead code elimination.)
  • SPIR-V supports optional debug information like variable names and source line numbers (SPIR-V 1.2 §2.15), but it is only used for diagnostic output. It is not used during parsing or validation.

    • Any error messages produced during shader validation can still refer to the developer's original variable names.
      • And if the ingested SPIR-V is produced by an SL compiler toolchain, as it almost always will be, it should always be valid. Any errors in the SL source should be caught by the SL compiler.
    • Source maps, or a similar mechanism, can be used to provide the original source for shaders during development. Source maps are also used in WebAssembly to enable debugging and variable inspection for binaries compiled from any source language. (Recently implemented in Firefox.)

The benefits of ingesting a less complex verification target are significant:

  • [R2] HLSL/GLSL compiler bugs are no longer portability or security problems. (See Better for Web developers.)
  • Less buggy browser implementations
    • A simpler implementation will be less buggy.
  • More consistent browser implementations
    • Two implementations will be more consistent if they are less buggy.
    • Tighter specification (see below) means better consistency.
  • Better security
    • SPIR-V is a smaller attack surface and a smaller fuzzing target. Fuzzing can thus be more effective.
  • Potentially better ingestion performance
    • By eliminating the parsing step and related complexity.

Better for Web developers

  • A hallmark of modern Web development is that applications are highly portable across browsers, with very minimal porting effort. Cross-browser consistency is critical.
    • [R2] Portability problems caused by HLSL/GLSL compiler bugs are eliminated: If the application is responsible for compiling HLSL shaders (whether during build or at runtime), they will build once or ship with a single version of a compiler (such as DXC) which behaves consistently across clients. Any HLSL compiler bugs which affect an application can be caught in application testing, and will never be browser or system dependent. The developer can work around them, or they can fix them and upstream fixes.
  • [R2] Developers still get to take advantage of the well-established HLSL ecosystem and catalog.
  • Developers simultaneously get to take advantage of the rich SPIR-V ecosystem (optimizer, validator, cross-compilation, etc.).
    • An evolution of HLSL can target SPIR-V. Targeting SPIR-V makes it much easier to evolve a language, because the browser does not need to implement language changes - an application developer can pick up new language developments whenever they want, [R2] as well as control for regressions.
    • [R2] It also eases development of new languages, and allows some languages designed for Vulkan/OpenGL/OpenCL to be used in WebGPU. This flexibility provides value without undermining the well-lit path of HLSL.
  • It has been argued that Web developers have complained about the "lack of view-source" in WebAssembly, and that some WebAssembly WG members disagree with the final, binary format of WebAssembly (though we do not know what motivates either of these opinions). These viewpoints are not reflected in our experiences with WebGL developers. Vocal WebGL developers consistently request flexibility, performance, and performance features; view-source for shaders on third-party websites does not seem to be a big concern.
    • View-source during development can be provided by SPIR-V debug information and/or source maps.
  • For developers who want or need online compilation of human-writable shaders, a shader compiler ([R2] like shaderc or DXC) can be easily ([R2] compiled to WebAssembly and) packaged as a JavaScript library. See Appendix: Engine development strategies for WebGPU shaders.

SPIR-V: tight specification and active ecosystem

  • SPIR-V is very stable. There have been minimal recent changes to its specification (diff from 1.1 to 1.2). This makes it a more stable target as there is minimal need for any given tool (such as an HLSL compiler) to target multiple SPIR-V versions.

  • SPIR-V is tightly specified. The complexity of the format is much lower than GLSL/HLSL, so its prose specification is able to be more precise. Lower complexity also leaves fewer holes for underspecification or self-contradiction.

    • GLSL ES 3.20: 218 content pages for GLSL graphics/compute (mostly long prose, very dense)
    • SPIR-V 1.2: 192 content pages for graphics/compute and OpenCL (some readable long prose, mostly well-organized tables with prose)

    Since SPIR-V is less complex, a conformance test suite of the same "size" should intuitively be able to cover more cases and thus more effectively complement the prose spec. (We don't have data to go with this, since it's very hard to compare the size and coverage of SPIR-V in the Vulkan CTS with the size and coverage of GLSL in the OpenGL CTS.)

  • If we need to add a feature to SPIR-V, it can be done so as an Extension to SPIR-V. The WebGPU group can effectively own these Extensions.

  • SPIR-V's interaction with WebGPU will be defined by an Environment Specification. This will encompass limitations and additional validation rules we apply to SPIR-V. It can also require support for new SPIR-V extensions.

    • SPIR-V adds constraints on the CFG (like structured control flow) that make it possible to translate into the AST-level (like GLSL/HLSL/MSL).
    • Further constraints can be added (to an environment specification) to define a canonical ordering for the encoded CFG, such that it is easier to validate and easier to translate to the AST-level. (David Neto has started work on this.)
  • The SPIR-V ecosystem is very active, because it is used in Vulkan (and OpenCL, OpenGL, and Vulkan Portability). This lets us provide better tools for developers and better browser implementations. It allows WebGPU developers to take advantages of SPIR-V ecosystem developments, including human-writable shading language advancements like an evolution of HLSL.

Appendix: Engine development strategies for WebGPU shaders

There are ~four categories of engine development:

  • New WebGPU-only engines: They can base the engine around offline shader compilation, or use online shader compilation for prototyping.
  • Cross-compiled native engines (Unity, Unreal, etc.): They can already output both HLSL and SPIR-V.
  • User-generated shader content (Shadertoy): Shadertoy developers can trivially ship a shader compiler like shaderc or DXC. It will make users' content more consistent across browsers.
    • Shadertoy could also, for example, choose to use a heavier compiler ([R2] or more expensive compiler options) with better diagnostic messages. Good diagnostic messages add even more complexity to an implementation, and for the reasons above, it is problematic to (1) add that complexity to every browser and (2) require it to run on every shader compile.
  • Engines which want to target both WebGL and WebGPU (Three.js, Cesium.js, etc.): These developers will want their existing GLSL shaders and GLSL-text-snipping engines to work on WebGPU. They will need to continue supporting WebGL 1.0 for compatibility. The development complexity is actually very similar regardless of the ingested format; [R2] ingesting SPIR-V does not make it harder:
Options if browser ingests HLSL Options if browser ingests SPIR-V
1. Online cross-compile GLSL to HLSL with a third-party library. (shaderc+SPIRV-Cross?) 1. Online cross-compile GLSL to SPIR-V with a third-party library. (shaderc)
2. Maintain, in parallel with GLSL code, a separate library of HLSL and an HLSL-text-snipping engine. 2. Maintain a separate library of some SL, and offline compile it to SPIR-V (shaderc or DXC). Do online linking and specialization with a JS library.
3. An HLSL library and HLSL-text-snipping engine (as above), plus online-compile HLSL to GLSL (if maintaining WebGL as a "slower fallback path") with a third-party library. 3. An SL library compiled SPIR-V (as above), plus online-compile SPIR-V to GLSL (if maintaining WebGL as a "slower fallback path"). (Aside: offline compilation from SPIR-V to GLSL may even be possible, with a simple JS implementation of linking and specialization for GLSL.)

[R2] Addendum: Blessing and supporting HLSL (or an HLSL evolution)

Obviously, application developers will not normally write SPIR-V by hand. Instead, they will compile to SPIR-V (either online or offline) from a human-writable shading language. The WebGPU working group should bless a single such language, HLSL, and take responsibility for the HLSL development path.

  • HLSL has the richest library of existing source code.
  • HLSL to SPIR-V compilation is under development in DXC.
  • The WebGPU working group is expected to own specification, conformance, and development of HLSL or an evolution thereof.
  • The WebGPU working group should bless HLSL by:
    • Using it in WebGPU documentation, and recommending its use in third-party documentation/tutorials/etc.
    • Maintaining an online compilation path to WebGPU-compatible SPIR-V, e.g. DXC compiled to WASM.
    • Maintaining an offline compilation path to WebGPU-compatible SPIR-V, e.g. DXC as a webpack packaging step using WASM DXC, and native or nodejs packages for Mac/Linux.

For developers with existing content in GLSL, we should also ensure the ecosystem includes a well-supported GLSL path (for example via shaderc).

Metadata

Metadata

Assignees

No one assigned

    Labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions