rendiation icon indicating copy to clipboard operation
rendiation copied to clipboard

Investigate how to express the global scope dependency in wgsl_fn!()

Open mikialex opened this issue 1 year ago • 1 comments

The below example shows too much input in the function definition. This is largely due to the current limitation: we don't support global scope dependency now.

wgsl_fn!(
  fn linear_blur(
    direction: vec2<f32>,
    weights: array<f32, 32>,
    weight_count: i32,
    texture: texture_2d<f32>,
    sp: sampler,
    uv: vec2<f32>,
    texel_size: vec2<f32>,
  ) -> vec4<f32> {
    let sample_offset = texel_size * direction;
    var sum: vec4<f32>;
    for (var i: i32 = 2; i < weight_count; i++) {
        let samples = textureSample(texture, sp, uv + f32(i) * sample_offset);
        sum = lin_space(1.0, sum, weights[i].inner, samples);
    }
    return sum;
  }
);

One promising design may be:

//##uniform weights: array<f32, 32>,
//##uniform weight_count: i32,
//##uniform texture: texture_2d<f32>,
//##uniform sp: sampler,
wgsl_fn!(
  fn linear_blur(
    direction: vec2<f32>,
    sp: sampler,
    uv: vec2<f32>,
    texel_size: vec2<f32>,
  ) -> vec4<f32> {
    let sample_offset = texel_size * direction;
    var sum: vec4<f32>;
    for (var i: i32 = 2; i < weight_count; i++) {
        let samples = textureSample(texture, sp, uv + f32(i) * sample_offset);
        sum = lin_space(1.0, sum, weights[i].inner, samples);
    }
    return sum;
  }
);

At the call site, we expand to this:

impl<'a, T> ShaderGraphProvider for LinearBlurTask<'a, T> {
  fn build(
    &self,
    builder: &mut ShaderGraphRenderPipelineBuilder,
  ) -> Result<(), ShaderGraphBuildError> {
    builder.log_result = true;
    builder.fragment(|builder, binding| {
      let config = binding.uniform_by(self.config, SB::Material).expand();

      let uv = builder.query::<FragmentUv>()?.get();
      let size = builder.query::<TexelSize>()?.get();

      let blurred = linear_blur {
        weights: binding.uniform_by(&self.weights.weights, SB::Material);
        weight_count: binding.uniform_by(&self.weights.weight_count, SB::Material);
        input: binding.uniform_by(&self.input, SB::Material);
        sp: binding.uniform::<GPUSamplerView>(SB::Material);
      }.call(
        config.direction,
        uv,
        size,
      ) // or use the nightly closure feature

      builder.set_fragment_out(0, blurred)
    })
  }
}

mikialex avatar Aug 24 '22 18:08 mikialex

The line of code doesn't save, but only for passing the wgsl validation case that:

fn test(a: array<vec4<f32>,8u>) {
    for(var i:i32 = 0; i<count; i++){
        let a = a[i]; // validation err , must be const expr, even if the a is from uniform..
    }
}

var<uniform> global: array<vec4<f32>,8u>;
fn test(a: array<vec4<f32>,8u>) {
    for(var i:i32 = 0; i<count; i++){
        let a = global[i]; // validation ok
    }
}

mikialex avatar Aug 25 '22 14:08 mikialex