RESOLVED FIXED Bug 233613
[GPU Process] [Filters 15/23] Calculate the result image rectangle of the FilterEffect in filter coordinates
https://bugs.webkit.org/show_bug.cgi?id=233613
Summary [GPU Process] [Filters 15/23] Calculate the result image rectangle of the Fil...
Said Abou-Hallawa
Reported 2021-11-29 18:56:44 PST
The FilterEffect lengths (like the stdDeviation of FEGaussianBlur) are in filter coordinates. Using the filter coordinates will simplify the image rectangle calculations. Only when creating the FilterImage we can convert the image rectangle from filter coordinates to user space coordinates.
Attachments
Patch (98.12 KB, patch)
2021-11-29 20:29 PST, Said Abou-Hallawa
ews-feeder: commit-queue-
Patch (98.91 KB, patch)
2021-11-29 20:47 PST, Said Abou-Hallawa
heycam: review+
Patch (100.27 KB, patch)
2021-11-30 00:20 PST, Said Abou-Hallawa
no flags
Said Abou-Hallawa
Comment 1 2021-11-29 20:29:01 PST
Said Abou-Hallawa
Comment 2 2021-11-29 20:47:37 PST
Cameron McCormack (:heycam)
Comment 3 2021-11-29 22:26:47 PST
Comment on attachment 445376 [details] Patch View in context: https://bugs.webkit.org/attachment.cgi?id=445376&action=review > Source/WebCore/platform/graphics/GraphicsContext.cpp:646 > + scale({ 1 / filter.filterScale().width(), 1 / filter.filterScale().height() }); > drawImageBuffer(*imageBuffer, result->absoluteImageRect()); > + scale(filter.filterScale()); I meant to mention this in a previous patch too, but I think I forgot. There's always risk with applying a transform and then its inverse later that there is sufficient loss of precision that you don't end up with the original CTM. Not sure if it's a practical issue but something to consider? > Source/WebCore/platform/graphics/filters/FEComposite.cpp:95 > // For In and Atop the first effect just influences the result of > // the second effect. So just use the absolute paint rect of the second effect here. Update this comment so it no longer talks about the "absolute paint rect". > Source/WebCore/platform/graphics/filters/FEComposite.cpp:99 > // Arithmetic may influnce the compele filter primitive region. So we can't Pre-existing: "complete" (or "entire" would sound better) > Source/WebCore/platform/graphics/filters/FEDropShadow.cpp:60 > // We take the half kernel size and multiply it with three, because we run box blur three times. > - absolutePaintRect.inflateX(3 * kernelSize.width() * 0.5f); > - absolutePaintRect.inflateY(3 * kernelSize.height() * 0.5f); > + imageRect.inflateX(3 * kernelSize.width() * 0.5f); > + imageRect.inflateY(3 * kernelSize.height() * 0.5f); > Pre-existing, but why don't we inflate imageRectWithOffset instead of the final imageRect value? > Source/WebCore/platform/graphics/filters/Filter.cpp:77 > +FloatRect Filter::clipToMaxEffectRect(const FloatRect& imageRect, const FloatRect& primitiveSubregion) const > +{ > + auto maxEffectRect = this->maxEffectRect(primitiveSubregion); > + return m_clipOperation == ClipOperation::Intersect ? intersection(imageRect, maxEffectRect) : unionRect(imageRect, maxEffectRect); > +} Seems weird to me that the function is called "clipToMaxEffectRect" but m_clipOperation causes it to either clip or to unite. But I don't have a better name suggestion right now. > Source/WebCore/rendering/RenderLayerFilters.cpp:135 > + auto logicalSize = filter.sourceImageRect().size() * filter.filterScale(); Use scaledByFilterScale maybe? Size is the easy one to write out instead of calling the function, but may as well consistently use it.
Cameron McCormack (:heycam)
Comment 4 2021-11-29 22:28:23 PST
Comment on attachment 445376 [details] Patch View in context: https://bugs.webkit.org/attachment.cgi?id=445376&action=review > Source/WebCore/platform/graphics/filters/SpotLightSource.cpp:44 > static const float antiAliasTreshold = 0.016f; Pre-existing: "antialiasThreshold"
Said Abou-Hallawa
Comment 5 2021-11-30 00:20:35 PST
Comment on attachment 445376 [details] Patch View in context: https://bugs.webkit.org/attachment.cgi?id=445376&action=review >> Source/WebCore/platform/graphics/GraphicsContext.cpp:646 >> + scale(filter.filterScale()); > > I meant to mention this in a previous patch too, but I think I forgot. There's always risk with applying a transform and then its inverse later that there is sufficient loss of precision that you don't end up with the original CTM. Not sure if it's a practical issue but something to consider? Using save()/restore() or using GraphicsContextStateSaver is expensive. In the old code we were creating an AffineTransform and we were applying its inverse before drawing and applying it after drawing. So I think scaling with the reciprocal of filter.filterScale() is more accurate than applying the inverse of AffineTransform. But I will think about it. >> Source/WebCore/platform/graphics/filters/FEComposite.cpp:95 >> // the second effect. So just use the absolute paint rect of the second effect here. > > Update this comment so it no longer talks about the "absolute paint rect". Fixed. >> Source/WebCore/platform/graphics/filters/FEComposite.cpp:99 >> // Arithmetic may influnce the compele filter primitive region. So we can't > > Pre-existing: "complete" (or "entire" would sound better) Fixed. >> Source/WebCore/platform/graphics/filters/FEDropShadow.cpp:60 >> > > Pre-existing, but why don't we inflate imageRectWithOffset instead of the final imageRect value? Because the final imageRect will be different if { m_dx, m_dy } are negative. Suppose inputs[0]->imageRect() = { 30, 30, 100, 100 } { m_dx, m_dy } = { -10, -10 } { m_stdX, m_stdY } = { 10, 10 } => kernelSize = { 10, 10 } Current calculations are: imageRect = { 30, 30, 100, 100 } imageRectWithOffset = { 20, 20, 100, 100 } // after imageRectWithOffset.move({ -10, -10 }) imageRect = { 20, 20, 110, 110 }. // after imageRect.unite({ 20, 20, 100, 100 }) imageRect = { 5, 5, 140, 140 }. // after imageRect.inflate({15, 15}) Calculations with your suggestion are: imageRect = { 30, 30, 100, 100 } imageRectWithOffset = { 20, 20, 100, 100 } // after imageRectWithOffset.move({ -10, -10 }) imageRectWithOffset = { 5, 5, 130, 130 }. // after imageRect.inflate({15, 15}) imageRect = { 5, 5, 130, 130 }. // after imageRect.unite({ 5, 5, 130, 130 }) >> Source/WebCore/platform/graphics/filters/SpotLightSource.cpp:44 >> static const float antiAliasTreshold = 0.016f; > > Pre-existing: "antialiasThreshold" Fixed. >> Source/WebCore/rendering/RenderLayerFilters.cpp:135 >> + auto logicalSize = filter.sourceImageRect().size() * filter.filterScale(); > > Use scaledByFilterScale maybe? Size is the easy one to write out instead of calling the function, but may as well consistently use it. Fixed.
Said Abou-Hallawa
Comment 6 2021-11-30 00:20:53 PST
EWS
Comment 7 2021-11-30 01:19:23 PST
Committed r286287 (244646@main): <https://commits.webkit.org/244646@main> All reviewed patches have been landed. Closing bug and clearing flags on attachment 445390 [details].
Radar WebKit Bug Importer
Comment 8 2021-11-30 01:20:21 PST
Cameron McCormack (:heycam)
Comment 9 2021-11-30 13:58:00 PST
(In reply to Said Abou-Hallawa from comment #5) > >> Source/WebCore/platform/graphics/filters/FEDropShadow.cpp:60 > >> > > > > Pre-existing, but why don't we inflate imageRectWithOffset instead of the final imageRect value? > > Because the final imageRect will be different if { m_dx, m_dy } are > negative. Suppose > > inputs[0]->imageRect() = { 30, 30, 100, 100 } > { m_dx, m_dy } = { -10, -10 } > { m_stdX, m_stdY } = { 10, 10 } => kernelSize = { 10, 10 } > > Current calculations are: > > imageRect = { 30, 30, 100, 100 } > imageRectWithOffset = { 20, 20, 100, 100 } // after > imageRectWithOffset.move({ -10, -10 }) > imageRect = { 20, 20, 110, 110 }. // after imageRect.unite({ 20, 20, 100, > 100 }) > imageRect = { 5, 5, 140, 140 }. // after imageRect.inflate({15, 15}) > > Calculations with your suggestion are: > > imageRect = { 30, 30, 100, 100 } > imageRectWithOffset = { 20, 20, 100, 100 } // after > imageRectWithOffset.move({ -10, -10 }) > imageRectWithOffset = { 5, 5, 130, 130 }. // after imageRect.inflate({15, > 15}) > imageRect = { 5, 5, 130, 130 }. // after imageRect.unite({ 5, 5, 130, 130 }) But isn't that fine? The rendered result of using the filter is a blurred shadow covering { 5, 5, 130, 130 } with the unblurred input covering { 30, 30, 100, 100 } composited on top. The image rect doesn't need to cover the extra space down to (140, 140).
Arcady Goldmints-Orlov
Comment 10 2022-04-28 19:49:44 PDT
*** Bug 233611 has been marked as a duplicate of this bug. ***
Note You need to log in before you can comment on or make changes to this bug.