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