Bug 213673

Summary: CoreImage Implementation of SourceGraphic and saturate(), hue-rotate(), grayscale() and sepia()
Product: WebKit Reporter: frankhome61
Component: CSSAssignee: frankhome61
Status: RESOLVED FIXED    
Severity: Normal CC: cdumez, changseok, darin, dino, esprehn+autocc, ews-watchlist, frankhome61, glenn, jbedard, kondapallykalyan, mmaxfield, pdr, rniwa, sabouhallawa, sam, simon.fraser, webkit-bug-importer
Priority: P2 Keywords: InRadar
Version: Other   
Hardware: Unspecified   
OS: Unspecified   
See Also: https://bugs.webkit.org/show_bug.cgi?id=215958
Bug Depends on:    
Bug Blocks: 215957, 215958, 215956, 231902    
Attachments:
Description Flags
Patch
none
Patch
none
Patch
none
Patch
none
Patch
darin: review+
Ready for commit
none
Ready for Commit none

frankhome61
Reported 2020-06-26 19:41:10 PDT
SourceGraphic contains the graphics elements that were the original input into filters. The first step to render CSS filters is to implement SourceGraphic in CoreImage, since for each possible CSS filter graph, the root is a SourceGraphic. This is a good starting point to transitioning to CoreImage rendering.
Attachments
Patch (13.13 KB, patch)
2020-07-27 10:49 PDT, frankhome61
no flags
Patch (26.33 KB, patch)
2020-08-28 15:31 PDT, frankhome61
no flags
Patch (28.96 KB, patch)
2020-08-31 19:14 PDT, frankhome61
no flags
Patch (27.60 KB, patch)
2020-09-01 10:20 PDT, frankhome61
no flags
Patch (26.93 KB, patch)
2020-09-02 13:02 PDT, frankhome61
darin: review+
Ready for commit (27.58 KB, patch)
2020-09-02 14:03 PDT, frankhome61
no flags
Ready for Commit (28.80 KB, patch)
2020-09-02 17:23 PDT, frankhome61
no flags
Radar WebKit Bug Importer
Comment 1 2020-06-26 19:41:54 PDT
frankhome61
Comment 2 2020-07-27 10:49:10 PDT
Sam Weinig
Comment 3 2020-07-27 11:23:47 PDT
Comment on attachment 405293 [details] Patch View in context: https://bugs.webkit.org/attachment.cgi?id=405293&action=review > Source/WebCore/platform/graphics/coreimage/FilterEffectRendererCoreImage.mm:196 > + CIFilter* colorMatrixFilter = [CIFilter filterWithName:@"CIColorMatrix"]; > + [colorMatrixFilter setValue:inputImage forKey:kCIInputImageKey]; > + > + switch (colorMatrixEffect.type()) { > + case FECOLORMATRIX_TYPE_SATURATE: > + case FECOLORMATRIX_TYPE_HUEROTATE: { > + [colorMatrixFilter setValue:[CIVector vectorWithX:components[0] Y:components[1] Z:components[2] W:0] forKey:@"inputRVector"]; > + [colorMatrixFilter setValue:[CIVector vectorWithX:components[3] Y:components[4] Z:components[5] W:0] forKey:@"inputGVector"]; > + [colorMatrixFilter setValue:[CIVector vectorWithX:components[6] Y:components[7] Z:components[8] W:0] forKey:@"inputBVector"]; > + [colorMatrixFilter setValue:[CIVector vectorWithX:0 Y:0 Z:0 W:1] forKey:@"inputAVector"]; > + [colorMatrixFilter setValue:[CIVector vectorWithX:0 Y:0 Z:0 W:0] forKey:@"inputBiasVector"]; > + break; > + } Seems like this is starting to duplicate code that's already in PlatformCAFilters::setFiltersOnLayer(). Can we avoid this? > PerformanceTests/MotionMark/tests/master/resources/focus.js:84 > - Utilities.setElementPrefixedProperty(this.particle, "filter", "blur(" + blur + "px) opacity(" + opacity + "%)"); > - this.particle.style.transform = "translate3d(" + left + "%, " + top + "%, 0)"; > + Utilities.setElementPrefixedProperty(this.particle, "filter", "saturate(" + blur + "%)"); > + this.particle.style.transform = "translate2d(" + left + "%, " + top + "%, 0)"; This seems unrelated and probably not something you want to check in.
Sam Weinig
Comment 4 2020-07-27 11:29:33 PDT
(In reply to Sam Weinig from comment #3) > Comment on attachment 405293 [details] > Patch > > View in context: > https://bugs.webkit.org/attachment.cgi?id=405293&action=review > > > Source/WebCore/platform/graphics/coreimage/FilterEffectRendererCoreImage.mm:196 > > + CIFilter* colorMatrixFilter = [CIFilter filterWithName:@"CIColorMatrix"]; > > + [colorMatrixFilter setValue:inputImage forKey:kCIInputImageKey]; > > + > > + switch (colorMatrixEffect.type()) { > > + case FECOLORMATRIX_TYPE_SATURATE: > > + case FECOLORMATRIX_TYPE_HUEROTATE: { > > + [colorMatrixFilter setValue:[CIVector vectorWithX:components[0] Y:components[1] Z:components[2] W:0] forKey:@"inputRVector"]; > > + [colorMatrixFilter setValue:[CIVector vectorWithX:components[3] Y:components[4] Z:components[5] W:0] forKey:@"inputGVector"]; > > + [colorMatrixFilter setValue:[CIVector vectorWithX:components[6] Y:components[7] Z:components[8] W:0] forKey:@"inputBVector"]; > > + [colorMatrixFilter setValue:[CIVector vectorWithX:0 Y:0 Z:0 W:1] forKey:@"inputAVector"]; > > + [colorMatrixFilter setValue:[CIVector vectorWithX:0 Y:0 Z:0 W:0] forKey:@"inputBiasVector"]; > > + break; > > + } > > Seems like this is starting to duplicate code that's already in > PlatformCAFilters::setFiltersOnLayer(). Can we avoid this? Nevermind, looks like I am wrong here. HUEROTATE is implemented via [CAFilter filterWithType:kCAFilterColorHueRotate] in PlatformCAFilters (other filters do use CIColorMatrix though). Does make me wonder if we should use hueAdjustFilter and other builtin filters for this.
Darin Adler
Comment 5 2020-07-27 12:06:14 PDT
Comment on attachment 405293 [details] Patch View in context: https://bugs.webkit.org/attachment.cgi?id=405293&action=review > Source/WebCore/platform/graphics/coreimage/FilterEffectRendererCoreImage.h:61 > + CIImage* feSourceGraphicImage(FilterEffect&); > + CIImage* feColorMatrixImage(FilterEffect&, Vector<CIImage*>&); WebKit coding style says we write CIImage * with a space before the * because this is an Objective-C class. The input should be const Vector&, not Vector&. > Source/WebCore/platform/graphics/coreimage/FilterEffectRendererCoreImage.mm:62 > + FEColorMatrix& colorMatrixEffect = static_cast<FEColorMatrix&>(effect); auto& But also, maybe this can go inside the switch; don’t really need a separate local variable. > Source/WebCore/platform/graphics/coreimage/FilterEffectRendererCoreImage.mm:151 > + SourceGraphic& sourceGraphicEffect = static_cast<SourceGraphic&>(effect); auto& Also consider merging with the next line. > Source/WebCore/platform/graphics/coreimage/FilterEffectRendererCoreImage.mm:152 > + ImageBuffer* sourceImage = sourceGraphicEffect.filter().sourceImage(); auto. > Source/WebCore/platform/graphics/coreimage/FilterEffectRendererCoreImage.mm:155 > + NativeImagePtr sourceCGImageRef = sourceImage->copyNativeImage(); auto Also consider merging with the next line. > Source/WebCore/platform/graphics/coreimage/FilterEffectRendererCoreImage.mm:162 > + CIImage* inputImage = inputImages.at(0); Normal we’d prefer to use inputImages[0] rather than calling at(). But also, why are we passing in a vector just to extract the first image from it? > Source/WebCore/platform/graphics/coreimage/FilterEffectRendererCoreImage.mm:163 > + FEColorMatrix& colorMatrixEffect = static_cast<FEColorMatrix&>(effect); auto& > Source/WebCore/platform/graphics/coreimage/FilterEffectRendererCoreImage.mm:164 > + Vector<float> values = FEColorMatrix::normalizedFloats(colorMatrixEffect.values()); auto > Source/WebCore/platform/graphics/coreimage/FilterEffectRendererCoreImage.mm:168 > + case FECOLORMATRIX_TYPE_SATURATE: { No need for braces here in WebKit coding style. Please don’t use them. > Source/WebCore/platform/graphics/coreimage/FilterEffectRendererCoreImage.mm:172 > + case FECOLORMATRIX_TYPE_HUEROTATE: { Ditto. > Source/WebCore/platform/graphics/coreimage/FilterEffectRendererCoreImage.mm:184 > + CIFilter* colorMatrixFilter = [CIFilter filterWithName:@"CIColorMatrix"]; auto > Source/WebCore/platform/graphics/coreimage/FilterEffectRendererCoreImage.mm:189 > + case FECOLORMATRIX_TYPE_HUEROTATE: { No need for braces here in WebKit coding style. Please don’t use them. > Source/WebCore/platform/graphics/coreimage/FilterEffectRendererCoreImage.mm:197 > + case FECOLORMATRIX_TYPE_MATRIX: { Ditto. > Source/WebCore/platform/graphics/filters/FEColorMatrix.h:39 > class FEColorMatrix : public FilterEffect { Should be marked final, and platformApplySoftware also should. > Source/WebCore/platform/graphics/filters/FEColorMatrix.h:41 > + friend class FilterEffectRendererCoreImage; We almost never use friend in WebKit. Is this the best solution? What do we need access to? We already have both get and set for all the data members.
frankhome61
Comment 6 2020-07-27 12:39:46 PDT
(In reply to Sam Weinig from comment #3) > Comment on attachment 405293 [details] > Patch > > View in context: > https://bugs.webkit.org/attachment.cgi?id=405293&action=review > > > Source/WebCore/platform/graphics/coreimage/FilterEffectRendererCoreImage.mm:196 > > + CIFilter* colorMatrixFilter = [CIFilter filterWithName:@"CIColorMatrix"]; > > + [colorMatrixFilter setValue:inputImage forKey:kCIInputImageKey]; > > + > > + switch (colorMatrixEffect.type()) { > > + case FECOLORMATRIX_TYPE_SATURATE: > > + case FECOLORMATRIX_TYPE_HUEROTATE: { > > + [colorMatrixFilter setValue:[CIVector vectorWithX:components[0] Y:components[1] Z:components[2] W:0] forKey:@"inputRVector"]; > > + [colorMatrixFilter setValue:[CIVector vectorWithX:components[3] Y:components[4] Z:components[5] W:0] forKey:@"inputGVector"]; > > + [colorMatrixFilter setValue:[CIVector vectorWithX:components[6] Y:components[7] Z:components[8] W:0] forKey:@"inputBVector"]; > > + [colorMatrixFilter setValue:[CIVector vectorWithX:0 Y:0 Z:0 W:1] forKey:@"inputAVector"]; > > + [colorMatrixFilter setValue:[CIVector vectorWithX:0 Y:0 Z:0 W:0] forKey:@"inputBiasVector"]; > > + break; > > + } > > Seems like this is starting to duplicate code that's already in > PlatformCAFilters::setFiltersOnLayer(). Can we avoid this? > > > PerformanceTests/MotionMark/tests/master/resources/focus.js:84 > > - Utilities.setElementPrefixedProperty(this.particle, "filter", "blur(" + blur + "px) opacity(" + opacity + "%)"); > > - this.particle.style.transform = "translate3d(" + left + "%, " + top + "%, 0)"; > > + Utilities.setElementPrefixedProperty(this.particle, "filter", "saturate(" + blur + "%)"); > > + this.particle.style.transform = "translate2d(" + left + "%, " + top + "%, 0)"; > > This seems unrelated and probably not something you want to check in. no, this won't get checked in, this temporary change is for Simon to help me with some performance issues
frankhome61
Comment 7 2020-07-27 12:42:13 PDT
(In reply to Darin Adler from comment #5) > Comment on attachment 405293 [details] > Patch > > View in context: > https://bugs.webkit.org/attachment.cgi?id=405293&action=review > > > Source/WebCore/platform/graphics/coreimage/FilterEffectRendererCoreImage.h:61 > > + CIImage* feSourceGraphicImage(FilterEffect&); > > + CIImage* feColorMatrixImage(FilterEffect&, Vector<CIImage*>&); > > WebKit coding style says we write CIImage * with a space before the * > because this is an Objective-C class. > > The input should be const Vector&, not Vector&. > > > Source/WebCore/platform/graphics/coreimage/FilterEffectRendererCoreImage.mm:62 > > + FEColorMatrix& colorMatrixEffect = static_cast<FEColorMatrix&>(effect); > > auto& > > But also, maybe this can go inside the switch; don’t really need a separate > local variable. > > > Source/WebCore/platform/graphics/coreimage/FilterEffectRendererCoreImage.mm:151 > > + SourceGraphic& sourceGraphicEffect = static_cast<SourceGraphic&>(effect); > > auto& > > Also consider merging with the next line. > > > Source/WebCore/platform/graphics/coreimage/FilterEffectRendererCoreImage.mm:152 > > + ImageBuffer* sourceImage = sourceGraphicEffect.filter().sourceImage(); > > auto. > > > Source/WebCore/platform/graphics/coreimage/FilterEffectRendererCoreImage.mm:155 > > + NativeImagePtr sourceCGImageRef = sourceImage->copyNativeImage(); > > auto > > Also consider merging with the next line. > > > Source/WebCore/platform/graphics/coreimage/FilterEffectRendererCoreImage.mm:162 > > + CIImage* inputImage = inputImages.at(0); > > Normal we’d prefer to use inputImages[0] rather than calling at(). But also, > why are we passing in a vector just to extract the first image from it? > > > Source/WebCore/platform/graphics/coreimage/FilterEffectRendererCoreImage.mm:163 > > + FEColorMatrix& colorMatrixEffect = static_cast<FEColorMatrix&>(effect); > > auto& > > > Source/WebCore/platform/graphics/coreimage/FilterEffectRendererCoreImage.mm:164 > > + Vector<float> values = FEColorMatrix::normalizedFloats(colorMatrixEffect.values()); > > auto > > > Source/WebCore/platform/graphics/coreimage/FilterEffectRendererCoreImage.mm:168 > > + case FECOLORMATRIX_TYPE_SATURATE: { > > No need for braces here in WebKit coding style. Please don’t use them. > > > Source/WebCore/platform/graphics/coreimage/FilterEffectRendererCoreImage.mm:172 > > + case FECOLORMATRIX_TYPE_HUEROTATE: { > > Ditto. > > > Source/WebCore/platform/graphics/coreimage/FilterEffectRendererCoreImage.mm:184 > > + CIFilter* colorMatrixFilter = [CIFilter filterWithName:@"CIColorMatrix"]; > > auto > > > Source/WebCore/platform/graphics/coreimage/FilterEffectRendererCoreImage.mm:189 > > + case FECOLORMATRIX_TYPE_HUEROTATE: { > > No need for braces here in WebKit coding style. Please don’t use them. > > > Source/WebCore/platform/graphics/coreimage/FilterEffectRendererCoreImage.mm:197 > > + case FECOLORMATRIX_TYPE_MATRIX: { > > Ditto. > > > Source/WebCore/platform/graphics/filters/FEColorMatrix.h:39 > > class FEColorMatrix : public FilterEffect { > > Should be marked final, and platformApplySoftware also should. > > > Source/WebCore/platform/graphics/filters/FEColorMatrix.h:41 > > + friend class FilterEffectRendererCoreImage; > > We almost never use friend in WebKit. Is this the best solution? What do we > need access to? We already have both get and set for all the data members. There are some functions in FEColorMatrix, for example, calculateSaturateComponents that is a protected member function, not sure if we want to make it public though. Any thoughts? This applies to other FilterEffects as well
Darin Adler
Comment 8 2020-07-27 13:02:10 PDT
Comment on attachment 405293 [details] Patch View in context: https://bugs.webkit.org/attachment.cgi?id=405293&action=review >>> Source/WebCore/platform/graphics/coreimage/FilterEffectRendererCoreImage.h:61 >>> + CIImage* feColorMatrixImage(FilterEffect&, Vector<CIImage*>&); >> >> WebKit coding style says we write CIImage * with a space before the * because this is an Objective-C class. >> >> The input should be const Vector&, not Vector&. > > There are some functions in FEColorMatrix, for example, calculateSaturateComponents that is a protected member function, not sure if we want to make it public though. Any thoughts? This applies to other FilterEffects as well My first thought would be to make things public before starting to use friend.
frankhome61
Comment 9 2020-08-28 15:31:47 PDT
Simon Fraser (smfr)
Comment 10 2020-08-28 16:16:30 PDT
Comment on attachment 407508 [details] Patch View in context: https://bugs.webkit.org/attachment.cgi?id=407508&action=review > Source/WebCore/ChangeLog:11 > + Tests: css3/filters/effect-grayscale-square.html > + css3/filters/effect-hue-rotate-square.html > + css3/filters/effect-saturate-square.html > + css3/filters/effect-sepia-square.html Since you're adding caching of CIFilters here, you need 1. a test that renders twice, changing the value of an input in between 2. a test that renders twice, changing the filter chain 3. Maybe more. > Source/WebCore/platform/graphics/coreimage/FilterEffectRendererCoreImage.h:61 > + CIImage *feSourceGraphicImage(SourceGraphic&); imageForSourceGraphic > Source/WebCore/platform/graphics/coreimage/FilterEffectRendererCoreImage.h:62 > + CIImage *feColorMatrixImage(FEColorMatrix&, const Vector<CIImage *>&, int); imageForFEMatrixFilter. Name the non-obvious parameters. I think it would nicer to explicitly ref-count these and return RetainPtr<CIImage> > Source/WebCore/platform/graphics/coreimage/FilterEffectRendererCoreImage.h:65 > + HashMap<int, Vector<RetainPtr<CIFilter>>> m_ciFilterStorageMap; What is the key? Why did you have to change this? I think we can also improve the name of m_ciFilterStorageMap. It's clear from the type that it's a map, and of course it's storage. The name should describe how it maps. fooToFooMap. > Source/WebCore/platform/graphics/coreimage/FilterEffectRendererCoreImage.mm:57 > +CIContext *FilterEffectRendererCoreImage::getCIContext() > +{ > + static NeverDestroyed<RetainPtr<CIContext>> ciContext; > + if (!ciContext.get()) > + ciContext.get() = adoptNS([CIContext contextWithOptions: @{ kCIContextWorkingColorSpace: (__bridge id)CGColorSpaceCreateWithName(kCGColorSpaceSRGB)}]); > + return [ciContext.get() retain]; > +} I don't think we can use a single shared CIContext. We risk state leaking between documents, which might lead to things like timing attacks. Maybe cache one per Document (e.g. via RenderLayerCompositor). > Source/WebCore/platform/graphics/coreimage/FilterEffectRendererCoreImage.mm:67 > + switch (static_cast<FEColorMatrix&>(effect).type()) { You should add SPECIALIZE_TYPE_TRAITS for FilterEffect subclasses to avoid this static_cast. This should be a downcast<>. > Source/WebCore/platform/graphics/coreimage/FilterEffectRendererCoreImage.mm:109 > +CIImage *FilterEffectRendererCoreImage::connectCIFilters(FilterEffect& effect, int traversalOrder) Order or index? > Source/WebCore/platform/graphics/coreimage/FilterEffectRendererCoreImage.mm:172 > +CIImage *FilterEffectRendererCoreImage::feColorMatrixImage(FEColorMatrix& effect, const Vector<CIImage *>& inputImages, int traversalOrder) This is both creating the filter, and setting the inputImage. Might be clearer to split those two responsibilities. > Source/WebCore/platform/graphics/coreimage/FilterEffectRendererCoreImage.mm:204 > + Vector<RetainPtr<CIFilter>> filtersToBeCached; > + filtersToBeCached.insert(0, colorMatrixFilter); > + m_ciFilterStorageMap.add(traversalOrder, filtersToBeCached); There's a way to do this with map.ensure(). > Source/WebCore/platform/graphics/coreimage/FilterEffectRendererCoreImage.mm:271 > + CIRenderDestination* destination = [[[CIRenderDestination alloc] initWithIOSurface:(::IOSurface*)surface.surface()] autorelease]; Use RetainPtr<> and avoid autorelease. > Source/WebCore/platform/graphics/coreimage/FilterEffectRendererCoreImage.mm:297 > + , m_ciFilterStorageMap() Not necessary.
Darin Adler
Comment 11 2020-08-28 16:51:09 PDT
Comment on attachment 407508 [details] Patch View in context: https://bugs.webkit.org/attachment.cgi?id=407508&action=review > Source/WebCore/platform/graphics/coreimage/FilterEffectRendererCoreImage.mm:55 > + static NeverDestroyed<RetainPtr<CIContext>> ciContext; > + if (!ciContext.get()) > + ciContext.get() = adoptNS([CIContext contextWithOptions: @{ kCIContextWorkingColorSpace: (__bridge id)CGColorSpaceCreateWithName(kCGColorSpaceSRGB)}]); This should just be a single line. There’s no need for this three line form.
frankhome61
Comment 12 2020-08-29 12:13:47 PDT
(In reply to Simon Fraser (smfr) from comment #10) > Comment on attachment 407508 [details] > Patch > > View in context: > https://bugs.webkit.org/attachment.cgi?id=407508&action=review > > > Source/WebCore/ChangeLog:11 > > + Tests: css3/filters/effect-grayscale-square.html > > + css3/filters/effect-hue-rotate-square.html > > + css3/filters/effect-saturate-square.html > > + css3/filters/effect-sepia-square.html > > Since you're adding caching of CIFilters here, you need > 1. a test that renders twice, changing the value of an input in between > 2. a test that renders twice, changing the filter chain > 3. Maybe more. > > > Source/WebCore/platform/graphics/coreimage/FilterEffectRendererCoreImage.h:61 > > + CIImage *feSourceGraphicImage(SourceGraphic&); > > imageForSourceGraphic > > > Source/WebCore/platform/graphics/coreimage/FilterEffectRendererCoreImage.h:62 > > + CIImage *feColorMatrixImage(FEColorMatrix&, const Vector<CIImage *>&, int); > > imageForFEMatrixFilter. Name the non-obvious parameters. > > I think it would nicer to explicitly ref-count these and return > RetainPtr<CIImage> > > > Source/WebCore/platform/graphics/coreimage/FilterEffectRendererCoreImage.h:65 > > + HashMap<int, Vector<RetainPtr<CIFilter>>> m_ciFilterStorageMap; > > What is the key? Why did you have to change this? So originally I chose to use FilterEffect nodes as the key, but turns out FilterEffects gets destroyed and rebuilt on each render update, so that cannot be a key anymore, so instead I chose one thing that's consistent across each draw is the graph itself, as in the structure of the filter graph, and thus the traversal order of this graph is consistent between updates. And therefore it could be used as a hash map key > > I think we can also improve the name of m_ciFilterStorageMap. It's clear > from the type that it's a map, and of course it's storage. The name should > describe how it maps. fooToFooMap. > > > Source/WebCore/platform/graphics/coreimage/FilterEffectRendererCoreImage.mm:57 > > +CIContext *FilterEffectRendererCoreImage::getCIContext() > > +{ > > + static NeverDestroyed<RetainPtr<CIContext>> ciContext; > > + if (!ciContext.get()) > > + ciContext.get() = adoptNS([CIContext contextWithOptions: @{ kCIContextWorkingColorSpace: (__bridge id)CGColorSpaceCreateWithName(kCGColorSpaceSRGB)}]); > > + return [ciContext.get() retain]; > > +} > > I don't think we can use a single shared CIContext. We risk state leaking > between documents, which might lead to things like timing attacks. Maybe > cache one per Document (e.g. via RenderLayerCompositor). > > > Source/WebCore/platform/graphics/coreimage/FilterEffectRendererCoreImage.mm:67 > > + switch (static_cast<FEColorMatrix&>(effect).type()) { > > You should add SPECIALIZE_TYPE_TRAITS for FilterEffect subclasses to avoid > this static_cast. This should be a downcast<>. > > > Source/WebCore/platform/graphics/coreimage/FilterEffectRendererCoreImage.mm:109 > > +CIImage *FilterEffectRendererCoreImage::connectCIFilters(FilterEffect& effect, int traversalOrder) > > Order or index? > > > Source/WebCore/platform/graphics/coreimage/FilterEffectRendererCoreImage.mm:172 > > +CIImage *FilterEffectRendererCoreImage::feColorMatrixImage(FEColorMatrix& effect, const Vector<CIImage *>& inputImages, int traversalOrder) > > This is both creating the filter, and setting the inputImage. Might be > clearer to split those two responsibilities. > > > Source/WebCore/platform/graphics/coreimage/FilterEffectRendererCoreImage.mm:204 > > + Vector<RetainPtr<CIFilter>> filtersToBeCached; > > + filtersToBeCached.insert(0, colorMatrixFilter); > > + m_ciFilterStorageMap.add(traversalOrder, filtersToBeCached); > > There's a way to do this with map.ensure(). > > > Source/WebCore/platform/graphics/coreimage/FilterEffectRendererCoreImage.mm:271 > > + CIRenderDestination* destination = [[[CIRenderDestination alloc] initWithIOSurface:(::IOSurface*)surface.surface()] autorelease]; > > Use RetainPtr<> and avoid autorelease. > > > Source/WebCore/platform/graphics/coreimage/FilterEffectRendererCoreImage.mm:297 > > + , m_ciFilterStorageMap() > > Not necessary.
Myles C. Maxfield
Comment 13 2020-08-31 15:31:39 PDT
> I don't think we can use a single shared CIContext. We risk state leaking between documents, which might lead to things like timing attacks. Maybe cache one per Document (e.g. via RenderLayerCompositor). There is no (architectural) state on the CIContext that is modified by our filter code, so the only state we would be leaking are things like "has this web process rendered a blur filter before" or "has this web process rendered a color matrix filter before." It seems like this wouldn't be sensitive information; so what if the web process has rendered that stuff before? Indeed, it may even be better to have a singleton because that timing attack is possible: the second webpage the user navigates to would perform faster because it can re-use shader compilation artifacts etc. from the first webpage the user navigates to. It seems like a waste of perf trying to protect benign information. (This is also how fonts work; we don't clear the font cache on every page load...)
frankhome61
Comment 14 2020-08-31 19:14:16 PDT
frankhome61
Comment 15 2020-09-01 10:20:35 PDT
Darin Adler
Comment 16 2020-09-01 10:40:09 PDT
Comment on attachment 407691 [details] Patch View in context: https://bugs.webkit.org/attachment.cgi?id=407691&action=review > Source/WebCore/platform/graphics/coreimage/FilterEffectRendererCoreImage.mm:53 > + static NeverDestroyed<RetainPtr<CIContext>> ciContext = adoptNS([CIContext contextWithOptions: @{ kCIContextWorkingColorSpace: (__bridge id)CGColorSpaceCreateWithName(kCGColorSpaceSRGB)}]); This over-releases. It’s incorrect to call adoptNS on the result of +[CIContext contextWithOptions:] because that function returns something that’s autoreleased. Simplest way to fix this is to remove the adoptNS. > Source/WebCore/platform/graphics/coreimage/FilterEffectRendererCoreImage.mm:54 > + return [ciContext.get() retain]; This over-retains. Putting a CIContext into a RetainPtr<CIContext> will already retain it. This double retains it every time this function is called.
Darin Adler
Comment 17 2020-09-01 10:40:40 PDT
Comment on attachment 407691 [details] Patch View in context: https://bugs.webkit.org/attachment.cgi?id=407691&action=review >> Source/WebCore/platform/graphics/coreimage/FilterEffectRendererCoreImage.mm:54 >> + return [ciContext.get() retain]; > > This over-retains. Putting a CIContext into a RetainPtr<CIContext> will already retain it. This double retains it every time this function is called. Simplest way to fix this is to just write: return ciContext;
Darin Adler
Comment 18 2020-09-01 10:44:49 PDT
Comment on attachment 407691 [details] Patch View in context: https://bugs.webkit.org/attachment.cgi?id=407691&action=review > Source/WebCore/platform/graphics/coreimage/FilterEffectRendererCoreImage.mm:163 > + auto& surface = downcast<AcceleratedImageBuffer>(*sourceImage).surface(); > + IOSurfaceRef surfaceRef = surface.surface(); > + return RetainPtr<CIImage>([CIImage imageWithIOSurface:surfaceRef]); This should not require an explicit cast to RetainPtr. Also, the local variables aren’t helping. I suggest doing it in a single line: return [CIImage imageWithIOSurface:downcast<AcceleratedImageBuffer>(*sourceImage).surface().surface()]; > Source/WebCore/platform/graphics/coreimage/FilterEffectRendererCoreImage.mm:166 > + NativeImagePtr sourceCGImageRef = sourceImage->copyNativeImage(); > + return RetainPtr<CIImage>([CIImage imageWithCGImage:sourceCGImageRef.get()]); This should not require an explicit cast to RetainPtr. Also, the local variable isn’t helping. I suggest doing it in a single line: return [CIImage imageWithCGImage:sourceImage->copyNativeImage().get()]; > Source/WebCore/platform/graphics/coreimage/FilterEffectRendererCoreImage.mm:218 > + return RetainPtr<CIImage>(colorMatrixFilter.outputImage); This should not require an explicit cast to RetainPtr. > Source/WebCore/platform/graphics/coreimage/FilterEffectRendererCoreImage.mm:258 > + RetainPtr<CIRenderDestination> destination = adoptNS([[CIRenderDestination alloc] initWithIOSurface:(::IOSurface*)surface.surface()]); Pleas use auto here. I am surprised that a cast to IOSurface* is required. If it’s not, please omit it. Even if it is required, I suggest the (IOSurface*) syntax rather than (::IOSurface*) syntax.
frankhome61
Comment 19 2020-09-01 10:58:33 PDT
(In reply to Darin Adler from comment #18) > Comment on attachment 407691 [details] > Patch > > View in context: > https://bugs.webkit.org/attachment.cgi?id=407691&action=review > > > Source/WebCore/platform/graphics/coreimage/FilterEffectRendererCoreImage.mm:163 > > + auto& surface = downcast<AcceleratedImageBuffer>(*sourceImage).surface(); > > + IOSurfaceRef surfaceRef = surface.surface(); > > + return RetainPtr<CIImage>([CIImage imageWithIOSurface:surfaceRef]); > > This should not require an explicit cast to RetainPtr. Also, the local > variables aren’t helping. I suggest doing it in a single line: > > return [CIImage > imageWithIOSurface:downcast<AcceleratedImageBuffer>(*sourceImage).surface(). > surface()]; > > > Source/WebCore/platform/graphics/coreimage/FilterEffectRendererCoreImage.mm:166 > > + NativeImagePtr sourceCGImageRef = sourceImage->copyNativeImage(); > > + return RetainPtr<CIImage>([CIImage imageWithCGImage:sourceCGImageRef.get()]); > > This should not require an explicit cast to RetainPtr. Also, the local > variable isn’t helping. I suggest doing it in a single line: > > return [CIImage imageWithCGImage:sourceImage->copyNativeImage().get()]; > > > Source/WebCore/platform/graphics/coreimage/FilterEffectRendererCoreImage.mm:218 > > + return RetainPtr<CIImage>(colorMatrixFilter.outputImage); > > This should not require an explicit cast to RetainPtr. > > > Source/WebCore/platform/graphics/coreimage/FilterEffectRendererCoreImage.mm:258 > > + RetainPtr<CIRenderDestination> destination = adoptNS([[CIRenderDestination alloc] initWithIOSurface:(::IOSurface*)surface.surface()]); > > Pleas use auto here. > > I am surprised that a cast to IOSurface* is required. If it’s not, please > omit it. Even if it is required, I suggest the (IOSurface*) syntax rather > than (::IOSurface*) syntax. The problem here is that there is a name collision, there is a WebCore::IOSurface and an Objective-C IOSurface, and without ::IOSurface* the compiler always resolve (IOSurface*) to WebCore::IOSurface*
Darin Adler
Comment 20 2020-09-01 10:59:38 PDT
(In reply to guowei_yang from comment #19) > (In reply to Darin Adler from comment #18) > > I am surprised that a cast to IOSurface* is required. If it’s not, please > > omit it. Even if it is required, I suggest the (IOSurface*) syntax rather > > than (::IOSurface*) syntax. > > The problem here is that there is a name collision, there is a > WebCore::IOSurface and an Objective-C IOSurface, and without ::IOSurface* > the compiler always resolve (IOSurface*) to WebCore::IOSurface* OK. But can you just remove the cast?
frankhome61
Comment 21 2020-09-01 11:16:45 PDT
(In reply to Darin Adler from comment #20) > (In reply to guowei_yang from comment #19) > > (In reply to Darin Adler from comment #18) > > > I am surprised that a cast to IOSurface* is required. If it’s not, please > > > omit it. Even if it is required, I suggest the (IOSurface*) syntax rather > > > than (::IOSurface*) syntax. > > > > The problem here is that there is a name collision, there is a > > WebCore::IOSurface and an Objective-C IOSurface, and without ::IOSurface* > > the compiler always resolve (IOSurface*) to WebCore::IOSurface* > > OK. But can you just remove the cast? Hmmm I don't think so, .surface() returns an IOSurfaceRef, which is "an rvalue of type 'IOSurfaceRef' (aka '__IOSurface *')", but initWithIOSurface expects "IOSurface * _Nonnull"
Darin Adler
Comment 22 2020-09-01 13:07:17 PDT
(In reply to guowei_yang from comment #21) > Hmmm I don't think so, .surface() returns an IOSurfaceRef, which is "an > rvalue of type 'IOSurfaceRef' (aka '__IOSurface *')", but initWithIOSurface > expects "IOSurface * _Nonnull" I see, it’s a toll-free bridged type, but it’s the CoreFoundation vs. Objective-C version of that type. So this is a bridge cast.
frankhome61
Comment 23 2020-09-01 14:15:45 PDT
Comment on attachment 407691 [details] Patch I am going to temporarily change the review status to r? so that I can investigate failed builds
frankhome61
Comment 24 2020-09-02 13:02:02 PDT
Darin Adler
Comment 25 2020-09-02 13:15:58 PDT
Comment on attachment 407790 [details] Patch View in context: https://bugs.webkit.org/attachment.cgi?id=407790&action=review Looks good. A few optional ideas for further refinement. > Source/WebCore/platform/graphics/coreimage/FilterEffectRendererCoreImage.mm:53 > + static NeverDestroyed<RetainPtr<CIContext>> ciContext = [CIContext contextWithOptions: @{ kCIContextWorkingColorSpace: (__bridge id)CGColorSpaceCreateWithName(kCGColorSpaceSRGB)}]; Another way to write this is: static auto context = makeNeverDestroyed([CIContext ...]); I think it’s nicer. > Source/WebCore/platform/graphics/coreimage/FilterEffectRendererCoreImage.mm:156 > + ImageBuffer* sourceImage = effect.filter().sourceImage(); auto > Source/WebCore/platform/graphics/coreimage/FilterEffectRendererCoreImage.mm:170 > + Vector<float> values = FEColorMatrix::normalizedFloats(effect.values()); auto > Source/WebCore/platform/graphics/coreimage/FilterEffectRendererCoreImage.mm:190 > + CIFilter *colorMatrixFilter = [CIFilter filterWithName:@"CIColorMatrix"]; auto > Source/WebCore/platform/graphics/coreimage/FilterEffectRendererCoreImage.mm:252 > + auto ciContext = getCIContext(); Not sure we need a local variable. > Source/WebCore/platform/graphics/filters/FilterEffect.h:179 > + Vector<float> normalizedValues(values.size()); > + for (size_t i = 0; i < values.size(); ++i) > + normalizedValues[i] = normalizedFloat(values[i]); > + return normalizedValues; This could be nicer if it used Vector::map instead of writing a loop. > Source/WebCore/rendering/CSSFilter.cpp:343 > - setSourceImage(ImageBuffer::create(logicalSize, renderingMode(), filterScale())); > + if (m_filterRenderer) > + setSourceImage(ImageBuffer::create(logicalSize, RenderingMode::Accelerated, filterScale())); > + else > + setSourceImage(ImageBuffer::create(logicalSize, renderingMode(), filterScale())); Could do it with a local instead of an if statement: auto mode = m_filterRenderer ? RenderingMode::Accelerated : renderingMode(); setSourceImage(ImageBuffer::create(logicalSize, mode, filterScale()));
Simon Fraser (smfr)
Comment 26 2020-09-02 13:25:01 PDT
Comment on attachment 407790 [details] Patch View in context: https://bugs.webkit.org/attachment.cgi?id=407790&action=review > Source/WebCore/platform/graphics/coreimage/FilterEffectRendererCoreImage.h:47 > + RetainPtr<CIContext> getCIContext(); This should be a static function. I think you should name it sharedCIContext() to make it clear it returns a global. > Source/WebCore/platform/graphics/coreimage/FilterEffectRendererCoreImage.h:61 > + RetainPtr<CIImage> imageForSourceGraphic(SourceGraphic&); Can the argument be const SourceGraphic&? > Source/WebCore/platform/graphics/coreimage/FilterEffectRendererCoreImage.h:62 > + RetainPtr<CIImage> imageForFEColorMatrix(FEColorMatrix&, const Vector<RetainPtr<CIImage>>&); const FEColorMatrix& > Source/WebCore/platform/graphics/coreimage/FilterEffectRendererCoreImage.mm:188 > + case FECOLORMATRIX_TYPE_SATURATE: { > + FEColorMatrix::calculateSaturateComponents(components, values[0]); > + break; > + } > + case FECOLORMATRIX_TYPE_HUEROTATE: { > + FEColorMatrix::calculateHueRotateComponents(components, values[0]); > + break; > + } > + case FECOLORMATRIX_TYPE_MATRIX: > + break; > + > + case FECOLORMATRIX_TYPE_UNKNOWN: > + case FECOLORMATRIX_TYPE_LUMINANCETOALPHA: // FIXME: Add Luminance to Alpha Implementation > + return nullptr; > + } You don't need any of the braces.
frankhome61
Comment 27 2020-09-02 13:39:03 PDT
(In reply to Simon Fraser (smfr) from comment #26) > Comment on attachment 407790 [details] > Patch > > View in context: > https://bugs.webkit.org/attachment.cgi?id=407790&action=review > > > Source/WebCore/platform/graphics/coreimage/FilterEffectRendererCoreImage.h:47 > > + RetainPtr<CIContext> getCIContext(); > > This should be a static function. I think you should name it > sharedCIContext() to make it clear it returns a global. > > > Source/WebCore/platform/graphics/coreimage/FilterEffectRendererCoreImage.h:61 > > + RetainPtr<CIImage> imageForSourceGraphic(SourceGraphic&); > > Can the argument be const SourceGraphic&? Unfortunately, I need to access some of the non-const functions in FilterEffect and/or it's derived class I don't think this argument could be const > > > Source/WebCore/platform/graphics/coreimage/FilterEffectRendererCoreImage.h:62 > > + RetainPtr<CIImage> imageForFEColorMatrix(FEColorMatrix&, const Vector<RetainPtr<CIImage>>&); > > const FEColorMatrix& ditto > > > Source/WebCore/platform/graphics/coreimage/FilterEffectRendererCoreImage.mm:188 > > + case FECOLORMATRIX_TYPE_SATURATE: { > > + FEColorMatrix::calculateSaturateComponents(components, values[0]); > > + break; > > + } > > + case FECOLORMATRIX_TYPE_HUEROTATE: { > > + FEColorMatrix::calculateHueRotateComponents(components, values[0]); > > + break; > > + } > > + case FECOLORMATRIX_TYPE_MATRIX: > > + break; > > + > > + case FECOLORMATRIX_TYPE_UNKNOWN: > > + case FECOLORMATRIX_TYPE_LUMINANCETOALPHA: // FIXME: Add Luminance to Alpha Implementation > > + return nullptr; > > + } > > You don't need any of the braces.
frankhome61
Comment 28 2020-09-02 13:45:27 PDT
(In reply to guowei_yang from comment #27) > (In reply to Simon Fraser (smfr) from comment #26) > > Comment on attachment 407790 [details] > > Patch > > > > View in context: > > https://bugs.webkit.org/attachment.cgi?id=407790&action=review > > > > > Source/WebCore/platform/graphics/coreimage/FilterEffectRendererCoreImage.h:47 > > > + RetainPtr<CIContext> getCIContext(); > > > > This should be a static function. I think you should name it > > sharedCIContext() to make it clear it returns a global. > > > > > Source/WebCore/platform/graphics/coreimage/FilterEffectRendererCoreImage.h:61 > > > + RetainPtr<CIImage> imageForSourceGraphic(SourceGraphic&); > > > > Can the argument be const SourceGraphic&? > Unfortunately, I need to access some of the non-const functions in > FilterEffect and/or it's derived class I don't think this argument could be > const > > > > > Source/WebCore/platform/graphics/coreimage/FilterEffectRendererCoreImage.h:62 > > > + RetainPtr<CIImage> imageForFEColorMatrix(FEColorMatrix&, const Vector<RetainPtr<CIImage>>&); > > > > const FEColorMatrix& > ditto Actually, this can be const, but not SourceGraphic, since FilterEffect::filter() is not const > > > > > Source/WebCore/platform/graphics/coreimage/FilterEffectRendererCoreImage.mm:188 > > > + case FECOLORMATRIX_TYPE_SATURATE: { > > > + FEColorMatrix::calculateSaturateComponents(components, values[0]); > > > + break; > > > + } > > > + case FECOLORMATRIX_TYPE_HUEROTATE: { > > > + FEColorMatrix::calculateHueRotateComponents(components, values[0]); > > > + break; > > > + } > > > + case FECOLORMATRIX_TYPE_MATRIX: > > > + break; > > > + > > > + case FECOLORMATRIX_TYPE_UNKNOWN: > > > + case FECOLORMATRIX_TYPE_LUMINANCETOALPHA: // FIXME: Add Luminance to Alpha Implementation > > > + return nullptr; > > > + } > > > > You don't need any of the braces.
frankhome61
Comment 29 2020-09-02 14:00:24 PDT
(In reply to Darin Adler from comment #25) > Comment on attachment 407790 [details] > Patch > > View in context: > https://bugs.webkit.org/attachment.cgi?id=407790&action=review > > Looks good. A few optional ideas for further refinement. > > > Source/WebCore/platform/graphics/coreimage/FilterEffectRendererCoreImage.mm:53 > > + static NeverDestroyed<RetainPtr<CIContext>> ciContext = [CIContext contextWithOptions: @{ kCIContextWorkingColorSpace: (__bridge id)CGColorSpaceCreateWithName(kCGColorSpaceSRGB)}]; > > Another way to write this is: > > static auto context = makeNeverDestroyed([CIContext ...]); Seems that using auto will resolve the return type to be WTF::NeverDestroyed<CIContext *, WTF::AnyThreadsAccessTraits>, which didn't get converted to RetainPtr, so I am keeping it as is > > I think it’s nicer. > > > Source/WebCore/platform/graphics/coreimage/FilterEffectRendererCoreImage.mm:156 > > + ImageBuffer* sourceImage = effect.filter().sourceImage(); > > auto > > > Source/WebCore/platform/graphics/coreimage/FilterEffectRendererCoreImage.mm:170 > > + Vector<float> values = FEColorMatrix::normalizedFloats(effect.values()); > > auto > > > Source/WebCore/platform/graphics/coreimage/FilterEffectRendererCoreImage.mm:190 > > + CIFilter *colorMatrixFilter = [CIFilter filterWithName:@"CIColorMatrix"]; > > auto > > > Source/WebCore/platform/graphics/coreimage/FilterEffectRendererCoreImage.mm:252 > > + auto ciContext = getCIContext(); > > Not sure we need a local variable. > > > Source/WebCore/platform/graphics/filters/FilterEffect.h:179 > > + Vector<float> normalizedValues(values.size()); > > + for (size_t i = 0; i < values.size(); ++i) > > + normalizedValues[i] = normalizedFloat(values[i]); > > + return normalizedValues; > > This could be nicer if it used Vector::map instead of writing a loop. > > > Source/WebCore/rendering/CSSFilter.cpp:343 > > - setSourceImage(ImageBuffer::create(logicalSize, renderingMode(), filterScale())); > > + if (m_filterRenderer) > > + setSourceImage(ImageBuffer::create(logicalSize, RenderingMode::Accelerated, filterScale())); > > + else > > + setSourceImage(ImageBuffer::create(logicalSize, renderingMode(), filterScale())); > > Could do it with a local instead of an if statement: > > auto mode = m_filterRenderer ? RenderingMode::Accelerated : > renderingMode(); > setSourceImage(ImageBuffer::create(logicalSize, mode, filterScale()));
frankhome61
Comment 30 2020-09-02 14:03:00 PDT
Created attachment 407804 [details] Ready for commit
Darin Adler
Comment 31 2020-09-02 14:17:22 PDT
Comment on attachment 407790 [details] Patch View in context: https://bugs.webkit.org/attachment.cgi?id=407790&action=review >>> Source/WebCore/platform/graphics/coreimage/FilterEffectRendererCoreImage.mm:53 >>> + static NeverDestroyed<RetainPtr<CIContext>> ciContext = [CIContext contextWithOptions: @{ kCIContextWorkingColorSpace: (__bridge id)CGColorSpaceCreateWithName(kCGColorSpaceSRGB)}]; >> >> Another way to write this is: >> >> static auto context = makeNeverDestroyed([CIContext ...]); >> >> I think it’s nicer. > > Seems that using auto will resolve the return type to be WTF::NeverDestroyed<CIContext *, WTF::AnyThreadsAccessTraits>, which didn't get converted to RetainPtr, so I am keeping it as is Yes, overlooked that. It would need to be: static auto context = makeNeverDestroyed(retainPtr([CIContext ...]));
frankhome61
Comment 32 2020-09-02 17:23:08 PDT
Created attachment 407837 [details] Ready for Commit
EWS
Comment 33 2020-09-03 13:51:17 PDT
EWS
Comment 34 2020-09-03 14:04:11 PDT
Committed r266542: <https://trac.webkit.org/changeset/266542> All reviewed patches have been landed. Closing bug and clearing flags on attachment 407837 [details].
Note You need to log in before you can comment on or make changes to this bug.