在自定义视图的onDraw方法中使用硬件层

8

我想了解如何在自定义的 View 中正确使用硬件加速(如果可用)来持久地进行动画。这是我的 onDraw() 的基本原则:

canvas.drawColor(mBackgroundColor);

for (Layer layer : mLayers) {
    canvas.save();
    canvas.translate(layer.x, layer.y);

    //Draw that number of images in a grid, offset by -1
    for (int i = -1; i < layer.xCount - 1; i++) {
        for (int j = -1; j < layer.yCount - 1; j++) {
            canvas.drawBitmap(layer.bitmap, layer.w * i, layer.h * j, null);
        }
    }

    //If the layer's x has moved past its width, reset back to a seamless position
    layer.x += ((difference * layer.xSpeed) / 1000f);
    float xOverlap = layer.x % layer.w;
    if (xOverlap > 0) {
        layer.x = xOverlap;
    }

    //If the layer's y has moved past its height, reset back to a seamless position
    layer.y += ((difference * layer.ySpeed) / 1000f);
    float yOverlap = layer.y % layer.h;
    if (yOverlap > 0) {
        layer.y = yOverlap;
    }

    canvas.restore();
}

//Redraw the view
ViewCompat.postInvalidateOnAnimation(this);

我正在onAttachedToWindow()中启用硬件层,并在onDetachedFromWindow()中禁用它们,但我想知道是否真的在使用它。基本上,调用drawBitmap()循环永远不会改变;唯一改变的是Canvas的平移。 Bitmap自动保存到GPU作为纹理背后的过程,还是需要手动执行某些操作?

我可能误解了问题,但是你是否为你的视图设置了 setLayerType(View.LAYER_TYPE_HARDWARE, null);?GPU仅在用户正在主动滚动时缓存图像,但在其他情况下不会缓存,这是为了消耗更少的资源而做出的权衡。 - Vrashabh Irde
@Slartibartfast 是的,我已经将层类型设置为硬件。用户实际上永远不会滚动;视图正在持续滚动其自身内容。我可能误解了HW加速,但我觉得我正在绘制的位图网格应该能够被渲染到硬件层中,并且只需翻译而不是在每个帧上重新绘制位图。 - Kevin Coppock
2个回答

8
你在哪些视图上设置了“View.LAYER_TYPE_HARDWARE”?如果你在包含上述绘图代码的视图上设置硬件层,那么你会让系统执行比必要更多的工作。由于你只是绘制位图,所以这里不需要做任何事情。如果你调用“Canvas.drawBitmap()”,框架将代表你缓存生成的OpenGL纹理。
然而,你可以进一步优化你的代码。你可以使用子视图而不是调用“drawBitmap()”。如果你使用“offset*()”方法(或“setX()”/“setY()”)移动这些子视图,框架将应用进一步优化,避免再次调用“draw()”方法。
通常,硬件层应该设置在耗费大量绘制资源且内容不经常改变的视图上(基本上和你目前所做的相反 :)

谢谢@RomainGuy。我在上面显示的View上设置了LAYER_TYPE_HARDWARE。所以纹理会自动缓存?这就是我想要的。那么您是说添加两个子视图并在这些子视图上使用翻译比直接在画布上绘制位图更有效吗?我会研究一下。谢谢! - Kevin Coppock
1
是的,纹理将被自动缓存。您可以使用adb shell dumpsys gfxinfo com.your.app从命令行查询各种缓存的状态。在您的情况下,使用Views更有效,因为您经常移动位图。我们使用Views检测到这种情况,而不是再次调用draw()方法,我们只是在渲染器内部设置本机属性。这几乎是免费的。 - Romain Guy

1
你可以使用Android的OpenGL ES跟踪器来查看您的视图是否存在OpenGL命令问题。
来自developer.android.com

跟踪器是一种用于分析Android应用程序中OpenGL嵌入式系统(ES)代码的工具。该工具允许您捕获OpenGL ES命令和逐帧图像,以帮助您了解如何执行您的图形命令。

还有一篇由Romain Guy撰写的Android性能研究教程,几乎逐步描述了其使用方法。

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接