8

So I'm trying to understand how I can properly use hardware acceleration (when available) in a custom View that is persistently animating. This is the basic premise of my 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);

I'm enabling hardware layers in onAttachedToWindow() and disabling them in onDetachedFromWindow(), but I'm trying to understand whether or not I'm actually using it. Essentially, the i/j loop that calls drawBitmap() never changes; the only thing that changes is the Canvas translation. Is the Bitmap automatically saved to the GPU as a texture behind the scenes, or is there something I need to do manually to do so?

Kevin Coppock
  • 133,643
  • 45
  • 263
  • 274
  • I might have misunderstood the question but have you set `setLayerType(View.LAYER_TYPE_HARDWARE, null);` for your view? The GPU Caches the images only as long as the user is actively scrolling but does not otherwise, as a tradeoff for consuming lesser resources. – Vrashabh Irde Jun 28 '13 at 11:24
  • @Slartibartfast Yeah, I've set the layer type to hardware. The user will never actually be scrolling; the view is scrolling its own contents continuously. I might be misunderstanding HW Acceleration, but I feel like that grid of bitmaps I'm drawing should be able to be rendered into a hardware layer and just translated rather than redrawing the bitmaps on every frame. – Kevin Coppock Jun 28 '13 at 16:25

2 Answers2

8

On what view(s) are you setting View.LAYER_TYPE_HARDWARE exactly? If you are setting a hardware layer on the view that contains the drawing code shown above, you are causing the system to do a lot more work than necessary. Since you are only drawing bitmaps you don't need to do anything here. If you call Canvas.drawBitmap() the framework will cache the resulting OpenGL texture on your behalf.

You could however optimize your code a little more. Instead of calling drawBitmap(), you could use child views. If you move these children using the offset*() methods (or setX()/setY()) the framework will apply further optimizations to avoid calling the draw() methods again.

In general, hardware layers should be set on views that are expensive to draw and whose content won't change often (so pretty much the opposite of what you're doing :)

Romain Guy
  • 97,993
  • 18
  • 219
  • 200
  • Thanks @RomainGuy. I was setting `LAYER_TYPE_HARDWARE` on the `View` shown above. So the texture will automatically be cached? That's what I was looking for. So you're saying it's actually more efficient to add two child views and use translations on those child views, rather than draw the bitmaps on the canvas directly? I'll look into that. Thanks! – Kevin Coppock Jul 01 '13 at 22:44
  • 1
    Yes, textures will be automatically cached. You can query the state of the various caches from the command line using adb shell dumpsys gfxinfo com.your.app. It is more efficient to use Views *in your case*, because you are moving the bitmaps a lot. We detect this situation with Views and instead of calling the draw() methods again, we just set native properties internally in the renderer. It's almost free. – Romain Guy Jul 02 '13 at 01:21
1

You can use Android's Tracer for OpenGL ES to see if your view issue OpenGL commands.

From developer.android.com

Tracer is a tool for analyzing OpenGL for Embedded Systems (ES) code in your Android application. The tool allows you to capture OpenGL ES commands and frame by frame images to help you understand how your graphics commands are being executed.

There is also a tutorial about Android Performance Study by Romain Guy which describes its use almost step by step.

auselen
  • 27,577
  • 7
  • 73
  • 114