Skip to content

Commit

Permalink
Updated API for enabling hardware Bitmaps.
Browse files Browse the repository at this point in the history
  • Loading branch information
sjudd committed Jul 23, 2021
1 parent 6e3f870 commit 7d1717b
Showing 1 changed file with 87 additions and 2 deletions.
89 changes: 87 additions & 2 deletions _posts/2018-02-11-hardwarebitmaps.md
Expand Up @@ -19,9 +19,16 @@ Only one copy of pixel data is stored for hardware `Bitmaps`. Normally there’s
* Hardware `Bitmaps` avoid jank caused by texture uploads at draw time.

### How do we enable hardware Bitmaps?
Temporarily, set the default [`DecodeFormat`][1] to [`DecodeFormat.PREFER_ARGB_8888`][2] 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][4].

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.
For now, you need to set an explicit `RequestOption` to enable hardware Bitmaps:

```java
new RequestOption().set(Downsampler.ALLOW_HARDWARE_CONFIG, true);
```

Sadly we're finding a number of cases where using Hardware Bitmaps leads to crashes on some devices. I'd only recommend default enabling hardware Bitmaps on Android 9 (API 28) or higher.

In the long run we hope that 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()`][5]:
Expand Down Expand Up @@ -83,6 +90,84 @@ java.lang.IllegalStateException: Software rendering doesn't support hardware bit
[snip]
```

* Low FD Limits on some devices on Android O

```
Cause: null pointer dereference
x0 0000007c09c1e4c0 x1 000000000000060a x2 0000000070071de8 x3 0000000000000000
x4 0000000000000000 x5 00000000ffffffff x6 00000000ffffffff x7 0000007bca0a7100
x8 0000007bca2bf6c0 x9 0000007c19510000 x10 0000007c19510000 x11 0000007bcaf25300
x12 0000000000000000 x13 000000000000004e x14 0000000000000000 x15 0000007c09c02c90
x16 0000007c183e0cb0 x17 0000007c1837d740 x18 0000000000000000 x19 0000000000000000
x20 0000007c09c1e4c0 x21 00000000ffffffff x22 0000000000000000 x23 0000000000000000
x24 0000000000000002 x25 0000000000000000 x26 0000007bca0a85b0 x27 0000000000000000
x28 0000000000000000 x29 0000007bca0a8470 x30 0000007c19340a60
sp 0000007bca0a8410 pc 0000007c19340a80 pstate 0000000060000000
backtrace:
#00 pc 0000000000177a80 /system/lib64/libandroid_runtime.so (_ZN7android6bitmap12createBitmapEP7_JNIEnvPNS_6BitmapEiP11_jbyteArrayP8_jobjecti+96)
#01 pc 000000000017da60 /system/lib64/libandroid_runtime.so (_ZL8doDecodeP7_JNIEnvP18SkStreamRewindableP8_jobjectS4_+4640)
#02 pc 0000000000bc6c30 /system/framework/arm64/boot-framework.oat (offset 0x692000) (android.graphics.BitmapFactory.nativeDecodeStream [DEDUPED]+256)
#03 pc 0000000000bc6520 /system/framework/arm64/boot-framework.oat (offset 0x692000) (android.graphics.BitmapFactory.decodeStream+272)
#04 pc 000000000052e638 /system/lib64/libart.so (art_quick_invoke_static_stub+600)
#05 pc 00000000000d86e4 /system/lib64/libart.so (_ZN3art9ArtMethod6InvokeEPNS_6ThreadEPjjPNS_6JValueEPKc+260)
#06 pc 0000000000291710 /system/lib64/libart.so
```

* NPE on O/OMR1 in RenderThread

This might be caused by a race between the render of the first frame and the first hardware bitmap decode. If the hardware bitmap decode wins, we NPE. Unfortunately attempts to force Glide to wait to use hardware bitmaps until after a frame has been rendered haven't eliminated this issue. Either the implementation in Glide is missing some number of cases or there's some other issue on O that produces a similar stack trace.

```
pid: 16455, tid: 16504, name: RenderThread >>> com.google.android.apps.photos <<<
signal 11 (SIGSEGV), code 1 (SEGV_MAPERR), fault addr 0x4
Cause: null pointer dereference
backtrace:
#00 pc 003ec6dc /vendor/lib/egl/libGLES_mali.so (cobj_instance_retain+8)
#01 pc 003b0b28 /vendor/lib/egl/libGLES_mali.so (egl_get_egl_image_template_gles+156)
#02 pc 00389a08 /vendor/lib/egl/libGLES_mali.so (gles_texture_egl_image_target_texture_2d_oes+216)
#03 pc 00035a05 /system/lib/libhwui.so (android::uirenderer::debug::GlesErrorCheckWrapper::glEGLImageTargetTexture2DOES_(unsigned int, void*)+12)
#04 pc 0004cb77 /system/lib/libhwui.so (android::uirenderer::renderthread::OpenGLPipeline::uploadBitmapToGraphicBuffer(android::uirenderer::Caches&, SkBitmap&, android::GraphicBuffer&, int, int)+114)
#05 pc 0004cf49 /system/lib/libhwui.so (android::uirenderer::renderthread::OpenGLPipeline::allocateHardwareBitmap(android::uirenderer::renderthread::RenderThread&, SkBitmap&)+496)
#06 pc 0005284f /system/lib/libhwui.so (android::uirenderer::renderthread::RenderThread::allocateHardwareBitmap(SkBitmap&)+30)
#07 pc 0005131d /system/lib/libhwui.so (android::uirenderer::renderthread::Bridge_allocateHardwareBitmap(android::uirenderer::renderthread::allocateHardwareBitmapArgs*)+20)
#08 pc 00051533 /system/lib/libhwui.so (android::uirenderer::renderthread::MethodInvokeRenderTask::run()+10)
#09 pc 000516b3 /system/lib/libhwui.so (android::uirenderer::renderthread::SignalingRenderTask::run()+10)
#10 pc 00052403 /system/lib/libhwui.so (android::uirenderer::renderthread::RenderThread::threadLoop()+178)
#11 pc 0000d1e9 /system/lib/libutils.so (android::Thread::_threadLoop(void*)+144)
#12 pc 00071681 /system/lib/libandroid_runtime.so (android::AndroidRuntime::javaThreadShell(void*)+80)
#13 pc 00049107 /system/lib/libc.so (__pthread_start(void*)+22)
#14 pc 0001b055 /system/lib/libc.so (__start_thread+32)
```

Another trace that might be from the same cause:

```
pid: 1610, tid: 1683, name: RenderThread >>> com.google.android.apps.photos <<<
signal 6 (SIGABRT), code -6 (SI_TKILL), fault addr --------
Abort message: 'glTexSubImage2D error! GL_INVALID_OPERATION (0x502)'
r0 00000000 r1 00000693 r2 00000006 r3 00000008
r4 0000064a r5 00000693 r6 93b752b4 r7 0000010c
r8 00000000 r9 ae9708b4 sl ae970880 fp ae9708b4
ip ae970854 sp 93b752a0 lr b043f87d pc b04393ce cpsr 20000030
backtrace:
#00 pc 0001a3ce /system/lib/libc.so (abort+63)
#01 pc 0000655d /system/lib/liblog.so (__android_log_assert+156)
#02 pc 00031851 /system/lib/libhwui.so (android::uirenderer::debug::GlesErrorCheckWrapper::assertNoErrors(char const*)+192)
#03 pc 0002f271 /system/lib/libhwui.so (wrap_glTexSubImage2D(unsigned int, int, int, int, int, int, unsigned int, unsigned int, void const*)+52)
#04 pc 000547c7 /system/lib/libhwui.so (android::uirenderer::renderthread::OpenGLPipeline::allocateHardwareBitmap(android::uirenderer::renderthread::RenderThread&, SkBitmap&)+634)
#05 pc 0005b0bf /system/lib/libhwui.so (android::uirenderer::renderthread::RenderThread::allocateHardwareBitmap(SkBitmap&)+30)
#06 pc 00059a89 /system/lib/libhwui.so (android::uirenderer::renderthread::Bridge_allocateHardwareBitmap(android::uirenderer::renderthread::allocateHardwareBitmapArgs*)+20)
#07 pc 00059c9b /system/lib/libhwui.so (android::uirenderer::renderthread::MethodInvokeRenderTask::run()+10)
#08 pc 00059e1b /system/lib/libhwui.so (android::uirenderer::renderthread::SignalingRenderTask::run()+10)
#09 pc 0005ac73 /system/lib/libhwui.so (android::uirenderer::renderthread::RenderThread::threadLoop()+178)
#10 pc 0000d1c9 /system/lib/libutils.so (android::Thread::_threadLoop(void*)+144)
#11 pc 0006eef9 /system/lib/libandroid_runtime.so (android::AndroidRuntime::javaThreadShell(void*)+80)
#12 pc 000475bf /system/lib/libc.so (__pthread_start(void*)+22)
#13 pc 0001af35 /system/lib/libc.so (__start_thread+32)
```

### 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`][7].
* [Bitmap#copy](https://developer.android.com/reference/android/graphics/Bitmap.html#copy(android.graphics.Bitmap.Config, boolean))
Expand Down

0 comments on commit 7d1717b

Please sign in to comment.