applyShader method

void applyShader(
  1. Shader fragmentShader, {
  2. Map<String, Texture> textures = const {},
  3. Map<String, SamplerOptions> samplers = const {},
  4. Map<String, ByteData> uniforms = const {},
  5. bool frameInfo = false,
})

Runs fragmentShader as a full-screen pass that advances this stage's color chain: the engine binds the current color as sampler2D input_color (sampled at the v_uv varying), renders into the next buffer, and makes it the current color for downstream passes.

Bind extra inputs with textures (each a sampler2D by name, sampled with samplers or a default linear-clamp sampler) and uniforms (each a std140 uniform block by name). Set frameInfo when the shader declares a PostFrameInfo block (resolution / texel_size / time), the same contract as a PostEffect.

Call at most once per pass; for multiple chained effects use multiple CustomRenderPasses. At an HDR stage the shader must output linear HDR premultiplied by alpha (the material-shader contract).

Implementation

void applyShader(
  gpu.Shader fragmentShader, {
  Map<String, gpu.Texture> textures = const {},
  Map<String, gpu.SamplerOptions> samplers = const {},
  Map<String, ByteData> uniforms = const {},
  bool frameInfo = false,
}) {
  final input = _context.blackboard.require<gpu.Texture>(_chainKey);

  final commandBuffer = gpu.gpuContext.createCommandBuffer();
  final renderPass = commandBuffer.createRenderPass(
    gpu.RenderTarget.singleColor(gpu.ColorAttachment(texture: _destination)),
  );
  renderPass.bindPipeline(resolvePipeline(_vertexShader, fragmentShader));
  bindVertexBufferCompat(renderPass, _quadView, 6);

  renderPass.bindTexture(
    fragmentShader.getUniformSlot('input_color'),
    input,
    sampler: _linearClamp,
  );

  if (frameInfo) {
    final w = dimensions.width;
    final h = dimensions.height;
    final info = Float32List(8)
      ..[0] = w
      ..[1] = h
      ..[2] = w == 0 ? 0.0 : 1.0 / w
      ..[3] = h == 0 ? 0.0 : 1.0 / h
      ..[4] = _time;
    renderPass.bindUniform(
      fragmentShader.getUniformSlot('PostFrameInfo'),
      _context.transientsBuffer.emplace(ByteData.sublistView(info)),
    );
  }

  if (textures.isNotEmpty || uniforms.isNotEmpty) {
    final bindings = ShaderUniformBindings();
    for (final entry in uniforms.entries) {
      bindings.setUniformBlock(entry.key, entry.value);
    }
    for (final entry in textures.entries) {
      bindings.setTexture(
        entry.key,
        entry.value,
        sampler: samplers[entry.key] ?? _linearClamp,
      );
    }
    bindings.bind(renderPass, fragmentShader, _context.transientsBuffer);
  }

  drawCompat(renderPass, 6);
  rendererSubmissions.submit(commandBuffer);

  _wrote = true;
}