Home | History | Annotate | Download | only in hardware
      1 /*
      2  * Copyright (C) 2017 The Android Open Source Project
      3  *
      4  * Licensed under the Apache License, Version 2.0 (the "License");
      5  * you may not use this file except in compliance with the License.
      6  * You may obtain a copy of the License at
      7  *
      8  *      http://www.apache.org/licenses/LICENSE-2.0
      9  *
     10  * Unless required by applicable law or agreed to in writing, software
     11  * distributed under the License is distributed on an "AS IS" BASIS,
     12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
     13  * See the License for the specific language governing permissions and
     14  * limitations under the License.
     15  */
     16 
     17 package android.hardware;
     18 
     19 import android.annotation.IntDef;
     20 import android.annotation.IntRange;
     21 import android.annotation.LongDef;
     22 import android.annotation.NonNull;
     23 import android.annotation.UnsupportedAppUsage;
     24 import android.graphics.GraphicBuffer;
     25 import android.os.Build;
     26 import android.os.Parcel;
     27 import android.os.Parcelable;
     28 
     29 import dalvik.annotation.optimization.FastNative;
     30 import dalvik.system.CloseGuard;
     31 
     32 import libcore.util.NativeAllocationRegistry;
     33 
     34 import java.lang.annotation.Retention;
     35 import java.lang.annotation.RetentionPolicy;
     36 
     37 /**
     38  * HardwareBuffer wraps a native <code>AHardwareBuffer</code> object, which is a low-level object
     39  * representing a memory buffer accessible by various hardware units. HardwareBuffer allows sharing
     40  * buffers across different application processes. In particular, HardwareBuffers may be mappable
     41  * to memory accessibly to various hardware systems, such as the GPU, a sensor or context hub, or
     42  * other auxiliary processing units.
     43  *
     44  * For more information, see the NDK documentation for <code>AHardwareBuffer</code>.
     45  */
     46 public final class HardwareBuffer implements Parcelable, AutoCloseable {
     47     /** @hide */
     48     @Retention(RetentionPolicy.SOURCE)
     49     @IntDef(prefix = { "RGB", "BLOB", "D_", "DS_", "S_" }, value = {
     50             RGBA_8888,
     51             RGBA_FP16,
     52             RGBA_1010102,
     53             RGBX_8888,
     54             RGB_888,
     55             RGB_565,
     56             BLOB,
     57             D_16,
     58             D_24,
     59             DS_24UI8,
     60             D_FP32,
     61             DS_FP32UI8,
     62             S_UI8,
     63     })
     64     public @interface Format {
     65     }
     66 
     67     @Format
     68     /** Format: 8 bits each red, green, blue, alpha */
     69     public static final int RGBA_8888    = 1;
     70     /** Format: 8 bits each red, green, blue, alpha, alpha is always 0xFF */
     71     public static final int RGBX_8888    = 2;
     72     /** Format: 8 bits each red, green, blue, no alpha */
     73     public static final int RGB_888      = 3;
     74     /** Format: 5 bits each red and blue, 6 bits green, no alpha */
     75     public static final int RGB_565      = 4;
     76     /** Format: 16 bits each red, green, blue, alpha */
     77     public static final int RGBA_FP16    = 0x16;
     78     /** Format: 10 bits each red, green, blue, 2 bits alpha */
     79     public static final int RGBA_1010102 = 0x2b;
     80     /** Format: opaque format used for raw data transfer; must have a height of 1 */
     81     public static final int BLOB         = 0x21;
     82     /** Format: 16 bits depth */
     83     public static final int D_16         = 0x30;
     84     /** Format: 24 bits depth */
     85     public static final int D_24         = 0x31;
     86     /** Format: 24 bits depth, 8 bits stencil */
     87     public static final int DS_24UI8     = 0x32;
     88     /** Format: 32 bits depth */
     89     public static final int D_FP32       = 0x33;
     90     /** Format: 32 bits depth, 8 bits stencil */
     91     public static final int DS_FP32UI8   = 0x34;
     92     /** Format: 8 bits stencil */
     93     public static final int S_UI8        = 0x35;
     94 
     95     // Note: do not rename, this field is used by native code
     96     @UnsupportedAppUsage
     97     private long mNativeObject;
     98 
     99     // Invoked on destruction
    100     private Runnable mCleaner;
    101 
    102     private final CloseGuard mCloseGuard = CloseGuard.get();
    103 
    104     /** @hide */
    105     @Retention(RetentionPolicy.SOURCE)
    106     @LongDef(flag = true, value = {USAGE_CPU_READ_RARELY, USAGE_CPU_READ_OFTEN,
    107             USAGE_CPU_WRITE_RARELY, USAGE_CPU_WRITE_OFTEN, USAGE_GPU_SAMPLED_IMAGE,
    108             USAGE_GPU_COLOR_OUTPUT, USAGE_PROTECTED_CONTENT, USAGE_VIDEO_ENCODE,
    109             USAGE_GPU_DATA_BUFFER, USAGE_SENSOR_DIRECT_DATA, USAGE_GPU_CUBE_MAP,
    110             USAGE_GPU_MIPMAP_COMPLETE})
    111     public @interface Usage {};
    112 
    113     @Usage
    114     /** Usage: The buffer will sometimes be read by the CPU */
    115     public static final long USAGE_CPU_READ_RARELY       = 2;
    116     /** Usage: The buffer will often be read by the CPU */
    117     public static final long USAGE_CPU_READ_OFTEN        = 3;
    118 
    119     /** Usage: The buffer will sometimes be written to by the CPU */
    120     public static final long USAGE_CPU_WRITE_RARELY      = 2 << 4;
    121     /** Usage: The buffer will often be written to by the CPU */
    122     public static final long USAGE_CPU_WRITE_OFTEN       = 3 << 4;
    123 
    124     /** Usage: The buffer will be read from by the GPU */
    125     public static final long USAGE_GPU_SAMPLED_IMAGE      = 1 << 8;
    126     /** Usage: The buffer will be written to by the GPU */
    127     public static final long USAGE_GPU_COLOR_OUTPUT       = 1 << 9;
    128     /** Usage: The buffer must not be used outside of a protected hardware path */
    129     public static final long USAGE_PROTECTED_CONTENT      = 1 << 14;
    130     /** Usage: The buffer will be read by a hardware video encoder */
    131     public static final long USAGE_VIDEO_ENCODE           = 1 << 16;
    132     /** Usage: The buffer will be used for sensor direct data */
    133     public static final long USAGE_SENSOR_DIRECT_DATA     = 1 << 23;
    134     /** Usage: The buffer will be used as a shader storage or uniform buffer object */
    135     public static final long USAGE_GPU_DATA_BUFFER        = 1 << 24;
    136     /** Usage: The buffer will be used as a cube map texture */
    137     public static final long USAGE_GPU_CUBE_MAP           = 1 << 25;
    138     /** Usage: The buffer contains a complete mipmap hierarchy */
    139     public static final long USAGE_GPU_MIPMAP_COMPLETE    = 1 << 26;
    140 
    141     // The approximate size of a native AHardwareBuffer object.
    142     private static final long NATIVE_HARDWARE_BUFFER_SIZE = 232;
    143     /**
    144      * Creates a new <code>HardwareBuffer</code> instance.
    145      *
    146      * <p>Calling this method will throw an <code>IllegalStateException</code> if
    147      * format is not a supported Format type.</p>
    148      *
    149      * @param width The width in pixels of the buffer
    150      * @param height The height in pixels of the buffer
    151      * @param format The @Format of each pixel
    152      * @param layers The number of layers in the buffer
    153      * @param usage The @Usage flags describing how the buffer will be used
    154      * @return A <code>HardwareBuffer</code> instance if successful, or throws an
    155      *     IllegalArgumentException if the dimensions passed are invalid (either zero, negative, or
    156      *     too large to allocate), if the format is not supported, if the requested number of layers
    157      *     is less than one or not supported, or if the passed usage flags are not a supported set.
    158      */
    159     @NonNull
    160     public static HardwareBuffer create(
    161             @IntRange(from = 1) int width, @IntRange(from = 1) int height,
    162             @Format int format, @IntRange(from = 1) int layers, @Usage long usage) {
    163         if (!HardwareBuffer.isSupportedFormat(format)) {
    164             throw new IllegalArgumentException("Invalid pixel format " + format);
    165         }
    166         if (width <= 0) {
    167             throw new IllegalArgumentException("Invalid width " + width);
    168         }
    169         if (height <= 0) {
    170             throw new IllegalArgumentException("Invalid height " + height);
    171         }
    172         if (layers <= 0) {
    173             throw new IllegalArgumentException("Invalid layer count " + layers);
    174         }
    175         if (format == BLOB && height != 1) {
    176             throw new IllegalArgumentException("Height must be 1 when using the BLOB format");
    177         }
    178         long nativeObject = nCreateHardwareBuffer(width, height, format, layers, usage);
    179         if (nativeObject == 0) {
    180             throw new IllegalArgumentException("Unable to create a HardwareBuffer, either the " +
    181                     "dimensions passed were too large, too many image layers were requested, " +
    182                     "or an invalid set of usage flags or invalid format was passed");
    183         }
    184         return new HardwareBuffer(nativeObject);
    185     }
    186 
    187     /**
    188      * Queries whether the given buffer description is supported by the system. If this returns
    189      * true, then the allocation may succeed until resource exhaustion occurs. If this returns
    190      * false then this combination will never succeed.
    191      *
    192      * @param width The width in pixels of the buffer
    193      * @param height The height in pixels of the buffer
    194      * @param format The @Format of each pixel
    195      * @param layers The number of layers in the buffer
    196      * @param usage The @Usage flags describing how the buffer will be used
    197      * @return True if the combination is supported, false otherwise.
    198      */
    199     public static boolean isSupported(@IntRange(from = 1) int width, @IntRange(from = 1) int height,
    200             @Format int format, @IntRange(from = 1) int layers, @Usage long usage) {
    201         if (!HardwareBuffer.isSupportedFormat(format)) {
    202             throw new IllegalArgumentException("Invalid pixel format " + format);
    203         }
    204         if (width <= 0) {
    205             throw new IllegalArgumentException("Invalid width " + width);
    206         }
    207         if (height <= 0) {
    208             throw new IllegalArgumentException("Invalid height " + height);
    209         }
    210         if (layers <= 0) {
    211             throw new IllegalArgumentException("Invalid layer count " + layers);
    212         }
    213         if (format == BLOB && height != 1) {
    214             throw new IllegalArgumentException("Height must be 1 when using the BLOB format");
    215         }
    216         return nIsSupported(width, height, format, layers, usage);
    217     }
    218 
    219     /**
    220      * @hide
    221      * Returns a <code>HardwareBuffer</code> instance from <code>GraphicBuffer</code>
    222      *
    223      * @param graphicBuffer A GraphicBuffer to be wrapped as HardwareBuffer
    224      * @return A <code>HardwareBuffer</code> instance.
    225      */
    226     @NonNull
    227     public static HardwareBuffer createFromGraphicBuffer(@NonNull GraphicBuffer graphicBuffer) {
    228         long nativeObject = nCreateFromGraphicBuffer(graphicBuffer);
    229         return new HardwareBuffer(nativeObject);
    230     }
    231 
    232     /**
    233      * Private use only. See {@link #create(int, int, int, int, long)}. May also be
    234      * called from JNI using an already allocated native <code>HardwareBuffer</code>.
    235      */
    236     @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P, trackingBug = 115609023)
    237     private HardwareBuffer(long nativeObject) {
    238         mNativeObject = nativeObject;
    239 
    240         ClassLoader loader = HardwareBuffer.class.getClassLoader();
    241         NativeAllocationRegistry registry = new NativeAllocationRegistry(
    242                 loader, nGetNativeFinalizer(), NATIVE_HARDWARE_BUFFER_SIZE);
    243         mCleaner = registry.registerNativeAllocation(this, mNativeObject);
    244         mCloseGuard.open("close");
    245     }
    246 
    247     @Override
    248     protected void finalize() throws Throwable {
    249         try {
    250             mCloseGuard.warnIfOpen();
    251             close();
    252         } finally {
    253             super.finalize();
    254         }
    255     }
    256 
    257     /**
    258      * Returns the width of this buffer in pixels.
    259      */
    260     public int getWidth() {
    261         if (isClosed()) {
    262             throw new IllegalStateException("This HardwareBuffer has been closed and its width "
    263                     + "cannot be obtained.");
    264         }
    265         return nGetWidth(mNativeObject);
    266     }
    267 
    268     /**
    269      * Returns the height of this buffer in pixels.
    270      */
    271     public int getHeight() {
    272         if (isClosed()) {
    273             throw new IllegalStateException("This HardwareBuffer has been closed and its height "
    274                     + "cannot be obtained.");
    275         }
    276         return nGetHeight(mNativeObject);
    277     }
    278 
    279     /**
    280      * Returns the @Format of this buffer.
    281      */
    282     @Format
    283     public int getFormat() {
    284         if (isClosed()) {
    285             throw new IllegalStateException("This HardwareBuffer has been closed and its format "
    286                     + "cannot be obtained.");
    287         }
    288         return nGetFormat(mNativeObject);
    289     }
    290 
    291     /**
    292      * Returns the number of layers in this buffer.
    293      */
    294     public int getLayers() {
    295         if (isClosed()) {
    296             throw new IllegalStateException("This HardwareBuffer has been closed and its layer "
    297                     + "count cannot be obtained.");
    298         }
    299         return nGetLayers(mNativeObject);
    300     }
    301 
    302     /**
    303      * Returns the usage flags of the usage hints set on this buffer.
    304      */
    305     public long getUsage() {
    306         if (isClosed()) {
    307             throw new IllegalStateException("This HardwareBuffer has been closed and its usage "
    308                     + "cannot be obtained.");
    309         }
    310         return nGetUsage(mNativeObject);
    311     }
    312 
    313     /** @removed replaced by {@link #close()} */
    314     @Deprecated
    315     public void destroy() {
    316         close();
    317     }
    318 
    319     /** @removed replaced by {@link #isClosed()} */
    320     @Deprecated
    321     public boolean isDestroyed() {
    322         return isClosed();
    323     }
    324 
    325     /**
    326      * Destroys this buffer immediately. Calling this method frees up any
    327      * underlying native resources. After calling this method, this buffer
    328      * must not be used in any way.
    329      *
    330      * @see #isClosed()
    331      */
    332     @Override
    333     public void close() {
    334         if (!isClosed()) {
    335             mCloseGuard.close();
    336             mNativeObject = 0;
    337             mCleaner.run();
    338             mCleaner = null;
    339         }
    340     }
    341 
    342     /**
    343      * Indicates whether this buffer has been closed. A closed buffer cannot
    344      * be used in any way: the buffer cannot be written to a parcel, etc.
    345      *
    346      * @return True if this <code>HardwareBuffer</code> is in a closed state,
    347      *         false otherwise.
    348      *
    349      * @see #close()
    350      */
    351     public boolean isClosed() {
    352         return mNativeObject == 0;
    353     }
    354 
    355     @Override
    356     public int describeContents() {
    357         return Parcelable.CONTENTS_FILE_DESCRIPTOR;
    358     }
    359 
    360     /**
    361      * Flatten this object in to a Parcel.
    362      *
    363      * <p>Calling this method will throw an <code>IllegalStateException</code> if
    364      * {@link #close()} has been previously called.</p>
    365      *
    366      * @param dest The Parcel in which the object should be written.
    367      * @param flags Additional flags about how the object should be written.
    368      *              May be 0 or {@link #PARCELABLE_WRITE_RETURN_VALUE}.
    369      */
    370     @Override
    371     public void writeToParcel(Parcel dest, int flags) {
    372         if (isClosed()) {
    373             throw new IllegalStateException("This HardwareBuffer has been closed and cannot be "
    374                     + "written to a parcel.");
    375         }
    376         nWriteHardwareBufferToParcel(mNativeObject, dest);
    377     }
    378 
    379     public static final @android.annotation.NonNull Parcelable.Creator<HardwareBuffer> CREATOR =
    380             new Parcelable.Creator<HardwareBuffer>() {
    381         public HardwareBuffer createFromParcel(Parcel in) {
    382             long nativeObject = nReadHardwareBufferFromParcel(in);
    383             if (nativeObject != 0) {
    384                 return new HardwareBuffer(nativeObject);
    385             }
    386             return null;
    387         }
    388 
    389         public HardwareBuffer[] newArray(int size) {
    390             return new HardwareBuffer[size];
    391         }
    392     };
    393 
    394     /**
    395      * Validates whether a particular format is supported by HardwareBuffer.
    396      *
    397      * @param format The format to validate.
    398      *
    399      * @return True if <code>format</code> is a supported format. false otherwise.
    400      * See {@link #create(int, int, int, int, long)}.
    401      */
    402     private static boolean isSupportedFormat(@Format int format) {
    403         switch(format) {
    404             case RGBA_8888:
    405             case RGBA_FP16:
    406             case RGBA_1010102:
    407             case RGBX_8888:
    408             case RGB_565:
    409             case RGB_888:
    410             case BLOB:
    411             case D_16:
    412             case D_24:
    413             case DS_24UI8:
    414             case D_FP32:
    415             case DS_FP32UI8:
    416             case S_UI8:
    417                 return true;
    418         }
    419         return false;
    420     }
    421 
    422     private static native long nCreateHardwareBuffer(int width, int height, int format, int layers,
    423             long usage);
    424     private static native long nCreateFromGraphicBuffer(GraphicBuffer graphicBuffer);
    425     private static native long nGetNativeFinalizer();
    426     private static native void nWriteHardwareBufferToParcel(long nativeObject, Parcel dest);
    427     private static native long nReadHardwareBufferFromParcel(Parcel in);
    428     @FastNative
    429     private static native int nGetWidth(long nativeObject);
    430     @FastNative
    431     private static native int nGetHeight(long nativeObject);
    432     @FastNative
    433     private static native int nGetFormat(long nativeObject);
    434     @FastNative
    435     private static native int nGetLayers(long nativeObject);
    436     @FastNative
    437     private static native long nGetUsage(long nativeObject);
    438     private static native boolean nIsSupported(int width, int height, int format, int layers,
    439             long usage);
    440 }
    441