绘图路径和硬件加速

时间:2013-02-23 11:10:29

标签: android graphics opengl-es

我在视图中画了一条相当大的路径,我遇到了一些性能问题。该路径目前长达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绘制视图所花费的时间,令我惊讶的是硬件加速速度要慢得多:

使用硬件加速:

enter image description here

没有硬件加速:

enter image description here

硬件加速版每帧大约需要200-300毫秒,大多数花费在处理阶段。非加速版本大约需要50毫秒,Draw阶段为2/3,处理阶段为1/3。

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

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

我现在想知道的是

  • 绘制线条/路径只是GPU不好的事情而且不应该尝试硬件加速,或者我是否可能做错了会导致性能不佳?
  • 我能做些什么来画出可以接受表演的巨大路径吗?

3 个答案:

答案 0 :(得分:47)

  

绘制线条/路径只是GPU不好的东西和那个   不应该尝试硬件加速,或者我可能做某事   错误导致糟糕的表现?

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

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

  

我能做些什么来画出可以接受的巨大路径   性能

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

答案 1 :(得分:5)

似乎您可能遇到了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缓存。

答案 2 :(得分:3)

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

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