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.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", "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 D_16, 58 D_24, 59 DS_24UI8, 60 D_FP32, 61 DS_FP32UI8, 62 S_UI8, 63 }) 64 public @interface Format { 65 } 66 67 @Format 68 /** Format: 8 bits each red, green, blue, alpha */ 69 public static final int RGBA_8888 = 1; 70 /** Format: 8 bits each red, green, blue, alpha, alpha is always 0xFF */ 71 public static final int RGBX_8888 = 2; 72 /** Format: 8 bits each red, green, blue, no alpha */ 73 public static final int RGB_888 = 3; 74 /** Format: 5 bits each red and blue, 6 bits green, no alpha */ 75 public static final int RGB_565 = 4; 76 /** Format: 16 bits each red, green, blue, alpha */ 77 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; 80 /** Format: opaque format used for raw data transfer; must have a height of 1 */ 81 public static final int BLOB = 0x21; 82 /** 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; 94 95 // Note: do not rename, this field is used by native code 96 @UnsupportedAppUsage 97 private long mNativeObject; 98 99 // Invoked on destruction 100 private Runnable mCleaner; 101 102 private final CloseGuard mCloseGuard = CloseGuard.get(); 103 104 /** @hide */ 105 @Retention(RetentionPolicy.SOURCE) 106 @LongDef(flag = true, value = {USAGE_CPU_READ_RARELY, USAGE_CPU_READ_OFTEN, 107 USAGE_CPU_WRITE_RARELY, USAGE_CPU_WRITE_OFTEN, USAGE_GPU_SAMPLED_IMAGE, 108 USAGE_GPU_COLOR_OUTPUT, USAGE_PROTECTED_CONTENT, USAGE_VIDEO_ENCODE, 109 USAGE_GPU_DATA_BUFFER, USAGE_SENSOR_DIRECT_DATA, USAGE_GPU_CUBE_MAP, 110 USAGE_GPU_MIPMAP_COMPLETE}) 111 public @interface Usage {}; 112 113 @Usage 114 /** 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; 136 /** 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; 140 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 151 * @param format The @Format of each pixel 152 * @param layers The number of layers in the buffer 153 * @param usage The @Usage flags describing how the buffer will be used 154 * @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 create( @ntRangefrom = 1) int width, @IntRange(from = 1) int height, @Format int format, @IntRange(from = 1) int layers, @Usage long usage)160 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) { 163 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 } 175 if (format == BLOB && height != 1) { 176 throw new IllegalArgumentException("Height must be 1 when using the BLOB format"); 177 } 178 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, " + 182 "or an invalid set of usage flags or invalid format was passed"); 183 } 184 return new HardwareBuffer(nativeObject); 185 } 186 187 /** 188 * 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 */ isSupported(@ntRangefrom = 1) int width, @IntRange(from = 1) int height, @Format int format, @IntRange(from = 1) int layers, @Usage long usage)199 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) { 201 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 /** 220 * @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 createFromGraphicBuffer(@onNull GraphicBuffer graphicBuffer)227 public static HardwareBuffer createFromGraphicBuffer(@NonNull GraphicBuffer graphicBuffer) { 228 long nativeObject = nCreateFromGraphicBuffer(graphicBuffer); 229 return new HardwareBuffer(nativeObject); 230 } 231 232 /** 233 * Private use only. See {@link #create(int, int, int, int, long)}. May also be 234 * called from JNI using an already allocated native <code>HardwareBuffer</code>. 235 */ 236 @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P, trackingBug = 115609023) HardwareBuffer(long nativeObject)237 private HardwareBuffer(long nativeObject) { 238 mNativeObject = nativeObject; 239 240 ClassLoader loader = HardwareBuffer.class.getClassLoader(); 241 NativeAllocationRegistry registry = new NativeAllocationRegistry( 242 loader, nGetNativeFinalizer(), NATIVE_HARDWARE_BUFFER_SIZE); 243 mCleaner = registry.registerNativeAllocation(this, mNativeObject); 244 mCloseGuard.open("close"); 245 } 246 247 @Override finalize()248 protected void finalize() throws Throwable { 249 try { 250 mCloseGuard.warnIfOpen(); 251 close(); 252 } finally { 253 super.finalize(); 254 } 255 } 256 257 /** 258 * Returns the width of this buffer in pixels. 259 */ getWidth()260 public int getWidth() { 261 if (isClosed()) { 262 throw new IllegalStateException("This HardwareBuffer has been closed and its width " 263 + "cannot be obtained."); 264 } 265 return nGetWidth(mNativeObject); 266 } 267 268 /** 269 * Returns the height of this buffer in pixels. 270 */ getHeight()271 public int getHeight() { 272 if (isClosed()) { 273 throw new IllegalStateException("This HardwareBuffer has been closed and its height " 274 + "cannot be obtained."); 275 } 276 return nGetHeight(mNativeObject); 277 } 278 279 /** 280 * Returns the @Format of this buffer. 281 */ 282 @Format getFormat()283 public int getFormat() { 284 if (isClosed()) { 285 throw new IllegalStateException("This HardwareBuffer has been closed and its format " 286 + "cannot be obtained."); 287 } 288 return nGetFormat(mNativeObject); 289 } 290 291 /** 292 * Returns the number of layers in this buffer. 293 */ getLayers()294 public int getLayers() { 295 if (isClosed()) { 296 throw new IllegalStateException("This HardwareBuffer has been closed and its layer " 297 + "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 */ getUsage()305 public long getUsage() { 306 if (isClosed()) { 307 throw new IllegalStateException("This HardwareBuffer has been closed and its usage " 308 + "cannot be obtained."); 309 } 310 return nGetUsage(mNativeObject); 311 } 312 313 /** @removed replaced by {@link #close()} */ 314 @Deprecated destroy()315 public void destroy() { 316 close(); 317 } 318 319 /** @removed replaced by {@link #isClosed()} */ 320 @Deprecated isDestroyed()321 public boolean isDestroyed() { 322 return isClosed(); 323 } 324 325 /** 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 * 330 * @see #isClosed() 331 */ 332 @Override close()333 public void close() { 334 if (!isClosed()) { 335 mCloseGuard.close(); 336 mNativeObject = 0; 337 mCleaner.run(); 338 mCleaner = null; 339 } 340 } 341 342 /** 343 * 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. 345 * 346 * @return True if this <code>HardwareBuffer</code> is in a closed state, 347 * false otherwise. 348 * 349 * @see #close() 350 */ isClosed()351 public boolean isClosed() { 352 return mNativeObject == 0; 353 } 354 355 @Override describeContents()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 364 * {@link #close()} has been previously called.</p> 365 * 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 writeToParcel(Parcel dest, int flags)371 public void writeToParcel(Parcel dest, int flags) { 372 if (isClosed()) { 373 throw new IllegalStateException("This HardwareBuffer has been closed and cannot be " 374 + "written to a parcel."); 375 } 376 nWriteHardwareBufferToParcel(mNativeObject, dest); 377 } 378 379 public static final @android.annotation.NonNull Parcelable.Creator<HardwareBuffer> CREATOR = 380 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. 400 * See {@link #create(int, int, int, int, long)}. 401 */ isSupportedFormat(@ormat int format)402 private static boolean isSupportedFormat(@Format int format) { 403 switch(format) { 404 case RGBA_8888: 405 case RGBA_FP16: 406 case RGBA_1010102: 407 case RGBX_8888: 408 case RGB_565: 409 case RGB_888: 410 case BLOB: 411 case D_16: 412 case D_24: 413 case DS_24UI8: 414 case D_FP32: 415 case DS_FP32UI8: 416 case S_UI8: 417 return true; 418 } 419 return false; 420 } 421 nCreateHardwareBuffer(int width, int height, int format, int layers, long usage)422 private static native long nCreateHardwareBuffer(int width, int height, int format, int layers, 423 long usage); nCreateFromGraphicBuffer(GraphicBuffer graphicBuffer)424 private static native long nCreateFromGraphicBuffer(GraphicBuffer graphicBuffer); nGetNativeFinalizer()425 private static native long nGetNativeFinalizer(); nWriteHardwareBufferToParcel(long nativeObject, Parcel dest)426 private static native void nWriteHardwareBufferToParcel(long nativeObject, Parcel dest); nReadHardwareBufferFromParcel(Parcel in)427 private static native long nReadHardwareBufferFromParcel(Parcel in); 428 @FastNative nGetWidth(long nativeObject)429 private static native int nGetWidth(long nativeObject); 430 @FastNative nGetHeight(long nativeObject)431 private static native int nGetHeight(long nativeObject); 432 @FastNative nGetFormat(long nativeObject)433 private static native int nGetFormat(long nativeObject); 434 @FastNative nGetLayers(long nativeObject)435 private static native int nGetLayers(long nativeObject); 436 @FastNative nGetUsage(long nativeObject)437 private static native long nGetUsage(long nativeObject); nIsSupported(int width, int height, int format, int layers, long usage)438 private static native boolean nIsSupported(int width, int height, int format, int layers, 439 long usage); 440 } 441