HTML5 Canvas 在 Chrome 上很慢,但在 FireFox 上很快

2023-11-26

我正在双核 2.8 GHz Pentium Windows 7 系统(具有 4 GB RAM(以及具有大量内存的高度加速显卡))上测试 Chrome 15.0.874.106m,并且正在单核上测试 FireFox 7.0.1 1.6 GHz Athalon Windows Vista 笔记本电脑,配备 2 GB RAM。然而,FireFox 系统的性能比 Chrome 系统高出约 10 倍(根据我的目测估计是 FPS 的 10 倍)。

我看到的大多数帖子都在 FireFox 和 Chrome 上遇到性能较慢的情况,表现还不错,但在这里我似乎遇到了严重相反的情况。关于造成这种情况的原因有什么想法吗?我正在测试的 HTML 文件(单个文件,无依赖项)约为 33 MB(压缩后 16 MB)并且可用here.

这是后续HTML5 canvas 在小文件和大文件上的性能.

我发现 chrome://tracing 帮助我通过 chrome 分析器运行问题文件来获取这些配置文件结果:

Edit: 结果被删除,我得到了一些新的更有趣的结果,我将在新部分中描述这些结果(见下文)。 End Edit

我还发现了 --show-fps-counter,它显示滚动速度约为 3.5 FPS。但我还是不清楚问题出在哪里。

我还找到了 --use-gl 开关并尝试了桌面、egl 和 osmesa。 osmesa 的性能似乎最好,但也只是勉强。我无法准确说出多少,因为 show-fps-counter 开关显然不能与 use-gl=osmesa 结合使用。 osmesa 在其他系统上的性能仍然不如 FireFox。

编辑续:由于事件处理中的侥幸,我不知怎的进入了一种模式,我可以在不按住鼠标按钮的情况下滚动地图。令我震惊和惊讶的是,它滚动得非常流畅!通过一些额外的编辑(即删除处理 mouseup 事件的代码),我切换了代码,这样我就不需要按住按钮来滚动。你瞧,我可以始终如一地 scroll very只要我不按住鼠标按钮,就可以顺利进行。因此,我使用 chrome://tracing 分析/跟踪了按住鼠标按钮和不按住鼠标按钮的行为。我的结果如下。

这是无需按住鼠标按钮即可平滑滚动的:



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
  

这是按住鼠标按钮时不稳定/缓慢的滚动:



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
  

从这个比较来看,在我看来,Chrome 的 OnHandleInputEvent 实现在这里一直在消耗时间。这是怎么回事?

效果是可见的,只是即使在更小/更简单的项目中也不那么明显。Here's这个示例只有大约 700K,这比 30+ MB 的项目更易于管理。如果您单击并拖动,您会看到滚动稍微不稳定,但如果释放鼠标按钮,它将继续滚动得更加平滑。


Edit:问题并不在于这个答案中提出的问题。我还编辑了代码以提供更多信息。


蓝僧MN:从这个比较来看,在我看来,Chrome 的 OnHandleInputEvent 实现在这里一直在消耗时间。这是怎么回事?

效果是可见的,只是即使在更小/更简单的项目中也不那么明显。下面是一个只有大约 700K 大小的示例,与 30+ MB 的项目相比,它更易于管理。如果您单击并拖动,您会看到滚动稍微不稳定,但如果释放鼠标按钮,它将继续滚动得更加平滑。

查看您的代码(如下),我可以看到您的事件处理程序代码正在调用重绘方法(这就是为什么大量 cpu 时间花费在事件处理程序上的原因)。它应该做的就是更新状态。你的重画应该发生在你的游戏循环,这将使整体管理变得更加容易。

考虑删除使用instanceof in MapLayer.prototype.draw而是寻找另一种方式来获取帧。instanceof这是一项成本高昂的操作,通常有一种更优雅的方法不需要这样做。其中一些 Tile/Map 对象应该通过函数调用而不是数组索引来访问,然后您可以在返回的对象类型上有更多的自由,框架可以更新,并且整个MapLayer.prototype.draw方法可以干净很多。

另外,为什么每帧都有一个循环渲染如果typeof frames !== 'number'?调试时它往往只渲染两帧,但它很突出。

再说一遍,您确实应该在游戏循环中进行渲染,事件处理程序中不应该发生任何重大事件。为了使其更容易,请尝试为单个框架构建基准jsperf.com,这样您就会知道该函数花费了多少时间。您可以通过对代码的不同方面进行基准测试来缩小瓶颈范围。

// 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);
}
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

HTML5 Canvas 在 Chrome 上很慢,但在 FireFox 上很快 的相关文章

随机推荐