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