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