Skip to content

Commit

Permalink
Add workaround for AOSP bug with decoding single channel hardware gai…
Browse files Browse the repository at this point in the history
…nmaps using BitmapFactory.

Android U devices that use skiagl for hwui renderering (currently the vast majority) have a bug
where uplading single channel bitmaps to hardware bitmaps fails. This bug essentially breaks
single channel gainmap rendering using hardware bitmaps, which is a common use case on devices
that have Ultra HDR as the default capture format.

The workaround is as follows:
1. Detect the presence of the bug by attempting to copy a 1x1 single channel bitmap to hardware.
2. Memoize the result
3. For BitmapFactory.decode* calls, if the input bitmap has a gainmap, copy it to a three-channel
gainmap. This step seems wasteful, but in practice, the Android OS already does some copying when
creating hardware bitmaps. Also, more importantly, there is an AOSP fix for this bug, and as
devices are updated with this fix, this flow will no longer be exercised.
  • Loading branch information
falhassen committed Jan 26, 2024
1 parent e77562a commit 32ef712
Show file tree
Hide file tree
Showing 4 changed files with 352 additions and 19 deletions.
14 changes: 14 additions & 0 deletions library/src/main/java/com/bumptech/glide/GlideBuilder.java
Original file line number Diff line number Diff line change
Expand Up @@ -499,6 +499,17 @@ public GlideBuilder setPreserveGainmapAndColorSpaceForTransformations(boolean is
return this;
}

/**
* Fixes decoding of hardware gainmaps from Ultra HDR images on Android U.
*
* <p>Without this flag on, gainmaps may be dropped when decoding Ultra HDR on Android U devices
* using skiagl for hwui..
*/
public GlideBuilder setEnableHardwareGainmapFixOnU(boolean isEnabled) {
glideExperimentsBuilder.update(new EnableHardwareGainmapFixOnU(), isEnabled);
return this;
}

/**
* @deprecated This method does nothing. It will be hard coded and removed in a future release
* without further warning.
Expand Down Expand Up @@ -618,6 +629,9 @@ static final class ManualOverrideHardwareBitmapMaxFdCount implements Experiment
*/
static final class PreserveGainmapAndColorSpaceForTransformations implements Experiment {}

/** Fixes decoding of hardware gainmaps from Ultra HDR images on Android U. */
static final class EnableHardwareGainmapFixOnU implements Experiment {}

static final class EnableImageDecoderForBitmaps implements Experiment {}

/** See {@link #setLogRequestOrigins(boolean)}. */
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@
import android.os.ParcelFileDescriptor;
import androidx.annotation.Nullable;
import androidx.tracing.Trace;
import com.bumptech.glide.GlideBuilder.EnableHardwareGainmapFixOnU;
import com.bumptech.glide.GlideBuilder.EnableImageDecoderForBitmaps;
import com.bumptech.glide.GlideBuilder.PreserveGainmapAndColorSpaceForTransformations;
import com.bumptech.glide.gifdecoder.GifDecoder;
Expand Down Expand Up @@ -160,7 +161,8 @@ private static void initializeDefaults(
resources.getDisplayMetrics(),
bitmapPool,
arrayPool,
experiments.isEnabled(PreserveGainmapAndColorSpaceForTransformations.class));
experiments.isEnabled(PreserveGainmapAndColorSpaceForTransformations.class),
experiments.isEnabled(EnableHardwareGainmapFixOnU.class));

ResourceDecoder<ByteBuffer, Bitmap> byteBufferBitmapDecoder;
ResourceDecoder<InputStream, Bitmap> streamBitmapDecoder;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -65,6 +65,7 @@ public final class Downsampler {
*/
public static final Option<PreferredColorSpace> PREFERRED_COLOR_SPACE =
Option.memory("com.bumptech.glide.load.resource.bitmap.Downsampler.PreferredColorSpace");

/**
* Indicates the {@link com.bumptech.glide.load.resource.bitmap.DownsampleStrategy} option that
* will be used to calculate the sample size to use to downsample an image given the original and
Expand All @@ -74,6 +75,7 @@ public final class Downsampler {
*/
@Deprecated
public static final Option<DownsampleStrategy> DOWNSAMPLE_STRATEGY = DownsampleStrategy.OPTION;

/**
* Ensure that the size of the bitmap is fixed to the requested width and height of the resource
* from the caller. The final resource dimensions may differ from the requested width and height,
Expand Down Expand Up @@ -140,6 +142,7 @@ public void onDecodeComplete(BitmapPool bitmapPool, Bitmap downsampled) {
private final List<ImageHeaderParser> parsers;
private final HardwareConfigState hardwareConfigState = HardwareConfigState.getInstance();
private final boolean preserveGainmapAndColorSpaceForTransformations;
private final boolean enableHardwareGainmapFixOnU;

public Downsampler(
List<ImageHeaderParser> parsers,
Expand All @@ -151,7 +154,8 @@ public Downsampler(
displayMetrics,
bitmapPool,
byteArrayPool,
/* preserveGainmapAndColorSpaceForTransformations= */ false);
/* preserveGainmapAndColorSpaceForTransformations= */ false,
/* enableHardwareGainmapFixOnU= */ false);
}

/**
Expand All @@ -165,13 +169,37 @@ public Downsampler(
BitmapPool bitmapPool,
ArrayPool byteArrayPool,
boolean preserveGainmapAndColorSpaceForTransformations) {
this(
parsers,
displayMetrics,
bitmapPool,
byteArrayPool,
preserveGainmapAndColorSpaceForTransformations,
/* enableHardwareGainmapFixOnU= */ false);
}

/**
* @param preserveGainmapAndColorSpaceForTransformations Preserves gainmap and color space for
* transformation, e.g., the color space of wide gamut images or the gainmap of Ultra HDR
* images.
* @param enableHardwareGainmapFixOnU Fixes issues with hardware gainmaps on U.
*/
public Downsampler(
List<ImageHeaderParser> parsers,
DisplayMetrics displayMetrics,
BitmapPool bitmapPool,
ArrayPool byteArrayPool,
boolean preserveGainmapAndColorSpaceForTransformations,
boolean enableHardwareGainmapFixOnU) {
this.parsers = parsers;
this.displayMetrics = Preconditions.checkNotNull(displayMetrics);
this.bitmapPool = Preconditions.checkNotNull(bitmapPool);
this.byteArrayPool = Preconditions.checkNotNull(byteArrayPool);
this.preserveGainmapAndColorSpaceForTransformations =
preserveGainmapAndColorSpaceForTransformations;
this.enableHardwareGainmapFixOnU = enableHardwareGainmapFixOnU;
}

public boolean handles(@SuppressWarnings("unused") InputStream is) {
// We expect Downsampler to handle any available type Android supports.
return true;
Expand Down Expand Up @@ -206,7 +234,8 @@ public Resource<Bitmap> decode(
ByteBuffer buffer, int requestedWidth, int requestedHeight, Options options)
throws IOException {
return decode(
new ImageReader.ByteBufferReader(buffer, parsers, byteArrayPool),
new ImageReader.ByteBufferReader(
buffer, parsers, byteArrayPool, enableHardwareGainmapFixOnU),
requestedWidth,
requestedHeight,
options,
Expand Down Expand Up @@ -241,7 +270,8 @@ public Resource<Bitmap> decode(
DecodeCallbacks callbacks)
throws IOException {
return decode(
new ImageReader.InputStreamImageReader(is, parsers, byteArrayPool),
new ImageReader.InputStreamImageReader(
is, parsers, byteArrayPool, enableHardwareGainmapFixOnU),
requestedWidth,
requestedHeight,
options,
Expand All @@ -252,7 +282,7 @@ public Resource<Bitmap> decode(
void decode(byte[] bytes, int requestedWidth, int requestedHeight, Options options)
throws IOException {
decode(
new ImageReader.ByteArrayReader(bytes, parsers, byteArrayPool),
new ImageReader.ByteArrayReader(bytes, parsers, byteArrayPool, enableHardwareGainmapFixOnU),
requestedWidth,
requestedHeight,
options,
Expand All @@ -263,7 +293,7 @@ void decode(byte[] bytes, int requestedWidth, int requestedHeight, Options optio
void decode(File file, int requestedWidth, int requestedHeight, Options options)
throws IOException {
decode(
new ImageReader.FileReader(file, parsers, byteArrayPool),
new ImageReader.FileReader(file, parsers, byteArrayPool, enableHardwareGainmapFixOnU),
requestedWidth,
requestedHeight,
options,
Expand All @@ -276,7 +306,7 @@ public Resource<Bitmap> decode(
throws IOException {
return decode(
new ImageReader.ParcelFileDescriptorImageReader(
parcelFileDescriptor, parsers, byteArrayPool),
parcelFileDescriptor, parsers, byteArrayPool, enableHardwareGainmapFixOnU),
outWidth,
outHeight,
options,
Expand Down
Loading

0 comments on commit 32ef712

Please sign in to comment.