diff options
| -rw-r--r-- | core/api/current.txt | 25 | ||||
| -rw-r--r-- | core/java/android/hardware/DisplayLuts.java | 286 | ||||
| -rw-r--r-- | core/java/android/hardware/LutProperties.java | 27 | ||||
| -rw-r--r-- | core/java/android/hardware/OverlayProperties.java | 7 | ||||
| -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.java | 29 | ||||
| -rw-r--r-- | core/jni/android_hardware_OverlayProperties.cpp | 2 | ||||
| -rw-r--r-- | core/jni/android_view_SurfaceControl.cpp | 98 |
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); } |