Add API to allow overriding a gainmap in BitmapShader
Fixes: 296482289
Test: atest android.uirendering.cts.testclasses.GainmapTests -- --template:map preparers=template/preparers/feature-flags --flag-value core_graphics/com.android.graphics.hwui.flags.gainmap_animations=true
Change-Id: I1984a625ff3740e8fffd4d1ffc6f16132dfc6788
diff --git a/core/api/current.txt b/core/api/current.txt
index d48685b..2cafc5b 100644
--- a/core/api/current.txt
+++ b/core/api/current.txt
@@ -15222,6 +15222,7 @@
method public int getMaxAnisotropy();
method public void setFilterMode(int);
method public void setMaxAnisotropy(@IntRange(from=1) int);
+ method @FlaggedApi("com.android.graphics.hwui.flags.gainmap_animations") public void setOverrideGainmap(@Nullable android.graphics.Gainmap);
field public static final int FILTER_MODE_DEFAULT = 0; // 0x0
field public static final int FILTER_MODE_LINEAR = 2; // 0x2
field public static final int FILTER_MODE_NEAREST = 1; // 0x1
diff --git a/graphics/java/android/graphics/BitmapShader.java b/graphics/java/android/graphics/BitmapShader.java
index 5c06577..dcfff62 100644
--- a/graphics/java/android/graphics/BitmapShader.java
+++ b/graphics/java/android/graphics/BitmapShader.java
@@ -16,9 +16,13 @@
package android.graphics;
+import android.annotation.FlaggedApi;
import android.annotation.IntDef;
import android.annotation.IntRange;
import android.annotation.NonNull;
+import android.annotation.Nullable;
+
+import com.android.graphics.hwui.flags.Flags;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
@@ -32,6 +36,7 @@
* Prevent garbage collection.
*/
/*package*/ Bitmap mBitmap;
+ private Gainmap mOverrideGainmap;
private int mTileX;
private int mTileY;
@@ -173,6 +178,24 @@
}
/**
+ * Draws the BitmapShader with a copy of the given gainmap instead of the gainmap on the Bitmap
+ * the shader was constructed from
+ *
+ * @param overrideGainmap The gainmap to draw instead, null to use any gainmap on the Bitmap
+ */
+ @FlaggedApi(Flags.FLAG_GAINMAP_ANIMATIONS)
+ public void setOverrideGainmap(@Nullable Gainmap overrideGainmap) {
+ if (!Flags.gainmapAnimations()) throw new IllegalStateException("API not available");
+
+ if (overrideGainmap == null) {
+ mOverrideGainmap = null;
+ } else {
+ mOverrideGainmap = new Gainmap(overrideGainmap, overrideGainmap.getGainmapContents());
+ }
+ discardNativeInstance();
+ }
+
+ /**
* Returns the current max anisotropic filtering value configured by
* {@link #setFilterMode(int)}. If {@link #setFilterMode(int)} is invoked this returns zero.
*/
@@ -199,14 +222,9 @@
mIsDirectSampled = mRequestDirectSampling;
mRequestDirectSampling = false;
-
- if (mMaxAniso > 0) {
- return nativeCreateWithMaxAniso(nativeMatrix, mBitmap.getNativeInstance(), mTileX,
- mTileY, mMaxAniso, mIsDirectSampled);
- } else {
- return nativeCreate(nativeMatrix, mBitmap.getNativeInstance(), mTileX, mTileY,
- enableLinearFilter, mIsDirectSampled);
- }
+ return nativeCreate(nativeMatrix, mBitmap.getNativeInstance(), mTileX,
+ mTileY, mMaxAniso, enableLinearFilter, mIsDirectSampled,
+ mOverrideGainmap != null ? mOverrideGainmap.mNativePtr : 0);
}
/** @hide */
@@ -217,9 +235,7 @@
}
private static native long nativeCreate(long nativeMatrix, long bitmapHandle,
- int shaderTileModeX, int shaderTileModeY, boolean filter, boolean isDirectSampled);
-
- private static native long nativeCreateWithMaxAniso(long nativeMatrix, long bitmapHandle,
- int shaderTileModeX, int shaderTileModeY, int maxAniso, boolean isDirectSampled);
+ int shaderTileModeX, int shaderTileModeY, int maxAniso, boolean filter,
+ boolean isDirectSampled, long overrideGainmapHandle);
}
diff --git a/libs/hwui/jni/Shader.cpp b/libs/hwui/jni/Shader.cpp
index 2c13ceb..a952be0 100644
--- a/libs/hwui/jni/Shader.cpp
+++ b/libs/hwui/jni/Shader.cpp
@@ -65,21 +65,41 @@
return static_cast<jlong>(reinterpret_cast<uintptr_t>(&Shader_safeUnref));
}
-static jlong createBitmapShaderHelper(JNIEnv* env, jobject o, jlong matrixPtr, jlong bitmapHandle,
- jint tileModeX, jint tileModeY, bool isDirectSampled,
- const SkSamplingOptions& sampling) {
+///////////////////////////////////////////////////////////////////////////////////////////////
+
+static SkGainmapInfo sNoOpGainmap = {
+ .fGainmapRatioMin = {1.f, 1.f, 1.f, 1.0},
+ .fGainmapRatioMax = {1.f, 1.f, 1.f, 1.0},
+ .fGainmapGamma = {1.f, 1.f, 1.f, 1.f},
+ .fEpsilonSdr = {0.f, 0.f, 0.f, 1.0},
+ .fEpsilonHdr = {0.f, 0.f, 0.f, 1.0},
+ .fDisplayRatioSdr = 1.f,
+ .fDisplayRatioHdr = 1.f,
+};
+
+static jlong BitmapShader_constructor(JNIEnv* env, jobject o, jlong matrixPtr, jlong bitmapHandle,
+ jint tileModeX, jint tileModeY, jint maxAniso, bool filter,
+ bool isDirectSampled, jlong overrideGainmapPtr) {
+ SkSamplingOptions sampling = maxAniso > 0 ? SkSamplingOptions::Aniso(static_cast<int>(maxAniso))
+ : SkSamplingOptions(filter ? SkFilterMode::kLinear
+ : SkFilterMode::kNearest,
+ SkMipmapMode::kNone);
const SkMatrix* matrix = reinterpret_cast<const SkMatrix*>(matrixPtr);
+ const Gainmap* gainmap = reinterpret_cast<Gainmap*>(overrideGainmapPtr);
sk_sp<SkImage> image;
if (bitmapHandle) {
// Only pass a valid SkBitmap object to the constructor if the Bitmap exists. Otherwise,
// we'll pass an empty SkBitmap to avoid crashing/excepting for compatibility.
auto& bitmap = android::bitmap::toBitmap(bitmapHandle);
image = bitmap.makeImage();
+ if (!gainmap && bitmap.hasGainmap()) {
+ gainmap = bitmap.gainmap().get();
+ }
- if (!isDirectSampled && bitmap.hasGainmap()) {
- sk_sp<SkShader> gainmapShader = MakeGainmapShader(
- image, bitmap.gainmap()->bitmap->makeImage(), bitmap.gainmap()->info,
- (SkTileMode)tileModeX, (SkTileMode)tileModeY, sampling);
+ if (!isDirectSampled && gainmap && gainmap->info != sNoOpGainmap) {
+ sk_sp<SkShader> gainmapShader =
+ MakeGainmapShader(image, gainmap->bitmap->makeImage(), gainmap->info,
+ (SkTileMode)tileModeX, (SkTileMode)tileModeY, sampling);
if (gainmapShader) {
if (matrix) {
gainmapShader = gainmapShader->makeWithLocalMatrix(*matrix);
@@ -111,26 +131,6 @@
///////////////////////////////////////////////////////////////////////////////////////////////
-static jlong BitmapShader_constructor(JNIEnv* env, jobject o, jlong matrixPtr, jlong bitmapHandle,
- jint tileModeX, jint tileModeY, bool filter,
- bool isDirectSampled) {
- SkSamplingOptions sampling(filter ? SkFilterMode::kLinear : SkFilterMode::kNearest,
- SkMipmapMode::kNone);
- return createBitmapShaderHelper(env, o, matrixPtr, bitmapHandle, tileModeX, tileModeY,
- isDirectSampled, sampling);
-}
-
-static jlong BitmapShader_constructorWithMaxAniso(JNIEnv* env, jobject o, jlong matrixPtr,
- jlong bitmapHandle, jint tileModeX,
- jint tileModeY, jint maxAniso,
- bool isDirectSampled) {
- auto sampling = SkSamplingOptions::Aniso(static_cast<int>(maxAniso));
- return createBitmapShaderHelper(env, o, matrixPtr, bitmapHandle, tileModeX, tileModeY,
- isDirectSampled, sampling);
-}
-
-///////////////////////////////////////////////////////////////////////////////////////////////
-
static std::vector<SkColor4f> convertColorLongs(JNIEnv* env, jlongArray colorArray) {
const size_t count = env->GetArrayLength(colorArray);
const jlong* colorValues = env->GetLongArrayElements(colorArray, nullptr);
@@ -419,8 +419,7 @@
};
static const JNINativeMethod gBitmapShaderMethods[] = {
- {"nativeCreate", "(JJIIZZ)J", (void*)BitmapShader_constructor},
- {"nativeCreateWithMaxAniso", "(JJIIIZ)J", (void*)BitmapShader_constructorWithMaxAniso},
+ {"nativeCreate", "(JJIIIZZJ)J", (void*)BitmapShader_constructor},
};