Bug 117550

Summary: [CSS Shaders] Animations and transitions should use validated custom programs
Product: WebKit Reporter: Ralph T <ralpht+bugs>
Component: New BugsAssignee: Nobody <webkit-unassigned>
Status: RESOLVED WONTFIX    
Severity: Normal CC: achicu, commit-queue, esprehn+autocc, glenn, ralpht+bugs, sergio, simon.fraser
Priority: P2    
Version: 528+ (Nightly build)   
Hardware: Unspecified   
OS: Unspecified   
Bug Depends on: 117763    
Bug Blocks:    
Attachments:
Description Flags
Patch
none
Updated test section of changelog
none
Patch none

Description Ralph T 2013-06-12 09:33:31 PDT
[CSS Shaders] Animations and transitions should use validated custom programs
Comment 1 Ralph T 2013-06-12 09:37:32 PDT
Created attachment 204448 [details]
Patch
Comment 2 Ralph T 2013-06-12 09:45:01 PDT
CoordinatedGraphics is unable to proxy non-validated custom shaders to the UIProcess. I don't know enough about the architecture of custom filters to know that the filters in keyframes should be validated though.

Also, none of the CoordinatedGraphics ports enable CSS Shaders. With this patch and some others (which I will submit next) I have made everything work on EFL, but I don't know if this change regresses Mac (I'm a long-time reader, first time writer, so please forgive me if I've gone about this all wrong).
Comment 3 Alexandru Chiculita 2013-06-12 10:41:16 PDT
Comment on attachment 204448 [details]
Patch

r=me
Comment 4 Alexandru Chiculita 2013-06-12 10:41:37 PDT
Comment on attachment 204448 [details]
Patch

actually.. you need a test for it.
Comment 5 Alexandru Chiculita 2013-06-12 10:46:24 PDT
Comment on attachment 204448 [details]
Patch

Ok, looks like no platform can run this yet. Add a comment in the changelog saying that you had no new tests as no platform can do custom-filters accelerated animations yet.
Comment 6 Ralph T 2013-06-12 10:55:21 PDT
Created attachment 204456 [details]
Updated test section of changelog

Add note to changelog that there are no new tests because no platform currently runs accelerated custom filter animations.
Comment 7 WebKit Commit Bot 2013-06-12 10:59:14 PDT
Comment on attachment 204456 [details]
Updated test section of changelog

Rejecting attachment 204456 [details] from commit-queue.

Failed to run "['/Volumes/Data/EWS/WebKit/Tools/Scripts/webkit-patch', '--status-host=webkit-queues.appspot.com', '--bot-id=webkit-cq-01', 'validate-changelog', '--check-oops', '--non-interactive', 204456, '--port=mac']" exit_code: 1 cwd: /Volumes/Data/EWS/WebKit

ChangeLog entry in Source/WebCore/ChangeLog contains OOPS!.

Full output: http://webkit-queues.appspot.com/results/726829
Comment 8 Alexandru Chiculita 2013-06-12 11:01:22 PDT
Comment on attachment 204456 [details]
Updated test section of changelog

Trying the cq again.
Comment 9 WebKit Commit Bot 2013-06-12 11:28:37 PDT
Comment on attachment 204456 [details]
Updated test section of changelog

Clearing flags on attachment: 204456

Committed r151513: <http://trac.webkit.org/changeset/151513>
Comment 10 WebKit Commit Bot 2013-06-12 11:28:39 PDT
All reviewed patches have been landed.  Closing bug.
Comment 11 WebKit Commit Bot 2013-06-18 16:36:19 PDT
Re-opened since this is blocked by bug 117763
Comment 12 Ralph T 2013-06-19 07:35:54 PDT
This change was rolled out because it caused an assert in StyleCustomFilterProgram.h StyleCustomFilterProgram::isLoaded called from RenderLayer::computeFilterOperations.


    virtual bool isLoaded() const
    {
        // Do not use the CachedResource:isLoaded method here, because it actually means !isLoading(),
        // so missing and canceled resources will have isLoaded set to true, even if they are not loaded yet.
        ASSERT(!m_vertexShader || m_vertexShader->isCachedShader());
        ASSERT(!m_fragmentShader || m_fragmentShader->isCachedShader());
        ASSERT(m_cachedVertexShader.get() || m_cachedFragmentShader.get());
        return (!m_cachedVertexShader.get() || m_isVertexShaderLoaded)
            && (!m_cachedFragmentShader.get() || m_isFragmentShaderLoaded);
    }

The third assert failed on keyframe animations where the custom filter existed only in a keyframe and had never been loaded before -- m_cachedVertexShader and m_cachedFragmentShader were both null.

If I do something to cause StyleCustomFilterProgram::willHaveClients to be called then the layout tests work without assertions.

I'm not sure what the right approach is here. Some questions:

1. Are there any other keyframe animatable resources which are loaded?

2. Does the RenderLayer want to become the loader client for all custom shaders in keyframes for the duration of the keyframe animation?

3. Does anything break like this if the server is slow to serve up fragment and vertex shaders? (i.e.: in the unanimated case, RenderLayer::computeFilterOperations is called with custom shaders in a state that the assertions above fail). I can test this one later today.
Comment 13 Simon Fraser (smfr) 2013-06-19 08:19:38 PDT
 >2. Does the RenderLayer want to become the loader client for all custom shaders in keyframes for the duration of the keyframe animation?
No. It's wrong for RenderLayer to have to know anything about shaders.
Comment 14 Ralph T 2013-06-19 08:34:29 PDT
Ok, would it be OK for RenderLayerFilterInfo to become the CustomFilterClient for all of the custom filters in an animation?

This would need plumbing in RenderLayerBacking::startAnimation, animationFinished, startTransition and transitionFinished. Obviously RenderLayerBacking doesn't see the keyframes after the animation has started, so RenderLayerFilterInfo would have to keep a map from animation name to a list of CustomFilterPrograms (instead of the single list that it keeps right now).

The GraphicsLayer implementations already keep a list of animations and add and remove from it. Maybe the GraphicsLayer implementation has to load and validate custom filters in keyframes? I could add this to GraphicsLayerAnimations so that texmap/CoordinatedGraphics does it -- it will basically duplicate RenderLayer::computeFilterOperations and an empty implementation of CustomFilterProgramClient.

Also the GraphicsLayer is the only thing that knows if it can run custom filter animations itself and the only thing that can invalidate if an animated shader loads partway though an animation. So maybe making GraphicsLayer responsible for loading and validating is OK?
Comment 15 Simon Fraser (smfr) 2013-06-19 12:44:55 PDT
(In reply to comment #14)
> Ok, would it be OK for RenderLayerFilterInfo to become the CustomFilterClient for all of the custom filters in an animation?
> 
> This would need plumbing in RenderLayerBacking::startAnimation, animationFinished, startTransition and transitionFinished. Obviously RenderLayerBacking doesn't see the keyframes after the animation has started, so RenderLayerFilterInfo would have to keep a map from animation name to a list of CustomFilterPrograms (instead of the single list that it keeps right now).
> 
> The GraphicsLayer implementations already keep a list of animations and add and remove from it. Maybe the GraphicsLayer implementation has to load and validate custom filters in keyframes? I could add this to GraphicsLayerAnimations so that texmap/CoordinatedGraphics does it -- it will basically duplicate RenderLayer::computeFilterOperations and an empty implementation of CustomFilterProgramClient.
> 
> Also the GraphicsLayer is the only thing that knows if it can run custom filter animations itself and the only thing that can invalidate if an animated shader loads partway though an animation. So maybe making GraphicsLayer responsible for loading and validating is OK?

GraphicsLayer should not do any loading. If you are going to kick off resource loads, you should do that in a similar way to how we load images for style, or something.
Comment 16 Alexandru Chiculita 2013-06-19 15:40:42 PDT
(In reply to comment #15)
> (In reply to comment #14)
> GraphicsLayer should not do any loading. If you are going to kick off resource loads, you should do that in a similar way to how we load images for style, or something.

I think we should teach RenderLayer::updateOrRemoveFilterClients about the animations. It should iterate on the "-webkit-filter" property keyframes and add the clients as needed. I suppose you would need to slightly change RenderLayerFilterInfo::updateCustomFilterClients to do that. This way the shaders are going to be loaded ahead of time, even if the animation is not running in the compositor.

AnimationController should be able to tell what are the animations running on a RenderObject and iterate on the keyframes of a specific property.
Comment 17 Ralph T 2013-06-23 18:01:00 PDT
(In reply to comment #15)
> GraphicsLayer should not do any loading. If you are going to kick off resource loads, you should do that in a similar way to how we load images for style, or something.

I misspoke. The loads are scheduled by StyleResolver when the animated style is computed.

I have a patch which does the following in RenderLayerBacking:

 1. Checks a filter list for custom filters. These will be of type StyleCustomFilterProgram. If any shaders haven't been downloaded then we don't offer them to GraphicsLayer to animate.

  XXX: The isLoaded method on StyleCustomFilterProgram isn't exactly what I want; I want to know if all of the shaders are available and not ASSERT that they are. Currently I add an empty CustomFilterProgramClient prior to calling isLoaded but this isn't really correct either.

 2. If a filter is loaded, then we can add a CustomFilterProgramClient for it, which grabs the cached shaders and lets us retrieve the shader strings.

 3. We can validate loaded shaders. This creates a list of filters with ValidatedCustomFilterPrograms, not StyleCustomFilterPrograms. We don't care about keeping the cached shaders or StyleCustomFilterPrograms anymore.

 4. Remove our empty client from the StyleCustomFilterPrograms, since they're unneeded.

My reasoning for doing the above is:
 1. If a shader isn't loaded yet, we can't animate it anyway, so the compositor shouldn't be offered it.

 2. It's OK to use an empty CustomFilterProgramClient in this case, because we only need the shader strings to mangle through ANGLE. We check that the shader is loaded, so the notifyCustomFilterProgram loaded is useless to us.
Comment 18 Ralph T 2013-06-23 18:03:05 PDT
Created attachment 205273 [details]
Patch
Comment 19 Ralph T 2013-06-23 18:04:41 PDT
Comment on attachment 205273 [details]
Patch

Simon, Alexandru, is this on the right track or am I off in the weeds?
Comment 20 Alexandru Chiculita 2013-06-26 05:45:26 PDT
(In reply to comment #19)
> (From update of attachment 205273 [details])
> Simon, Alexandru, is this on the right track or am I off in the weeds?

I think you can update computeFilterOperations to avoid adding the clients, but I think that we still need a real client. For example, what happens if the shaders are loaded when the animation is already supposed to be running? My expectation would be that the animation will load the shaders and still be able to run. At least that's what happens in the software pipeline.

Also, this problem might be a good question for the w3c CSS group: Should the navigator postpone the start of the filter animations until the shaders are loaded? I think shaders are the first to have this problem.
Comment 21 Ralph T 2013-06-26 06:55:11 PDT
(In reply to comment #20)
> I think you can update computeFilterOperations to avoid adding the clients, but I think that we still need a real client. For example, what happens if the shaders are loaded when the animation is already supposed to be running? My expectation would be that the animation will load the shaders and still be able to run. At least that's what happens in the software pipeline.

With this patch I'm saying that if a shader isn't loaded at the start of the animation then the compositor shouldn't run the animation -- WebCore will run it instead (as it runs all custom filter animations currently). The compositor running animations is just a fast path to avoid recalculating style for every frame.

So if a shader does load while the animation is running then this patch doesn't change behavior -- and I think it's OK to say that the compositor won't handle any "hard" cases.

> Also, this problem might be a good question for the w3c CSS group: Should the navigator postpone the start of the filter animations until the shaders are loaded? I think shaders are the first to have this problem.

Personally I wouldn't want that in the places I'm using CSS Shaders -- for transitional effects where I wouldn't want the page to block on a load.

I think of it like animating background-position when the background-image hasn't loaded.
Comment 22 Alexandru Chiculita 2013-07-08 05:09:58 PDT
(In reply to comment #21)
> (In reply to comment #20)
> > I think you can update computeFilterOperations to avoid adding the clients, but I think that we still need a real client. For example, what happens if the shaders are loaded when the animation is already supposed to be running? My expectation would be that the animation will load the shaders and still be able to run. At least that's what happens in the software pipeline.
> 
> With this patch I'm saying that if a shader isn't loaded at the start of the animation then the compositor shouldn't run the animation -- WebCore will run it instead (as it runs all custom filter animations currently). The compositor running animations is just a fast path to avoid recalculating style for every frame.
> 
> So if a shader does load while the animation is running then this patch doesn't change behavior -- and I think it's OK to say that the compositor won't handle any "hard" cases.
Ok, now I get it. Makes sense.

> 
> > Also, this problem might be a good question for the w3c CSS group: Should the navigator postpone the start of the filter animations until the shaders are loaded? I think shaders are the first to have this problem.
> 
> Personally I wouldn't want that in the places I'm using CSS Shaders -- for transitional effects where I wouldn't want the page to block on a load.
> 
> I think of it like animating background-position when the background-image hasn't loaded.
Ok.
Comment 23 Ralph T 2013-07-10 10:27:53 PDT
So should I clean this up and submit something for review?

I don't like the empty client, but I'm not sure how to do away with it.

I need to coerce the StyleCustomFilterProgram into being loaded if the shader strings are available and the client mechanism causes all of this to happen (it extracts the "CachedShaders", becomes a client of them which updates the m_isXYZShaderLoaded values, which makes isLoaded return a reasonable value).

Is the empty client something that would cause an r-? I think this case is unique since there are no animations of something that's loaded currently...
Comment 24 Simon Fraser (smfr) 2013-08-02 10:52:29 PDT
Comment on attachment 205273 [details]
Patch

View in context: https://bugs.webkit.org/attachment.cgi?id=205273&action=review

> Source/WebCore/rendering/RenderLayerBacking.cpp:2120
> +        // Calling CustomFilterProgram::isLoaded with no clients will make it assert; add

If you need EmptyCustomFilterProgramClient just for this, why not fix the assert?

> Source/WebCore/rendering/RenderLayerBacking.cpp:2268
> +            FilterOperations validatedFromFilters;
> +            FilterOperations validatedToFilters;
> +            if (validateCustomFilters(owningLayer(), fromStyle, validatedFromFilters))
> +                filterVector.insert(FilterAnimationValue::create(0, validatedFromFilters));
> +            if (validateCustomFilters(owningLayer(), toStyle, validatedToFilters))
> +                filterVector.insert(FilterAnimationValue::create(1, validatedToFilters));

I don't think we should pay the cost of two FilterOperations on the stack when there are no custom filters.
Comment 25 Csaba Osztrogon√°c 2014-02-13 04:04:59 PST
Comment on attachment 204448 [details]
Patch

Cleared Alexandru Chiculita's review+ from obsolete attachment 204448 [details] so that this bug does not appear in http://webkit.org/pending-commit.
Comment 26 Ralph T 2014-02-13 07:18:38 PST
CSS Shaders are gone. Don't need this bug anymore.