【问题标题】:Drawing paths and hardware acceleration绘制路径和硬件加速
【发布时间】:2013-02-23 11:10:28
【问题描述】:

在我看来,我正在绘制一条相当大的路径,并且遇到了一些性能问题。该路径目前有 32,000 点长,但我的应用程序应该扩展到至少 128,000 点。我无法对路径的大小做任何事情,因为数据集就是那么大,我需要能够一次显示整个路径并允许放大。

我使用的是运行 Android 4.2 的 Nexus 10,它默认为未明确禁用它的应用程序启用硬件加速。

路径是用以下代码创建的(我省略了一些设置和其他不相关的部分):

dataPath.moveTo(0, offset - (float) data[leftLimit]/ scalingFactor);
        for (int i = leftLimit; i < rightLimit; ++i) {
            x = (i - leftLimit) * dx;
            y = offset - (float) data[i]/ scalingFactor;
            dataPath.lineTo(x, y);
        }

然后在onDraw()方法中绘制:

canvas.drawColor(Color.WHITE);
canvas.drawPath(dataPath, linePaint);

我测量了使用adb shell dumpsys gfxinfo 在有和没有硬件加速的情况下绘制视图所需的时间,令我惊讶的是,硬件加速要慢得多:

使用硬件加速:

没有硬件加速:

硬件加速版本每帧大约需要 200-300 毫秒,大部分时间花在处理阶段。非加速版本大约需要 50 毫秒,其中 2/3 在 Draw 阶段,1/3 在 process 阶段。

显然,即使我没有硬件加速的更快版本仍然太慢而无法达到 60 fps,或者当我转移到更大的数据集时甚至几乎无法使用。

在我的情况下,将路径渲染到位图然后仅转换该位图以适应屏幕的想法也是有问题的。我需要支持将路径放大到很远,并且为了在路径质量不变得更差的情况下进行放大,我必须渲染路径的超大位图(并且可能会遇到内存限制和纹理大小限制)。当放大很远时,我要么只创建路径的一部分的新图像,要么切换到直接渲染路径,如果性能仍然与我所拥有的相似,这可能会导致延迟大于帧速率现在。

我现在想知道的是

  • 绘制线条/路径只是 GPU 不擅长的事情,不应该尝试硬件加速,还是我可能做错了什么导致性能不佳?
  • 我可以做些什么来以可接受的性能绘制如此巨大的路径吗?

【问题讨论】:

  • OpenGL 究竟是如何适应这一点的?
  • 硬件加速使用OpenGL,据我了解。但我不确定在那里使用哪个标签。
  • 你是怎么画这个的?如果您一次将 1 个点绘制到 GPU 上,那么您可能会获得更差的性能,但如果您将其全部批处理,您应该会看到增加,至少在理论上是这样。
  • @Cort3z 我添加了绘制路径的代码,我正在创建完整的路径,然后一口气绘制它。
  • 如果缩小,画128k点真的有用吗?最有可能的是,这些将无法区分。我建议,如果您被缩小,您可以跳过或平均其中一些点。

标签: android graphics opengl-es


【解决方案1】:

绘制线条/路径只是 GPU 不擅长的事情吗? 不应该尝试硬件加速,或者我可能正在做某事 错误导致性能不佳?

路径总是使用 CPU 渲染。当应用程序是硬件加速时,这意味着渲染器将首先使用 CPU 将您的路径绘制成位图,然后将该位图作为纹理上传到 GPU,最后在屏幕上绘制纹理。

线路完全是硬件加速的。在这种情况下,我建议您使用 Canvas.drawLines(),而不是使用 Path

我能做些什么来画出这样巨大的路径吗? 性能?

您应该使用Canvas.drawLines() 或自己将路径渲染为您管理的Bitmap

【讨论】:

  • 至于将绘图路径手动放入Bitmap 并允许它们在屏幕上移动,我推送了简单的代码here。我使用相同的技术在 GPU 加速的 MapView 上将此类路径绘制为叠加层(由于 GPU 的纹理大小限制,通常 GPU 加速的在叠加层上绘制路径的方法会导致 Shape path too large to be rendered into a texture 错误)。跨度>
  • 对我来说,将Canvas.drawLines(float[], Paint) 与一批点一起使用,而不是多次调用Canvas.drawLine(int. int, int, int) 与单点,显着提高了性能。
  • 是否有官方网站或文档说明 Path 使用 CPU 而Canvas.drawLines() 使用硬件加速?我问这个是因为我的表现非常糟糕,搜索了性能提示但没有找到有意义的东西,直到我阅读了这个答案。
  • @RomainGuy 我开始使用 drawLines 而不是 drawPath 并看到了显着的性能改进。但是,我找不到像使用 drawPath 那样有很好连接线的方法,请查看此图像:i.stack.imgur.com/NMpFo.png。你知道如何解决这个问题吗?
【解决方案2】:

您似乎遇到了 GPU 的一般瓶颈。请查看以下链接:

How to make route drawing more efficient

Android canvas path real time performance

Switching from canvas to OpenGL

尤其是第一个,它建议您制作位图并绘制它。如果您更改为 openGL,看起来您可以获得更好的性能。可能有一些神奇的方法可以让现有方法发挥作用,但我目前还没有意识到这一点。

为什么您会看到您所做的行为可能是因为您在每次绘制之间将所有数据发送到 GPU。您应该将其缓存在 GPU 上并改用翻译。不重新创建数据并将其全部发送到 GPU。您可能是I/O bound,这意味着 CPU 和 GPU 之间的传输速率限制了您的性能。根据您提供的数据,我不能 100% 确定这一点,但这是我最好的猜测。尝试不同的缓存技术,主要是来自链接 #1 的 png-cache。

【讨论】:

    【解决方案3】:

    绘制路径不仅仅是“告诉”GPU 绘制线条。路径具有许多特征,例如如何处理线的末端或点线,这是 GPU 加速的。当您遇到许多行导致 CPU 和 GPU 加速的组合变慢时,可能会有 另一个 故障。上面建议的解决方案转移到canvas.drawLines 而不是canvs.drawPath 并尽量不使用花哨的Paint 方法可能会有所帮助。

    如果这没有帮助,您可以尝试使用 GLSurfaceView 并将线条直接渲染到其中。这将涉及一些 OpenGL ES 知识,但应该不会很难做到,而且可能会更有效。

    【讨论】:

    • 虽然与硬件加速问题没有直接关系(但与给出的示例有关),但我发现使用 Matrix 类来缩放和转换点和路径列表比循环快很多倍你的代码。快 20 到 50 倍。我有一些需要路径的复杂区域。缩放从循环的 240 毫秒到矩阵的 6 毫秒。 matrix.setScale(factor, factor, centerX, centerY) 然后是 path.transform(matrix)。或 matrix.mapPoints(pointsarray).
    猜你喜欢
    • 1970-01-01
    • 2012-12-11
    • 2016-07-28
    • 2011-03-10
    • 1970-01-01
    • 1970-01-01
    • 2012-01-30
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多