Hardware Bitmaps
- What are hardware Bitmaps?
- Why should we use hardware Bitmaps?
- How do we enable hardware Bitmaps?
- How do we disable hardware Bitmaps?
- What’s broken when we use hardware Bitmaps?
- What’s less efficient when we use hardware Bitmaps?
What are hardware Bitmaps?
Bitmap.Config.HARDWARE
is a new Bitmap
format that was added in Android O. Hardware Bitmaps
store pixel data only in graphics memory and are optimal for cases where the Bitmap
is only drawn to the screen.
Why should we use hardware Bitmaps?
Only one copy of pixel data is stored for hardware Bitmaps
. Normally there’s one copy of pixel data in application memory (the pixel byte array) and one copy in graphics memory (after the pixels are uploaded to the GPU). Hardware Bitmaps
retain only the copy uploaded to the GPU. As a result:
- Hardware
Bitmaps
require ½ the memory of other Bitmap configurations - Hardware
Bitmaps
avoid jank caused by texture uploads at draw time.
How do we enable hardware Bitmaps?
Temporarily, set the default DecodeFormat
to DecodeFormat.PREFER_ARGB_8888
in your Glide requests. To do so for all requests in your application, set the DecodeFormat
in the default options in your GlideModule
, see the configuration page.
In the long run Glide will load hardware Bitmaps
by default and no changes will be needed to enable the format, only to disable it.
How do we disable hardware Bitmaps?
If you need to disable hardware Bitmaps
, you should try to do so only for requests where you need to do one of the slow or broken things below. You can disable hardware Bitmaps
for a particular request using disallowHardwareConfig()
.
If you’re using the generated API:
GlideApp.with(fragment)
.load(url)
.disallowHardwareConfig()
.into(imageView);
Or just via RequestOptions
:
RequestOptions options = new RequestOptions().disallowHardwareConfig();
Glide.with(fragment)
.load(url)
.apply(options)
.into(imageView);
What’s broken when we use hardware Bitmaps?
Storing pixel data in graphics memory means that the pixel data isn’t readily accessible, which will cause exceptions in some cases. All of the known cases are listed below:
- Reading/writing pixel data in Java, including:
- Reading/writing pixel data in native code
- Rendering hardware
Bitmaps
with a software Canvas:Canvas canvas = new Canvas(normalBitmap) canvas.drawBitmap(hardwareBitmap, 0, 0, new Paint());
- Using software layer types in views that draw Bitmaps (to draw a shadow for example)
ImageView imageView = … imageView.setImageBitmap(hardwareBitmap); imageView.setLayerType(View.LAYER_TYPE_SOFTWARE, null);
-
Opening too many file descriptors.
Each hardware
Bitmap
consumes a file descriptor. There’s a per process FD limit (O & earlier typically 1024, in some builds of O-MR1 & higher it’s 32k). Glide attempts to limit the number of hardwareBitmaps
allocated to stay under the limit, but if you’re already allocating large numbers of FDs, this may be an issue. - Preconditions that expect
ARGB_8888 Bitmaps
-
Screenshots triggered by code that try to draw the view hierarchy with
Canvas
.PixelCopy
can be used instead on O+. - Shared element transitions (fixed in OMR1)
An example trace will look something like this:
java.lang.IllegalStateException: Software rendering doesn't support hardware bitmaps at android.graphics.BaseCanvas.throwIfHwBitmapInSwMode(BaseCanvas.java:532) at android.graphics.BaseCanvas.throwIfCannotDraw(BaseCanvas.java:62) at android.graphics.BaseCanvas.drawBitmap(BaseCanvas.java:120) at android.graphics.Canvas.drawBitmap(Canvas.java:1434) at android.graphics.drawable.BitmapDrawable.draw(BitmapDrawable.java:529) at android.widget.ImageView.onDraw(ImageView.java:1367) [snip] at android.view.View.draw(View.java:19089) at android.transition.TransitionUtils.createViewBitmap(TransitionUtils.java:168) at android.transition.TransitionUtils.copyViewImage(TransitionUtils.java:102) at android.transition.Visibility.onDisappear(Visibility.java:380) at android.transition.Visibility.createAnimator(Visibility.java:249) at android.transition.Transition.createAnimators(Transition.java:732) at android.transition.TransitionSet.createAnimators(TransitionSet.java:396) [snip]
What’s less efficient when we use hardware Bitmaps?
In some cases to avoid breaking users, the Bitmap
class will perform an expensive copy of the graphics memory. In some cases where any of these methods are used, you should consider avoiding using the hardware Bitmap
configuration to begin with depending on the frequency the slow methods are used. If you do use these methods, the framework will log a message: “Warning attempt to read pixels from hardware bitmap, which is very slow operation”
and also trigger a StrictMode#noteSlowCall
.