WebKit Bugzilla
New
Browse
Log In
×
Sign in with GitHub
or
Remember my login
Create Account
·
Forgot Password
Forgotten password account recovery
RESOLVED FIXED
92059
[chromium] Combine color matrix filters and apply them in a single pass.
https://bugs.webkit.org/show_bug.cgi?id=92059
Summary
[chromium] Combine color matrix filters and apply them in a single pass.
Antoine Labour
Reported
2012-07-23 20:54:05 PDT
[chromium] Combine color matrix filters and apply them in a single pass.
Attachments
Patch
(11.50 KB, patch)
2012-07-23 20:57 PDT
,
Antoine Labour
no flags
Details
Formatted Diff
Diff
Patch
(25.40 KB, patch)
2012-07-24 17:43 PDT
,
Antoine Labour
no flags
Details
Formatted Diff
Diff
Patch
(26.63 KB, patch)
2012-07-24 17:50 PDT
,
Antoine Labour
no flags
Details
Formatted Diff
Diff
Patch
(26.64 KB, patch)
2012-07-24 18:01 PDT
,
Antoine Labour
no flags
Details
Formatted Diff
Diff
Patch
(70.32 KB, patch)
2012-07-25 16:45 PDT
,
Antoine Labour
no flags
Details
Formatted Diff
Diff
Patch
(70.55 KB, patch)
2012-07-25 21:05 PDT
,
Antoine Labour
no flags
Details
Formatted Diff
Diff
Patch for landing
(71.46 KB, patch)
2012-07-26 12:29 PDT
,
Antoine Labour
no flags
Details
Formatted Diff
Diff
Show Obsolete
(6)
View All
Add attachment
proposed patch, testcase, etc.
Antoine Labour
Comment 1
2012-07-23 20:57:11 PDT
Created
attachment 153949
[details]
Patch
Antoine Labour
Comment 2
2012-07-23 20:58:05 PDT
See
http://code.google.com/p/chromium/issues/detail?id=138645
for a use case for this optimization.
Adrienne Walker
Comment 3
2012-07-23 23:07:48 PDT
Comment on
attachment 153949
[details]
Patch View in context:
https://bugs.webkit.org/attachment.cgi?id=153949&action=review
R=me.
> Source/WebCore/platform/graphics/chromium/cc/CCRenderSurfaceFilters.cpp:224 > +class ScopedScratchCanvas {
Nice. :)
Stephen White
Comment 4
2012-07-24 06:49:18 PDT
Comment on
attachment 153949
[details]
Patch As tempting as this optimization is (and I have been tempted), I don't think it's correct for CSS filters. The reason is that colour clamping must occur after each matrix is applied. E.g., if a translation by +255 followed by -255 were applied, it should end up at black, not at the original colour. I'd suggest two possibilities: add a flag so that it is only enabled for your use case, and not CSS filters, or implement a generic colour matrix filter, and convert and concatenate your matrices outside this code. Alternately, I suppose we could try to detect the case where clamping would occur, and avoid the optimization, but that might be tricky.
Stephen White
Comment 5
2012-07-24 06:59:04 PDT
(In reply to
comment #4
)
> I'd suggest two possibilities: add a flag so that it is only enabled for your use case, and not CSS filters, or implement a generic colour matrix filter, and convert and concatenate your matrices outside this code. Alternately, I suppose we could try to detect the case where clamping would occur, and avoid the optimization, but that might be tricky.
After thinking about it a bit, I'd prefer the generic colour matrix filter option, since we'll need that for some upcoming work anyway.
Dana Jansens
Comment 6
2012-07-24 09:13:53 PDT
It's tempting to just remove all the color matrix filter operations and keep a single "matrix" operation, but that may be shooting ourselves in the foot if we decide to animate filters inside the compositor someday, as each filter needs to be animated independently rather than interpolating between two matrices. And in this case, the UI would want to use separate filters also, not a single matrix. So I'm a proponent of adding a useStrictClamping flag or somesuch to WebFilterOperations and doing these sorts of optimizations when it is false.
Antoine Labour
Comment 7
2012-07-24 10:01:00 PDT
(In reply to
comment #6
)
> It's tempting to just remove all the color matrix filter operations and keep a single "matrix" operation, but that may be shooting ourselves in the foot if we decide to animate filters inside the compositor someday, as each filter needs to be animated independently rather than interpolating between two matrices.
Yeah, that's what happens.
> > And in this case, the UI would want to use separate filters also, not a single matrix. So I'm a proponent of adding a useStrictClamping flag or somesuch to WebFilterOperations and doing these sorts of optimizations when it is false.
I think I like this option. The flag can be kept off for web stuff.
Stephen White
Comment 8
2012-07-24 10:27:09 PDT
Comment on
attachment 153949
[details]
Patch View in context:
https://bugs.webkit.org/attachment.cgi?id=153949&action=review
> Source/WebCore/platform/graphics/chromium/cc/CCRenderSurfaceFilters.cpp:307 > + if (getColorMatrix(op, matrix)) { > + if (hasMatrix) { > + SkScalar newMatrix[20]; > + multColorMatrix(matrix, combinedMatrix, newMatrix); > + memcpy(combinedMatrix, newMatrix, sizeof(combinedMatrix)); > + } else { > + memcpy(combinedMatrix, matrix, sizeof(combinedMatrix)); > + hasMatrix = true; > + } > + } else { > + if (hasMatrix) { > + ScopedScratchCanvas canvas(gr, desc, &source); > + if (!canvas.isValid()) > + return SkBitmap(); > + applyColorMatrix(canvas.canvas(), source, combinedMatrix); > + hasMatrix = false; > + }
This seems to be a lot of special cases (and separate texture allocations) inside what's essentially a pretty simple loop. Could we instead pre-process the list of filters into an optimized list, consisting of matrix and non-matrix operations? Also please add a test in css3/filters to test for the colour clamping I mentioned. You'll need a regular and -hw flavour of the test.
Stephen White
Comment 9
2012-07-24 10:28:59 PDT
(In reply to
comment #7
)
> (In reply to
comment #6
) > > It's tempting to just remove all the color matrix filter operations and keep a single "matrix" operation, but that may be shooting ourselves in the foot if we decide to animate filters inside the compositor someday, as each filter needs to be animated independently rather than interpolating between two matrices. > > Yeah, that's what happens. > > > > > And in this case, the UI would want to use separate filters also, not a single matrix. So I'm a proponent of adding a useStrictClamping flag or somesuch to WebFilterOperations and doing these sorts of optimizations when it is false. > > I think I like this option. The flag can be kept off for web stuff.
Here's another option: create a matrix filter type, but for now only use it inside CCRenderSurfaceFilters.cpp (we can expose it later). Pre-process the list of filters into a list of collapsed matrices and non-matrix operations. Then the processing loop can be simple, as it was before, with only a single backing store allocation.
Antoine Labour
Comment 10
2012-07-24 17:43:11 PDT
Created
attachment 154196
[details]
Patch
Antoine Labour
Comment 11
2012-07-24 17:45:12 PDT
As discussed directly, this new patch does: - automatically figures out if we need clamping, in which case it will apply filters separately. - reuse textures across filter passes (flip-flops) - add layout tests for the clamping case - a few minor simplifications to make the loop body state machine more readable.
WebKit Review Bot
Comment 12
2012-07-24 17:46:46 PDT
Attachment 154196
[details]
did not pass style-queue: Failed to run "['Tools/Scripts/check-webkit-style', '--diff-files', u'LayoutTests/css3/filters/effect-brightness..." exit_code: 1 Source/WebCore/ChangeLog:14: Line contains tab character. [whitespace/tab] [5] Total errors found: 1 in 6 files If any of these errors are false positives, please file a bug against check-webkit-style.
Dana Jansens
Comment 13
2012-07-24 17:49:26 PDT
Comment on
attachment 154196
[details]
Patch View in context:
https://bugs.webkit.org/attachment.cgi?id=154196&action=review
> Source/WebCore/platform/graphics/chromium/cc/CCRenderSurfaceFilters.cpp:170 > + for (int j = 0; j < 4; ++j)
this should have a { as well as the for loop inside it
Antoine Labour
Comment 14
2012-07-24 17:50:11 PDT
Created
attachment 154199
[details]
Patch
Antoine Labour
Comment 15
2012-07-24 18:01:10 PDT
Created
attachment 154201
[details]
Patch
Antoine Labour
Comment 16
2012-07-24 18:01:46 PDT
Comment on
attachment 154196
[details]
Patch View in context:
https://bugs.webkit.org/attachment.cgi?id=154196&action=review
>> Source/WebCore/platform/graphics/chromium/cc/CCRenderSurfaceFilters.cpp:170 >> + for (int j = 0; j < 4; ++j) > > this should have a { as well as the for loop inside it
Done.
Dana Jansens
Comment 17
2012-07-24 19:13:03 PDT
Comment on
attachment 154201
[details]
Patch View in context:
https://bugs.webkit.org/attachment.cgi?id=154201&action=review
Sorry for the horde of nits, also I think I see an extra copy now?
> Source/WebCore/platform/graphics/chromium/cc/CCRenderSurfaceFilters.cpp:164 > +// c = a*b;
maybe rename "c" to something like "out" or "result" to make this clear instead of requiring this comment?
> Source/WebCore/platform/graphics/chromium/cc/CCRenderSurfaceFilters.cpp:253 > + FilterBufferState(GrContext* gr, const WebCore::FloatSize& size, unsigned textureId) > + : m_gr(gr)
s/gr/grContext/ ?
> Source/WebCore/platform/graphics/chromium/cc/CCRenderSurfaceFilters.cpp:255 > + // Wrap the RenderSurface's texture in a Ganesh platform texture.
nit: let's use terminology of "input texture" or something, rather than RenderSurface explicitly, since that will be wrong once we allow filters without a surface in the single-layer case.
> Source/WebCore/platform/graphics/chromium/cc/CCRenderSurfaceFilters.cpp:256 > + GrPlatformTextureDesc platformTexDesc;
There's lots of abbreviations in this file which we avoid generally. Sorry to bikeshed on them, but maybe we can clean them up now? eg textureDescription?
> Source/WebCore/platform/graphics/chromium/cc/CCRenderSurfaceFilters.cpp:345 > + SkScalar combinedMatrix[20];
combinedColorMatrix?
> Source/WebCore/platform/graphics/chromium/cc/CCRenderSurfaceFilters.cpp:346 > + bool hasMatrix = false;
Can we call this "haveCombinedColorMatrix" or "combinedColorMatrixIsEmpty" or "combinedColorMatrixHasValue" or something? I feel like hasMatrix is a bit more ambiguous about which matrix its meaning.
> Source/WebCore/platform/graphics/chromium/cc/CCRenderSurfaceFilters.cpp:376 > + if (hasMatrix && !applyColorMatrix(&state, combinedMatrix)) > + return SkBitmap(); > + hasMatrix = false; > + > + SkCanvas* canvas = state.canvas(); > + if (!canvas) > return SkBitmap(); > - SkGpuDevice device(gr, destination.get()); > - SkCanvas canvas(&device); > - canvas.clear(0x0); > switch (op.type()) {
If we have a combinedColorMatrix and succeed at applying it, should we do a "continue" after marking the combinedColorMatrix as being non-present? Right now, we'll fall into the default: case of the switch statement after applying the color matrix, which will do a copy of the source to the new destination texture (swapped in at the end of the apply).
Stephen White
Comment 18
2012-07-25 08:29:58 PDT
Comment on
attachment 154201
[details]
Patch View in context:
https://bugs.webkit.org/attachment.cgi?id=154201&action=review
Thanks very much for implementing this optimization. It's great that we can apply it to web content as well.
> Source/WebCore/platform/graphics/chromium/cc/CCRenderSurfaceFilters.cpp:189 > +bool componentNeedsClamping(SkScalar line[5])
Nit: Could we call this "row" rather than "line"? Matrices usually have rows.
> Source/WebCore/platform/graphics/chromium/cc/CCRenderSurfaceFilters.cpp:316 > + OwnPtr<SkGpuDevice> m_device; > + OwnPtr<SkCanvas> m_canvas;
I seem to recall problems with using OwnPtr and Skia stuff in the past, since it has its own ref counting. Consider using an SkAutoTUnref on the device & canvas as well (if you like.. your call).
>> Source/WebCore/platform/graphics/chromium/cc/CCRenderSurfaceFilters.cpp:346 >> + bool hasMatrix = false; > > Can we call this "haveCombinedColorMatrix" or "combinedColorMatrixIsEmpty" or "combinedColorMatrixHasValue" or something? I feel like hasMatrix is a bit more ambiguous about which matrix its meaning.
Perhaps "accumulated" instead of "combined"? "accumulatedColorMatrix" and "haveAccumulatedColorMatrix"?
> Source/WebCore/platform/graphics/chromium/cc/CCRenderSurfaceFilters.cpp:376 > switch (op.type()) {
Good catch, Dana (although I think it's only a problem in the clamping case). Maybe we could apply the matrix right away above if it needs clamping, and continue in both the clamping and non-clamping cases: if (matrixNeedsClamping(combinedMatrix)) && !applyColorMatrix(&state, combinedMatrix)) return SkBitmap(); continue; Alternately, we could probably get rid of the identity draw in the default case now since it'll just pick up the previous source, although it would require moving the swap() into the blur and drop-shadow draws so it wouldn't happen in the default case either.
> LayoutTests/css3/filters/effect-brightness-clamping-hw.html:13 > +<img style="-webkit-filter: brightness(1) brightness(-1)" src="resources/reference.png">
I'd like to see more coverage here, e.g., brightness followed by blur or drop-shadow.
Dana Jansens
Comment 19
2012-07-25 08:35:06 PDT
(In reply to
comment #18
)
> (From update of
attachment 154201
[details]
) > View in context:
https://bugs.webkit.org/attachment.cgi?id=154201&action=review
> > Source/WebCore/platform/graphics/chromium/cc/CCRenderSurfaceFilters.cpp:376 > > switch (op.type()) { > > Good catch, Dana (although I think it's only a problem in the clamping case). Maybe we could apply the matrix right away above if it needs clamping, and continue in both the clamping and non-clamping cases: > > if (matrixNeedsClamping(combinedMatrix)) && !applyColorMatrix(&state, combinedMatrix)) > return SkBitmap(); > continue; > > Alternately, we could probably get rid of the identity draw in the default case now since it'll just pick up the previous source, although it would require moving the swap() into the blur and drop-shadow draws so it wouldn't happen in the default case either.
If we can get rid of the default case, (and add back all the color matrix cases going to the same case-body) that could possibly be nice. That way we would also get compiler errors if a new operation type is added to the enum but not to the switch.
Antoine Labour
Comment 20
2012-07-25 16:45:17 PDT
Created
attachment 154481
[details]
Patch
Antoine Labour
Comment 21
2012-07-25 16:48:19 PDT
Comment on
attachment 154201
[details]
Patch View in context:
https://bugs.webkit.org/attachment.cgi?id=154201&action=review
>> Source/WebCore/platform/graphics/chromium/cc/CCRenderSurfaceFilters.cpp:164 >> +// c = a*b; > > maybe rename "c" to something like "out" or "result" to make this clear instead of requiring this comment?
Done.
>> Source/WebCore/platform/graphics/chromium/cc/CCRenderSurfaceFilters.cpp:189 >> +bool componentNeedsClamping(SkScalar line[5]) > > Nit: Could we call this "row" rather than "line"? Matrices usually have rows.
Done.
>> Source/WebCore/platform/graphics/chromium/cc/CCRenderSurfaceFilters.cpp:253 >> + : m_gr(gr) > > s/gr/grContext/ ?
Done.
>> Source/WebCore/platform/graphics/chromium/cc/CCRenderSurfaceFilters.cpp:255 >> + // Wrap the RenderSurface's texture in a Ganesh platform texture. > > nit: let's use terminology of "input texture" or something, rather than RenderSurface explicitly, since that will be wrong once we allow filters without a surface in the single-layer case.
Done.
>> Source/WebCore/platform/graphics/chromium/cc/CCRenderSurfaceFilters.cpp:256 >> + GrPlatformTextureDesc platformTexDesc; > > There's lots of abbreviations in this file which we avoid generally. Sorry to bikeshed on them, but maybe we can clean them up now? eg textureDescription?
Done.
>> Source/WebCore/platform/graphics/chromium/cc/CCRenderSurfaceFilters.cpp:316 >> + OwnPtr<SkCanvas> m_canvas; > > I seem to recall problems with using OwnPtr and Skia stuff in the past, since it has its own ref counting. Consider using an SkAutoTUnref on the device & canvas as well (if you like.. your call).
Done. I'm not familiar with Skia's flavor of refcounting / smart pointers - my understanding is that a new class starts with a ref of 1 and SkAutoTUnref doesn't add a ref on assignment - so please double-check my usage.
>>> Source/WebCore/platform/graphics/chromium/cc/CCRenderSurfaceFilters.cpp:346 >>> + bool hasMatrix = false; >> >> Can we call this "haveCombinedColorMatrix" or "combinedColorMatrixIsEmpty" or "combinedColorMatrixHasValue" or something? I feel like hasMatrix is a bit more ambiguous about which matrix its meaning. > > Perhaps "accumulated" instead of "combined"? > "accumulatedColorMatrix" and "haveAccumulatedColorMatrix"?
Done.
>>>> Source/WebCore/platform/graphics/chromium/cc/CCRenderSurfaceFilters.cpp:376 >>>> switch (op.type()) { >>> >>> If we have a combinedColorMatrix and succeed at applying it, should we do a "continue" after marking the combinedColorMatrix as being non-present? Right now, we'll fall into the default: case of the switch statement after applying the color matrix, which will do a copy of the source to the new destination texture (swapped in at the end of the apply). >> >> Good catch, Dana (although I think it's only a problem in the clamping case). Maybe we could apply the matrix right away above if it needs clamping, and continue in both the clamping and non-clamping cases: >> >> if (matrixNeedsClamping(combinedMatrix)) && !applyColorMatrix(&state, combinedMatrix)) >> return SkBitmap(); >> continue; >> >> Alternately, we could probably get rid of the identity draw in the default case now since it'll just pick up the previous source, although it would require moving the swap() into the blur and drop-shadow draws so it wouldn't happen in the default case either. > > If we can get rid of the default case, (and add back all the color matrix cases going to the same case-body) that could possibly be nice. That way we would also get compiler errors if a new operation type is added to the enum but not to the switch.
Done.
>> LayoutTests/css3/filters/effect-brightness-clamping-hw.html:13 >> +<img style="-webkit-filter: brightness(1) brightness(-1)" src="resources/reference.png"> > > I'd like to see more coverage here, e.g., brightness followed by blur or drop-shadow.
Done.
Dana Jansens
Comment 22
2012-07-25 17:00:32 PDT
Comment on
attachment 154481
[details]
Patch nice, thanks for all the renames!
Antoine Labour
Comment 23
2012-07-25 21:05:20 PDT
Created
attachment 154532
[details]
Patch
Antoine Labour
Comment 24
2012-07-25 21:06:49 PDT
PTAL, I noticed the previous patch was creating a canvas that it never used in one case (when the last filter is a matrix that needs clamping), causing possibly an extra alloc and a clear. New patch addresses that.
Stephen White
Comment 25
2012-07-26 07:07:47 PDT
Comment on
attachment 154532
[details]
Patch View in context:
https://bugs.webkit.org/attachment.cgi?id=154532&action=review
Looks good. r=me Note that your new test will likely cause the non-Linux WebKit canary bots to go red (due to pixel differences), so please either land with a suppression in TestExpectations, or rebaseline the tests after landing.
> Source/WebCore/platform/graphics/chromium/cc/CCRenderSurfaceFilters.cpp:198 > + return (maxValue > 255) || (minValue < 0);
It just occurred to me.. if the matrix is really large, is there a possibility for float overflow here? I guess it'll just end up at inf or -inf, probably safe for comparison purposes?
> Source/WebCore/platform/graphics/chromium/cc/CCRenderSurfaceFilters.cpp:388 > + SkCanvas* canvas = state.canvas(); > + if (!canvas) > + return SkBitmap();
I'm going to be annoying and point out that, if we did this optimization as a pre-processing pass, we'd know exactly how many textures we'd need to allocate, and we could do all allocations up front, without the need for all these checks and early-outs. That could be done as a later change, though.
Antoine Labour
Comment 26
2012-07-26 10:12:45 PDT
Comment on
attachment 154532
[details]
Patch View in context:
https://bugs.webkit.org/attachment.cgi?id=154532&action=review
>> Source/WebCore/platform/graphics/chromium/cc/CCRenderSurfaceFilters.cpp:198 >> + return (maxValue > 255) || (minValue < 0); > > It just occurred to me.. if the matrix is really large, is there a possibility for float overflow here? I guess it'll just end up at inf or -inf, probably safe for comparison purposes?
Correct, float overflow is a lot nicer than unsigned int (let alone int!) for this sort of things. FYI, during my testing I noticed that some matrices (at least the grayscale one depending on the amount value) trigger this because of precision issues. I think I can change the way it's computed to make sure it's stable (will do in a follow up), or possibly add a fudge factor here (I'd rather not).
Antoine Labour
Comment 27
2012-07-26 12:29:34 PDT
Created
attachment 154718
[details]
Patch for landing
WebKit Review Bot
Comment 28
2012-07-26 13:54:38 PDT
Comment on
attachment 154718
[details]
Patch for landing Clearing flags on attachment: 154718 Committed
r123790
: <
http://trac.webkit.org/changeset/123790
>
WebKit Review Bot
Comment 29
2012-07-26 13:54:43 PDT
All reviewed patches have been landed. Closing bug.
Note
You need to
log in
before you can comment on or make changes to this bug.
Top of Page
Format For Printing
XML
Clone This Bug