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