📜 ⬆️ ⬇️

Canvas hardware acceleration in Android

Suppose we decided to write a new Android application. Due to design considerations, standard UI components do not suit us and we will draw a lot of graphics via Canvas or OpenGL ES. The latter method is somewhat more laborious, so we will not consider it yet. We are interested in graphics performance on Canvas. Can I speed it up? If you go to the official website of the android or the developers' blog , then you will notice that starting with Android 3.0 (API level 11), the platform now has the ability to enable Canvas hardware acceleration to output 2D graphics.

You might think: “ Super! I’ll add a hardware acceleration flag to my app now! ”. Moreover, some sites claim that the application will work quietly on Android 2.x - such applications will simply ignore the acceleration flag. Other sites say hardware acceleration is enabled by default since Android 4.0. In fact, everything is not so.

And of course, we are interested in the question of how much the application performance will increase when hardware acceleration is enabled.
')
image



The first thing I came across when turning on the hardware acceleration flag is that the application completely refused to start on Android 2.x. "Syntax error. There was a problem analyzing the package. ”At the same time, the application normally starts on Android 3.x.

android:hardwareAccelerated="true" 


Go ahead. In applications with dynamic graphics, as a rule, a loop is created (app / game loop), in which the application logic and drawing graphics are executed. On android, the cycle can be implemented through a timer with a delay of 1 ms with a call to postInvalidate () or for this purpose you can create a new stream. However, as it turned out, Canvas hardware acceleration does not support operation in a separate thread.

 Canvas canvas = surfaceHolder.lockCanvas(); // no hardware acceleration in this case 


Interestingly, how much does the speed increase when you turn on the acceleration? To answer this question, I wrote a simple Android application that draws a 128x128 image on Canvas 100 times in a random place, plus shows FPS . Additionally, the user can choose to draw in the main stream or in the additional stream, and also to enable or disable the setting of the hardware acceleration flag.

First of all, the code was modified so that it could run on Android 2.x. The hardware acceleration flag was removed from AndroidManifest.xml and added to the activity, i.e. we will enable acceleration programmatically by setting the flag FLAG_HARDWARE_ACCELERATED.

  public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); boolean enableAccelerationFlag = getIntent().getExtras() .getBoolean(MainActivity.HW_ENABLED_KEY); if (enableAccelerationFlag) { // Build target in AndroidManifest.xml and/or Eclipse must be 11 or // higher to compile this code. getWindow().setFlags(WindowManager.LayoutParams.FLAG_HARDWARE_ACCELERATED, WindowManager.LayoutParams.FLAG_HARDWARE_ACCELERATED); } setContentView(R.layout.single_thread); surfaceView = (SingleThreadSurfaceView) findViewById(R.id.single_thread_view); // Enable calling onDraw() method that is switched off by default. surfaceView.setWillNotDraw(false); } 


The next block shows how the pictures are being drawn. It also contains a block for Android 3.x or higher with the isHardwareAccelerated () call. This method cannot be called on a lower version, t.ch. check for the operating system version.

  @SuppressLint("NewApi") private void draw(Canvas canvas) { canvas.drawColor(Color.RED); for (int i = 0; i < IMAGES_PER_FRAME; i++) { int x = (int) (Math.random() * (canvas.getWidth() - bitmap.getWidth())); int y = (int) (Math.random() * (canvas.getHeight() - bitmap.getHeight())); canvas.drawBitmap(bitmap, x, y, null); } canvas.drawText("fps=" + fps, 0, 30, paint); boolean isViewAccelerated = false; boolean isCanvasAccelerated = false; if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.HONEYCOMB) { // This code must not be executed on a device with API // level less than 11 (Android 2.x, 1.x) isViewAccelerated = surfaceView.isHardwareAccelerated(); isCanvasAccelerated = canvas.isHardwareAccelerated(); } canvas.drawText("isViewAccelerated=" + isViewAccelerated, 0, 60, paint); canvas.drawText("isCanvasAccelerated=" + isCanvasAccelerated, 0, 75, paint); } 


FPS is calculated quite simply and is called before drawing pictures.

  private void measureFps() { frameCounter++; long now = SystemClock.uptimeMillis(); long delta = now - lastFpsCalcUptime; if (delta > FPS_CALC_INTERVAL) { fps = frameCounter * FPS_CALC_INTERVAL / delta; frameCounter = 0; lastFpsCalcUptime = now; } } 


Below is a summary table of performance testing for 3 available devices and an emulator. The last two columns are the result of executing the isHardwareAccelerated () methods for View and Canvas, respectively.

Platform / DeviceGraphic ModelFPSView sped up?Canvas accelerated?
Android 2.2
Emulator
800x480
1. Main flow, no accelerationfournotnot
2. Additional flow, no acceleration20notnot
Android 2.2.2
HTC Desire
800x480
1. Main flow, no acceleration7notnot
2. Additional flow, no acceleration50notnot
Android 3.2.1
Acer A500
1280x800
1. Main stream, default acceleration20notnot
2. Main stream, acceleration flag set28YesYes
3. Extra flow, default accelerationthirtynotnot
4. Extra flow, acceleration flag setthirtyYesnot
Android 4.0.3
HTC Sensation XE
960x540
1. Main stream, default acceleration26notnot
2. Main stream, acceleration flag set39YesYes
3. Extra flow, default acceleration26notnot
4. Extra flow, acceleration flag set26Yesnot


The results are impressive! Honestly, I did not expect this.
  1. If you need support for Android 2.x, you should use an additional stream for the logic / drawing loop.
  2. Setting the hardware support flag on Android 3.x using the main thread shows the same results as without acceleration, but in an additional stream.
  3. Hardware acceleration is turned off by default on Android 4.x, and shows a significant acceleration of graphics output in the main stream when it is turned on.
  4. The emulator runs 5 times faster when drawing is performed in a separate stream.



The source code of the project is available for download here .
image

Source: https://habr.com/ru/post/147781/


All Articles