Skip to content

impr: Origin chain #2421

@cieplypolar

Description

@cieplypolar

The purpose of this issue is to introduce concept of the origin chain. It should help with forbidding the following

const i = 0;
const iRef = d.ref(i);

and would make consumption tracking easier.


Origin chaining is allowing the snippet to be origin field value.

origin: Origin | Snippet

If origin field is a snippet then it should reference the highest snippet in a chain (snippet with origin: Origin) .


This table shows current and future behavior of snippets (we examine returned value):

description current after notes
basic
const a = 1;
return a;
[..., i32, 'constant']
[..., i32, snippet(1, i32, 'constant')]
It is required for the d.ref case mentioned above
const a = 1;
const b = a;
return b;
[..., i32, 'constant']
[..., i32, snippet(1, i32, 'constant')]
 Note that b 'references' a in the code, but the origin points
 to the highest snippet in the chain.
fn([i32])((a) => return a);
[..., i32, 'argument']
[..., i32, 'argument']
Non-ref arguments are copied, so a is the highest origin
fn([i32])((a) => {
  const b = a;
  return b;
})
[..., i32, 'runtime']
[..., i32, snippet(a, i32, 'argument')]
return getOne();
[..., i32, 'runtime']
[..., i32, 'runtime']
Here, we can potentially run into issue with getById, calls should be represented by separate snippets
const b = getOne();
return b;
[..., i32, 'runtime']
[..., i32, snippet('getOne()', i32, 'runtime')]
return vec2i(7);
[..., vec2i, 'constant']
[..., vec2i, 'constant']
const a = vec2i(7);
return a;
[..., vec2i, 'this-function']
[..., vec2i, snippet(vec2i(7), vec2i, 'constant')]
const a = vec2i(7);
const b = a;
return b;
[..., iptr<function,vec2i,rw>, 'this-function']
[..., iptr<function,vec2i,rw>, snippet(vec2i(7), vec2i, 'constant')]
Note, how datatype has changed
fn([vec2i])((a) => return a);
[..., vec2i, 'argument']
[..., vec2i, 'argument']
Uninterrupted flow :)
fn([vec2i])((a) => {
  const b = a;
  return b;
})
[..., vec2i, 'argument']
[..., vec2i, snippet(a, vec2i, 'argument')]
Implicit pointer btw, but currently cannot take pointer to te argument. TODO: carefully handle this case
fn([vec2i])((a) => return a.x);
[..., i32, 'argument']
[..., i32, 'argument']
Uninterrupted flow :)
fn([vec2i])((a) => {
  const b = a.x;
  return b;
})
[..., i32, 'runtime']
[..., i32, snippet('a.x', i32, 'argument')]
Comparing to the above flow, origin has changed. Maybe it should remain 'runtime'
return getV();
[..., vec3f, 'runtime']
[..., vec3f, 'runtime']
const b = getV();
return b;
[..., vec3f, 'this-function']
[..., vec3f, snippet('getV()', vec3f, 'runtime')]
Cannot really put 'this-function' origin here, what if we assign the result to a buffer?
uniform
return buf.$;
[..., f32, 'runtime']
[..., f32, 'runtime']
Buffer element is naturally ephemeral
const b = buf.$;
return b;
[..., f32, 'runtime']
[..., f32, snippet('buf', f32, 'runtime')]
On the contrary to the function call, we should distribute only
1 reference to buffer access snippet
return buf.$;
[..., vec3f, 'uniform']
[..., vec3f, 'uniform']
Buffer element is NOT naturally ephemeral
const b = buf.$;
return b;
[..., iptr<uniform,vec3f,r>, 'uniform']
[..., iptr<uniform,vec3f,r>, snippet('buf', vec3f, 'uniform')]
readonly
return buf.$;
[..., f32, 'runtime']
[..., f32, 'runtime']
const b = buf.$;
return b;
[..., f32, 'runtime']
[..., f32, snippet('buf', f32, 'runtime')]
return buf.$;
[..., vec3f, 'readonly']
[..., vec3f, 'readonly']
const b = buf.$;
return b;
[..., iptr<storage,vec3f,r>, 'readonly']
[..., iptr<storage,vec3f,r>, snippet('buf', vec3f, 'readonly')]
mutable
return buf.$;
[..., f32, 'runtime']
[..., f32, 'runtime']
const b = buf.$;
return b;
[..., f32, 'runtime']
[..., f32, snippet('buf', f32, 'runtime')]
return buf.$;
[..., vec3f, 'mutable']
[..., vec3f, 'mutable']
const b = buf.$;
return b;
[..., iptr<storage,vec3f,rw>, 'mutable']
[..., iptr<storage,vec3f,rw>, snippet('buf', vec3f, 'mutable')]
private
return pv.$;
[..., f32, 'runtime']
[..., f32, 'runtime']
const b = pv.$;
return b;
[..., f32, 'runtime']
[..., f32, snippet('pv', f32, 'runtime')]
return pv.$;
[..., vec3f, 'private']
[..., vec3f, 'private']
const b = pv.$;
return b;
[..., iptr<private,vec3f,rw>, 'private']
[..., iptr<private,vec3f,rw>, snippet('pv', vec3f, 'private')]
workgroup
return wgv.$;
[..., f32, 'runtime']
[..., f32, 'runtime']
const b = wgv.$;
return b;
[..., f32, 'runtime']
[..., f32, snippet('wgv', f32, 'runtime')]
return wgv.$;
[..., vec3f, 'workgroup']
[..., vec3f, 'workgroup']
const b = wgv.$;
return b;
[..., iptr<workgroup,vec3f,rw>, 'workgroup']
[..., iptr<workgroup,vec3f,rw>, snippet('wgv', vec3f, 'workgroup')]
handle
return layout.$.s;
[..., sampler, 'handle']
[..., sampler, 'handle']
For now, you cannot assign sampler or texture to a variable
tgpu.const
return c.$;
[..., u32, 'constant']
[..., u32, 'constant']
const b = c.$;
return b;
[..., u32, 'constant']
[..., u32, snippet('c', u32, 'constant')]
return c.$;
[..., vec3f, 'constant-tgpu-const-ref']
[..., vec3f, 'constant-tgpu-const-ref']
const b = c.$;
return b;
[..., vec3f, 'constant-tgpu-const-ref']
[..., vec3f, snippet('c', vec3f, 'constant-tgpu-const-ref')]
fn([i32])((i) => return arr.$[i]);
[..., f32, 'runtime']
[..., f32, 'runtime']
fn([i32])((i) => {
  const b = arr.$[i];
  return b;
})
[..., f32, 'runtime']
[..., f32, snippet('arr[i]', f32, 'runtime')]
fn([i32])((i) => return arr.$[i]);
[..., vec3f, 'runtime-tgpu-const-ref']
[..., vec3f, 'runtime-tgpu-const-ref']
fn([i32])((i) => {
  const b = arr.$[i];
  return b;
})
[..., vec3f, 'runtime-tgpu-const-ref']
[..., vec3f, snippet('arr[i]', vec3f, 'runtime-tgpu-const-ref')]
struct
return buf.$.count;
[..., u32, 'runtime']
[..., u32, 'runtime']
const b = buf.$.count;
return b;
[..., u32, 'runtime']
[..., u32, snippet('buf.count', u32, 'runtime')]
Access to struct should be distributed as reference to one unique snippet
return buf.$.pos;
[..., vec3f, 'uniform']
[..., vec3f, 'uniform']
const b = buf.$.pos;
return b;
[..., iptr<uniform,vec3f,r>, 'uniform']
[..., iptr<uniform,vec3f,r>, snippet('buf.$.pos', vec3f, 'uniform')]
swizzle
fn([vec3f])((v) => return v.x);
[..., f32, 'argument']
[..., f32, 'argument']
fn([vec3f])((v) => {
  const b = v.x;
  return b;
})
[..., f32, 'runtime']
[..., f32, snippet('v.x', f32, 'runtime')]
fn([vec3f])((v) => return v.xy);
[..., vec2f, 'runtime']
[..., vec2f, 'runtime']
fn([vec3f])((v) => {
  const b = v.xy;
  return b;
})
[..., vec2f, 'this-function']
[..., vec2f, snippet('v.xy', vec2f, 'runtime')]
d.ref
const b = d.ref(u32(0));
return b;
[..., ptr<function,u32,rw>, 'function']
[..., ptr<function,u32,rw>, snippet(u32(0), u32, 'constant')]
Not sure about that
const b = d.ref(vec2f());
return b;
[..., ptr<function,vec2f,rw>, 'function']
[..., ptr<function,vec2f,rw>, snippet(vec2f(0), vec2f, 'constant')]
mixed origins in complex types
return vec4f(7).xz;
[..., vec2f, 'constant']
[..., vec2f, 'constant']
const b = vec4f(7).xz;
return b;
[..., vec2f, 'this-function']
[..., vec2f, snippet(vec4f(7).xz, vec2f, 'constant')]
return vec4f(buf.$, 1).xw;
[..., vec2f, 'runtime']
[..., vec2f, 'runtime']
const b = vec4f(buf.$, 1).xw;
return b;
[..., vec2f, 'this-function']
[..., vec2f, snippet(vec4f(buf.$, 1), vec2f, 'runtime')]
Constructors perform deep copy :))
const a = Boid();
return a.pos;
[..., vec2f, 'this-function']
[..., vec2f, 'this-function']
Not sure about that because there is nothing to be referenced
const a = Boid();
const b = a.pos;
return b;
[..., iptr<function,vec2f,rw>, 'this-function']
[..., iptr<function,vec2f,rw>, snippet(a.pos, vec2f, 'this-function')]
const a = Boid({ pos: buf.$, ... });
return a.pos;
[..., vec2f, 'this-function']
[..., vec2f, 'this-function']
Again, constructors perform deep copy
const a = Boid({ pos: buf.$, ... });
const b = a.pos;
return b;
[..., iptr<function,vec2f,rw>, 'this-function']
[..., iptr<function,vec2f,rw>, snippet(a.pos, vec2f, 'this-function')]

TODO:

  • add more tests with d.ref (maybe examining last statement will allow to check inter state of the d.ref)

Metadata

Metadata

Assignees

Labels

No labels
No labels

Type

No type

Projects

No projects

Milestone

No milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions