简体   繁体   English

HTML5 Canvas在Chrome上速度较慢,但​​在FireFox上速度很快

[英]HTML5 Canvas slow on Chrome, but fast on FireFox

I'm testing Chrome 15.0.874.106m on a dual-core 2.8 GHz Pentium Windows 7 system with 4 GB RAM (and a highly accelerated video card with lots of memory) and I'm testing FireFox 7.0.1 on a single-core 1.6 GHz Athalon Windows Vista Laptop with 2 GB RAM. 我在具有4 GB RAM的双核2.8 GHz Pentium Windows 7系统(以及具有大量内存的高速加速视频卡)上测试Chrome 15.0.874.106m,我在单核上测试FireFox 7.0.1具有2 GB RAM的1.6 GHz Athalon Windows Vista笔记本电脑。 Yet the FireFox system is outperforming the Chrome system by about 10 times (10 times the FPS by my visual estimation). 然而,FireFox系统的性能比Chrome系统高出约10倍(根据我的视觉估计,是FPS的10倍)。

Most of the posts I see are experiencing slower performance on FireFox and Chrome doing alright, but here I seem to have a severely reversed case. 我看到的大多数帖子在FireFox和Chrome上都表现不佳,但在这里我似乎有一个严重逆转的情况。 Any ideas on what could be responsible for this? 关于什么可能对此负责的任何想法? The HTML file (single file, no dependencies) I'm testing is about 33 MB (16 MB compressed) and is available here . 我正在测试的HTML文件(单个文件,没有依赖项)大约是33 MB(16 MB压缩),可以在这里找到

This is a follow up to HTML5 canvas performance on small vs. large files . 这是对小文件和大文件的HTML5画布性能的跟进。

I have discovered chrome://tracing which helped me acquire these profile results from running the problem file through the chrome profiler: 我发现了chrome:// tracing,它帮助我通过chrome profiler运行问题文件来获取这些配置文件结果:

Edit: Results deleted, I got some new much more interesting results which I will describe in the new section (see below). 编辑: 删除结果,我得到了一些新的更有趣的结果,我将在新的部分中描述(见下文)。 End Edit 结束编辑

I also discovered the --show-fps-counter, which showed the scrolling running around 3.5 FPS. 我还发现了--show-fps-counter,它显示滚动运行大约3.5 FPS。 But I'm still not clear where the problem is. 但我还不清楚问题出在哪里。

I also found the --use-gl switch and tried desktop, egl and osmesa. 我还找到了--use-gl开关并尝试了桌面,egl和osmesa。 The performance seemed to be best with osmesa, but only barely. 对于osmesa来说,性能似乎最好,但只是勉强。 I couldn't tell exactly how much because the show-fps-counter switch apparently doesn't work in conjunction with use-gl=osmesa. 我无法确切知道多少因为show-fps-counter开关显然不能与use-gl = osmesa一起使用。 osmesa still doesn't perform nearly as well as FireFox on the other system. 在另一个系统上,osmesa的性能仍然不如FireFox。

Edit Continued: Thanks to a fluke in the event handling I somehow got into a mode where I could scroll the map without holding the mouse button down. 编辑续:感谢事件处理中的侥幸,我以某种方式进入了一种模式,我可以在不按住鼠标按钮的情况下滚动地图。 To my shock and amazement, it was scrolling very smoothly! 令我震惊和惊讶的是,滚动非常顺利! With a few additional edits (namely, removing the code that handles the mouseup event) I switched the code so that I never need to hold the button to scroll. 通过一些额外的编辑(即删除处理mouseup事件的代码),我切换了代码,以便我永远不需要按住按钮进行滚动。 Lo and behold, I can consistently scroll very smoothly so long as I am not holding down the mouse button. 瞧,只要我没有按住鼠标按钮,我就能一直滚动得非常顺畅。 So I profiled/traced the behavior using chrome://tracing with and without holding the mouse button down. 因此,我使用chrome://跟踪使用和不按住鼠标按钮来跟踪行为。 My results are below. 我的结果如下。

This is smooth scrolling without holding down the mouse button: 这是平滑滚动而无需按住鼠标按钮:

Selection summary:
 RenderWidget::OnHandleInputEvent                       :   1340.968ms     212 occurrences
 RenderWidget::InvalidationCallback                     :      7.867ms      27 occurrences
 RenderWidget::OnUpdateRectAck                          :      1.319ms     173 occurrences
 RenderWidget::OnSwapBuffersComplete                    :    129.018ms     173 occurrences
 V8EventListener::callListenerFunction                  :   1306.923ms     173 occurrences
 RenderWidget::DoDeferredUpdate                         :    120.033ms     204 occurrences
 EarlyOut_UpdateReplyPending                            :      0.004ms       4 occurrences
 EarlyOut_SwapStillPending                              :      0.181ms     165 occurrences
 CommandBufferHelper::WaitForToken                      :      8.358ms       3 occurrences
 WebViewImpl::layout                                    :       1.24ms     190 occurrences
 CCLayerTreeHost::updateLayers                          :     34.726ms     173 occurrences
 CCLayerTreeHost::commitTo                              :     24.426ms     173 occurrences
 CCLayerTreeHostImpl::drawLayers                        :     24.483ms     173 occurrences
 LayerRendererChromium::present                         :      8.434ms     173 occurrences
 EarlyOut_NoPendingUpdate                               :      0.018ms      17 occurrences
 CommandBufferProxy::FlushSync                          :      8.307ms       3 occurrences
 CCLayerTreeHost::updateLayers::calcDrawEtc             :     15.871ms     173 occurrences
 LayerRendererChromium::drawLayers                      :     23.441ms     173 occurrences
 RenderWidget::OnSwapBuffersPosted                      :      0.185ms     173 occurrences
 RendererGLContext::SwapBuffers                         :      4.431ms     173 occurrences
 LayerRendererChromium::drawLayersInternal::calcDrawEtc :     10.783ms     173 occurrences
 GpuCommandBufferStub::OnFlush                          :      7.581ms       3 occurrences
 GpuCommandBufferStub::OnAsyncFlush                     :   2825.339ms     352 occurrences
 GpuCommandBufferStub::OnEcho                           :       0.83ms     173 occurrences
 GpuScheduler:PutChanged                                :   2823.239ms     355 occurrences
 GLES2DecoderImpl::HandleTexImage2D                     :      5.779ms       6 occurrences
 GLES2DecoderImpl::HandleTexSubImage2D                  :      1.784ms       3 occurrences
 GLES2DecoderImpl::HandleSwapBuffers                    :   2387.561ms     173 occurrences
 GLContext::SwapBuffers                                 :   2384.623ms     173 occurrences
 ScheduledAction::execute                               :      2.453ms      16 occurrences
 v8.compile                                             :      1.037ms      14 occurrences
 v8.run                                                 :      3.142ms      14 occurrences
 EarlyOut_NotVisible                                    :      0.021ms      14 occurrences
 RenderWidgetHost::ForwardMouseEvent                    :      7.465ms     538 occurrences
 RenderWidgetHost::OnMsgInputEventAck                   :      5.218ms     212 occurrences
 RenderWidgetHost::OnMsgUpdateRect                      :      4.172ms     173 occurrences
 RenderWidgetHost::ForwardInputEvent                    :      4.551ms     212 occurrences
*Totals                                                 :  13535.811ms    5332 occurrences

Selection start                                         :    986.276ms
Selection extent                                        :   3320.488ms

And this is the choppy/slow scrolling when holding down the mouse button: 这是按住鼠标按钮时的不稳定/慢速滚动:

Selection summary:
 RenderWidget::OnHandleInputEvent                       :   3852.921ms      61 occurrences
 RenderWidget::InvalidationCallback                     :      4.549ms      61 occurrences
 RenderWidget::OnUpdateRectAck                          :      1.235ms      40 occurrences
 RenderWidget::OnSwapBuffersComplete                    :     20.684ms      40 occurrences
 V8EventListener::callListenerFunction                  :    357.075ms      39 occurrences
 RenderWidget::DoDeferredUpdate                         :     25.208ms     132 occurrences
 EarlyOut_SwapStillPending                              :      0.004ms       6 occurrences
 EarlyOut_UpdateReplyPending                            :      0.032ms      32 occurrences
 CommandBufferHelper::WaitForToken                      :       8.09ms       3 occurrences
 WebViewImpl::layout                                    :      0.346ms      78 occurrences
 CCLayerTreeHost::updateLayers                          :      7.805ms      40 occurrences
 CCLayerTreeHost::commitTo                              :      4.727ms      40 occurrences
 CCLayerTreeHostImpl::drawLayers                        :      9.449ms      40 occurrences
 LayerRendererChromium::present                         :      1.122ms      40 occurrences
 EarlyOut_NoPendingUpdate                               :      0.038ms      38 occurrences
 CommandBufferProxy::FlushSync                          :       8.05ms       3 occurrences
 CCLayerTreeHost::updateLayers::calcDrawEtc             :      3.694ms      40 occurrences
 LayerRendererChromium::drawLayers                      :      9.177ms      40 occurrences
 RenderWidget::OnSwapBuffersPosted                      :      0.035ms      40 occurrences
 RendererGLContext::SwapBuffers                         :      0.684ms      40 occurrences
 LayerTextureUpdaterCanvas::paint                       :      0.483ms       1 occurrences
 LayerTextureSubImage::uploadWithMapTexSubImage         :       0.02ms       1 occurrences
 LayerRendererChromium::drawLayersInternal::calcDrawEtc :      2.329ms      40 occurrences
 GpuCommandBufferStub::OnFlush                          :      7.326ms       3 occurrences
 GpuCommandBufferStub::OnAsyncFlush                     :     226.88ms     121 occurrences
 GpuCommandBufferStub::OnEcho                           :      0.377ms      40 occurrences
 GpuScheduler:PutChanged                                :      230.2ms     124 occurrences
 GLES2DecoderImpl::HandleTexImage2D                     :      5.705ms       8 occurrences
 GLES2DecoderImpl::HandleTexSubImage2D                  :      2.057ms       4 occurrences
 GLES2DecoderImpl::HandleSwapBuffers                    :    113.857ms      40 occurrences
 GLContext::SwapBuffers                                 :    113.377ms      40 occurrences
 ScheduledAction::execute                               :     12.708ms      83 occurrences
 v8.compile                                             :      1.982ms      25 occurrences
 v8.run                                                 :      4.499ms      25 occurrences
 EarlyOut_NotVisible                                    :      0.022ms      25 occurrences
 RenderWidgetHost::ForwardMouseEvent                    :      4.671ms     640 occurrences
 RenderWidgetHost::OnMsgInputEventAck                   :      1.102ms      61 occurrences
 RenderWidgetHost::OnMsgUpdateRect                      :      0.894ms      40 occurrences
 RenderWidgetHost::ForwardInputEvent                    :      1.527ms      61 occurrences
*Totals                                                 :   5044.941ms    2235 occurrences

Selection start                                         :    956.043ms
Selection extent                                        :   6082.888ms

From this comparison, it looks to me like Chrome's OnHandleInputEvent implementation is eating up all the time here. 从这个比较中,我认为Chrome的OnHandleInputEvent实现在这里一直在吃东西。 What's going on? 这是怎么回事?

The effect is visible, just not as pronounced even on much smaller/simpler projects. 效果是可见的,即使在更小/更简单的项目上也不那么明显。 Here's an example that's only about 700K which is a much more manageable thing to test with than the 30+ MB project. 这是一个只有大约700K的例子,比30+ MB项目更易于管理。 If you click and drag you can see is scrolls slightly choppily, but if you release the mouse button it will continue scrolling much more smoothly. 如果单击并拖动,您可以看到滚动略微不卷曲,但如果松开鼠标按钮,它将继续滚动得更顺畅。

Edit : Issue was not down to the issues raised in this answer. 编辑 :问题不在于此答案中提出的问题。 I've also edited the code to be a little more informative. 我还编辑了代码,以提供更多信息。


BlueMonkMN : From this comparison, it looks to me like Chrome's OnHandleInputEvent implementation is eating up all the time here. BlueMonkMN :从这个比较中,我认为Chrome的OnHandleInputEvent实现在这里一直在吃东西。 What's going on? 这是怎么回事?

The effect is visible, just not as pronounced even on much smaller/simpler projects. 效果是可见的,即使在更小/更简单的项目上也不那么明显。 Here's an example that's only about 700K which is a much more manageable thing to test with than the 30+ MB project. 这是一个只有大约700K的例子,比30+ MB项目更易于管理。 If you click and drag you can see is scrolls slightly choppily, but if you release the mouse button it will continue scrolling much more smoothly. 如果单击并拖动,您可以看到滚动略微不卷曲,但如果松开鼠标按钮,它将继续滚动得更顺畅。

Looking at your code (below), I can see that your event handler code is calling redraw methods ( this is why a lot of the cpu time is spent in event handlers ). 查看您的代码(下面),我可以看到您的事件处理程序代码正在调用重绘方法( 这就是为什么在事件处理程序中花费了大量的cpu时间 )。 All it should be doing is updating state. 它应该做的就是更新状态。 Your redraw should take place in your Game Loop , which would make it much easier to manage as a whole. 您的重绘应该在您的游戏循环中进行 ,这将使整体管理变得更加容易。

Consider removing the use of instanceof in MapLayer.prototype.draw and instead finding another way to get the frames. 考虑在MapLayer.prototype.draw删除instanceof的使用,而是找到另一种获取帧的方法。 instanceof is a costly operation, and there is often a much more elegant approach that does not require that. instanceof是一项代价高昂的操作,并且通常有一种更优雅的方法,不需要这样做。 Some of those Tile/Map objects should be accessed through function calls rather than array indexes, then you can have more freedom on the type of object returned, frames can be updates, and that whole MapLayer.prototype.draw method can be a lot cleaner. 其中一些Tile / Map对象应该通过函数调用而不是数组索引来访问,那么你可以对返回的对象类型有更多的自由,框架可以更新,整个MapLayer.prototype.draw方法可以更清洁。

Also, why is there a loop rendering every frame if typeof frames !== 'number' ? 另外,为什么每个帧都有循环渲染,如果是typeof frames !== 'number' When debugging it tends to only be rendering two frames, but it stood out. 在调试时,它往往只渲染两帧,但它很突出。

Again, you really ought to be rendering in the game loop, nothing major should ever take place in event handlers. 再一次,你真的应该在游戏循环中渲染,在事件处理程序中不应该发生任何重大事件。 And to make it easier, try constructing a benchmark for a single frame on jsperf.com , that way you will know how much time it spent in that function. 为了更容易,尝试在jsperf.com上为单个帧构建基准,这样您就会知道它在该函数中花费了多少时间。 And you can narrow down on the bottleneck by benchmarking different aspects of your code. 您可以通过对代码的不同方面进行基准测试来缩小瓶颈。

// Section of our code
function beginDrag(e) {
   dragX = e.clientX;
   dragY = e.clientY;
   var srcEl = e.srcElement ? e.srcElement : e.target;
   srcEl.onmousemove = processDrag;
   return false;
}
// **Note** called on mouseout, not mouseup
function endDrag(e) {
   var srcEl = e.srcElement ? e.srcElement : e.target;
   srcEl.onmousemove = null;
}
function processDrag(e) {
   e = e || window.event;
   drag(e.clientX, e.clientY);
   return false;
}
function drag(newX, newY) {
   currentMap.scroll(currentMap.scrollX + newX - dragX, currentMap.scrollY + newY - dragY);
   dragX = newX;
   dragY = newY;
   // --- this should not be executed during an event handler, draw takes place in game loop.
   currentMap.draw(gameViewContext);
}

The bug I reported ( https://code.google.com/p/chromium/issues/detail?id=103148 ) has since been remarked on as "unable to reproduce" if I read correctly, so I'm going to run on the assumption that this was a bug in Chrome and has been fixed (intentionally or not) by other updates. 我报告的错误( https://code.google.com/p/chromium/issues/detail?id=103148 )已经被评为“如果我正确读取就无法重现”,所以我要去运行假设这是Chrome中的一个错误,并且已被其他更新修改(有意或无意)。 In any case, I don't have the issue any more myself. 无论如何,我自己也没有这个问题了。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM