RESOLVED FIXED 88638
[Qt] requestAnimationFrame should only trigger when a new frame can be displayed.
https://bugs.webkit.org/show_bug.cgi?id=88638
Summary [Qt] requestAnimationFrame should only trigger when a new frame can be displa...
Zeno Albisser
Reported 2012-06-08 02:07:56 PDT
Right now the QtWebProcess is executing javascript way too often when relying on requestAnimationFrame. This is because a timer is being used to service scripted animations. In case of WK2 we should instead use LayerTreeHostQt::renderNextFrame to be notified when we should execute scripted code Qt/WK1 nevertheless does not have the concept of painting a complete frame at once, so we need to fallback to the timer in this case. Because Qt needs to support WK1 and WK2 from the same binary we must be able to decide at runtime if we want to use the timer or rely on renderNextFrame.
Attachments
patch for review. (11.80 KB, patch)
2012-06-08 02:54 PDT, Zeno Albisser
webkit.review.bot: commit-queue-
patch for review. (10.68 KB, patch)
2012-06-08 05:16 PDT, Zeno Albisser
webkit.review.bot: commit-queue-
Archive of layout-test-results from ec2-cr-linux-02 (848.93 KB, application/zip)
2012-06-08 05:56 PDT, WebKit Review Bot
no flags
patch for testing with ews. (10.68 KB, patch)
2012-06-08 08:02 PDT, Zeno Albisser
jamesr: review-
patch for review. (14.67 KB, patch)
2012-06-25 15:35 PDT, Zeno Albisser
no flags
patch for review. - use an enum as a return value for scheduleAnimation as requested. (14.89 KB, patch)
2012-07-09 09:37 PDT, Zeno Albisser
webkit.review.bot: commit-queue-
patch for review. (14.90 KB, patch)
2012-07-09 10:25 PDT, Zeno Albisser
webkit.review.bot: commit-queue-
patch for review. (14.90 KB, patch)
2012-07-09 14:04 PDT, Zeno Albisser
hausmann: review-
patch for review. (14.38 KB, patch)
2012-07-24 07:14 PDT, Zeno Albisser
noam: review-
patch for review. - fixed issues as commented before. (11.56 KB, patch)
2012-07-24 13:43 PDT, Zeno Albisser
no flags
patch for review. (11.25 KB, patch)
2012-07-25 10:11 PDT, Zeno Albisser
no flags
patch for review. (11.29 KB, patch)
2012-07-26 04:55 PDT, Zeno Albisser
jturcotte: review+
Zeno Albisser
Comment 1 2012-06-08 02:54:48 PDT
Created attachment 146525 [details] patch for review.
WebKit Review Bot
Comment 2 2012-06-08 03:50:00 PDT
Comment on attachment 146525 [details] patch for review. Attachment 146525 [details] did not pass chromium-ews (chromium-xvfb): Output: http://queues.webkit.org/results/12908655
Zeno Albisser
Comment 3 2012-06-08 05:16:06 PDT
Created attachment 146541 [details] patch for review.
Jocelyn Turcotte
Comment 4 2012-06-08 05:30:40 PDT
Comment on attachment 146541 [details] patch for review. View in context: https://bugs.webkit.org/attachment.cgi?id=146541&action=review > Source/WebKit2/ChangeLog:3 > + requestAnimationFrame should only trigger when a new frame can be displayed. Please prepend with [Qt] Looks fine to me otherwise once it passes the chrome ews.
WebKit Review Bot
Comment 5 2012-06-08 05:56:48 PDT
Comment on attachment 146541 [details] patch for review. Attachment 146541 [details] did not pass chromium-ews (chromium-xvfb): Output: http://queues.webkit.org/results/12909625 New failing tests: platform/chromium/compositing/layout-width-change.html platform/chromium/compositing/render-surface-alpha-blending.html platform/chromium/compositing/tiny-layer-rotated.html platform/chromium/compositing/huge-layer-rotated.html fast/loader/loadInProgress.html platform/chromium/compositing/3d-corners.html platform/chromium/compositing/video-frame-size-change.html platform/chromium/compositing/perpendicular-layer-sorting.html fast/loader/unload-form-post-about-blank.html platform/chromium/compositing/child-layer-3d-sorting.html platform/chromium/compositing/accelerated-drawing/svg-filters.html compositing/geometry/fixed-position-transform-composited-page-scale.html platform/chromium/compositing/lost-compositor-context-permanently.html http/tests/media/video-play-progress.html platform/chromium/compositing/filters/background-filter-blur-outsets.html platform/chromium/compositing/lost-compositor-context-with-video.html platform/chromium/compositing/accelerated-drawing/alpha.html http/tests/xmlhttprequest/zero-length-response.html http/tests/security/script-crossorigin-loads-correctly.html platform/chromium/compositing/webgl-loses-compositor-context.html platform/chromium/compositing/backface-visibility-transformed.html platform/chromium/compositing/lost-compositor-context-with-rendersurface.html platform/chromium/compositing/lost-compositor-context.html platform/chromium/compositing/filters/background-filter-blur-off-axis.html platform/chromium/compositing/img-layer-grow.html platform/chromium/compositing/lost-compositor-context-twice.html
WebKit Review Bot
Comment 6 2012-06-08 05:56:53 PDT
Created attachment 146546 [details] Archive of layout-test-results from ec2-cr-linux-02 The attached test failures were seen while running run-webkit-tests on the chromium-ews. Bot: ec2-cr-linux-02 Port: <class 'webkitpy.common.config.ports.ChromiumXVFBPort'> Platform: Linux-2.6.35-28-virtual-x86_64-with-Ubuntu-10.10-maverick
Zeno Albisser
Comment 7 2012-06-08 08:02:53 PDT
Created attachment 146574 [details] patch for testing with ews.
Nat Duca
Comment 8 2012-06-08 10:45:36 PDT
Comment on attachment 146574 [details] patch for testing with ews. This "returning false if you want to use the timer" is a bit confusing. For instance, Chrome has a scheduleAnimation() that returns a bool but in the false case, you're not necessarily being told to schedule a timer. Would an enum help clarify this? Maybe in doing that, you can get rid of the #ifdefs entirely? There are three states that I know of: yes i scheduled this no i didn't schedule this and i need the caller to do it for me yes I scheduled this but not for anytime soon (case where a raf was registered while the webview was hidden)
Zeno Albisser
Comment 9 2012-06-11 01:17:16 PDT
(In reply to comment #8) > (From update of attachment 146574 [details]) > This "returning false if you want to use the timer" is a bit confusing. For instance, Chrome has a scheduleAnimation() that returns a bool but in the false case, you're not necessarily being told to schedule a timer. > > Would an enum help clarify this? Maybe in doing that, you can get rid of the #ifdefs entirely? There are three states that I know of: > yes i scheduled this > no i didn't schedule this and i need the caller to do it for me > yes I scheduled this but not for anytime soon (case where a raf was registered while the webview was hidden) I look at the timer as a fallback solution. And therefore i understand returning false much more as a "you asked me to schedule an animation, but i did not do it. - Please handle that yourself". Falling back to the timer seems to be appropriate in the cases i have seen, but may not be the generic solution. Personally i would prefer a boolean to an enum, it seems more straight forward to me. But i do not have a strong preference about it anyway.
James Robinson
Comment 10 2012-06-11 11:29:17 PDT
Comment on attachment 146574 [details] patch for testing with ews. You need a ChangeLog entry for the WebCore changes describing what they do and why they are needed.
Nat Duca
Comment 11 2012-06-11 11:45:11 PDT
(In reply to comment #9) > > Would an enum help clarify this? Maybe in doing that, you can get rid of the #ifdefs entirely? There are three states that I know of: > > yes i scheduled this > > no i didn't schedule this and i need the caller to do it for me > > yes I scheduled this but not for anytime soon (case where a raf was registered while the webview was hidden) > > I look at the timer as a fallback solution. And therefore i understand returning false much more as a "you asked me to schedule an animation, but i did not do it. - Please handle that yourself". Falling back to the timer seems to be appropriate in the cases i have seen, but may not be the generic solution. > Personally i would prefer a boolean to an enum, it seems more straight forward to me. > But i do not have a strong preference about it anyway. How do you represent the decision: "I dont want you to tick scheduledAnimations via the timer because I'm invisible"? Does the chrome return true?
Zeno Albisser
Comment 12 2012-06-25 13:46:52 PDT
(In reply to comment #11) > (In reply to comment #9) > > > Would an enum help clarify this? Maybe in doing that, you can get rid of the #ifdefs entirely? There are three states that I know of: > > > yes i scheduled this > > > no i didn't schedule this and i need the caller to do it for me > > > yes I scheduled this but not for anytime soon (case where a raf was registered while the webview was hidden) ... > How do you represent the decision: > "I dont want you to tick scheduledAnimations via the timer because I'm invisible"? > > Does the chrome return true? I've been looking at this patch again, and I cannot see a good reason why an enum should be used for that. In the case you mentioned, I think returning true would be appropriate. It should not matter to the caller how the callee is handling the scheduling. The callee decides if it is handled immediately or delayed because of being hidden. The only thing that seems to be important for the caller is to know, if the scheduling will be handled or if the timer should be used. So i only really see two rather than three states here. I will of course fix the ChangeLog. :)
Zeno Albisser
Comment 13 2012-06-25 15:35:07 PDT
Created attachment 149372 [details] patch for review.
Nat Duca
Comment 14 2012-06-26 10:56:15 PDT
Sure, thats true for your current use cases on your port. The difficult case arises with compositor-accelerated css animations. If you dont plan on doing them, then the third state is not going to be an issue for you. But, if you plan on using them, then the callee needs to know if raf is going to be called soon so that it can fire the animaitonStarted event back to the animation controller. I'm not going to argue too hard since its not in your immediate codebase to have that issue. I'm just sort of warning you of fun things to come. :)
Zeno Albisser
Comment 15 2012-07-09 09:37:00 PDT
Created attachment 151259 [details] patch for review. - use an enum as a return value for scheduleAnimation as requested.
WebKit Review Bot
Comment 16 2012-07-09 10:02:20 PDT
Comment on attachment 151259 [details] patch for review. - use an enum as a return value for scheduleAnimation as requested. Attachment 151259 [details] did not pass chromium-ews (chromium-xvfb): Output: http://queues.webkit.org/results/13163327
Zeno Albisser
Comment 17 2012-07-09 10:25:59 PDT
Created attachment 151271 [details] patch for review.
WebKit Review Bot
Comment 18 2012-07-09 10:33:59 PDT
Comment on attachment 151271 [details] patch for review. Attachment 151271 [details] did not pass chromium-ews (chromium-xvfb): Output: http://queues.webkit.org/results/13168273
Zeno Albisser
Comment 19 2012-07-09 14:04:52 PDT
Created attachment 151313 [details] patch for review.
Simon Hausmann
Comment 20 2012-07-13 04:48:57 PDT
Comment on attachment 151313 [details] patch for review. I think the scheduleAnimation() interface should remain as-is and serve one single purpose only: schedule an animation. I don't think it should at the same time serve as a "decision" maker whether to fall back to timers or not. For our purposes it is not even necessary to decide that for each scheduleAnimation() call but instead it could simply live as a setting in WebCore::Settings. In WK1 we'd set a scheduleAnimationsWithTimer alike property to true, in WK2 we'd leave it as false. That way I think you could also avoid the #if PLATFORM(QT) in WebChromeClient::scheduleAnimation(), making it easier for other ports that use WK2 AC to re-use the same code path of properly synchronized RAF calls.
Simon Hausmann
Comment 21 2012-07-18 07:36:12 PDT
Multiple long (and very interesting) discussions brought us now to the following design proposal: 1) WebChromeClient::scheduleAnimation() should send a message to the UI process 2) On the UI process we should tie ourselves to Qt's animation driver / unified timer, which will either be a timer driven or frame driven update mechanism (QQuickWindowManager takes care of that). The tie-in happens for example through a QAbstractAnimation implementation, so it's not bound to QQuick in any way and will just work. The connection happens behind the scenes. 3) When Qt decides that animations should be advanced, we send a ServiceScriptedAnimations message to the web process, that should do what the name says :) In an ideal world the ServiceScriptedAnimations message to the WebProcess will result in a DidRenderFrame response to the UI process _just_ in time before the scene graph calls our QSGRenderNode. This model also supports a RequestAnimationFrame "use-case" where the JS callback won't end up changing anything in the DOM/canvas (maybe just send a network message but otherwise decide nothing changed) and then schedules the next RAF. That next RAF callback will be then served at the refresh rate decided by the QAnimationDriver, which seems like the correct thing to do.
Simon Hausmann
Comment 22 2012-07-18 07:38:11 PDT
Tagging this bug with [Qt], because it is primarily a Qt issue at this point. In the long run any port that uses WK2 and does _not_ have a DisplayRefreshMonitor implementation should use the WK2 IPC messages/callbacks that result from this work, to avoid the timer driver RAF fallback that has the beautiful tendency to hog the CPU :)
Zeno Albisser
Comment 23 2012-07-24 07:14:17 PDT
Created attachment 154054 [details] patch for review.
Kenneth Rohde Christiansen
Comment 24 2012-07-24 10:40:19 PDT
Comment on attachment 154054 [details] patch for review. View in context: https://bugs.webkit.org/attachment.cgi?id=154054&action=review > Source/WebKit/qt/WebCoreSupport/ChromeClientQt.cpp:103 > + m_chromeClient->refreshAnimationCallback(); We normally don't use Callback in the naming. > Source/WebKit/qt/WebCoreSupport/ChromeClientQt.cpp:647 > +void ChromeClientQt::refreshAnimationCallback() > +{ > + m_webPage->mainFrame()->d->frame->view()->serviceScriptedAnimations(convertSecondsToDOMTimeStamp(currentTime())); > +} None here can be null?
Noam Rosenthal
Comment 25 2012-07-24 10:49:27 PDT
Comment on attachment 154054 [details] patch for review. View in context: https://bugs.webkit.org/attachment.cgi?id=154054&action=review Please submit Mac disabling of GraphicsSurface separately > Source/WebCore/ChangeLog:9 > + Disable CopyToTexture feature for GraphicsSurface on Mac. > + While this is actually working, it is currently used for Tiles > + that are single buffered, and therefore requires a call to glFlush. > + This call blocks the GPU for about 40ms which would make smooth animations impossible. This needs to be a different patch.
Zeno Albisser
Comment 26 2012-07-24 13:30:50 PDT
Comment on attachment 154054 [details] patch for review. View in context: https://bugs.webkit.org/attachment.cgi?id=154054&action=review >> Source/WebCore/ChangeLog:9 >> + This call blocks the GPU for about 40ms which would make smooth animations impossible. > > This needs to be a different patch. sure. - I'll create a separate one. >> Source/WebKit/qt/WebCoreSupport/ChromeClientQt.cpp:103 >> + m_chromeClient->refreshAnimationCallback(); > > We normally don't use Callback in the naming. I renamed this to serviceScriptedAnimations, as this is what it actually does. >> Source/WebKit/qt/WebCoreSupport/ChromeClientQt.cpp:647 >> +} > > None here can be null? If i read the code correctly, - none of them. m_webPage: initialized in constructor initialization list mainFrame: created when called d: initialized in constructor initialization list frame: in QWebFramePrivate::init() view: instantiated by FrameLoaderClientQt. As far as i see the only one that theoretically can be null. But then again, if it was null there would not be a FrameView and the animation would not be triggered.
Zeno Albisser
Comment 27 2012-07-24 13:43:29 PDT
Created attachment 154134 [details] patch for review. - fixed issues as commented before.
Zeno Albisser
Comment 28 2012-07-25 10:11:33 PDT
Created attachment 154380 [details] patch for review.
Jocelyn Turcotte
Comment 29 2012-07-25 10:19:08 PDT
Comment on attachment 154380 [details] patch for review. View in context: https://bugs.webkit.org/attachment.cgi?id=154380&action=review > Source/WTF/ChangeLog:7 > + the servicing of scripted animations to the renderNextFrame call for WK2. the renderNextFrame call -> layer syncing > Source/WebKit2/ChangeLog:7 > + the servicing of scripted animations to the renderNextFrame call for WK2. Same here. > Source/WebKit2/WebProcess/WebPage/LayerTreeCoordinator/LayerTreeCoordinator.cpp:360 > + m_webPage->corePage()->mainFrame()->view()->serviceScriptedAnimations(convertSecondsToDOMTimeStamp(currentTime())); Please add a comment on what this achieves and when it is needed. > Source/WebKit2/WebProcess/WebPage/LayerTreeCoordinator/LayerTreeCoordinator.h:90 > +#if ENABLE(REQUEST_ANIMATION_FRAME) && !USE(REQUEST_ANIMATION_FRAME_TIMER) The guard should go in the cpp too, or be removed from the header.
Jocelyn Turcotte
Comment 30 2012-07-25 11:27:50 PDT
Comment on attachment 154380 [details] patch for review. View in context: https://bugs.webkit.org/attachment.cgi?id=154380&action=review >> Source/WebKit2/WebProcess/WebPage/LayerTreeCoordinator/LayerTreeCoordinator.h:90 >> +#if ENABLE(REQUEST_ANIMATION_FRAME) && !USE(REQUEST_ANIMATION_FRAME_TIMER) > > The guard should go in the cpp too, or be removed from the header. As chatted on Irc you could instead move LayerTreeHost::scheduleAnimation under USE(UI_SIDE_COMPOSITING) and not use guards here. WebChromeClient::scheduleAnimation could look like: #if ENABLE(REQUEST_ANIMATION_FRAME) && !USE(REQUEST_ANIMATION_FRAME_TIMER) void WebChromeClient::scheduleAnimation() { #if USE(UI_SIDE_COMPOSITING) m_page->drawingArea()->layerTreeHost()->scheduleAnimation(); #endif } #endif
Zeno Albisser
Comment 31 2012-07-26 04:55:21 PDT
Created attachment 154613 [details] patch for review.
Simon Hausmann
Comment 32 2012-07-26 06:46:47 PDT
Comment on attachment 154613 [details] patch for review. View in context: https://bugs.webkit.org/attachment.cgi?id=154613&action=review Great work! Awesome to have this in place finally :) Just one small comment below: > Source/WebKit2/WebProcess/WebPage/LayerTreeCoordinator/LayerTreeCoordinator.cpp:361 > + m_webPage->corePage()->mainFrame()->view()->serviceScriptedAnimations(convertSecondsToDOMTimeStamp(currentTime())); I wonder if strictly speaking this call should be guarded by #ifdefs (RAF && !RAF_TIMER && !RAF_REFRESH_MONITOR). It's not doing any harm right now, but if a port decides to use WK2 AC and the platform happens to have a DisplayRefreshMonitor implementation, then enabling it will silently cause too many calls to serviceScriptedAnimations. Anyway, just a thought, not sure how likely it is that somebody is going to run into this.
Zeno Albisser
Comment 33 2012-07-26 07:48:47 PDT
(In reply to comment #32) > I wonder if strictly speaking this call should be guarded by #ifdefs (RAF && !RAF_TIMER && !RAF_REFRESH_MONITOR). It's not doing any harm right now, but if a port decides to use WK2 AC and the platform happens to have a DisplayRefreshMonitor implementation, then enabling it will silently cause too many calls to serviceScriptedAnimations. > > Anyway, just a thought, not sure how likely it is that somebody is going to run into this. I guess an additional #ifdef will not do any harm. - I'll add it before landing.
Zeno Albisser
Comment 34 2012-07-26 13:16:50 PDT
Note You need to log in before you can comment on or make changes to this bug.