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", "YCBCR_", "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 YCBCR_420_888, 58 D_16, 59 D_24, 60 DS_24UI8, 61 D_FP32, 62 DS_FP32UI8, 63 S_UI8, 64 }) 65 public @interface Format { 66 } 67 68 @Format 69 /** Format: 8 bits each red, green, blue, alpha */ 70 public static final int RGBA_8888 = 1; 71 /** Format: 8 bits each red, green, blue, alpha, alpha is always 0xFF */ 72 public static final int RGBX_8888 = 2; 73 /** Format: 8 bits each red, green, blue, no alpha */ 74 public static final int RGB_888 = 3; 75 /** Format: 5 bits each red and blue, 6 bits green, no alpha */ 76 public static final int RGB_565 = 4; 77 /** Format: 16 bits each red, green, blue, alpha */ 78 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; 81 /** Format: opaque format used for raw data transfer; must have a height of 1 */ 82 public static final int BLOB = 0x21; 83 /** Format: Planar YCbCr 420; must have an even width and height */ 84 public static final int YCBCR_420_888 = 0x23; 85 /** 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; 97 98 // Note: do not rename, this field is used by native code 99 @UnsupportedAppUsage 100 private long mNativeObject; 101 102 // Invoked on destruction 103 private Runnable mCleaner; 104 105 private final CloseGuard mCloseGuard = CloseGuard.get(); 106 107 /** @hide */ 108 @Retention(RetentionPolicy.SOURCE) 109 @LongDef(flag = true, value = {USAGE_CPU_READ_RARELY, USAGE_CPU_READ_OFTEN, 110 USAGE_CPU_WRITE_RARELY, USAGE_CPU_WRITE_OFTEN, USAGE_GPU_SAMPLED_IMAGE, 111 USAGE_GPU_COLOR_OUTPUT, USAGE_PROTECTED_CONTENT, USAGE_VIDEO_ENCODE, 112 USAGE_GPU_DATA_BUFFER, USAGE_SENSOR_DIRECT_DATA, USAGE_GPU_CUBE_MAP, 113 USAGE_GPU_MIPMAP_COMPLETE}) 114 public @interface Usage {}; 115 116 @Usage 117 /** 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; 139 /** 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; 143 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 154 * @param format The @Format of each pixel 155 * @param layers The number of layers in the buffer 156 * @param usage The @Usage flags describing how the buffer will be used 157 * @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 create( @ntRangefrom = 1) int width, @IntRange(from = 1) int height, @Format int format, @IntRange(from = 1) int layers, @Usage long usage)163 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) { 166 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 } 178 if (format == BLOB && height != 1) { 179 throw new IllegalArgumentException("Height must be 1 when using the BLOB format"); 180 } 181 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, " + 185 "or an invalid set of usage flags or invalid format was passed"); 186 } 187 return new HardwareBuffer(nativeObject); 188 } 189 190 /** 191 * 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 */ isSupported(@ntRangefrom = 1) int width, @IntRange(from = 1) int height, @Format int format, @IntRange(from = 1) int layers, @Usage long usage)202 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) { 204 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 /** 223 * @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 createFromGraphicBuffer(@onNull GraphicBuffer graphicBuffer)230 public static HardwareBuffer createFromGraphicBuffer(@NonNull GraphicBuffer graphicBuffer) { 231 long nativeObject = nCreateFromGraphicBuffer(graphicBuffer); 232 return new HardwareBuffer(nativeObject); 233 } 234 235 /** 236 * Private use only. See {@link #create(int, int, int, int, long)}. May also be 237 * called from JNI using an already allocated native <code>HardwareBuffer</code>. 238 */ 239 @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P, trackingBug = 115609023) HardwareBuffer(long nativeObject)240 private HardwareBuffer(long nativeObject) { 241 mNativeObject = nativeObject; 242 243 ClassLoader loader = HardwareBuffer.class.getClassLoader(); 244 NativeAllocationRegistry registry = new NativeAllocationRegistry( 245 loader, nGetNativeFinalizer(), NATIVE_HARDWARE_BUFFER_SIZE); 246 mCleaner = registry.registerNativeAllocation(this, mNativeObject); 247 mCloseGuard.open("close"); 248 } 249 250 @Override finalize()251 protected void finalize() throws Throwable { 252 try { 253 mCloseGuard.warnIfOpen(); 254 close(); 255 } finally { 256 super.finalize(); 257 } 258 } 259 260 /** 261 * Returns the width of this buffer in pixels. 262 */ getWidth()263 public int getWidth() { 264 if (isClosed()) { 265 throw new IllegalStateException("This HardwareBuffer has been closed and its width " 266 + "cannot be obtained."); 267 } 268 return nGetWidth(mNativeObject); 269 } 270 271 /** 272 * Returns the height of this buffer in pixels. 273 */ getHeight()274 public int getHeight() { 275 if (isClosed()) { 276 throw new IllegalStateException("This HardwareBuffer has been closed and its height " 277 + "cannot be obtained."); 278 } 279 return nGetHeight(mNativeObject); 280 } 281 282 /** 283 * Returns the @Format of this buffer. 284 */ 285 @Format getFormat()286 public int getFormat() { 287 if (isClosed()) { 288 throw new IllegalStateException("This HardwareBuffer has been closed and its format " 289 + "cannot be obtained."); 290 } 291 return nGetFormat(mNativeObject); 292 } 293 294 /** 295 * Returns the number of layers in this buffer. 296 */ getLayers()297 public int getLayers() { 298 if (isClosed()) { 299 throw new IllegalStateException("This HardwareBuffer has been closed and its layer " 300 + "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 */ getUsage()308 public long getUsage() { 309 if (isClosed()) { 310 throw new IllegalStateException("This HardwareBuffer has been closed and its usage " 311 + "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 * 321 * @see #isClosed() 322 */ 323 @Override close()324 public void close() { 325 if (!isClosed()) { 326 mCloseGuard.close(); 327 mNativeObject = 0; 328 mCleaner.run(); 329 mCleaner = null; 330 } 331 } 332 333 /** 334 * 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. 336 * 337 * @return True if this <code>HardwareBuffer</code> is in a closed state, 338 * false otherwise. 339 * 340 * @see #close() 341 */ isClosed()342 public boolean isClosed() { 343 return mNativeObject == 0; 344 } 345 346 @Override describeContents()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 355 * {@link #close()} has been previously called.</p> 356 * 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 writeToParcel(Parcel dest, int flags)362 public void writeToParcel(Parcel dest, int flags) { 363 if (isClosed()) { 364 throw new IllegalStateException("This HardwareBuffer has been closed and cannot be " 365 + "written to a parcel."); 366 } 367 nWriteHardwareBufferToParcel(mNativeObject, dest); 368 } 369 370 public static final @android.annotation.NonNull Parcelable.Creator<HardwareBuffer> CREATOR = 371 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. 391 * See {@link #create(int, int, int, int, long)}. 392 */ isSupportedFormat(@ormat int format)393 private static boolean isSupportedFormat(@Format int format) { 394 switch(format) { 395 case RGBA_8888: 396 case RGBA_FP16: 397 case RGBA_1010102: 398 case RGBX_8888: 399 case RGB_565: 400 case RGB_888: 401 case BLOB: 402 case YCBCR_420_888: 403 case D_16: 404 case D_24: 405 case DS_24UI8: 406 case D_FP32: 407 case DS_FP32UI8: 408 case S_UI8: 409 return true; 410 } 411 return false; 412 } 413 nCreateHardwareBuffer(int width, int height, int format, int layers, long usage)414 private static native long nCreateHardwareBuffer(int width, int height, int format, int layers, 415 long usage); nCreateFromGraphicBuffer(GraphicBuffer graphicBuffer)416 private static native long nCreateFromGraphicBuffer(GraphicBuffer graphicBuffer); nGetNativeFinalizer()417 private static native long nGetNativeFinalizer(); nWriteHardwareBufferToParcel(long nativeObject, Parcel dest)418 private static native void nWriteHardwareBufferToParcel(long nativeObject, Parcel dest); nReadHardwareBufferFromParcel(Parcel in)419 private static native long nReadHardwareBufferFromParcel(Parcel in); 420 @FastNative nGetWidth(long nativeObject)421 private static native int nGetWidth(long nativeObject); 422 @FastNative nGetHeight(long nativeObject)423 private static native int nGetHeight(long nativeObject); 424 @FastNative nGetFormat(long nativeObject)425 private static native int nGetFormat(long nativeObject); 426 @FastNative nGetLayers(long nativeObject)427 private static native int nGetLayers(long nativeObject); 428 @FastNative nGetUsage(long nativeObject)429 private static native long nGetUsage(long nativeObject); nIsSupported(int width, int height, int format, int layers, long usage)430 private static native boolean nIsSupported(int width, int height, int format, int layers, 431 long usage); 432 } 433