summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--core/api/current.txt25
-rw-r--r--core/java/android/hardware/DisplayLuts.java286
-rw-r--r--core/java/android/hardware/LutProperties.java27
-rw-r--r--core/java/android/hardware/OverlayProperties.java7
-rw-r--r--core/java/android/hardware/flags/flags.aconfig (renamed from core/java/android/hardware/flags/overlayproperties_flags.aconfig)9
-rw-r--r--core/java/android/view/SurfaceControl.java29
-rw-r--r--core/jni/android_hardware_OverlayProperties.cpp2
-rw-r--r--core/jni/android_view_SurfaceControl.cpp98
8 files changed, 371 insertions, 112 deletions
diff --git a/core/api/current.txt b/core/api/current.txt
index 8c36a472ba29..674941fbe14a 100644
--- a/core/api/current.txt
+++ b/core/api/current.txt
@@ -18826,6 +18826,19 @@ package android.hardware {
field public static final int TRANSFER_UNSPECIFIED = 0; // 0x0
}
+ @FlaggedApi("android.hardware.flags.luts_api") public final class DisplayLuts {
+ ctor @FlaggedApi("android.hardware.flags.luts_api") public DisplayLuts();
+ method @FlaggedApi("android.hardware.flags.luts_api") public void set(@NonNull android.hardware.DisplayLuts.Entry);
+ method @FlaggedApi("android.hardware.flags.luts_api") public void set(@NonNull android.hardware.DisplayLuts.Entry, @NonNull android.hardware.DisplayLuts.Entry);
+ }
+
+ @FlaggedApi("android.hardware.flags.luts_api") public static class DisplayLuts.Entry {
+ ctor @FlaggedApi("android.hardware.flags.luts_api") public DisplayLuts.Entry(@NonNull float[], int, int);
+ method @FlaggedApi("android.hardware.flags.luts_api") @NonNull public float[] getBuffer();
+ method @FlaggedApi("android.hardware.flags.luts_api") public int getDimension();
+ method @FlaggedApi("android.hardware.flags.luts_api") public int getSamplingKey();
+ }
+
public class GeomagneticField {
ctor public GeomagneticField(float, float, float, long);
method public float getDeclination();
@@ -18887,8 +18900,19 @@ package android.hardware {
field @FlaggedApi("android.media.codec.p210_format_support") public static final int YCBCR_P210 = 60; // 0x3c
}
+ @FlaggedApi("android.hardware.flags.luts_api") public final class LutProperties {
+ method @FlaggedApi("android.hardware.flags.luts_api") public int getDimension();
+ method @FlaggedApi("android.hardware.flags.luts_api") @NonNull public int[] getSamplingKeys();
+ method @FlaggedApi("android.hardware.flags.luts_api") public int getSize();
+ field @FlaggedApi("android.hardware.flags.luts_api") public static final int ONE_DIMENSION = 1; // 0x1
+ field @FlaggedApi("android.hardware.flags.luts_api") public static final int SAMPLING_KEY_MAX_RGB = 1; // 0x1
+ field @FlaggedApi("android.hardware.flags.luts_api") public static final int SAMPLING_KEY_RGB = 0; // 0x0
+ field @FlaggedApi("android.hardware.flags.luts_api") public static final int THREE_DIMENSION = 3; // 0x3
+ }
+
@FlaggedApi("android.hardware.flags.overlayproperties_class_api") public final class OverlayProperties implements android.os.Parcelable {
method @FlaggedApi("android.hardware.flags.overlayproperties_class_api") public int describeContents();
+ method @FlaggedApi("android.hardware.flags.luts_api") @NonNull public android.hardware.LutProperties[] getLutProperties();
method @FlaggedApi("android.hardware.flags.overlayproperties_class_api") public boolean isCombinationSupported(int, int);
method @FlaggedApi("android.hardware.flags.overlayproperties_class_api") public boolean isMixedColorSpacesSupported();
method @FlaggedApi("android.hardware.flags.overlayproperties_class_api") public void writeToParcel(@NonNull android.os.Parcel, int);
@@ -53173,6 +53197,7 @@ package android.view {
method @FlaggedApi("com.android.window.flags.sdk_desired_present_time") @NonNull public android.view.SurfaceControl.Transaction setFrameTimeline(long);
method @Deprecated @NonNull public android.view.SurfaceControl.Transaction setGeometry(@NonNull android.view.SurfaceControl, @Nullable android.graphics.Rect, @Nullable android.graphics.Rect, int);
method @NonNull public android.view.SurfaceControl.Transaction setLayer(@NonNull android.view.SurfaceControl, @IntRange(from=java.lang.Integer.MIN_VALUE, to=java.lang.Integer.MAX_VALUE) int);
+ method @FlaggedApi("android.hardware.flags.luts_api") @NonNull public android.view.SurfaceControl.Transaction setLuts(@NonNull android.view.SurfaceControl, @Nullable android.hardware.DisplayLuts);
method @NonNull public android.view.SurfaceControl.Transaction setOpaque(@NonNull android.view.SurfaceControl, boolean);
method @NonNull public android.view.SurfaceControl.Transaction setPosition(@NonNull android.view.SurfaceControl, float, float);
method @NonNull public android.view.SurfaceControl.Transaction setScale(@NonNull android.view.SurfaceControl, float, float);
diff --git a/core/java/android/hardware/DisplayLuts.java b/core/java/android/hardware/DisplayLuts.java
index b162ad6e2d15..6343ba19f569 100644
--- a/core/java/android/hardware/DisplayLuts.java
+++ b/core/java/android/hardware/DisplayLuts.java
@@ -16,116 +16,294 @@
package android.hardware;
+import android.annotation.FlaggedApi;
import android.annotation.NonNull;
+import android.hardware.flags.Flags;
import android.util.IntArray;
import java.util.ArrayList;
-import java.util.List;
/**
- * @hide
+ * DisplayLuts provides the developers to apply Lookup Tables (Luts) to a
+ * {@link android.view.SurfaceControl}. Luts provides ways to control tonemapping
+ * for specific content.
+ *
+ * The general flow is as follows:
+ * <p>
+ * <img src="{@docRoot}reference/android/images/graphics/DisplayLuts.png" />
+ * <figcaption style="text-align: center;">DisplayLuts flow</figcaption>
+ * </p>
+ *
+ * @see LutProperties
*/
+@FlaggedApi(Flags.FLAG_LUTS_API)
public final class DisplayLuts {
+ private ArrayList<Entry> mEntries;
private IntArray mOffsets;
private int mTotalLength;
- private List<float[]> mLutBuffers;
- private IntArray mLutDimensions;
- private IntArray mLutSizes;
- private IntArray mLutSamplingKeys;
- private static final int LUT_LENGTH_LIMIT = 100000;
-
+ /**
+ * Create a {@link DisplayLuts} instance.
+ */
+ @FlaggedApi(Flags.FLAG_LUTS_API)
public DisplayLuts() {
+ mEntries = new ArrayList<>();
mOffsets = new IntArray();
mTotalLength = 0;
-
- mLutBuffers = new ArrayList<>();
- mLutDimensions = new IntArray();
- mLutSizes = new IntArray();
- mLutSamplingKeys = new IntArray();
}
- /**
- * Add the lut to be applied.
- *
- * @param buffer
- * @param dimension either 1D or 3D
- * @param size
- * @param samplingKey
- */
- public void addLut(@NonNull float[] buffer, @LutProperties.Dimension int dimension,
- int size, @LutProperties.SamplingKey int samplingKey) {
+ @FlaggedApi(Flags.FLAG_LUTS_API)
+ public static class Entry {
+ private float[] mBuffer;
+ private @LutProperties.Dimension int mDimension;
+ private int mSize;
+ private @LutProperties.SamplingKey int mSamplingKey;
+
+ private static final int LUT_LENGTH_LIMIT = 100000;
+
+ /**
+ * Create a Lut entry.
+ *
+ * <p>
+ * Noted that 1D Lut(s) are treated as gain curves.
+ * For 3D Lut(s), 3D Lut(s) are used for direct color manipulations.
+ * The values of 3D Lut(s) data should be normalized to the range {@code 0.0}
+ * to {@code 1.0}, inclusive. And 3D Lut(s) data is organized in the order of
+ * R, G, B channels.
+ *
+ * @param buffer The raw lut data
+ * @param dimension Either 1D or 3D
+ * @param samplingKey The sampling kay used for the Lut
+ */
+ @FlaggedApi(Flags.FLAG_LUTS_API)
+ public Entry(@NonNull float[] buffer,
+ @LutProperties.Dimension int dimension,
+ @LutProperties.SamplingKey int samplingKey) {
+ if (buffer == null || buffer.length < 1) {
+ throw new IllegalArgumentException("The buffer cannot be empty!");
+ }
+
+ if (buffer.length >= LUT_LENGTH_LIMIT) {
+ throw new IllegalArgumentException("The lut length is too big to handle!");
+ }
+
+ if (dimension != LutProperties.ONE_DIMENSION
+ && dimension != LutProperties.THREE_DIMENSION) {
+ throw new IllegalArgumentException("The dimension should be either 1D or 3D!");
+ }
+
+ if (dimension == LutProperties.THREE_DIMENSION) {
+ if (buffer.length <= 3) {
+ throw new IllegalArgumentException(
+ "The 3d lut size of each dimension should be over 1!");
+ }
+ int lengthPerChannel = buffer.length;
+ if (lengthPerChannel % 3 != 0) {
+ throw new IllegalArgumentException(
+ "The lut buffer of 3dlut should have 3 channels!");
+ }
+ lengthPerChannel /= 3;
- int lutLength = 0;
- if (dimension == LutProperties.ONE_DIMENSION) {
- lutLength = size;
- } else if (dimension == LutProperties.THREE_DIMENSION) {
- lutLength = size * size * size;
- } else {
- clear();
- throw new IllegalArgumentException("The dimension is either 1D or 3D!");
+ double size = Math.cbrt(lengthPerChannel);
+ if (size == (int) size) {
+ mSize = (int) size;
+ } else {
+ throw new IllegalArgumentException(
+ "Cannot get the cube root of the 3d lut buffer!");
+ }
+ } else {
+ mSize = buffer.length;
+ }
+
+ mBuffer = buffer;
+ mDimension = dimension;
+ mSamplingKey = samplingKey;
}
- if (lutLength >= LUT_LENGTH_LIMIT) {
- clear();
- throw new IllegalArgumentException("The lut length is too big to handle!");
+ /**
+ * @return the dimension of the lut entry
+ */
+ @FlaggedApi(Flags.FLAG_LUTS_API)
+ public int getDimension() {
+ return mDimension;
}
- mOffsets.add(mTotalLength);
- mTotalLength += lutLength;
+ /**
+ * @return the size of the lut for each dimension
+ * @hide
+ */
+ public int getSize() {
+ return mSize;
+ }
+
+ /**
+ * @return the lut raw data of the lut
+ */
+ @FlaggedApi(Flags.FLAG_LUTS_API)
+ public @NonNull float[] getBuffer() {
+ return mBuffer;
+ }
+
+ /**
+ * @return the sampling key used by the lut
+ */
+ @FlaggedApi(Flags.FLAG_LUTS_API)
+ public int getSamplingKey() {
+ return mSamplingKey;
+ }
+
+ @Override
+ public String toString() {
+ return "Entry{"
+ + "dimension=" + DisplayLuts.Entry.dimensionToString(getDimension())
+ + ", size(each dimension)=" + getSize()
+ + ", samplingKey=" + samplingKeyToString(getSamplingKey()) + "}";
+ }
+
+ private static String dimensionToString(int dimension) {
+ switch(dimension) {
+ case LutProperties.ONE_DIMENSION:
+ return "ONE_DIMENSION";
+ case LutProperties.THREE_DIMENSION:
+ return "THREE_DIMENSION";
+ default:
+ return "";
+ }
+ }
+
+ private static String samplingKeyToString(int key) {
+ switch(key) {
+ case LutProperties.SAMPLING_KEY_RGB:
+ return "SAMPLING_KEY_RGB";
+ case LutProperties.SAMPLING_KEY_MAX_RGB:
+ return "SAMPLING_KEY_MAX_RGB";
+ default:
+ return "";
+ }
+ }
+ }
- mLutBuffers.add(buffer);
- mLutDimensions.add(dimension);
- mLutSizes.add(size);
- mLutSamplingKeys.add(samplingKey);
+ @Override
+ public String toString() {
+ StringBuilder sb = new StringBuilder("DisplayLuts{");
+ sb.append("\n");
+ for (DisplayLuts.Entry entry: mEntries) {
+ sb.append(entry.toString());
+ sb.append("\n");
+ }
+ sb.append("}");
+ return sb.toString();
+ }
+
+ private void addEntry(Entry entry) {
+ mEntries.add(entry);
+ mOffsets.add(mTotalLength);
+ mTotalLength += entry.getBuffer().length;
}
private void clear() {
- mTotalLength = 0;
mOffsets.clear();
- mLutBuffers.clear();
- mLutDimensions.clear();
- mLutSamplingKeys.clear();
+ mTotalLength = 0;
+ mEntries.clear();
+ }
+
+ /**
+ * Set a Lut to be applied.
+ *
+ * <p>Use either this or {@link #set(Entry, Entry)}. The function will
+ * replace any previously set lut(s).</p>
+ *
+ * @param entry Either an 1D Lut or a 3D Lut
+ */
+ @FlaggedApi(Flags.FLAG_LUTS_API)
+ public void set(@NonNull Entry entry) {
+ if (entry == null) {
+ throw new IllegalArgumentException("The entry is null!");
+ }
+ clear();
+ addEntry(entry);
+ }
+
+ /**
+ * Set Luts in order to be applied.
+ *
+ * <p> An 1D Lut and 3D Lut will be applied in order. Use either this or
+ * {@link #set(Entry)}. The function will replace any previously set lut(s)</p>
+ *
+ * @param first An 1D Lut
+ * @param second A 3D Lut
+ */
+ @FlaggedApi(Flags.FLAG_LUTS_API)
+ public void set(@NonNull Entry first, @NonNull Entry second) {
+ if (first == null || second == null) {
+ throw new IllegalArgumentException("The entry is null!");
+ }
+ if (first.getDimension() != LutProperties.ONE_DIMENSION
+ || second.getDimension() != LutProperties.THREE_DIMENSION) {
+ throw new IllegalArgumentException("The entries should be 1D and 3D in order!");
+ }
+ clear();
+ addEntry(first);
+ addEntry(second);
}
/**
- * @return the array of Lut buffers
+ * @hide
+ */
+ public boolean valid() {
+ return mEntries.size() > 0;
+ }
+
+ /**
+ * @hide
*/
public float[] getLutBuffers() {
float[] buffer = new float[mTotalLength];
- for (int i = 0; i < mLutBuffers.size(); i++) {
- float[] lutBuffer = mLutBuffers.get(i);
+ for (int i = 0; i < mEntries.size(); i++) {
+ float[] lutBuffer = mEntries.get(i).getBuffer();
System.arraycopy(lutBuffer, 0, buffer, mOffsets.get(i), lutBuffer.length);
}
return buffer;
}
/**
- * @return the starting point of each lut memory region of the lut buffer
+ * @hide
*/
public int[] getOffsets() {
return mOffsets.toArray();
}
/**
- * @return the array of Lut size
+ * @hide
*/
public int[] getLutSizes() {
- return mLutSizes.toArray();
+ int[] sizes = new int[mEntries.size()];
+ for (int i = 0; i < mEntries.size(); i++) {
+ sizes[i] = mEntries.get(i).getSize();
+ }
+ return sizes;
}
/**
- * @return the array of Lut dimension
+ * @hide
*/
public int[] getLutDimensions() {
- return mLutDimensions.toArray();
+ int[] dimensions = new int[mEntries.size()];
+ for (int i = 0; i < mEntries.size(); i++) {
+ dimensions[i] = mEntries.get(i).getDimension();
+ }
+ return dimensions;
}
/**
- * @return the array of sampling key
+ * @hide
*/
public int[] getLutSamplingKeys() {
- return mLutSamplingKeys.toArray();
+ int[] samplingKeys = new int[mEntries.size()];
+ for (int i = 0; i < mEntries.size(); i++) {
+ samplingKeys[i] = mEntries.get(i).getSamplingKey();
+ }
+ return samplingKeys;
}
}
diff --git a/core/java/android/hardware/LutProperties.java b/core/java/android/hardware/LutProperties.java
index c9c6d6d08ed2..bf40a415b0f7 100644
--- a/core/java/android/hardware/LutProperties.java
+++ b/core/java/android/hardware/LutProperties.java
@@ -16,23 +16,31 @@
package android.hardware;
+import android.annotation.FlaggedApi;
import android.annotation.IntDef;
+import android.annotation.NonNull;
+import android.hardware.flags.Flags;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
/**
- * Lut properties class.
+ * Provides Lut properties of the device.
*
- * A Lut (Look-Up Table) is a pre-calculated table for color transformation.
- *
- * @hide
+ * <p>
+ * A Lut (Look-Up Table) is a pre-calculated table for color correction.
+ * Applications may be interested in the Lut properties exposed by
+ * this class to determine if the Lut(s) they select using
+ * {@link android.view.SurfaceControl.Transaction#setLuts} are by the HWC.
+ * </p>
*/
+@FlaggedApi(Flags.FLAG_LUTS_API)
public final class LutProperties {
private final @Dimension int mDimension;
private final int mSize;
private final @SamplingKey int[] mSamplingKeys;
+ /** @hide */
@Retention(RetentionPolicy.SOURCE)
@IntDef(prefix = {"SAMPLING_KEY_"}, value = {
SAMPLING_KEY_RGB,
@@ -42,11 +50,14 @@ public final class LutProperties {
}
/** use r,g,b channel as the gain value of a Lut */
+ @FlaggedApi(Flags.FLAG_LUTS_API)
public static final int SAMPLING_KEY_RGB = 0;
/** use max of r,g,b channel as the gain value of a Lut */
+ @FlaggedApi(Flags.FLAG_LUTS_API)
public static final int SAMPLING_KEY_MAX_RGB = 1;
+ /** @hide */
@Retention(RetentionPolicy.SOURCE)
@IntDef(value = {
ONE_DIMENSION,
@@ -56,18 +67,22 @@ public final class LutProperties {
}
/** The Lut is one dimensional */
+ @FlaggedApi(Flags.FLAG_LUTS_API)
public static final int ONE_DIMENSION = 1;
/** The Lut is three dimensional */
+ @FlaggedApi(Flags.FLAG_LUTS_API)
public static final int THREE_DIMENSION = 3;
+ @FlaggedApi(Flags.FLAG_LUTS_API)
public @Dimension int getDimension() {
return mDimension;
}
/**
- * @return the size of the Lut.
+ * @return the size of the Lut for each dimension
*/
+ @FlaggedApi(Flags.FLAG_LUTS_API)
public int getSize() {
return mSize;
}
@@ -75,6 +90,8 @@ public final class LutProperties {
/**
* @return the list of sampling keys
*/
+ @FlaggedApi(Flags.FLAG_LUTS_API)
+ @NonNull
public @SamplingKey int[] getSamplingKeys() {
if (mSamplingKeys.length == 0) {
throw new IllegalStateException("no sampling key!");
diff --git a/core/java/android/hardware/OverlayProperties.java b/core/java/android/hardware/OverlayProperties.java
index 24cfc1b53e00..d42bfae23d2b 100644
--- a/core/java/android/hardware/OverlayProperties.java
+++ b/core/java/android/hardware/OverlayProperties.java
@@ -18,6 +18,7 @@ package android.hardware;
import android.annotation.FlaggedApi;
import android.annotation.NonNull;
+import android.annotation.SuppressLint;
import android.hardware.flags.Flags;
import android.os.Parcel;
import android.os.Parcelable;
@@ -72,9 +73,11 @@ public final class OverlayProperties implements Parcelable {
}
/**
- * Gets the lut properties of the display.
- * @hide
+ * Returns the lut properties of the device.
*/
+ @FlaggedApi(Flags.FLAG_LUTS_API)
+ @SuppressLint("ArrayReturn")
+ @NonNull
public LutProperties[] getLutProperties() {
if (mNativeObject == 0) {
return null;
diff --git a/core/java/android/hardware/flags/overlayproperties_flags.aconfig b/core/java/android/hardware/flags/flags.aconfig
index 6c86108c4034..5ca6c6bed1f0 100644
--- a/core/java/android/hardware/flags/overlayproperties_flags.aconfig
+++ b/core/java/android/hardware/flags/flags.aconfig
@@ -2,6 +2,15 @@ package: "android.hardware.flags"
container: "system"
flag {
+ name: "luts_api"
+ is_exported: true
+ is_fixed_read_only: true
+ namespace: "core_graphics"
+ description: "public Luts related Apis"
+ bug: "349667978"
+}
+
+flag {
name: "overlayproperties_class_api"
is_exported: true
namespace: "core_graphics"
diff --git a/core/java/android/view/SurfaceControl.java b/core/java/android/view/SurfaceControl.java
index 68efa79715a3..d56768d2db03 100644
--- a/core/java/android/view/SurfaceControl.java
+++ b/core/java/android/view/SurfaceControl.java
@@ -4566,14 +4566,31 @@ public final class SurfaceControl implements Parcelable {
return this;
}
- /** @hide */
+ /**
+ * Sets the Luts for the layer.
+ *
+ * <p> The function also allows to clear previously applied lut(s). To do this,
+ * set the displayluts to be either {@code nullptr} or
+ * an empty {@link android.hardware.DisplayLuts} instance.
+ *
+ * @param sc The SurfaceControl to update
+ *
+ * @param displayLuts The selected Lut(s)
+ *
+ * @return this
+ * @see DisplayLuts
+ */
+ @FlaggedApi(android.hardware.flags.Flags.FLAG_LUTS_API)
public @NonNull Transaction setLuts(@NonNull SurfaceControl sc,
- @NonNull DisplayLuts displayLuts) {
+ @Nullable DisplayLuts displayLuts) {
checkPreconditions(sc);
-
- nativeSetLuts(mNativeObject, sc.mNativeObject, displayLuts.getLutBuffers(),
- displayLuts.getOffsets(), displayLuts.getLutDimensions(),
- displayLuts.getLutSizes(), displayLuts.getLutSamplingKeys());
+ if (displayLuts != null && displayLuts.valid()) {
+ nativeSetLuts(mNativeObject, sc.mNativeObject, displayLuts.getLutBuffers(),
+ displayLuts.getOffsets(), displayLuts.getLutDimensions(),
+ displayLuts.getLutSizes(), displayLuts.getLutSamplingKeys());
+ } else {
+ nativeSetLuts(mNativeObject, sc.mNativeObject, null, null, null, null, null);
+ }
return this;
}
diff --git a/core/jni/android_hardware_OverlayProperties.cpp b/core/jni/android_hardware_OverlayProperties.cpp
index bb4084e8f39e..f64dec8eb215 100644
--- a/core/jni/android_hardware_OverlayProperties.cpp
+++ b/core/jni/android_hardware_OverlayProperties.cpp
@@ -106,7 +106,7 @@ static jobjectArray android_hardware_OverlayProperties_getLutProperties(JNIEnv*
jlong nativeObject) {
gui::OverlayProperties* overlayProperties =
reinterpret_cast<gui::OverlayProperties*>(nativeObject);
- if (overlayProperties->lutProperties.has_value()) {
+ if (!overlayProperties || !overlayProperties->lutProperties) {
return NULL;
}
auto& lutProperties = overlayProperties->lutProperties.value();
diff --git a/core/jni/android_view_SurfaceControl.cpp b/core/jni/android_view_SurfaceControl.cpp
index 82b463ec9091..450b88bbe218 100644
--- a/core/jni/android_view_SurfaceControl.cpp
+++ b/core/jni/android_view_SurfaceControl.cpp
@@ -758,54 +758,64 @@ static void nativeSetLuts(JNIEnv* env, jclass clazz, jlong transactionObj, jlong
auto transaction = reinterpret_cast<SurfaceComposerClient::Transaction*>(transactionObj);
SurfaceControl* const ctrl = reinterpret_cast<SurfaceControl*>(nativeObject);
- ScopedIntArrayRW joffsets(env, joffsetArray);
- if (joffsets.get() == nullptr) {
- jniThrowRuntimeException(env, "Failed to get ScopedIntArrayRW from joffsetArray");
- return;
- }
- ScopedIntArrayRW jdimensions(env, jdimensionArray);
- if (jdimensions.get() == nullptr) {
- jniThrowRuntimeException(env, "Failed to get ScopedIntArrayRW from jdimensionArray");
- return;
- }
- ScopedIntArrayRW jsizes(env, jsizeArray);
- if (jsizes.get() == nullptr) {
- jniThrowRuntimeException(env, "Failed to get ScopedIntArrayRW from jsizeArray");
- return;
- }
- ScopedIntArrayRW jsamplingKeys(env, jsamplingKeyArray);
- if (jsamplingKeys.get() == nullptr) {
- jniThrowRuntimeException(env, "Failed to get ScopedIntArrayRW from jsamplingKeyArray");
- return;
- }
+ std::vector<int32_t> offsets;
+ std::vector<int32_t> dimensions;
+ std::vector<int32_t> sizes;
+ std::vector<int32_t> samplingKeys;
+ int32_t fd = -1;
+
+ if (jdimensionArray) {
+ jsize numLuts = env->GetArrayLength(jdimensionArray);
+ ScopedIntArrayRW joffsets(env, joffsetArray);
+ if (joffsets.get() == nullptr) {
+ jniThrowRuntimeException(env, "Failed to get ScopedIntArrayRW from joffsetArray");
+ return;
+ }
+ ScopedIntArrayRW jdimensions(env, jdimensionArray);
+ if (jdimensions.get() == nullptr) {
+ jniThrowRuntimeException(env, "Failed to get ScopedIntArrayRW from jdimensionArray");
+ return;
+ }
+ ScopedIntArrayRW jsizes(env, jsizeArray);
+ if (jsizes.get() == nullptr) {
+ jniThrowRuntimeException(env, "Failed to get ScopedIntArrayRW from jsizeArray");
+ return;
+ }
+ ScopedIntArrayRW jsamplingKeys(env, jsamplingKeyArray);
+ if (jsamplingKeys.get() == nullptr) {
+ jniThrowRuntimeException(env, "Failed to get ScopedIntArrayRW from jsamplingKeyArray");
+ return;
+ }
- jsize numLuts = env->GetArrayLength(jdimensionArray);
- std::vector<int32_t> offsets(joffsets.get(), joffsets.get() + numLuts);
- std::vector<int32_t> dimensions(jdimensions.get(), jdimensions.get() + numLuts);
- std::vector<int32_t> sizes(jsizes.get(), jsizes.get() + numLuts);
- std::vector<int32_t> samplingKeys(jsamplingKeys.get(), jsamplingKeys.get() + numLuts);
+ if (numLuts > 0) {
+ offsets = std::vector<int32_t>(joffsets.get(), joffsets.get() + numLuts);
+ dimensions = std::vector<int32_t>(jdimensions.get(), jdimensions.get() + numLuts);
+ sizes = std::vector<int32_t>(jsizes.get(), jsizes.get() + numLuts);
+ samplingKeys = std::vector<int32_t>(jsamplingKeys.get(), jsamplingKeys.get() + numLuts);
- ScopedFloatArrayRW jbuffers(env, jbufferArray);
- if (jbuffers.get() == nullptr) {
- jniThrowRuntimeException(env, "Failed to get ScopedFloatArrayRW from jbufferArray");
- return;
- }
+ ScopedFloatArrayRW jbuffers(env, jbufferArray);
+ if (jbuffers.get() == nullptr) {
+ jniThrowRuntimeException(env, "Failed to get ScopedFloatArrayRW from jbufferArray");
+ return;
+ }
- // create the shared memory and copy jbuffers
- size_t bufferSize = jbuffers.size() * sizeof(float);
- int32_t fd = ashmem_create_region("lut_shread_mem", bufferSize);
- if (fd < 0) {
- jniThrowRuntimeException(env, "ashmem_create_region() failed");
- return;
- }
- void* ptr = mmap(nullptr, bufferSize, PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0);
- if (ptr == MAP_FAILED) {
- jniThrowRuntimeException(env, "Failed to map the shared memory");
- return;
+ // create the shared memory and copy jbuffers
+ size_t bufferSize = jbuffers.size() * sizeof(float);
+ fd = ashmem_create_region("lut_shared_mem", bufferSize);
+ if (fd < 0) {
+ jniThrowRuntimeException(env, "ashmem_create_region() failed");
+ return;
+ }
+ void* ptr = mmap(nullptr, bufferSize, PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0);
+ if (ptr == MAP_FAILED) {
+ jniThrowRuntimeException(env, "Failed to map the shared memory");
+ return;
+ }
+ memcpy(ptr, jbuffers.get(), bufferSize);
+ // unmap
+ munmap(ptr, bufferSize);
+ }
}
- memcpy(ptr, jbuffers.get(), bufferSize);
- // unmap
- munmap(ptr, bufferSize);
transaction->setLuts(ctrl, base::unique_fd(fd), offsets, dimensions, sizes, samplingKeys);
}