Skip to content

BackdropFilter shader UV sampling is incorrect on beta when using ClipRect and a composed blur #181660

Description

@timcreatedit

This issue is a spiritual successor to #178798

Steps to reproduce

  1. Run the code sample on the current beta channel

Expected results

The blur filter does not affect the rendering of the shader filter. Result should always be what it looks like when setting sigma to 0.

Actual results

With sigma = 0:

Image

Sigma = 1:

Image

Code sample

Code sample

assets/shaders/uv.frag

#version 460 core
precision mediump float;

#include <flutter/runtime_effect.glsl>

uniform vec2 uSize;
uniform sampler2D uTexture;

out vec4 fragColor;

void main() {
    vec2 fragCoord = FlutterFragCoord().xy;

    vec2 screenUV = vec2(fragCoord.x / uSize.x, fragCoord.y / uSize.y);        
    vec4 texColor = texture(uTexture, screenUV);
        
    #ifdef IMPELLER_TARGET_OPENGLES
        screenUV.y = 1.0 - screenUV.y;
    #endif
    
    // Check if we're within 20px of any edge
    float borderWidth = 20.0;
    bool inBorder = fragCoord.x < borderWidth || 
                    fragCoord.x > (uSize.x - borderWidth) ||
                    fragCoord.y < borderWidth || 
                    fragCoord.y > (uSize.y - borderWidth);
    
    if (inBorder) {
        fragColor = vec4(0.5, 0.0, 0.5, 1.0); // Purple border
    } else {
        fragColor = vec4(screenUV, 0.0, 1.0);
        fragColor = mix(fragColor, texColor, .5);
    }
}

pubspec.yaml

name: flutter_sandbox
description: "A new Flutter project."
publish_to: 'none'
version: 0.1.0

environment:
  sdk: ^3.9.2

dependencies:
  flutter:
    sdk: flutter
  flutter_shaders: ^0.1.3

dev_dependencies:
  flutter_test:
    sdk: flutter
  flutter_lints: ^5.0.0

flutter:
  uses-material-design: true

  shaders:
    - assets/shaders/uv.frag

lib/main.dart

import 'dart:ui';

import 'package:flutter/material.dart';
import 'package:flutter/rendering.dart';
import 'package:flutter_shaders/flutter_shaders.dart';

void main() {
  runApp(const MainApp());
}

class MainApp extends StatelessWidget {
  const MainApp({super.key});

  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      home: Scaffold(
        body: Stack(
          children: [
            Positioned.fill(child: GridPaper()),
            Positioned.fill(
              child: ShaderBuilder(
                assetKey: 'assets/shaders/uv.frag',
                (context, shader, child) => MyShaderWidget(shader: shader),
              ),
            ),
          ],
        ),
      ),
    );
  }
}

class MyShaderWidget extends SingleChildRenderObjectWidget {
  const MyShaderWidget({super.key, required this.shader, super.child});

  final FragmentShader shader;

  @override
  RenderObject createRenderObject(BuildContext context) {
    return RenderMyShader(shader);
  }
}

class RenderMyShader extends RenderProxyBox {
  RenderMyShader(this.shader);

  final FragmentShader shader;

  final LayerHandle<ClipRectLayer> _clipRectLayer =
      LayerHandle<ClipRectLayer>();

  final LayerHandle<BackdropFilterLayer> _backdropFilterLayer =
      LayerHandle<BackdropFilterLayer>();

  static const inset = EdgeInsets.all(66);

  @override
  void paint(PaintingContext context, Offset offset) {
    final rect = offset & size;
    _clipRectLayer.layer = context.pushClipRect(
      true,
      offset,
      inset.deflateRect(rect),
      (context, offset) {
        final layer = _backdropFilterLayer.layer ??= BackdropFilterLayer();

        layer.filter = ImageFilter.shader(shader);
        context.pushLayer(layer, (context, offset) {}, offset);
      },
      oldLayer: _clipRectLayer.layer,
    );

    super.paint(context, offset);
  }

  @override
  void dispose() {
    _clipRectLayer.layer = null;
    _backdropFilterLayer.layer = null;
    super.dispose();
  }
}

Screenshots or Video

No response

Logs

No response

Flutter Doctor output

Doctor output
[✓] Flutter (Channel beta, 3.41.0-0.1.pre, on macOS 15.7.3 24G419 darwin-arm64, locale en-US)
[✓] Android toolchain - develop for Android devices (Android SDK version 36.1.0-rc1)
[✓] Xcode - develop for iOS and macOS (Xcode 26.0)
[✓] Chrome - develop for the web
[✓] Connected device (3 available)
[✓] Network resources

• No issues found!

Metadata

Metadata

Assignees

Labels

P2Important issues not at the top of the work liste: impellerImpeller rendering backend issues and features requeststeam-engineOwned by Engine teamtriaged-engineTriaged by Engine team

Type

No type
No fields configured for issues without a type.

Projects

No projects

Milestone

No milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions