blob: c569e05112a38ee73adf02d3f39b60a7937b6182 [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;
Mathew Inwoodbcbe4402018-08-08 15:42:59 +010023import android.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)
Craig Donner7c37b902017-12-27 15:20:06 -080049 @IntDef(prefix = { "RGB", "BLOB", "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,
57 D_16,
58 D_24,
59 DS_24UI8,
60 D_FP32,
61 DS_FP32UI8,
62 S_UI8,
Jeff Sharkeyce8db992017-12-13 20:05:05 -070063 })
Romain Guy8ec21062017-02-10 18:49:33 -080064 public @interface Format {
65 }
Craig Donner1a4d07d2017-01-09 13:01:22 -080066
Craig Donner7c37b902017-12-27 15:20:06 -080067 @Format
Craig Donner1a4d07d2017-01-09 13:01:22 -080068 /** Format: 8 bits each red, green, blue, alpha */
Romain Guy8ec21062017-02-10 18:49:33 -080069 public static final int RGBA_8888 = 1;
Craig Donner1a4d07d2017-01-09 13:01:22 -080070 /** Format: 8 bits each red, green, blue, alpha, alpha is always 0xFF */
Romain Guy8ec21062017-02-10 18:49:33 -080071 public static final int RGBX_8888 = 2;
Craig Donner1a4d07d2017-01-09 13:01:22 -080072 /** Format: 8 bits each red, green, blue, no alpha */
Romain Guy8ec21062017-02-10 18:49:33 -080073 public static final int RGB_888 = 3;
Craig Donner1a4d07d2017-01-09 13:01:22 -080074 /** Format: 5 bits each red and blue, 6 bits green, no alpha */
Romain Guy8ec21062017-02-10 18:49:33 -080075 public static final int RGB_565 = 4;
Craig Donner1a4d07d2017-01-09 13:01:22 -080076 /** Format: 16 bits each red, green, blue, alpha */
Romain Guy8ec21062017-02-10 18:49:33 -080077 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;
Craig Donner2be5b9f2017-01-24 18:14:44 -080080 /** Format: opaque format used for raw data transfer; must have a height of 1 */
Romain Guy8ec21062017-02-10 18:49:33 -080081 public static final int BLOB = 0x21;
Craig Donner7c37b902017-12-27 15:20:06 -080082 /** 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;
Craig Donner1a4d07d2017-01-09 13:01:22 -080094
95 // Note: do not rename, this field is used by native code
Mathew Inwoodbcbe4402018-08-08 15:42:59 +010096 @UnsupportedAppUsage
Craig Donner1a4d07d2017-01-09 13:01:22 -080097 private long mNativeObject;
98
99 // Invoked on destruction
100 private Runnable mCleaner;
101
Craig Donnerfd5d3312017-04-19 18:33:36 -0700102 private final CloseGuard mCloseGuard = CloseGuard.get();
103
Craig Donner1a4d07d2017-01-09 13:01:22 -0800104 /** @hide */
105 @Retention(RetentionPolicy.SOURCE)
Tor Norbyef740c7e2017-11-16 14:47:04 -0800106 @LongDef(flag = true, value = {USAGE_CPU_READ_RARELY, USAGE_CPU_READ_OFTEN,
Mathias Agopian910ab132017-04-20 16:36:15 -0700107 USAGE_CPU_WRITE_RARELY, USAGE_CPU_WRITE_OFTEN, USAGE_GPU_SAMPLED_IMAGE,
108 USAGE_GPU_COLOR_OUTPUT, USAGE_PROTECTED_CONTENT, USAGE_VIDEO_ENCODE,
Craig Donner7c37b902017-12-27 15:20:06 -0800109 USAGE_GPU_DATA_BUFFER, USAGE_SENSOR_DIRECT_DATA, USAGE_GPU_CUBE_MAP,
110 USAGE_GPU_MIPMAP_COMPLETE})
Mathias Agopian910ab132017-04-20 16:36:15 -0700111 public @interface Usage {};
Craig Donner1a4d07d2017-01-09 13:01:22 -0800112
Craig Donner7c37b902017-12-27 15:20:06 -0800113 @Usage
Mathias Agopian910ab132017-04-20 16:36:15 -0700114 /** 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;
Craig Donner7c37b902017-12-27 15:20:06 -0800136 /** 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;
Craig Donner1a4d07d2017-01-09 13:01:22 -0800140
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
Craig Donner7c37b902017-12-27 15:20:06 -0800151 * @param format The @Format of each pixel
Craig Donner1a4d07d2017-01-09 13:01:22 -0800152 * @param layers The number of layers in the buffer
Craig Donner7c37b902017-12-27 15:20:06 -0800153 * @param usage The @Usage flags describing how the buffer will be used
Craig Donner1a4d07d2017-01-09 13:01:22 -0800154 * @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
John Reck24faae92019-02-20 10:23:41 -0800160 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) {
Craig Donner1a4d07d2017-01-09 13:01:22 -0800163 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 }
Craig Donner2be5b9f2017-01-24 18:14:44 -0800175 if (format == BLOB && height != 1) {
176 throw new IllegalArgumentException("Height must be 1 when using the BLOB format");
177 }
Craig Donner1a4d07d2017-01-09 13:01:22 -0800178 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, " +
Craig Donner7c37b902017-12-27 15:20:06 -0800182 "or an invalid set of usage flags or invalid format was passed");
Craig Donner1a4d07d2017-01-09 13:01:22 -0800183 }
184 return new HardwareBuffer(nativeObject);
185 }
186
187 /**
John Reck4d312b22019-01-25 15:20:24 -0800188 * 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 */
John Reck24faae92019-02-20 10:23:41 -0800199 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) {
John Reck4d312b22019-01-25 15:20:24 -0800201 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 /**
Peiyong Lin9d427402019-01-23 18:39:06 -0800220 * @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
227 public static HardwareBuffer createFromGraphicBuffer(@NonNull GraphicBuffer graphicBuffer) {
228 long nativeObject = nCreateFromGraphicBuffer(graphicBuffer);
229 return new HardwareBuffer(nativeObject);
230 }
231
232 /**
Romain Guy8ec21062017-02-10 18:49:33 -0800233 * Private use only. See {@link #create(int, int, int, int, long)}. May also be
Craig Donner1a4d07d2017-01-09 13:01:22 -0800234 * called from JNI using an already allocated native <code>HardwareBuffer</code>.
235 */
Mathew Inwood8c854f82018-09-14 12:35:36 +0100236 @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P, trackingBug = 115609023)
Craig Donner1a4d07d2017-01-09 13:01:22 -0800237 private HardwareBuffer(long nativeObject) {
238 mNativeObject = nativeObject;
239
Romain Guy8ec21062017-02-10 18:49:33 -0800240 ClassLoader loader = HardwareBuffer.class.getClassLoader();
Craig Donner1a4d07d2017-01-09 13:01:22 -0800241 NativeAllocationRegistry registry = new NativeAllocationRegistry(
Romain Guy8ec21062017-02-10 18:49:33 -0800242 loader, nGetNativeFinalizer(), NATIVE_HARDWARE_BUFFER_SIZE);
Craig Donner1a4d07d2017-01-09 13:01:22 -0800243 mCleaner = registry.registerNativeAllocation(this, mNativeObject);
Craig Donnerfd5d3312017-04-19 18:33:36 -0700244 mCloseGuard.open("close");
245 }
246
247 @Override
248 protected void finalize() throws Throwable {
249 try {
250 mCloseGuard.warnIfOpen();
251 close();
252 } finally {
253 super.finalize();
254 }
Craig Donner1a4d07d2017-01-09 13:01:22 -0800255 }
256
257 /**
258 * Returns the width of this buffer in pixels.
259 */
260 public int getWidth() {
Craig Donnerfd5d3312017-04-19 18:33:36 -0700261 if (isClosed()) {
262 throw new IllegalStateException("This HardwareBuffer has been closed and its width "
Craig Donner1a4d07d2017-01-09 13:01:22 -0800263 + "cannot be obtained.");
264 }
265 return nGetWidth(mNativeObject);
266 }
267
268 /**
269 * Returns the height of this buffer in pixels.
270 */
271 public int getHeight() {
Craig Donnerfd5d3312017-04-19 18:33:36 -0700272 if (isClosed()) {
273 throw new IllegalStateException("This HardwareBuffer has been closed and its height "
Craig Donner1a4d07d2017-01-09 13:01:22 -0800274 + "cannot be obtained.");
275 }
276 return nGetHeight(mNativeObject);
277 }
278
279 /**
Craig Donner7c37b902017-12-27 15:20:06 -0800280 * Returns the @Format of this buffer.
Craig Donner1a4d07d2017-01-09 13:01:22 -0800281 */
Romain Guy8ec21062017-02-10 18:49:33 -0800282 @Format
Craig Donner1a4d07d2017-01-09 13:01:22 -0800283 public int getFormat() {
Craig Donnerfd5d3312017-04-19 18:33:36 -0700284 if (isClosed()) {
285 throw new IllegalStateException("This HardwareBuffer has been closed and its format "
Craig Donner1a4d07d2017-01-09 13:01:22 -0800286 + "cannot be obtained.");
287 }
288 return nGetFormat(mNativeObject);
289 }
290
291 /**
292 * Returns the number of layers in this buffer.
293 */
294 public int getLayers() {
Craig Donnerfd5d3312017-04-19 18:33:36 -0700295 if (isClosed()) {
296 throw new IllegalStateException("This HardwareBuffer has been closed and its layer "
Craig Donner1a4d07d2017-01-09 13:01:22 -0800297 + "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 */
305 public long getUsage() {
Craig Donnerfd5d3312017-04-19 18:33:36 -0700306 if (isClosed()) {
307 throw new IllegalStateException("This HardwareBuffer has been closed and its usage "
Craig Donner1a4d07d2017-01-09 13:01:22 -0800308 + "cannot be obtained.");
309 }
310 return nGetUsage(mNativeObject);
311 }
312
Craig Donnerfd5d3312017-04-19 18:33:36 -0700313 /** @removed replaced by {@link #close()} */
314 @Deprecated
315 public void destroy() {
316 close();
317 }
318
319 /** @removed replaced by {@link #isClosed()} */
320 @Deprecated
321 public boolean isDestroyed() {
322 return isClosed();
323 }
324
Craig Donner1a4d07d2017-01-09 13:01:22 -0800325 /**
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 *
Craig Donnerfd5d3312017-04-19 18:33:36 -0700330 * @see #isClosed()
Craig Donner1a4d07d2017-01-09 13:01:22 -0800331 */
Craig Donnerfd5d3312017-04-19 18:33:36 -0700332 @Override
333 public void close() {
334 if (!isClosed()) {
335 mCloseGuard.close();
Craig Donner1a4d07d2017-01-09 13:01:22 -0800336 mNativeObject = 0;
337 mCleaner.run();
338 mCleaner = null;
339 }
340 }
341
342 /**
Craig Donnerfd5d3312017-04-19 18:33:36 -0700343 * 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.
Craig Donner1a4d07d2017-01-09 13:01:22 -0800345 *
Craig Donnerfd5d3312017-04-19 18:33:36 -0700346 * @return True if this <code>HardwareBuffer</code> is in a closed state,
Craig Donner1a4d07d2017-01-09 13:01:22 -0800347 * false otherwise.
348 *
Craig Donnerfd5d3312017-04-19 18:33:36 -0700349 * @see #close()
Craig Donner1a4d07d2017-01-09 13:01:22 -0800350 */
Craig Donnerfd5d3312017-04-19 18:33:36 -0700351 public boolean isClosed() {
Craig Donner1a4d07d2017-01-09 13:01:22 -0800352 return mNativeObject == 0;
353 }
354
355 @Override
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
Craig Donnerfd5d3312017-04-19 18:33:36 -0700364 * {@link #close()} has been previously called.</p>
Craig Donner1a4d07d2017-01-09 13:01:22 -0800365 *
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
371 public void writeToParcel(Parcel dest, int flags) {
Craig Donnerfd5d3312017-04-19 18:33:36 -0700372 if (isClosed()) {
373 throw new IllegalStateException("This HardwareBuffer has been closed and cannot be "
Craig Donner1a4d07d2017-01-09 13:01:22 -0800374 + "written to a parcel.");
375 }
376 nWriteHardwareBufferToParcel(mNativeObject, dest);
377 }
378
Jeff Sharkey9e8f83d2019-02-28 12:06:45 -0700379 public static final @android.annotation.NonNull Parcelable.Creator<HardwareBuffer> CREATOR =
Craig Donner1a4d07d2017-01-09 13:01:22 -0800380 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.
Romain Guy8ec21062017-02-10 18:49:33 -0800400 * See {@link #create(int, int, int, int, long)}.
Craig Donner1a4d07d2017-01-09 13:01:22 -0800401 */
402 private static boolean isSupportedFormat(@Format int format) {
403 switch(format) {
404 case RGBA_8888:
405 case RGBA_FP16:
Romain Guy8ec21062017-02-10 18:49:33 -0800406 case RGBA_1010102:
Craig Donner1a4d07d2017-01-09 13:01:22 -0800407 case RGBX_8888:
408 case RGB_565:
409 case RGB_888:
Craig Donner2be5b9f2017-01-24 18:14:44 -0800410 case BLOB:
Craig Donner7c37b902017-12-27 15:20:06 -0800411 case D_16:
412 case D_24:
413 case DS_24UI8:
414 case D_FP32:
415 case DS_FP32UI8:
416 case S_UI8:
Craig Donner1a4d07d2017-01-09 13:01:22 -0800417 return true;
418 }
419 return false;
420 }
421
422 private static native long nCreateHardwareBuffer(int width, int height, int format, int layers,
423 long usage);
Peiyong Lin9d427402019-01-23 18:39:06 -0800424 private static native long nCreateFromGraphicBuffer(GraphicBuffer graphicBuffer);
Craig Donner1a4d07d2017-01-09 13:01:22 -0800425 private static native long nGetNativeFinalizer();
426 private static native void nWriteHardwareBufferToParcel(long nativeObject, Parcel dest);
427 private static native long nReadHardwareBufferFromParcel(Parcel in);
428 @FastNative
429 private static native int nGetWidth(long nativeObject);
430 @FastNative
431 private static native int nGetHeight(long nativeObject);
432 @FastNative
433 private static native int nGetFormat(long nativeObject);
434 @FastNative
435 private static native int nGetLayers(long nativeObject);
436 @FastNative
437 private static native long nGetUsage(long nativeObject);
John Reck4d312b22019-01-25 15:20:24 -0800438 private static native boolean nIsSupported(int width, int height, int format, int layers,
439 long usage);
Craig Donner1a4d07d2017-01-09 13:01:22 -0800440}