Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[wgsl] Reasoning behind inheriting rust-like syntax #593

Closed
Yen opened this issue Mar 5, 2020 · 78 comments
Closed

[wgsl] Reasoning behind inheriting rust-like syntax #593

Yen opened this issue Mar 5, 2020 · 78 comments
Labels
wgsl WebGPU Shading Language Issues
Projects

Comments

@Yen
Copy link

Yen commented Mar 5, 2020

Looking at the limited samples and construct definitions in the spec, I think there is a lot of influence in the languages syntax from the syntax used in rust. Is there was a specific reason for this decision over inheriting syntax where possible from GLSL or in general, traditional C like constructs?

I might be incorrect on this but for the most part, I find that most of the constructs currently present in the spec were expressable in GLSL with less text. Using the EXAMPLE 1 from the WGSL spec:

[[location 0]] var<out> gl_FragColor : vec4<f32>;
fn main() -> void {
    gl_FragColor = vec4<f32>(0.4, 0.4, 0.8, 1.0);
    return;
}
entry_point fragment = main;

Could be expressed with more condensed syntax using a form of (slightly modified) GLSL:

layout (location = 0) out vec4<f32> gl_FragColor;
void main() {
    gl_FragColor = vec4<f32>(0.4, 0.4, 0.8, 1.0);
    return;
}
entry_point fragment = main;

The differences are small but I think overall there is a lot of syntax present in the spec that does not have reasoning as far as I can see. It is instead inherited from a more complex language where the verbostity in syntax avoids ambiguity, but as WGSL does not inherit the realted complexities, the syntax does not serve a clear purpose to me.

@Yen Yen added the wgsl WebGPU Shading Language Issues label Mar 5, 2020
@Kangz
Copy link
Contributor

Kangz commented Mar 5, 2020

In the initial idea there was the slight goal to get the syntax for types closer to Typescript (essentially a typed Javascript) to improve the familiarity for Web developers. That's why there is thevar name : type style. The syntax for function was indeed inspired from Rust.

@Yen
Copy link
Author

Yen commented Mar 5, 2020

In the initial idea there was the slight goal to get the syntax for types closer to Typescript (essentially a typed Javascript) to improve the familiarity for Web developers. That's why there is thevar name : type style. The syntax for function was indeed inspired from Rust.

If that is the case, then why was the function syntax chosen over a TypeScript like syntax, something like
functionName(parameter: type): returnType {?

I know this is quite pedantic, but as someone who uses TypeScript daily, I can't say I was immediately familiar with some of the choices.

@Kangz
Copy link
Contributor

Kangz commented Mar 5, 2020

Imho the -> syntax is cleaner from a type theoretical perspective. You were asking how it the syntax ended this way, and Typescript then Rust / Swift were part of the influences. The grammar can be changed but I don't personally care so I'll let others weigh in.

@dj2
Copy link
Member

dj2 commented Mar 5, 2020

Doing the more rust way with the return on the right makes parsing easier. You don't have to read the void then try to figure out if the thing after it is a function or a variable. You see the fn first.

We didn't use : as the return delimiter but went with -> as it is clearer it's the function return and not the type of a parameter when scanning the file.

Minimum number of characters to type is not a goal of WGSL.

@kainino0x
Copy link
Contributor

FWIW, though I also prefer -> to : for return types, it is probably a sound idea to stick closer to typescript and javascript syntax when there's no implementation cost.

@othermaciej
Copy link

othermaciej commented Mar 6, 2020

GLSL, HLSL and MSL all use C-family style declaration syntax with the type before the variable and return type before the function name. For that reason, I think C-style would be somewhat better better than Rust-style, because it would be more familiar.

The parsing complexity isn't really different. Whether using flex/bison or a recursive descent parser, it's easy to disambiguate this case.

(The type-at-the-end syntax is not that bad, but I do think it's mildly worse.)

@mehmetoguzderin
Copy link
Member

-> is also the choice of Swift and Haskell. Both are modern languages that pay special attention to observed beauty and parse-ability of syntax.

Haskell: https://www.haskell.org/tutorial/functions.html
Swift: https://docs.swift.org/swift-book/LanguageGuide/Functions.html

@Yen
Copy link
Author

Yen commented Mar 6, 2020

Is the claim made by @Kangz no longer relevant in the languages design? If so what differs WebGSL from any other shading language with a SPIR-V target?

In the initial idea there was the slight goal to get the syntax for types closer to Typescript (essentially a typed Javascript) to improve the familiarity for Web developers.

@kainino0x
Copy link
Contributor

kainino0x commented Mar 6, 2020

Rather than focusing on individual syntax items, I think we should choose what language we should generally be similar to, so that WGSL developers have less to learn (can think "it's like X language with these differences"). I don't feel strongly about what language it is, but it should probably be either GLSL/HLSL/MSL*/C/C++ [*edit: typo] or JavaScript/TypeScript/AssemblyScript. Then, we should stick to those only when there is no cost (e.g. : vs ->), but make choices when there is some tradeoff (e.g. angle brackets vs having many built-in names).

By this measure, though, comparing with Haskell isn't very useful, because the rest of the language doesn't match at all.

@kainino0x
Copy link
Contributor

kainino0x commented Mar 6, 2020

Is the claim made by @Kangz no longer relevant in the languages design? If so what differs WebGSL from any other shading language with a SPIR-V target?

It is defined by how it translates to SPIR-V (WGSL doesn't have its own semantics, and it isn't defined by-reference-to SPIR-V's semantics), and its definition is required to be "reasonably" simple (and "relatively" straightforward to implement).

@Yen
Copy link
Author

Yen commented Mar 6, 2020

WGSL doesn't have its own semantics, and it isn't defined by-reference-to SPIR-V's semantics

Can you clarify this in relation to the goal specifed in the current draft of the WGSL spec?

Features and semantics are exactly the ones of SPIR-V

@mehmetoguzderin
Copy link
Member

so that WGSL developers have less to learn (can think "it's like X language with these differences")

That reminds WSL (WHLSL).

By this measure, though, comparing with Haskell isn't very useful, because the rest of the language doesn't match at all.

The comment didn't compare on that measure for sure.

@frzi
Copy link
Contributor

frzi commented Mar 6, 2020

A more Typescript/Javascript(/Assemblyscript) esque looking version of the OP's code could look like this:

@location(0) @out let gl_FragColor: vec4<f32>;

@fragment function main(): void {
	gl_FragColor = vec4<f32>(0.4, 0.4, 0.8, 1.0);
	return;
}

Most notable difference, and one maybe worth pondering, is the @decorator syntax for any decorations. It's not an uncommon feature in programming languages. Swift, Kotlin, Java and Typescript all use the same syntax for decorations (sometimes called annotations). Curious if (web) developers would welcome the familiar syntax.

Also function instead of fn and let instead of var.

Though I kind of like how short and sweet fnis.

@Yen
Copy link
Author

Yen commented Mar 6, 2020

Though I kind of like how short and sweet fnis.

Functions omitting the function keyword are present in both JS and TS inside of object literals, and type definitions. I think the idea is that you dont need the function keyword in places where you cant have an expression statement since it would be ambiguous. By that logic JS allows for expressions in the global scope but not inside of object literals or type definitions so the function keyword can be omitted all together.

With that in mind, since WGSL does not allow for expression statements outside of a function definition, a keyword denoting a function is not required.

@location(0) @out let gl_FragColor: vec4<f32>;

@fragment main(): void {
	gl_FragColor = vec4<f32>(0.4, 0.4, 0.8, 1.0);
	return;
}

The other thing is that the use of keyword "modifiers" on varible and function definitions are not unknown to TS. An example of this is readonly, virtual, and abstract on function definitions within class definitions. As such, I think the use of decorator syntax would not be necessarily better then using straight custom keywords if something like these changes were to be considered. Not to mention to a JS/TS user, a decorator implies a code level construct, not a language level one.

location(0) out let gl_FragColor: vec4<f32>;

fragment main(): void {
	gl_FragColor = vec4<f32>(0.4, 0.4, 0.8, 1.0);
	return;
}

@dj2
Copy link
Member

dj2 commented Mar 6, 2020

Yes, you can parse with the type before the function or variable, but it also adds parsing complexity. Adding parsing complexity increases the chances of parsing differences between the browsers. Each time we add a 'little' complexity it adds up. Having the types on the right removes the complexity at all and makes it trivial to parse.

Having the fragment before the method does not work when coming from SPIR-V. You can have multiple entry points point to the same function with different entry point names. That is why there is a separate entry_point keyword.

I'd also rather avoid the 'you can not do X in this case, but must do it in this other case'. Having fn at the start is short and makes it obvious what you're parsing.

I think we should take influence where we can, but I don't think we need to adhere to any given language be that Rust, Typescript, C, GLSL, MSL or anything else. So, having parts of Rust and parts of Typescript are fine, programmers will pickup the syntax.

@dj2
Copy link
Member

dj2 commented Mar 6, 2020

Why is that better? Maximum number of characters to type is also not a goal.

The f32x4 is a lot harder to read then vec4<f32>. The fact it's a vector is important, it isn't hidden as ax4 at the end. As well, how would you do matrices? f32x4x2 that's really hard to read?

@Yen
Copy link
Author

Yen commented Mar 6, 2020

In this case much better I guess:

vec4<f32> ->  f32x4
vec2<i32> ->  i32x2
vec2<f64> ->  f64x2
vec3<bool> -> i1x3
// and etc

I think type literals are defined as they are currently due to how they are defined in SPIR-V where vectors are their own kind of thing. But if you were to follow that fully you would have vec<float, 3> which is verbose, but may or may not represent better what WGSL is trying to do. (I admit I am still not fully clear on the goals since the current ones defined in the spec seem to be more requirements than targets)

@MaxGraey
Copy link

MaxGraey commented Mar 6, 2020

The f32x4 is a lot harder to read then vec4. The fact it's a vector is important, it isn't hidden as ax4 at the end. As well, how would you do matrices? f32x4x2 that's really hard to read?

It depends. But f32, f32x3, f32x3x3 much easier refactoring

@dj2
Copy link
Member

dj2 commented Mar 6, 2020

What depends? What do you mean by refactoring?

We started with vec<float, 3> but found it was too verbose to write so we condensed it to vec3<f32>.

@dj2
Copy link
Member

dj2 commented Mar 6, 2020

(Reading your example above I had to read it twice before I realized the last example was a matrix. The x#'s all fade together.)

@Yen
Copy link
Author

Yen commented Mar 6, 2020

I wonder if we could get a statement from a on what the end goal for WGSL is in the context of WebGPU as I think there are issues here which cant be properly considered until resolved. I might be misreading but I cant see any reference in the spec to whether WGSL is even meant to be written by humans (different to human writable). Or if it is means to be a standard for consumption by WebGPU and the main priority is making it as easy as possible to do so (in which case more verbose syntax would probably win out).

@Yen
Copy link
Author

Yen commented Mar 6, 2020

I guess my main query is if this is meant to be GLSL for WebGPU or SPIR-V for WebGPU, because currently its sitting somewhere in the middle and I dont quite understand the reasoning behind it.

@MaxGraey
Copy link

MaxGraey commented Mar 6, 2020

Other alternatives: f32v3 and f32m3x3 instead mat3x3<f32>

@dj2
Copy link
Member

dj2 commented Mar 6, 2020

Sure, but what does f32m3x3 buy you other than saving a couple characters? It's still, to me, harder to read then mat3x3<f32>.

@dj2
Copy link
Member

dj2 commented Mar 6, 2020

There is an ongoing discussion in the FAQ pull requests you can see. There is also a CL open to update the Goals section of the spec.

@MaxGraey
Copy link

MaxGraey commented Mar 6, 2020

Sure, but what does f32m3x3 buy you other than saving a couple characters? It's still, to me, harder to read then mat3x3.

It more consistency. With mat3x3<f32> mat3x3 with shorthand f32 looks little bit strange. It should be mat3x3<float32> or use only first letter from every type I guess

@dj2
Copy link
Member

dj2 commented Mar 6, 2020

I'd say it's less consistent? mat vs vec is consistent. In theory array should be arr or ary but that's harder to read so we made it array. I don't see why float is better than f as it's obvious what it is when coupled with the 32, same with i and u.

@eXponenta
Copy link

eXponenta commented Mar 6, 2020

How about intellisense tools?
HLSL/GLSL/C/C.... etc has intellisense tools for different IDE, but when we use cool new sintaxis we spit on this.

How about that -> more complex that C style like, becouse there are a unnecessary 'fn' and '->'?
How about converting existing codebase to cool new sintaxis ?

@dj2
Copy link
Member

dj2 commented Mar 6, 2020

Having single letters for everything makes the language harder to read. Having full words for everything makes it overly verbose. There is a middle ground where some things are obvious from context without needing to be fully spelled out.

@dneto0
Copy link
Contributor

dneto0 commented Mar 7, 2020

WGSL is its own thing. (Apple strongly argued that WebGPU was its own thing, sui generis, uniquely different.)

The -> token used to join function parameter signature to return type is deeply traditional in both math and programming language type theory.

E.g. in math I can write f : R -> Z to mean f is a function from R to Z. Staring at the last bit, R -> Z is the set of functions from R to Z.

For a good and short introduction to notation in programming language theory, see http://siek.blogspot.com/2012/07/crash-course-on-notation-in-programming.html
By the time you get to the bottom of the posting, you some simple rule sets for type derivation for a very small language, getting the flavour of what actually happens in compilers, and may help you understand type error messages.

Rust is only one of the latest in a long line of languages using certain syntaxes for things we put into WGSL. That's why you see similar things in Haskell and Swift as noted above.

@Yen
Copy link
Author

Yen commented Mar 7, 2020

The -> token used to join function parameter signature to return type is deeply traditional in both math and programming language type theory.

Thats understandable but is it really a justification for the syntax in this context? Would you suggest we should be defining our functions as main : () -> void in that case? It would be nice to base to define everything based on mathematical syntaxes and I am sure some languages benefit from this approach, but there are also many other constructs in the WGSL spec that do not follow this methodology because its not as common to see them in mainstream languages.

Outside of rust, which I would still argue does not qualify as the frontend prospects are still very new, I cannot think of a language commonly used by web developers outside of elm? But even elm does not use this exact syntax, it does has the presence of -> within constructs, but not the same syntax at all.

There are references to alternative syntaxes above which relate to syntaxes seen in web languages (JavaScript/TypeScript) and all current "in use" shading languages (all I can think of are C style? let me know if I am wrong). These alternatives are able to express the same things as the current syntax is capable of expressing in the spec while being more familiar to what I think it is fair to say would qualify as majority used existing languages used for front end web development and existing graphics application development.

As such I dont see why its unfair to expect a syntax for a language to prioritise familiar and proven constructs from existing languages in the same areas where there is no or trivial differences in implementation and ambiguity.

@dj2
Copy link
Member

dj2 commented Mar 7, 2020

As above, doing it c-style makes parsing harder. Yes it's doable, but each time you make it harder you make it easier for their to be compatibility differences.

You could do : but, as I said above, it's easier to scan for the -> and see it, it's also non-ambiguous when reading that it's the function return.

@dj2
Copy link
Member

dj2 commented Mar 7, 2020

There will always be differences from other languages. Otherwise, we'd just use the other language. You will have to learn the differences otherwise things aren't going to work as you expect.

We're writing WGSL, not HLSL, MSL, GLSL, Rust, TypeScript, Javascript or anything else.

@pjoe
Copy link
Contributor

pjoe commented Mar 11, 2020

Having worked with WebGL for years and years, the most natural to me would be to use GLSL or something very similar. I realize there are lots of different interests here, just stating what I believe most WebGL developers would think 😄

Rust is cool and all (though still waiting for async to settle fully in libs etc.), but would seem very unnatural to me in this context.

Haskell is also very interesting in it's pure FP approach, but again not very natural here - to me.

@krogovin
Copy link

I am going to offer my two cents and it is related to another issue I filed.

Making (yet) another shading language is already a giant hassle. However, making a shading language that is so different than the high level shading languages used on native (GLSL, HLSL, MSL) really makes me sweat. I won't be able to hide the language differences behind #define's or #ifdef's.

The option I was told (at #609) is to rely on Chromium's Tint or Firefox's Naga to have translators FROM SPIR-V to WGSL. However, those are not guaranteeing the ability to do that, it is more like there is a plan that they will probably do that.

But this is just not the correct thing to do IMO. Porting a library or application to the web with WebGL1/2 was mostly fire up emscripten and tweak a few things (namely no buffer mapping) and a few extra tweaks to shaders to make them more compliant. With WebGPU the API being different is not so bad because it acts in spirit so similarly to Vulkan, Metal and D3D12 along with the fact that often I end up writing something to abstract that a little... but the shaders. Oh dear. Without reliable tools to get something to WGSL I am looking at these options:

  1. Rewrite the shaders for the new language and syntax. This is a huge non-trivial effort
  2. Do not bother with WebGPU and stick with WebGL. This is also a horrible choice because on some platforms WebGL2 is not available (although native has GLES3.x) and there are is no compute or image-load-store.
  3. Do not port to the web.

All of the above are horrible choices and I am not likely the only developer with the above; yet it could have been avoided (or atleast reduced a great deal) if WGSL was atleast more LIKE the other existing 3D API shading languages.

At this point, my enthusiasm for WebGPU is waning sadly and I'd be happy with updates to WebGL2 that were widely supported to include GLES3.1 feature sets. However, I know that is dead on arrival because of the devices already out there that have GLES3.1 natively but no WebGL2.

@kvark
Copy link
Contributor

kvark commented Mar 13, 2020

@krogovin your concern is well received. I don't think the goal for WGSL was ever to be that shiny new language not like anything else. The goal was to have something writable by hand, debuggable, readable, yet trivial convertable from SPIR-V and into the backend-specific shaders. So the promise we made is that you will be able to just use SPIR-V shaders by translating them into WGSL quickly and smoothly. That promise is yet to be fulfilled, since as you mentioned, neither Google or Mozilla have tools ready to do so. Rest assured we are working on them!

@pjoe
Copy link
Contributor

pjoe commented Mar 13, 2020

@krogovin I can only second you view 😟

TBH I am still scratching my head over why not just use GLSL ?

  • All browser already takes GLSL input (for WebGL) so would assume some part of parser could be re-used.
  • All major engines (unity, unreal, godot) already produce GLSL output (for WebGL builds)
  • All WebGL engines/frameworks (three.js, Babylon.js, CesiumJS) already use GLSL

Also apps would need to ship a GLSL shader compiler, for those dynamic generated shaders that cannot be handled build time. This will add substantially to bundle size (shaderc is ~3MB, think glslang is ~1MB, compare to typical webgl engine size of a few 100K) and add extra processing: shaders now have to go: GLSL -> WGSL -> browser -> SPIR-V/DXIL/MSL.

Alternative would be to rewrite all shaders in WGSL, but on top of having to port API to WebGPU, I suspect for many smaller teams, this just won't be feasible. We e.g. have ~2.2K lines of GLSL code, that have been hand tweaked over almost 10 years - porting that to WGSL is not a trivial task for us.

I may be missing something essential here, but really don't understand the reasoning 😟

@magcius
Copy link

magcius commented Mar 13, 2020

For various reasons (separable texture/samplers being a bit one), the version of GLSL used in WebGL and the version of GLSL that would used in WebGPU are incompatible.

That said, I expect a glslang -> SPIR-V -> WGSL path to be viable enough so you could ship GLSL source if wanted.

@kvark
Copy link
Contributor

kvark commented Mar 13, 2020

@pjoe this is getting way beyond the scope of this issue. It's more relevant to the early discussions about which shading language we could take, especially #219 . There are many reasons why GLSL wasn't picked, we'll be happy to elaborate.

@pjoe
Copy link
Contributor

pjoe commented Mar 13, 2020

sorry, didn't really mean to sidetrack this issue, anyway think it will be important to have a good documented motivation for this, especially for developers coming from a WebGL background.

@jeremyong
Copy link

For various reasons (separable texture/samplers being a bit one), the version of GLSL used in WebGL and the version of GLSL that would used in WebGPU are incompatible.

That said, I expect a glslang -> SPIR-V -> WGSL path to be viable enough so you could ship GLSL source if wanted.

Wouldn’t a webgpu flavored extension on top of glsl akin to the vulkan glsl extension work?

@kdashg
Copy link
Contributor

kdashg commented Mar 16, 2020

@krogovin

2. Do not bother with WebGPU and stick with WebGL. This is also a horrible choice because on some platforms WebGL2 is not available (although native has GLES3.x) and there are is no compute or image-load-store.

[...]
At this point, my enthusiasm for WebGPU is waning sadly and I'd be happy with updates to WebGL2 that were widely supported to include GLES3.1 feature sets. However, I know that is dead on arrival because of the devices already out there that have GLES3.1 natively but no WebGL2.

Expect there to be no devices or browsers that support WebGPU that do not support WebGL 2.

@krogovin
Copy link

Um no; Safari's WebGL2 support is not working really well. It might be advertised, but when running a sophisticated application using WebGL2, I found that Safari fell apart (where as Chrome and Firefox were fine). In addition, for iOS, WebGL2 is not enabled by default anyways.

@kainino0x
Copy link
Contributor

Safari hasn't finished implementing WebGL 2 yet. But it also hasn't finished implementing WebGPU yet (obviously).

@krogovin
Copy link

Considering how old WebGL2 already is, I would be moderately surprised if Safari's WebGL2 is ever really finished enough to be able to handle something hard. I admit that is moderately cynical, but it has been dragging for an incredibly long time.

@kainino0x
Copy link
Contributor

WebKit's difficulty with complex WebGL 2 content isn't poor implementation quality, it's just that many WebGL 2 entry points are unimplemented. Development on those is actively ongoing.

@kdashg
Copy link
Contributor

kdashg commented Mar 17, 2020

Expect there to be no devices or browsers that support WebGPU that do not support WebGL 2.
We do not design WebGPU with the expectation that WebGL 2 might be missing.
Expect WebGL 2 before WebGPU, and expect most all users will have WebGL 2 (~100%, ~95% in hardware) by the time WebGPU ships to even 50% of users.
(NB: I'm a WebGL WG Spec Editor)

@grorg
Copy link
Contributor

grorg commented Jun 15, 2020

I'm going to close this issue. Firstly, it's diverged a lot from the original question/request. Secondly, we have a FAQ document that attempts to address this.

WIP FAQ: #687

@grorg grorg closed this as completed Jun 15, 2020
WGSL automation moved this from Under Discussion to Done Jun 15, 2020
@CrazyPython
Copy link

CrazyPython commented Jun 24, 2020

In the initial idea there was the slight goal to get the syntax for types closer to Typescript (essentially a typed Javascript) to improve the familiarity for Web developers. That's why there is thevar name : type style. The syntax for function was indeed inspired from Rust.

#888 While the idea of helping JavaScript developers use WGSL is attractive, doing this simultaneously hurts their ability to transition into other systems languages such as C and C++.

It essentially suggests segregating the web to be apart from the rest of the game development community.

ben-clayton pushed a commit to ben-clayton/gpuweb that referenced this issue Sep 6, 2022
* add ErrorWithExtra for extra debug data

* Add a way to extend an ErrorWithExtra
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
wgsl WebGPU Shading Language Issues
Projects
WGSL
Done
Development

No branches or pull requests