blob: dd3493063e2877bcda8200fdf7e22ceec67da5e2 [file] [log] [blame]
Craig Donner1a4d07d2017-01-09 13:01:22 -08001/*
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
17package android.hardware;
18
19import android.annotation.IntDef;
John Reck24faae92019-02-20 10:23:41 -080020import android.annotation.IntRange;
Tor Norbyef740c7e2017-11-16 14:47:04 -080021import android.annotation.LongDef;
Craig Donner1a4d07d2017-01-09 13:01:22 -080022import android.annotation.NonNull;
Artur Satayev26958002019-12-10 17:47:52 +000023import android.compat.annotation.UnsupportedAppUsage;
Peiyong Lin9d427402019-01-23 18:39:06 -080024import android.graphics.GraphicBuffer;
Mathew Inwood8c854f82018-09-14 12:35:36 +010025import android.os.Build;
Craig Donner1a4d07d2017-01-09 13:01:22 -080026import android.os.Parcel;
27import android.os.Parcelable;
28
29import dalvik.annotation.optimization.FastNative;
Craig Donnerfd5d3312017-04-19 18:33:36 -070030import dalvik.system.CloseGuard;
Craig Donner1a4d07d2017-01-09 13:01:22 -080031
Craig Donner7c37b902017-12-27 15:20:06 -080032import libcore.util.NativeAllocationRegistry;
33
Craig Donner1a4d07d2017-01-09 13:01:22 -080034import java.lang.annotation.Retention;
35import java.lang.annotation.RetentionPolicy;
36
Craig Donner1a4d07d2017-01-09 13:01:22 -080037/**
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 */
Craig Donnerfd5d3312017-04-19 18:33:36 -070046public final class HardwareBuffer implements Parcelable, AutoCloseable {
Craig Donner1a4d07d2017-01-09 13:01:22 -080047 /** @hide */
48 @Retention(RetentionPolicy.SOURCE)
Wonsik Kim637afb22020-02-25 14:27:29 -080049 @IntDef(prefix = { "RGB", "BLOB", "YCBCR_", "D_", "DS_", "S_" }, value = {
Jeff Sharkeyce8db992017-12-13 20:05:05 -070050 RGBA_8888,
51 RGBA_FP16,
52 RGBA_1010102,
53 RGBX_8888,
54 RGB_888,
55 RGB_565,
Craig Donner7c37b902017-12-27 15:20:06 -080056 BLOB,
Wonsik Kim637afb22020-02-25 14:27:29 -080057 YCBCR_420_888,
Craig Donner7c37b902017-12-27 15:20:06 -080058 D_16,
59 D_24,
60 DS_24UI8,
61 D_FP32,
62 DS_FP32UI8,
63 S_UI8,
Jeff Sharkeyce8db992017-12-13 20:05:05 -070064 })
Romain Guy8ec21062017-02-10 18:49:33 -080065 public @interface Format {
66 }
Craig Donner1a4d07d2017-01-09 13:01:22 -080067
Craig Donner7c37b902017-12-27 15:20:06 -080068 @Format
Craig Donner1a4d07d2017-01-09 13:01:22 -080069 /** Format: 8 bits each red, green, blue, alpha */
Romain Guy8ec21062017-02-10 18:49:33 -080070 public static final int RGBA_8888 = 1;
Craig Donner1a4d07d2017-01-09 13:01:22 -080071 /** Format: 8 bits each red, green, blue, alpha, alpha is always 0xFF */
Romain Guy8ec21062017-02-10 18:49:33 -080072 public static final int RGBX_8888 = 2;
Craig Donner1a4d07d2017-01-09 13:01:22 -080073 /** Format: 8 bits each red, green, blue, no alpha */
Romain Guy8ec21062017-02-10 18:49:33 -080074 public static final int RGB_888 = 3;
Craig Donner1a4d07d2017-01-09 13:01:22 -080075 /** Format: 5 bits each red and blue, 6 bits green, no alpha */
Romain Guy8ec21062017-02-10 18:49:33 -080076 public static final int RGB_565 = 4;
Craig Donner1a4d07d2017-01-09 13:01:22 -080077 /** Format: 16 bits each red, green, blue, alpha */
Romain Guy8ec21062017-02-10 18:49:33 -080078 public static final int RGBA_FP16 = 0x16;
79 /** Format: 10 bits each red, green, blue, 2 bits alpha */
80 public static final int RGBA_1010102 = 0x2b;
Craig Donner2be5b9f2017-01-24 18:14:44 -080081 /** Format: opaque format used for raw data transfer; must have a height of 1 */
Romain Guy8ec21062017-02-10 18:49:33 -080082 public static final int BLOB = 0x21;
Wonsik Kim637afb22020-02-25 14:27:29 -080083 /** Format: Planar YCbCr 420; must have an even width and height */
84 public static final int YCBCR_420_888 = 0x23;
Craig Donner7c37b902017-12-27 15:20:06 -080085 /** Format: 16 bits depth */
86 public static final int D_16 = 0x30;
87 /** Format: 24 bits depth */
88 public static final int D_24 = 0x31;
89 /** Format: 24 bits depth, 8 bits stencil */
90 public static final int DS_24UI8 = 0x32;
91 /** Format: 32 bits depth */
92 public static final int D_FP32 = 0x33;
93 /** Format: 32 bits depth, 8 bits stencil */
94 public static final int DS_FP32UI8 = 0x34;
95 /** Format: 8 bits stencil */
96 public static final int S_UI8 = 0x35;
Craig Donner1a4d07d2017-01-09 13:01:22 -080097
98 // Note: do not rename, this field is used by native code
Mathew Inwoodbcbe4402018-08-08 15:42:59 +010099 @UnsupportedAppUsage
Craig Donner1a4d07d2017-01-09 13:01:22 -0800100 private long mNativeObject;
101
102 // Invoked on destruction
103 private Runnable mCleaner;
104
Craig Donnerfd5d3312017-04-19 18:33:36 -0700105 private final CloseGuard mCloseGuard = CloseGuard.get();
106
Craig Donner1a4d07d2017-01-09 13:01:22 -0800107 /** @hide */
108 @Retention(RetentionPolicy.SOURCE)
Tor Norbyef740c7e2017-11-16 14:47:04 -0800109 @LongDef(flag = true, value = {USAGE_CPU_READ_RARELY, USAGE_CPU_READ_OFTEN,
Mathias Agopian910ab132017-04-20 16:36:15 -0700110 USAGE_CPU_WRITE_RARELY, USAGE_CPU_WRITE_OFTEN, USAGE_GPU_SAMPLED_IMAGE,
111 USAGE_GPU_COLOR_OUTPUT, USAGE_PROTECTED_CONTENT, USAGE_VIDEO_ENCODE,
Craig Donner7c37b902017-12-27 15:20:06 -0800112 USAGE_GPU_DATA_BUFFER, USAGE_SENSOR_DIRECT_DATA, USAGE_GPU_CUBE_MAP,
113 USAGE_GPU_MIPMAP_COMPLETE})
Mathias Agopian910ab132017-04-20 16:36:15 -0700114 public @interface Usage {};
Craig Donner1a4d07d2017-01-09 13:01:22 -0800115
Craig Donner7c37b902017-12-27 15:20:06 -0800116 @Usage
Mathias Agopian910ab132017-04-20 16:36:15 -0700117 /** Usage: The buffer will sometimes be read by the CPU */
118 public static final long USAGE_CPU_READ_RARELY = 2;
119 /** Usage: The buffer will often be read by the CPU */
120 public static final long USAGE_CPU_READ_OFTEN = 3;
121
122 /** Usage: The buffer will sometimes be written to by the CPU */
123 public static final long USAGE_CPU_WRITE_RARELY = 2 << 4;
124 /** Usage: The buffer will often be written to by the CPU */
125 public static final long USAGE_CPU_WRITE_OFTEN = 3 << 4;
126
127 /** Usage: The buffer will be read from by the GPU */
128 public static final long USAGE_GPU_SAMPLED_IMAGE = 1 << 8;
129 /** Usage: The buffer will be written to by the GPU */
130 public static final long USAGE_GPU_COLOR_OUTPUT = 1 << 9;
131 /** Usage: The buffer must not be used outside of a protected hardware path */
132 public static final long USAGE_PROTECTED_CONTENT = 1 << 14;
133 /** Usage: The buffer will be read by a hardware video encoder */
134 public static final long USAGE_VIDEO_ENCODE = 1 << 16;
135 /** Usage: The buffer will be used for sensor direct data */
136 public static final long USAGE_SENSOR_DIRECT_DATA = 1 << 23;
137 /** Usage: The buffer will be used as a shader storage or uniform buffer object */
138 public static final long USAGE_GPU_DATA_BUFFER = 1 << 24;
Craig Donner7c37b902017-12-27 15:20:06 -0800139 /** Usage: The buffer will be used as a cube map texture */
140 public static final long USAGE_GPU_CUBE_MAP = 1 << 25;
141 /** Usage: The buffer contains a complete mipmap hierarchy */
142 public static final long USAGE_GPU_MIPMAP_COMPLETE = 1 << 26;
Craig Donner1a4d07d2017-01-09 13:01:22 -0800143
144 // The approximate size of a native AHardwareBuffer object.
145 private static final long NATIVE_HARDWARE_BUFFER_SIZE = 232;
146 /**
147 * Creates a new <code>HardwareBuffer</code> instance.
148 *
149 * <p>Calling this method will throw an <code>IllegalStateException</code> if
150 * format is not a supported Format type.</p>
151 *
152 * @param width The width in pixels of the buffer
153 * @param height The height in pixels of the buffer
Craig Donner7c37b902017-12-27 15:20:06 -0800154 * @param format The @Format of each pixel
Craig Donner1a4d07d2017-01-09 13:01:22 -0800155 * @param layers The number of layers in the buffer
Craig Donner7c37b902017-12-27 15:20:06 -0800156 * @param usage The @Usage flags describing how the buffer will be used
Craig Donner1a4d07d2017-01-09 13:01:22 -0800157 * @return A <code>HardwareBuffer</code> instance if successful, or throws an
158 * IllegalArgumentException if the dimensions passed are invalid (either zero, negative, or
159 * too large to allocate), if the format is not supported, if the requested number of layers
160 * is less than one or not supported, or if the passed usage flags are not a supported set.
161 */
162 @NonNull
John Reck24faae92019-02-20 10:23:41 -0800163 public static HardwareBuffer create(
164 @IntRange(from = 1) int width, @IntRange(from = 1) int height,
165 @Format int format, @IntRange(from = 1) int layers, @Usage long usage) {
Craig Donner1a4d07d2017-01-09 13:01:22 -0800166 if (!HardwareBuffer.isSupportedFormat(format)) {
167 throw new IllegalArgumentException("Invalid pixel format " + format);
168 }
169 if (width <= 0) {
170 throw new IllegalArgumentException("Invalid width " + width);
171 }
172 if (height <= 0) {
173 throw new IllegalArgumentException("Invalid height " + height);
174 }
175 if (layers <= 0) {
176 throw new IllegalArgumentException("Invalid layer count " + layers);
177 }
Craig Donner2be5b9f2017-01-24 18:14:44 -0800178 if (format == BLOB && height != 1) {
179 throw new IllegalArgumentException("Height must be 1 when using the BLOB format");
180 }
Craig Donner1a4d07d2017-01-09 13:01:22 -0800181 long nativeObject = nCreateHardwareBuffer(width, height, format, layers, usage);
182 if (nativeObject == 0) {
183 throw new IllegalArgumentException("Unable to create a HardwareBuffer, either the " +
184 "dimensions passed were too large, too many image layers were requested, " +
Craig Donner7c37b902017-12-27 15:20:06 -0800185 "or an invalid set of usage flags or invalid format was passed");
Craig Donner1a4d07d2017-01-09 13:01:22 -0800186 }
187 return new HardwareBuffer(nativeObject);
188 }
189
190 /**
John Reck4d312b22019-01-25 15:20:24 -0800191 * Queries whether the given buffer description is supported by the system. If this returns
192 * true, then the allocation may succeed until resource exhaustion occurs. If this returns
193 * false then this combination will never succeed.
194 *
195 * @param width The width in pixels of the buffer
196 * @param height The height in pixels of the buffer
197 * @param format The @Format of each pixel
198 * @param layers The number of layers in the buffer
199 * @param usage The @Usage flags describing how the buffer will be used
200 * @return True if the combination is supported, false otherwise.
201 */
John Reck24faae92019-02-20 10:23:41 -0800202 public static boolean isSupported(@IntRange(from = 1) int width, @IntRange(from = 1) int height,
203 @Format int format, @IntRange(from = 1) int layers, @Usage long usage) {
John Reck4d312b22019-01-25 15:20:24 -0800204 if (!HardwareBuffer.isSupportedFormat(format)) {
205 throw new IllegalArgumentException("Invalid pixel format " + format);
206 }
207 if (width <= 0) {
208 throw new IllegalArgumentException("Invalid width " + width);
209 }
210 if (height <= 0) {
211 throw new IllegalArgumentException("Invalid height " + height);
212 }
213 if (layers <= 0) {
214 throw new IllegalArgumentException("Invalid layer count " + layers);
215 }
216 if (format == BLOB && height != 1) {
217 throw new IllegalArgumentException("Height must be 1 when using the BLOB format");
218 }
219 return nIsSupported(width, height, format, layers, usage);
220 }
221
222 /**
Peiyong Lin9d427402019-01-23 18:39:06 -0800223 * @hide
224 * Returns a <code>HardwareBuffer</code> instance from <code>GraphicBuffer</code>
225 *
226 * @param graphicBuffer A GraphicBuffer to be wrapped as HardwareBuffer
227 * @return A <code>HardwareBuffer</code> instance.
228 */
229 @NonNull
230 public static HardwareBuffer createFromGraphicBuffer(@NonNull GraphicBuffer graphicBuffer) {
231 long nativeObject = nCreateFromGraphicBuffer(graphicBuffer);
232 return new HardwareBuffer(nativeObject);
233 }
234
235 /**
Romain Guy8ec21062017-02-10 18:49:33 -0800236 * Private use only. See {@link #create(int, int, int, int, long)}. May also be
Craig Donner1a4d07d2017-01-09 13:01:22 -0800237 * called from JNI using an already allocated native <code>HardwareBuffer</code>.
238 */
Mathew Inwood8c854f82018-09-14 12:35:36 +0100239 @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P, trackingBug = 115609023)
Craig Donner1a4d07d2017-01-09 13:01:22 -0800240 private HardwareBuffer(long nativeObject) {
241 mNativeObject = nativeObject;
242
Romain Guy8ec21062017-02-10 18:49:33 -0800243 ClassLoader loader = HardwareBuffer.class.getClassLoader();
Craig Donner1a4d07d2017-01-09 13:01:22 -0800244 NativeAllocationRegistry registry = new NativeAllocationRegistry(
Romain Guy8ec21062017-02-10 18:49:33 -0800245 loader, nGetNativeFinalizer(), NATIVE_HARDWARE_BUFFER_SIZE);
Craig Donner1a4d07d2017-01-09 13:01:22 -0800246 mCleaner = registry.registerNativeAllocation(this, mNativeObject);
Craig Donnerfd5d3312017-04-19 18:33:36 -0700247 mCloseGuard.open("close");
248 }
249
250 @Override
251 protected void finalize() throws Throwable {
252 try {
253 mCloseGuard.warnIfOpen();
254 close();
255 } finally {
256 super.finalize();
257 }
Craig Donner1a4d07d2017-01-09 13:01:22 -0800258 }
259
260 /**
261 * Returns the width of this buffer in pixels.
262 */
263 public int getWidth() {
Craig Donnerfd5d3312017-04-19 18:33:36 -0700264 if (isClosed()) {
265 throw new IllegalStateException("This HardwareBuffer has been closed and its width "
Craig Donner1a4d07d2017-01-09 13:01:22 -0800266 + "cannot be obtained.");
267 }
268 return nGetWidth(mNativeObject);
269 }
270
271 /**
272 * Returns the height of this buffer in pixels.
273 */
274 public int getHeight() {
Craig Donnerfd5d3312017-04-19 18:33:36 -0700275 if (isClosed()) {
276 throw new IllegalStateException("This HardwareBuffer has been closed and its height "
Craig Donner1a4d07d2017-01-09 13:01:22 -0800277 + "cannot be obtained.");
278 }
279 return nGetHeight(mNativeObject);
280 }
281
282 /**
Craig Donner7c37b902017-12-27 15:20:06 -0800283 * Returns the @Format of this buffer.
Craig Donner1a4d07d2017-01-09 13:01:22 -0800284 */
Romain Guy8ec21062017-02-10 18:49:33 -0800285 @Format
Craig Donner1a4d07d2017-01-09 13:01:22 -0800286 public int getFormat() {
Craig Donnerfd5d3312017-04-19 18:33:36 -0700287 if (isClosed()) {
288 throw new IllegalStateException("This HardwareBuffer has been closed and its format "
Craig Donner1a4d07d2017-01-09 13:01:22 -0800289 + "cannot be obtained.");
290 }
291 return nGetFormat(mNativeObject);
292 }
293
294 /**
295 * Returns the number of layers in this buffer.
296 */
297 public int getLayers() {
Craig Donnerfd5d3312017-04-19 18:33:36 -0700298 if (isClosed()) {
299 throw new IllegalStateException("This HardwareBuffer has been closed and its layer "
Craig Donner1a4d07d2017-01-09 13:01:22 -0800300 + "count cannot be obtained.");
301 }
302 return nGetLayers(mNativeObject);
303 }
304
305 /**
306 * Returns the usage flags of the usage hints set on this buffer.
307 */
308 public long getUsage() {
Craig Donnerfd5d3312017-04-19 18:33:36 -0700309 if (isClosed()) {
310 throw new IllegalStateException("This HardwareBuffer has been closed and its usage "
Craig Donner1a4d07d2017-01-09 13:01:22 -0800311 + "cannot be obtained.");
312 }
313 return nGetUsage(mNativeObject);
314 }
315
316 /**
317 * Destroys this buffer immediately. Calling this method frees up any
318 * underlying native resources. After calling this method, this buffer
319 * must not be used in any way.
320 *
Craig Donnerfd5d3312017-04-19 18:33:36 -0700321 * @see #isClosed()
Craig Donner1a4d07d2017-01-09 13:01:22 -0800322 */
Craig Donnerfd5d3312017-04-19 18:33:36 -0700323 @Override
324 public void close() {
325 if (!isClosed()) {
326 mCloseGuard.close();
Craig Donner1a4d07d2017-01-09 13:01:22 -0800327 mNativeObject = 0;
328 mCleaner.run();
329 mCleaner = null;
330 }
331 }
332
333 /**
Craig Donnerfd5d3312017-04-19 18:33:36 -0700334 * Indicates whether this buffer has been closed. A closed buffer cannot
335 * be used in any way: the buffer cannot be written to a parcel, etc.
Craig Donner1a4d07d2017-01-09 13:01:22 -0800336 *
Craig Donnerfd5d3312017-04-19 18:33:36 -0700337 * @return True if this <code>HardwareBuffer</code> is in a closed state,
Craig Donner1a4d07d2017-01-09 13:01:22 -0800338 * false otherwise.
339 *
Craig Donnerfd5d3312017-04-19 18:33:36 -0700340 * @see #close()
Craig Donner1a4d07d2017-01-09 13:01:22 -0800341 */
Craig Donnerfd5d3312017-04-19 18:33:36 -0700342 public boolean isClosed() {
Craig Donner1a4d07d2017-01-09 13:01:22 -0800343 return mNativeObject == 0;
344 }
345
346 @Override
347 public int describeContents() {
348 return Parcelable.CONTENTS_FILE_DESCRIPTOR;
349 }
350
351 /**
352 * Flatten this object in to a Parcel.
353 *
354 * <p>Calling this method will throw an <code>IllegalStateException</code> if
Craig Donnerfd5d3312017-04-19 18:33:36 -0700355 * {@link #close()} has been previously called.</p>
Craig Donner1a4d07d2017-01-09 13:01:22 -0800356 *
357 * @param dest The Parcel in which the object should be written.
358 * @param flags Additional flags about how the object should be written.
359 * May be 0 or {@link #PARCELABLE_WRITE_RETURN_VALUE}.
360 */
361 @Override
362 public void writeToParcel(Parcel dest, int flags) {
Craig Donnerfd5d3312017-04-19 18:33:36 -0700363 if (isClosed()) {
364 throw new IllegalStateException("This HardwareBuffer has been closed and cannot be "
Craig Donner1a4d07d2017-01-09 13:01:22 -0800365 + "written to a parcel.");
366 }
367 nWriteHardwareBufferToParcel(mNativeObject, dest);
368 }
369
Jeff Sharkey9e8f83d2019-02-28 12:06:45 -0700370 public static final @android.annotation.NonNull Parcelable.Creator<HardwareBuffer> CREATOR =
Craig Donner1a4d07d2017-01-09 13:01:22 -0800371 new Parcelable.Creator<HardwareBuffer>() {
372 public HardwareBuffer createFromParcel(Parcel in) {
373 long nativeObject = nReadHardwareBufferFromParcel(in);
374 if (nativeObject != 0) {
375 return new HardwareBuffer(nativeObject);
376 }
377 return null;
378 }
379
380 public HardwareBuffer[] newArray(int size) {
381 return new HardwareBuffer[size];
382 }
383 };
384
385 /**
386 * Validates whether a particular format is supported by HardwareBuffer.
387 *
388 * @param format The format to validate.
389 *
390 * @return True if <code>format</code> is a supported format. false otherwise.
Romain Guy8ec21062017-02-10 18:49:33 -0800391 * See {@link #create(int, int, int, int, long)}.
Craig Donner1a4d07d2017-01-09 13:01:22 -0800392 */
393 private static boolean isSupportedFormat(@Format int format) {
394 switch(format) {
395 case RGBA_8888:
396 case RGBA_FP16:
Romain Guy8ec21062017-02-10 18:49:33 -0800397 case RGBA_1010102:
Craig Donner1a4d07d2017-01-09 13:01:22 -0800398 case RGBX_8888:
399 case RGB_565:
400 case RGB_888:
Craig Donner2be5b9f2017-01-24 18:14:44 -0800401 case BLOB:
Wonsik Kim637afb22020-02-25 14:27:29 -0800402 case YCBCR_420_888:
Craig Donner7c37b902017-12-27 15:20:06 -0800403 case D_16:
404 case D_24:
405 case DS_24UI8:
406 case D_FP32:
407 case DS_FP32UI8:
408 case S_UI8:
Craig Donner1a4d07d2017-01-09 13:01:22 -0800409 return true;
410 }
411 return false;
412 }
413
414 private static native long nCreateHardwareBuffer(int width, int height, int format, int layers,
415 long usage);
Peiyong Lin9d427402019-01-23 18:39:06 -0800416 private static native long nCreateFromGraphicBuffer(GraphicBuffer graphicBuffer);
Craig Donner1a4d07d2017-01-09 13:01:22 -0800417 private static native long nGetNativeFinalizer();
418 private static native void nWriteHardwareBufferToParcel(long nativeObject, Parcel dest);
419 private static native long nReadHardwareBufferFromParcel(Parcel in);
420 @FastNative
421 private static native int nGetWidth(long nativeObject);
422 @FastNative
423 private static native int nGetHeight(long nativeObject);
424 @FastNative
425 private static native int nGetFormat(long nativeObject);
426 @FastNative
427 private static native int nGetLayers(long nativeObject);
428 @FastNative
429 private static native long nGetUsage(long nativeObject);
John Reck4d312b22019-01-25 15:20:24 -0800430 private static native boolean nIsSupported(int width, int height, int format, int layers,
431 long usage);
Craig Donner1a4d07d2017-01-09 13:01:22 -0800432}