0

Our applications need double buffering semantics e.g. when drawing a line in one paint operation the line should still be there the next time around (no wipe, use same buffer). This works very well for us with SurfaceView, lock etc.

However those cannot be hardware accelerated and we feel we might be missing out on some performance on some Android devices.

When running on iOS we use OpenGL and retained backing mode which prevents the OS from wiping the display on every redraw. I was hoping Android has something similar that will prevent an invalidate call from wiping the elements previously drawn on the screen but I could find no such option other than creating a Bitmap.

Drawing to a Bitmap would also be an option (that's what we do today), but then how do we leverage the hardware acceleration here?

Community
  • 1
  • 1
Shai Almog
  • 51,749
  • 5
  • 35
  • 65
  • OpenGLES is the safest way in the search for hardware acceleration. And I may be horribly wrong, but I think double buffering is enabled by default and it has nothing to do with what you describe. To preserve drawn shapes among frames, not calling glClear() in onDrawFrame should be enough(?) – foibs Jan 22 '14 at 20:58
  • Thanks but I'm not interested in porting the code to OpenGL, there is a lot of code and OGL isn't the best fit for this type of code (a lot of text etc.). We use OGL on iOS so I'm well aware of the pain I would be facing. – Shai Almog Jan 23 '14 at 05:04
  • Double buffering is all about preventing screen flicker caused by applications that _do_ need to clear the screen and draw every frame from scratch. You are asking for the screen _not_ to be wiped, but on the other hand you say you "need double buffering". That sounds contradictory; I'd say disable double buffering altogether and you should be good. Did I misunderstand the question, or am I missing something about Android that's different from the mobile platform that I used to work on years ago? – Ruud Helderman Jan 29 '14 at 08:18
  • Keyword in my question above: semantics... We need the semantics not the double buffering itself. – Shai Almog Jan 29 '14 at 12:28

3 Answers3

1

We had a similar challenge with the Androidplot library as we ruled out SurfaceView as a legitimate solution due to issues with displaying 2 or more SurfaceViews at once. We ended up creating our own BufferedCanvas implementation which is really nothing more than a ping pong buffer that uses Bitmaps.

As far as hardware acceleration goes, it should be enabled by default and from (what I understand) code should "just work" as long as you aren't using any unsupported drawing operations. You'll notice that the code linked above has to explicitly disable acceleration for this reason.

Nick
  • 8,181
  • 4
  • 38
  • 63
  • Thanks, unfortunately as far as I understand drawing to the bitmaps will use the CPU so only the blit portion will be hardware accelerated. This might not be bad for some use case but I hope there is something faster. – Shai Almog Jan 22 '14 at 20:49
  • Gotcha. FWIW you may be able to rule out hw acceleration for the render phase depending on which draw methods you use. As I understand it, if you use rely on any of them you'll either need to remove them or disable acceleration. For example if you use clipRect and want to support anything before API 18, you cant use it. It's not a solution to the question but maybe it makes things simpler – Nick Jan 22 '14 at 21:01
  • Edit to above: "...any of them.." translates to "...any unsupported drawing operations..." – Nick Jan 22 '14 at 22:07
  • The goal is to have hardware acceleration and use it to its full extent. As far as I understand most double buffering strategies effectively disable hardware acceleration. – Shai Almog Jan 23 '14 at 11:42
1

Don't draw to a Bitmap, stick with OpenGL and use a framebuffer object (FBO).

Reuben Scratton
  • 38,595
  • 9
  • 77
  • 86
  • Thanks, but I'm not building a game. A lot of the work I need to do is text drawing and while its possible to do in OGL (we do that on iOS) this sucks. OGL by default (on iOS) doesn't clear the screen but doesn't preserve it either, its a bit off topic though. I'm not sure what the situation is for Android but going the open GL route is not something I'm considering. – Shai Almog Jan 23 '14 at 05:02
  • Where did I say anything about games? You said you use OpenGL on your iOS version so presumably OpenGL on your Android version is extremely feasible since it's the exact same API. – Reuben Scratton Jan 23 '14 at 09:35
  • You can still draw text to a bitmap then render the bitmap to an FBO. I'm assuming the whole point is to reduce all the expensive per-frame text rendering (which presumably doesn't change per-frame) down to a single blit from an offscreen buffer. – Reuben Scratton Jan 23 '14 at 09:37
  • On iOS we use OpenGL since its the only option to do any performant graphics there. Its not an idea approach by a long shot. The iOS code relies on kEAGLDrawablePropertyRetainedBacking which isn't ideal either. – Shai Almog Jan 23 '14 at 11:44
0

It seems that this isn't doable in quite the same way as a double buffering approach.

What I ended up doing is use the postInvalidate(int, int, int, int) method and build a task queue to draw the elements that have changed. The thing that was really problematic for me was the fact that Android kept deleting the screen, this was actually because we didn't invoke activity.getWindow().setBackgroundDrawable(null); which we didn't feel with software rendering but causes screen wipes in hardware accelerated rendering.

Shai Almog
  • 51,749
  • 5
  • 35
  • 65
  • Just so that I understand properly (because I am potentially facing a similar situation), is it true to say that if drawing calls are made on a `Canvas` that is backed using a buffer `Bitmap`, then hardware acceleration does NOT assist in translating from drawing operations to pixels on the bitmap? Is this the reason why using a buffer `Bitmap` is being avoided in your situation? (To put this another way, is it the case that the only `Canvas` that will return `true` from `isHardwareAccelerated()` is the one supplied within the `onDraw()` of a `View`?) – Trevor Jan 27 '14 at 18:19
  • As far as I understand that is the case. It might be possible to get a hardware accelerated canvas in a different way but I could find no way to get a hardware accelerated canvas pointing at a bitmap which makes sense with my personal experience with OpenGL. – Shai Almog Jan 27 '14 at 18:27