You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
We want to let users write code in a language they know well, the same one that they use to write the rest of their project, that is TypeScript, and then execute this code on the GPU via the WebGPU API. We achieve this by parsing TypeScipt code into AST, then to more minimal AST (SMoL) and then to WGSL. By doing so we need to be aware of how these two languages (TS and WGSL) differ and handle this difference by either eliminating it (by clever code substitution) or by warning users of the potential mishaps.
Note
When we let the users write code in JS/TS, we aim to make the code function on the GPU in the same way that it would normally on the CPU, when it comes to the general, non-GPU related operations. We can't expect the users to assume the code to work like it would in WGSL; but rather how it works in JS/TS. Unless we signal the difference in a very obvious way.
Vectors and structures being value/reference types
The big difference in how JS and WGSL work is how they treat vector and struct types. In WGSL they are value types, meaning that when we assign them to variables they are copied. Whereas in JS, these types are objects which are treated as reference types. When assigning them to variables, they are passed as references, pointing to the same object.
WGSL:
vara=vec2u(1, 1);
varb=a; // copiedb.x =2; // a.x is still 1
TS:
leta=vec2u(1,1);letb=a;// pointing to the same objectb.x=2;// a.x is now 2
Solution proposal
Create .copy() method on vectors and structures in TS, resolving to the values themselves in WGSL. Alternatively copy by wrapping the vector in vec/struct functions (let b = vec2u(a);). This allows writing code that works like a native WGSL code (one without this explicit copy method invocation or wrapping).
When assigning let b = a; we register an alias in the resolution context (in the current scope(!)). Then when resolving to identifier we check if it is not aliased, if it is then we replace it with the alias instead. We create the alias only for vectors and structs, we can do it once we have the dataType information in the generator, which we plan on introducing soon.
Rejected idea
Another idea was to simulate reference types in WGSL by using pointers. Then we would have to replace var b = a; with let b = &a; and then b.x = 2; with (*b).x = 2; in WGSL. However, it seems as though pointers have quite a few limitations, including that we cannot have them set to vars, just lets. Therefore the idea was rejected
Passing arguments to functions as reference
In a very similar issue, structs and vectors are copied when passed as arguments to functions in WGSL. To achieve the behavior known from JS, where we can pass an object and modify it inside the function, it seems we have no choice, but to pass the argument to the function in WGSL as pointer to the value.
However, there's a few issues arising here. If we construct a function passing a WGSL string, which will be an option, then the function will work in a WGSL-way, that is by copying parameters, unless we perform the daunting operation of parsing and modifying passed string. That could lead to a disaster, we won't do that. So we will have functions with parameters passed by value and functions with parameters passed by reference. Therefore we need a way to distinguish them within their signatures (shells) anyways.
Solution proposal
I believe that the best approach here, is to make an exception here and make tgpu.fn TypeScript functions work like WGSL functions by default, when it comes to copying values when accepting them as arguments. Tgpu.fn and JS functions are not exactly the same thing anyways and then we don't have to generate specially modified WGSL. Also we can achieve the same behavior between JS and WGSL by just copying arguments when executing the function on the CPU. To allow functions to work like in TS (passing arguments via reference) we should introduce support for pointers fn(ptr(vec3f), []).... It's another step for 1:1 WGSL feature support and it makes it so that passing by reference is deliberate, achieved by the user when needed and not by TypeGPU magic.
TS const vs WGSL let
TS const doesn't have its exact WGSL counterpart. WGSL let seems close, but for vectors and structs, if we declare them with let in WGSL, we cannot modify their members' values, while with TS const we do.
Solution proposal
I believe our best bet here is to translate TS const to WGSL var, instead of let. It is still just as "safe" on the TS side and we won't modify or even display the generated WGSL code. The performance should (I think) stay the same.
reacted with thumbs up emoji reacted with thumbs down emoji reacted with laugh emoji reacted with hooray emoji reacted with confused emoji reacted with heart emoji reacted with rocket emoji reacted with eyes emoji
-
We want to let users write code in a language they know well, the same one that they use to write the rest of their project, that is TypeScript, and then execute this code on the GPU via the WebGPU API. We achieve this by parsing TypeScipt code into AST, then to more minimal AST (SMoL) and then to WGSL. By doing so we need to be aware of how these two languages (TS and WGSL) differ and handle this difference by either eliminating it (by clever code substitution) or by warning users of the potential mishaps.
Note
When we let the users write code in JS/TS, we aim to make the code function on the GPU in the same way that it would normally on the CPU, when it comes to the general, non-GPU related operations. We can't expect the users to assume the code to work like it would in WGSL; but rather how it works in JS/TS. Unless we signal the difference in a very obvious way.
Vectors and structures being value/reference types
The big difference in how JS and WGSL work is how they treat vector and struct types. In WGSL they are value types, meaning that when we assign them to variables they are copied. Whereas in JS, these types are objects which are treated as reference types. When assigning them to variables, they are passed as references, pointing to the same object.
WGSL:
TS:
Solution proposal
let b = vec2u(a);
). This allows writing code that works like a native WGSL code (one without this explicit copy method invocation or wrapping).let b = a;
we register an alias in the resolution context (in the current scope(!)). Then when resolving to identifier we check if it is not aliased, if it is then we replace it with the alias instead. We create the alias only for vectors and structs, we can do it once we have the dataType information in the generator, which we plan on introducing soon.Rejected idea
Another idea was to simulate reference types in WGSL by using pointers. Then we would have to replace
var b = a;
withlet b = &a
; and thenb.x = 2;
with(*b).x = 2;
in WGSL. However, it seems as though pointers have quite a few limitations, including that we cannot have them set to vars, just lets. Therefore the idea was rejectedPassing arguments to functions as reference
In a very similar issue, structs and vectors are copied when passed as arguments to functions in WGSL. To achieve the behavior known from JS, where we can pass an object and modify it inside the function, it seems we have no choice, but to pass the argument to the function in WGSL as pointer to the value.
However, there's a few issues arising here. If we construct a function passing a WGSL string, which will be an option, then the function will work in a WGSL-way, that is by copying parameters, unless we perform the daunting operation of parsing and modifying passed string. That could lead to a disaster, we won't do that. So we will have functions with parameters passed by value and functions with parameters passed by reference. Therefore we need a way to distinguish them within their signatures (shells) anyways.
Solution proposal
I believe that the best approach here, is to make an exception here and make tgpu.fn TypeScript functions work like WGSL functions by default, when it comes to copying values when accepting them as arguments. Tgpu.fn and JS functions are not exactly the same thing anyways and then we don't have to generate specially modified WGSL. Also we can achieve the same behavior between JS and WGSL by just copying arguments when executing the function on the CPU. To allow functions to work like in TS (passing arguments via reference) we should introduce support for pointers
fn(ptr(vec3f), [])...
. It's another step for 1:1 WGSL feature support and it makes it so that passing by reference is deliberate, achieved by the user when needed and not by TypeGPU magic.TS const vs WGSL let
TS
const
doesn't have its exact WGSL counterpart. WGSLlet
seems close, but for vectors and structs, if we declare them withlet
in WGSL, we cannot modify their members' values, while with TSconst
we do.Solution proposal
I believe our best bet here is to translate TS
const
to WGSLvar
, instead oflet
. It is still just as "safe" on the TS side and we won't modify or even display the generated WGSL code. The performance should (I think) stay the same.Beta Was this translation helpful? Give feedback.
All reactions