Picasso: Use Bitmap#prepareToDraw to upload Bitmaps to GPU in advance

Created on 8 May 2017  Â·  5Comments  Â·  Source: square/picasso

Hey, I work on UI Toolkit Graphics in Android. Wanted to pass on an optimization you can enable for displaying Bitmaps.

Android displays Bitmaps as OpenGL textures, and the first time a Bitmap is displayed in a frame, it’s uploaded to the GPU. That can take several milliseconds, but it’s necessary to display the image with the GPU.

In Android N, we added behavior to Bitmap#prepareToDraw() to send an async message to RenderThread to pre-upload. RenderThread uploads these to the GPU when it expects to be idle between frames, instead of while drawing the first frame that uses the Bitmap. If you can do this after decoding, you can make it much less likely that frames are dropped due to uploading.

In Systrace, you can see the problem by looking for sections labeled ‘Upload \

The drawback is that if you call it on a bitmap before you modify it, or if it doesn’t get drawn, you’ll be wasting the time spent uploading. If you’re reasonably sure the Bitmap in question will be displayed, it’s still a great way to prefetch the upload work on RenderThread.

Behavior added in Android N:
https://android.googlesource.com/platform/frameworks/base/+/4387190d8ec9fe4e953fcfeb093a644b82cf85ed

For reference, Glide implemented this here: https://github.com/bumptech/glide/commit/dce95506f138bd877aaed1183958f5e186a2bf

It's safe to call on older versions, so you don't need a version check. The method existed prior to N, but was a noop for normal Bitmaps.

Most helpful comment

If you're not already calling prepareToDraw for every Bitmap fetch, then yes - that's a good way to schedule both your Bitmap fetches and uploads early. You may get by with just calling prepareToDraw with every Bitmap fetch (either once decoded, or immediately when cached). It depends on what portion of the time Bitmaps are fetched, but not displayed immediately.

Any time a Bitmap has prepareToDraw called, but isn't displayed, it's either evicting other Bitmaps from the OpenGL LRU Bitmap cache, or is creating temporarily wasted (capped) graphics memory in that same cache.

All 5 comments

Very cool. Thanks for the heads up!

On Mon, May 8, 2017 at 5:51 PM Chris Craik notifications@github.com wrote:

Hey, I work on UI Toolkit Graphics in Android. Wanted to pass on an
optimization you can enable for displaying Bitmaps.

Android displays Bitmaps as OpenGL textures, and the first time a Bitmap
is displayed in a frame, it’s uploaded to the GPU. That can take several
milliseconds, but it’s necessary to display the image with the GPU.

In Android N, we added behavior to Bitmap#prepareToDraw() to send an async
message to RenderThread to pre-upload. RenderThread uploads these to the
GPU when it expects to be idle between frames, instead of while drawing the
first frame that uses the Bitmap. If you can do this after decoding, you
can make it much less likely that frames are dropped due to uploading.

In Systrace, you can see the problem by looking for sections labeled
‘Upload x Texture’. If those are happening in ‘DrawFrame’ on the
RenderThread, inside ‘syncFrameState,’ they haven’t been pre-uploaded, and
are on the critical path.

The drawback is that if you call it on a bitmap before you modify it, or
if it doesn’t get drawn, you’ll be wasting the time spent uploading. If
you’re reasonably sure the Bitmap in question will be displayed, it’s still
a great way to prefetch the upload work on RenderThread.

Behavior added in Android N:

https://android.googlesource.com/platform/frameworks/base/+/4387190d8ec9fe4e953fcfeb093a644b82cf85ed

For reference, Glide implemented this here: bumptech/glide@dce9550
https://github.com/bumptech/glide/commit/dce95506f138bd877aaed1183958f5e186a2bf

It's safe to call on older versions, so you don't need a version check.
The method existed prior to N, but was a noop for normal Bitmaps.

—
You are receiving this because you are subscribed to this thread.
Reply to this email directly, view it on GitHub
https://github.com/square/picasso/issues/1620, or mute the thread
https://github.com/notifications/unsubscribe-auth/AAEEEYBVtgDulbZKN1r_WPCuoq1PC4HUks5r345cgaJpZM4NUi72
.

@ChrisCraik What would be your advise for using this in conjunction with RecyclerView? Pre-loading by listening to scroll like this Glide sample?

https://github.com/bumptech/glide/blob/master/integration/recyclerview/src/main/java/com/bumptech/glide/integration/recyclerview/RecyclerViewPreloader.java

If you're not already calling prepareToDraw for every Bitmap fetch, then yes - that's a good way to schedule both your Bitmap fetches and uploads early. You may get by with just calling prepareToDraw with every Bitmap fetch (either once decoded, or immediately when cached). It depends on what portion of the time Bitmaps are fetched, but not displayed immediately.

Any time a Bitmap has prepareToDraw called, but isn't displayed, it's either evicting other Bitmaps from the OpenGL LRU Bitmap cache, or is creating temporarily wasted (capped) graphics memory in that same cache.

Uploads should show up on RenderThread as the same, outside of the frame
drawing sections ("DrawFrame" / "doFrame"). Likely right after "DrawFrame".

You can see the systrace screenshot that the Fresco folks added to the
issue I filed there: https://github.com/facebook/fresco/issues/1756

On Wed, May 31, 2017 at 5:30 PM, Christopher Perry <[email protected]

wrote:

@ChrisCraik https://github.com/chriscraik Where do the preloads to the
GPU show up in systrace?

—
You are receiving this because you were mentioned.
Reply to this email directly, view it on GitHub
https://github.com/square/picasso/issues/1620#issuecomment-305355465,
or mute the thread
https://github.com/notifications/unsubscribe-auth/AAXdtx2YAtsWX44i4XBQQoArXnNVCIweks5r_gYggaJpZM4NUi72
.

@ChrisCraik Thanks, I was able to do the same.

Was this page helpful?
0 / 5 - 0 ratings

Related issues

JakeWharton picture JakeWharton  Â·  7Comments

ghost picture ghost  Â·  5Comments

paatz04 picture paatz04  Â·  6Comments

pablojacobi picture pablojacobi  Â·  6Comments

virl picture virl  Â·  7Comments