Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 7e7f7559 authored by Sally Qi's avatar Sally Qi Committed by Android (Google) Code Review
Browse files

Merge "[Lut API] expose Lut-related APIs." into main

parents c75325ba fd9025d7
Loading
Loading
Loading
Loading
+25 −0
Original line number Diff line number Diff line
@@ -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);
+232 −54
Original line number Diff line number Diff line
@@ -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();
    }

    @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;

        /**
     * Add the lut to be applied.
         * Create a Lut entry.
         *
     * @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) {

        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!");
         * <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 (lutLength >= LUT_LENGTH_LIMIT) {
            clear();
            if (buffer.length >= LUT_LENGTH_LIMIT) {
                throw new IllegalArgumentException("The lut length is too big to handle!");
            }

        mOffsets.add(mTotalLength);
        mTotalLength += lutLength;
            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;

                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;
        }

        /**
         * @return the dimension of the lut entry
         */
        @FlaggedApi(Flags.FLAG_LUTS_API)
        public int getDimension() {
            return mDimension;
        }

        /**
         * @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;
        }

        mLutBuffers.add(buffer);
        mLutDimensions.add(dimension);
        mLutSizes.add(size);
        mLutSamplingKeys.add(samplingKey);
        @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 "";
            }
        }
    }

    @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();
    }

    /**
     * @return the array of Lut buffers
     * 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);
    }

    /**
     * @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;
    }
}
+22 −5
Original line number Diff line number Diff line
@@ -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!");
+5 −2
Original line number Diff line number Diff line
@@ -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;
+9 −0
Original line number Diff line number Diff line
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
Loading