Skip to content

Strict source rect for sub-rect image draws (flutter/flutter#67881) - #1

Open
lslv1243 wants to merge 3 commits into
fibula/base-3.27.1from
fibula/3.27.1-strict-src
Open

Strict source rect for sub-rect image draws (flutter/flutter#67881)#1
lslv1243 wants to merge 3 commits into
fibula/base-3.27.1from
fibula/3.27.1-strict-src

Conversation

@lslv1243

@lslv1243 lslv1243 commented Aug 1, 2026

Copy link
Copy Markdown
Owner

Fixes two rendering defects for Fibula Wars, at the engine root, on Flutter 3.27.1 (cb4b5fff73).

1. Strict source rect for sub-rect image draws (flutter/flutter#67881)

Canvas::drawImageRect hardcoded DlSrcRectConstraint::kFast, so sampling reads outside the source rect and atlas cells bleed into neighbours. This PR passes kStrict whenever the source rect does not cover the whole image:

  • lib/ui/painting/canvas.cc: conditional strict constraint.
  • impeller/display_list/dl_dispatcher.cc: forward the constraint to the Impeller canvas — the strict sampling pipeline existed upstream but the dispatcher dropped the parameter (still true on master as of 2026-08-01).

Validated with a sentinel-atlas harness (every neighbour cell magenta): 0/56 bleeding configs at both filter qualities on iOS (Skia Metal + Impeller Metal, sim debug + device release), Android emulator (Skia GL) and Android device (Impeller GLES). Bilinear atlas draws become pixel-identical to isolated textures (0/280).

2. Impeller: stale image color source suppresses texture-draw color filters

Paint::WithColorFilter early-returns when color_source is an image color source, assuming TiledTextureContents applied the filter. But dispatchers persist paint attributes across ops and image draws don't re-sync the color source — so after any ImageShader draw in the same display list, every later drawImageRect with a ColorFilter silently loses the filter (e.g. recolorable masks render their raw pixels).

Minimal repro: draw a fullscreen rect with an ImageShader paint, then drawImageRect with ColorFilter.mode(green, srcIn) + BlendMode.multiply over a gray base — renders raw red instead of green. Fix: Canvas::DrawImageRect clears color_source on a local paint copy (the texture is the source; the attribute is irrelevant there). Verified: filtered output returns to the mathematically expected value; full game mask-tint pipeline renders correctly over shader-painted backgrounds.

Upstream note: master retains the same early-return; current recording behavior happens to mask the bug there, but the hardening is applicable as-is.

Build compatibility (Xcode 26 / macOS 26 SDK)

Building this 2024-era checkout with Xcode 26 needs two buildroot/libcxx patches, carried in the sibling repos:

lslv1243 added 3 commits July 31, 2026 22:58
Canvas::drawImageRect always passed SrcRectConstraint::kFast, so atlas
cell draws could sample neighbouring cells. Pass kStrict whenever the
source rect is a strict sub-rect of the image; full-image draws keep
kFast semantics. Also forward the constraint in the Impeller dispatcher,
which received it and dropped it (the canvas + TextureContents strict
pipeline already existed, unwired).

Validated on iOS sim + macOS: sentinel-atlas bleed 0/56 configs on both
Skia and Impeller at FilterQuality.none and .low (stock: 3-30/56 none,
56/56 low).
…urce is set

DrawImageRect renders the given texture; the paint's color source is
irrelevant to it. Dispatchers persist paint attributes across ops and
image draws do not re-sync the color source, so a preceding ImageShader
draw leaves paint.color_source set. Paint::WithColorFilter's image-source
early-return then assumes the color filter was applied by
TiledTextureContents and drops it silently.

Repro: draw a rect with an ImageShader paint, then drawImageRect with a
ColorFilter - the filter is ignored (e.g. mask recolors render raw
pixels). Fix: clear the color source on a local paint copy before
building the texture entity. Upstream master retains the same
early-return; recording-order changes currently mask it there.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant