core/render: Implement BitmapData.generateFilterRect - #24136
Conversation
|
Referencing (mostly for the test, as it's ancient): #12417 |
The last part doesn't look like it holds... |
My oversight. I’ve already integrated the checks into my CI/CD scripts, but I forgot the imgtests. I’ll check and fix it. |
Can you describe, using your own words, what |
40a82ff to
ed85a7b
Compare
|
The problem is not at all the use of LLMs, it's purely about the result. And this is how we can keep the quality up, by not just trusting anything an LLM spits out, but actually understanding whether it's any good. Even if that is becoming increasingly controversial... |
Okay, I understand. The reason I always try to document everything well is to make your life at least a little easier, because I realize it's difficult to keep up with the current PR pace following the LLM boom. Regards |
989ae87 to
4538cfa
Compare
generateFilterRect was a stub that returned sourceRect unchanged, and
the wgpu applyFilter rendered filters into a texture the size of the
source rect, discarding the pixels a filter produces beyond it (blur
margins, drop shadow distance offset). Together these two gaps hide
every default Flex tooltip's drop shadow and rounded bottom edge:
mx.graphics.RectangularDropShadow relies on the difference between
generateFilterRect's report and applyFilter's writes to slice its
tile-able shadow bitmaps.
Add Filter::calculate_dest_margins as the single source of truth for
the per-side write reach, with values measured pixel-by-pixel from
Flash Player captures: a blur of strength b at q passes reaches
ceil((b - 1) * q / 2) pixels per side; drop shadow and bevel add the
distance offset on the side(s) they point towards; inner filters do
not expand. Implement generateFilterRect natively on top of it for
both AVM1 and AVM2.
In the wgpu backend, apply filters over a padded copy of the source,
shifting the destination point back by the margins so the expanded
output is written to the destination, as Flash does. Two more
Flash-matching behaviours the goldens revealed: a blur samples real
source pixels beyond the source rect within the bitmap's physical
bounds (the padded copy for blurs grows by the write ring to feed
the kernel real neighbors), and beyond the bitmap's physical bounds
the padding stays transparent, replacing the old edge-replication
that came from UV clamping. Filters that composite the source over
their output (glow, drop shadow, bevel) get transparent-only padding
— neighbor pixels under those would be painted into the margins.
bitmapdata_filter_sourcerect (a true Flash golden) now passes with
zero outliers; its "FIXME We're way off here compared to FP" 1700-
outlier allowance is removed. The Ruffle-canonical goldens of
bitmapdata_applyfilter_blur, visual/filters/blur_{quality,fractional}
and away3d_advanced_shallow_water_demo are regenerated: they encoded
the old no-expansion / edge-replication behaviour. destpoint_edges
stays known_failure due to its unsupported ConvolutionFilter; its
Ruffle-expected image is regenerated and its tolerance is raised
from 1 to 2 to accommodate the ~2/channel variance between GPUs
that gradual blur fades reveal (the two CI runners themselves differ
by 237 pixels at tolerance 1; every measured delta ≤2).
4538cfa to
f8805d7
Compare

What
Implements
BitmapData.generateFilterRect(previously a stub returningsourceRectunchanged, for both AVM1 and AVM2) and makes the wgpuapplyFilterwrite the filter's expanded output — the pixels a filterproduces beyond the source rect (blur margins, drop shadow distance
offset), which were previously discarded because the filter was rendered
into a texture the size of the source rect.
Why
The two halves fix a silent rendering gap that affects, among others,
every default Flex tooltip. Flex's
mx.graphics.RectangularDropShadow(used by the halo
ToolTipBorderskin, also under the Flex 4 Sparktheme) pre-renders its shadow like this:
BitmapData;generateFilterRectto learn how far aDropShadowFilterexpands it, deriving the shadow thickness on each edge;
applyFilterand slices the result into corner/edge bitmaps,which it then tiles with
beginBitmapFill.With
generateFilterRectreturning the source rect unchanged, everythickness came out as 0, no slices were created, and
drawShadow()drew nothing — Flex tooltips lost their drop shadow (and the rounded
bottom edge, which is the shadow). The same mechanism is used by the
mx preloader progress bars.
The two changes must ship together: with only
generateFilterRectfixed, the perimeter slices would read the destination bitmap's initial
fill (opaque white by default) instead of shadow pixels, which would
look worse than the current behavior.
How
Filter::calculate_dest_margins(render) — computes how far afilter's output extends beyond a source of a given pixel size,
rounding outwards to whole pixels. Single source of truth so that
generateFilterRect(what we report) andapplyFilter(what wewrite) always agree.
generateFilterRectimplemented natively for AVM2 and AVM1 on top ofit. The AVM2 ShaderFilter special case (Flash reports the whole
bitmap) is preserved, moved from ActionScript into the native method.
apply_filtercopies the source region into a zero-paddedintermediate texture, runs the filter over the whole padded area, and
shifts the destination point back by the margins. Padding is skipped
when the margins are empty or the padded texture would exceed
max_texture_dimension_2d.Notes
Filter::calculate_dest_rect, whose blurexpansion is intentionally approximate vs. Flash (see
PASS_SCALES),so the reported rect may be slightly larger than Flash Player's.
Internal consistency between the two APIs — which is what
RectangularDropShadow-style code depends on — is guaranteed.FIXME, comment updated).
Checklist