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.compat.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
create( @ntRangefrom = 1) int width, @IntRange(from = 1) int height, @Format int format, @IntRange(from = 1) int layers, @Usage long usage)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      */
isSupported(@ntRangefrom = 1) int width, @IntRange(from = 1) int height, @Format int format, @IntRange(from = 1) int layers, @Usage long usage)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
createFromGraphicBuffer(@onNull GraphicBuffer graphicBuffer)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)
HardwareBuffer(long nativeObject)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
finalize()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      */
getWidth()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      */
getHeight()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
getFormat()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      */
getLayers()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      */
getUsage()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
destroy()315     public void destroy() {
316         close();
317     }
318 
319     /** @removed replaced by {@link #isClosed()} */
320     @Deprecated
isDestroyed()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
close()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      */
isClosed()351     public boolean isClosed() {
352         return mNativeObject == 0;
353     }
354 
355     @Override
describeContents()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
writeToParcel(Parcel dest, int flags)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      */
isSupportedFormat(@ormat int format)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 
nCreateHardwareBuffer(int width, int height, int format, int layers, long usage)422     private static native long nCreateHardwareBuffer(int width, int height, int format, int layers,
423             long usage);
nCreateFromGraphicBuffer(GraphicBuffer graphicBuffer)424     private static native long nCreateFromGraphicBuffer(GraphicBuffer graphicBuffer);
nGetNativeFinalizer()425     private static native long nGetNativeFinalizer();
nWriteHardwareBufferToParcel(long nativeObject, Parcel dest)426     private static native void nWriteHardwareBufferToParcel(long nativeObject, Parcel dest);
nReadHardwareBufferFromParcel(Parcel in)427     private static native long nReadHardwareBufferFromParcel(Parcel in);
428     @FastNative
nGetWidth(long nativeObject)429     private static native int nGetWidth(long nativeObject);
430     @FastNative
nGetHeight(long nativeObject)431     private static native int nGetHeight(long nativeObject);
432     @FastNative
nGetFormat(long nativeObject)433     private static native int nGetFormat(long nativeObject);
434     @FastNative
nGetLayers(long nativeObject)435     private static native int nGetLayers(long nativeObject);
436     @FastNative
nGetUsage(long nativeObject)437     private static native long nGetUsage(long nativeObject);
nIsSupported(int width, int height, int format, int layers, long usage)438     private static native boolean nIsSupported(int width, int height, int format, int layers,
439             long usage);
440 }
441