466 lines
19 KiB
Java
466 lines
19 KiB
Java
/*
|
|
* Copyright (C) 2017 The Android Open Source Project
|
|
*
|
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
|
* you may not use this file except in compliance with the License.
|
|
* You may obtain a copy of the License at
|
|
*
|
|
* http://www.apache.org/licenses/LICENSE-2.0
|
|
*
|
|
* Unless required by applicable law or agreed to in writing, software
|
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
* See the License for the specific language governing permissions and
|
|
* limitations under the License.
|
|
*/
|
|
|
|
package android.hardware;
|
|
|
|
import android.annotation.FlaggedApi;
|
|
import android.annotation.IntDef;
|
|
import android.annotation.IntRange;
|
|
import android.annotation.LongDef;
|
|
import android.annotation.NonNull;
|
|
import android.compat.annotation.UnsupportedAppUsage;
|
|
import android.graphics.GraphicBuffer;
|
|
import android.os.BadParcelableException;
|
|
import android.os.Build;
|
|
import android.os.Parcel;
|
|
import android.os.Parcelable;
|
|
import android.view.SurfaceControl;
|
|
|
|
import dalvik.annotation.optimization.CriticalNative;
|
|
import dalvik.annotation.optimization.FastNative;
|
|
import dalvik.system.CloseGuard;
|
|
|
|
import libcore.util.NativeAllocationRegistry;
|
|
|
|
import java.lang.annotation.Retention;
|
|
import java.lang.annotation.RetentionPolicy;
|
|
|
|
/**
|
|
* HardwareBuffer wraps a native <code>AHardwareBuffer</code> object, which is a low-level object
|
|
* representing a memory buffer accessible by various hardware units. HardwareBuffer allows sharing
|
|
* buffers across different application processes. In particular, HardwareBuffers may be mappable
|
|
* to memory accessible to various hardware systems, such as the GPU, a sensor or context hub, or
|
|
* other auxiliary processing units.
|
|
*
|
|
* For more information, see the NDK documentation for <code>AHardwareBuffer</code>.
|
|
*/
|
|
public final class HardwareBuffer implements Parcelable, AutoCloseable {
|
|
/** @hide */
|
|
@Retention(RetentionPolicy.SOURCE)
|
|
@IntDef(prefix = { "RGB", "BLOB", "YCBCR_", "D_", "DS_", "S_" }, value = {
|
|
RGBA_8888,
|
|
RGBA_FP16,
|
|
RGBA_1010102,
|
|
RGBX_8888,
|
|
RGB_888,
|
|
RGB_565,
|
|
BLOB,
|
|
YCBCR_420_888,
|
|
D_16,
|
|
D_24,
|
|
DS_24UI8,
|
|
D_FP32,
|
|
DS_FP32UI8,
|
|
S_UI8,
|
|
YCBCR_P010,
|
|
R_8,
|
|
R_16,
|
|
RG_1616,
|
|
RGBA_10101010,
|
|
})
|
|
public @interface Format {
|
|
}
|
|
|
|
@Format
|
|
/** Format: 8 bits each red, green, blue, alpha */
|
|
public static final int RGBA_8888 = 1;
|
|
/** Format: 8 bits each red, green, blue, alpha, alpha is always 0xFF */
|
|
public static final int RGBX_8888 = 2;
|
|
/** Format: 8 bits each red, green, blue, no alpha */
|
|
public static final int RGB_888 = 3;
|
|
/** Format: 5 bits each red and blue, 6 bits green, no alpha */
|
|
public static final int RGB_565 = 4;
|
|
/** Format: 16 bits each red, green, blue, alpha */
|
|
public static final int RGBA_FP16 = 0x16;
|
|
/** Format: 10 bits each red, green, blue, 2 bits alpha */
|
|
public static final int RGBA_1010102 = 0x2b;
|
|
/** Format: opaque format used for raw data transfer; must have a height of 1 */
|
|
public static final int BLOB = 0x21;
|
|
/** Format: Planar YCbCr 420; must have an even width and height */
|
|
public static final int YCBCR_420_888 = 0x23;
|
|
/** Format: 16 bits depth */
|
|
public static final int D_16 = 0x30;
|
|
/** Format: 24 bits depth */
|
|
public static final int D_24 = 0x31;
|
|
/** Format: 24 bits depth, 8 bits stencil */
|
|
public static final int DS_24UI8 = 0x32;
|
|
/** Format: 32 bits depth */
|
|
public static final int D_FP32 = 0x33;
|
|
/** Format: 32 bits depth, 8 bits stencil */
|
|
public static final int DS_FP32UI8 = 0x34;
|
|
/** Format: 8 bits stencil */
|
|
public static final int S_UI8 = 0x35;
|
|
/**
|
|
* <p>Android YUV P010 format.</p>
|
|
*
|
|
* P010 is a 4:2:0 YCbCr semiplanar format comprised of a WxH Y plane
|
|
* followed by a Wx(H/2) CbCr plane. Each sample is represented by a 16-bit
|
|
* little-endian value, with the lower 6 bits set to zero.
|
|
*/
|
|
public static final int YCBCR_P010 = 0x36;
|
|
/** Format: 8 bits red */
|
|
@FlaggedApi(com.android.graphics.hwui.flags.Flags.FLAG_REQUESTED_FORMATS_V)
|
|
public static final int R_8 = 0x38;
|
|
/**
|
|
* Format: 16 bits red. When sampled on the GPU this is represented as an
|
|
* unsigned integer instead of implicit unsigned normalize.
|
|
* For more information see https://www.khronos.org/opengl/wiki/Normalized_Integer
|
|
*/
|
|
@FlaggedApi(com.android.graphics.hwui.flags.Flags.FLAG_REQUESTED_FORMATS_V)
|
|
public static final int R_16 = 0x39;
|
|
/**
|
|
* Format: 16 bits each red, green. When sampled on the GPU this is represented
|
|
* as an unsigned integer instead of implicit unsigned normalize.
|
|
* For more information see https://www.khronos.org/opengl/wiki/Normalized_Integer
|
|
*/
|
|
@FlaggedApi(com.android.graphics.hwui.flags.Flags.FLAG_REQUESTED_FORMATS_V)
|
|
public static final int RG_1616 = 0x3a;
|
|
/** Format: 10 bits each red, green, blue, alpha */
|
|
@FlaggedApi(com.android.graphics.hwui.flags.Flags.FLAG_REQUESTED_FORMATS_V)
|
|
public static final int RGBA_10101010 = 0x3b;
|
|
|
|
// Note: do not rename, this field is used by native code
|
|
@UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553)
|
|
private long mNativeObject;
|
|
|
|
// Invoked on destruction
|
|
private Runnable mCleaner;
|
|
|
|
private final CloseGuard mCloseGuard = CloseGuard.get();
|
|
|
|
/** @hide */
|
|
@Retention(RetentionPolicy.SOURCE)
|
|
@LongDef(flag = true, value = {USAGE_CPU_READ_RARELY, USAGE_CPU_READ_OFTEN,
|
|
USAGE_CPU_WRITE_RARELY, USAGE_CPU_WRITE_OFTEN, USAGE_GPU_SAMPLED_IMAGE,
|
|
USAGE_GPU_COLOR_OUTPUT, USAGE_COMPOSER_OVERLAY, USAGE_PROTECTED_CONTENT,
|
|
USAGE_VIDEO_ENCODE, USAGE_GPU_DATA_BUFFER, USAGE_SENSOR_DIRECT_DATA,
|
|
USAGE_GPU_CUBE_MAP, USAGE_GPU_MIPMAP_COMPLETE, USAGE_FRONT_BUFFER})
|
|
public @interface Usage {};
|
|
|
|
@Usage
|
|
/** Usage: The buffer will sometimes be read by the CPU */
|
|
public static final long USAGE_CPU_READ_RARELY = 2;
|
|
/** Usage: The buffer will often be read by the CPU */
|
|
public static final long USAGE_CPU_READ_OFTEN = 3;
|
|
|
|
/** Usage: The buffer will sometimes be written to by the CPU */
|
|
public static final long USAGE_CPU_WRITE_RARELY = 2 << 4;
|
|
/** Usage: The buffer will often be written to by the CPU */
|
|
public static final long USAGE_CPU_WRITE_OFTEN = 3 << 4;
|
|
|
|
/** Usage: The buffer will be read from by the GPU */
|
|
public static final long USAGE_GPU_SAMPLED_IMAGE = 1 << 8;
|
|
/** Usage: The buffer will be written to by the GPU */
|
|
public static final long USAGE_GPU_COLOR_OUTPUT = 1 << 9;
|
|
/**
|
|
* The buffer will be used as a hardware composer overlay layer. That is, it will be displayed
|
|
* using the system compositor via {@link SurfaceControl}
|
|
*
|
|
* This flag is currently only needed when using
|
|
* {@link android.view.SurfaceControl.Transaction#setBuffer(SurfaceControl, HardwareBuffer)}
|
|
* to set a buffer. In all other cases, the framework adds this flag
|
|
* internally to buffers that could be presented in a composer overlay.
|
|
*/
|
|
public static final long USAGE_COMPOSER_OVERLAY = 1 << 11;
|
|
/** Usage: The buffer must not be used outside of a protected hardware path */
|
|
public static final long USAGE_PROTECTED_CONTENT = 1 << 14;
|
|
/** Usage: The buffer will be read by a hardware video encoder */
|
|
public static final long USAGE_VIDEO_ENCODE = 1 << 16;
|
|
/** Usage: The buffer will be used for sensor direct data */
|
|
public static final long USAGE_SENSOR_DIRECT_DATA = 1 << 23;
|
|
/** Usage: The buffer will be used as a shader storage or uniform buffer object */
|
|
public static final long USAGE_GPU_DATA_BUFFER = 1 << 24;
|
|
/** Usage: The buffer will be used as a cube map texture */
|
|
public static final long USAGE_GPU_CUBE_MAP = 1 << 25;
|
|
/** Usage: The buffer contains a complete mipmap hierarchy */
|
|
public static final long USAGE_GPU_MIPMAP_COMPLETE = 1 << 26;
|
|
/** Usage: The buffer is used for front-buffer rendering. When front-buffering rendering is
|
|
* specified, different usages may adjust their behavior as a result. For example, when
|
|
* used as USAGE_GPU_COLOR_OUTPUT the buffer will behave similar to a single-buffered window.
|
|
* When used with USAGE_COMPOSER_OVERLAY, the system will try to prioritize the buffer
|
|
* receiving an overlay plane & avoid caching it in intermediate composition buffers. */
|
|
public static final long USAGE_FRONT_BUFFER = 1L << 32;
|
|
|
|
/**
|
|
* Creates a new <code>HardwareBuffer</code> instance.
|
|
*
|
|
* <p>Calling this method will throw an <code>IllegalStateException</code> if
|
|
* format is not a supported Format type.</p>
|
|
*
|
|
* @param width The width in pixels of the buffer
|
|
* @param height The height in pixels of the buffer
|
|
* @param format The @Format of each pixel
|
|
* @param layers The number of layers in the buffer
|
|
* @param usage The @Usage flags describing how the buffer will be used
|
|
* @return A <code>HardwareBuffer</code> instance if successful, or throws an
|
|
* IllegalArgumentException if the dimensions passed are invalid (either zero, negative, or
|
|
* too large to allocate), if the format is not supported, if the requested number of layers
|
|
* is less than one or not supported, or if the passed usage flags are not a supported set.
|
|
*/
|
|
@NonNull
|
|
public static HardwareBuffer create(
|
|
@IntRange(from = 1) int width, @IntRange(from = 1) int height,
|
|
@Format int format, @IntRange(from = 1) int layers, @Usage long usage) {
|
|
if (width <= 0) {
|
|
throw new IllegalArgumentException("Invalid width " + width);
|
|
}
|
|
if (height <= 0) {
|
|
throw new IllegalArgumentException("Invalid height " + height);
|
|
}
|
|
if (layers <= 0) {
|
|
throw new IllegalArgumentException("Invalid layer count " + layers);
|
|
}
|
|
if (format == BLOB && height != 1) {
|
|
throw new IllegalArgumentException("Height must be 1 when using the BLOB format");
|
|
}
|
|
long nativeObject = nCreateHardwareBuffer(width, height, format, layers, usage);
|
|
if (nativeObject == 0) {
|
|
throw new IllegalArgumentException("Unable to create a HardwareBuffer, either the " +
|
|
"dimensions passed were too large, too many image layers were requested, " +
|
|
"or an invalid set of usage flags or invalid format was passed");
|
|
}
|
|
return new HardwareBuffer(nativeObject);
|
|
}
|
|
|
|
/**
|
|
* Queries whether the given buffer description is supported by the system. If this returns
|
|
* true, then the allocation may succeed until resource exhaustion occurs. If this returns
|
|
* false then this combination will never succeed.
|
|
*
|
|
* @param width The width in pixels of the buffer
|
|
* @param height The height in pixels of the buffer
|
|
* @param format The @Format of each pixel
|
|
* @param layers The number of layers in the buffer
|
|
* @param usage The @Usage flags describing how the buffer will be used
|
|
* @return True if the combination is supported, false otherwise.
|
|
*/
|
|
public static boolean isSupported(@IntRange(from = 1) int width, @IntRange(from = 1) int height,
|
|
@Format int format, @IntRange(from = 1) int layers, @Usage long usage) {
|
|
if (width <= 0) {
|
|
throw new IllegalArgumentException("Invalid width " + width);
|
|
}
|
|
if (height <= 0) {
|
|
throw new IllegalArgumentException("Invalid height " + height);
|
|
}
|
|
if (layers <= 0) {
|
|
throw new IllegalArgumentException("Invalid layer count " + layers);
|
|
}
|
|
if (format == BLOB && height != 1) {
|
|
throw new IllegalArgumentException("Height must be 1 when using the BLOB format");
|
|
}
|
|
return nIsSupported(width, height, format, layers, usage);
|
|
}
|
|
|
|
/**
|
|
* @hide
|
|
* Returns a <code>HardwareBuffer</code> instance from <code>GraphicBuffer</code>
|
|
*
|
|
* @param graphicBuffer A GraphicBuffer to be wrapped as HardwareBuffer
|
|
* @return A <code>HardwareBuffer</code> instance.
|
|
*/
|
|
@NonNull
|
|
public static HardwareBuffer createFromGraphicBuffer(@NonNull GraphicBuffer graphicBuffer) {
|
|
long nativeObject = nCreateFromGraphicBuffer(graphicBuffer);
|
|
return new HardwareBuffer(nativeObject);
|
|
}
|
|
|
|
/**
|
|
* Private use only. See {@link #create(int, int, int, int, long)}. May also be
|
|
* called from JNI using an already allocated native <code>HardwareBuffer</code>.
|
|
*/
|
|
@UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P, trackingBug = 115609023)
|
|
private HardwareBuffer(long nativeObject) {
|
|
mNativeObject = nativeObject;
|
|
long bufferSize = nEstimateSize(nativeObject);
|
|
ClassLoader loader = HardwareBuffer.class.getClassLoader();
|
|
NativeAllocationRegistry registry = new NativeAllocationRegistry(
|
|
loader, nGetNativeFinalizer(), bufferSize);
|
|
mCleaner = registry.registerNativeAllocation(this, mNativeObject);
|
|
mCloseGuard.open("HardwareBuffer.close");
|
|
}
|
|
|
|
@Override
|
|
protected void finalize() throws Throwable {
|
|
try {
|
|
mCloseGuard.warnIfOpen();
|
|
close();
|
|
} finally {
|
|
super.finalize();
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Returns the width of this buffer in pixels.
|
|
*/
|
|
public int getWidth() {
|
|
checkClosed("width");
|
|
return nGetWidth(mNativeObject);
|
|
}
|
|
|
|
/**
|
|
* Returns the height of this buffer in pixels.
|
|
*/
|
|
public int getHeight() {
|
|
checkClosed("height");
|
|
return nGetHeight(mNativeObject);
|
|
}
|
|
|
|
/**
|
|
* Returns the @Format of this buffer.
|
|
*/
|
|
@Format
|
|
public int getFormat() {
|
|
checkClosed("format");
|
|
return nGetFormat(mNativeObject);
|
|
}
|
|
|
|
/**
|
|
* Returns the number of layers in this buffer.
|
|
*/
|
|
public int getLayers() {
|
|
checkClosed("layer count");
|
|
return nGetLayers(mNativeObject);
|
|
}
|
|
|
|
/**
|
|
* Returns the usage flags of the usage hints set on this buffer.
|
|
*/
|
|
public long getUsage() {
|
|
checkClosed("usage");
|
|
return nGetUsage(mNativeObject);
|
|
}
|
|
|
|
/**
|
|
* Returns the system-wide unique id for this buffer
|
|
*
|
|
* This can be useful as a cache key for associating additional objects with
|
|
* a given HardwareBuffer, such as associating an imported EGLImage with
|
|
* the target HardwareBuffer when processing a stream of buffers from
|
|
* ImageReader.
|
|
*
|
|
* This can also be useful for doing cross-process buffer caching. As sending
|
|
* a HardwareBuffer over Binder is slower than sending a long, this can be
|
|
* used as reliable cache key after an initial handshake that passes the
|
|
* HardwareBuffers themselves to later be referred to using only the id.
|
|
*/
|
|
public long getId() {
|
|
checkClosed("id");
|
|
return nGetId(mNativeObject);
|
|
}
|
|
|
|
private void checkClosed(String name) {
|
|
if (isClosed()) {
|
|
throw new IllegalStateException("This HardwareBuffer has been closed and its "
|
|
+ name + " cannot be obtained.");
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Destroys this buffer immediately. Calling this method frees up any
|
|
* underlying native resources. After calling this method, this buffer
|
|
* must not be used in any way.
|
|
*
|
|
* @see #isClosed()
|
|
*/
|
|
@Override
|
|
public void close() {
|
|
if (!isClosed()) {
|
|
mCloseGuard.close();
|
|
mNativeObject = 0;
|
|
mCleaner.run();
|
|
mCleaner = null;
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Indicates whether this buffer has been closed. A closed buffer cannot
|
|
* be used in any way: the buffer cannot be written to a parcel, etc.
|
|
*
|
|
* @return True if this <code>HardwareBuffer</code> is in a closed state,
|
|
* false otherwise.
|
|
*
|
|
* @see #close()
|
|
*/
|
|
public boolean isClosed() {
|
|
return mNativeObject == 0;
|
|
}
|
|
|
|
@Override
|
|
public int describeContents() {
|
|
return Parcelable.CONTENTS_FILE_DESCRIPTOR;
|
|
}
|
|
|
|
/**
|
|
* Flatten this object in to a Parcel.
|
|
*
|
|
* <p>Calling this method will throw an <code>IllegalStateException</code> if
|
|
* {@link #close()} has been previously called.</p>
|
|
*
|
|
* @param dest The Parcel in which the object should be written.
|
|
* @param flags Additional flags about how the object should be written.
|
|
* May be 0 or {@link #PARCELABLE_WRITE_RETURN_VALUE}.
|
|
*/
|
|
@Override
|
|
public void writeToParcel(Parcel dest, int flags) {
|
|
if (isClosed()) {
|
|
throw new IllegalStateException("This HardwareBuffer has been closed and cannot be "
|
|
+ "written to a parcel.");
|
|
}
|
|
nWriteHardwareBufferToParcel(mNativeObject, dest);
|
|
}
|
|
|
|
public static final @android.annotation.NonNull Parcelable.Creator<HardwareBuffer> CREATOR =
|
|
new Parcelable.Creator<HardwareBuffer>() {
|
|
public HardwareBuffer createFromParcel(Parcel in) {
|
|
if (in == null) {
|
|
throw new NullPointerException("null passed to createFromParcel");
|
|
}
|
|
long nativeObject = nReadHardwareBufferFromParcel(in);
|
|
if (nativeObject != 0) {
|
|
return new HardwareBuffer(nativeObject);
|
|
}
|
|
throw new BadParcelableException("Failed to read hardware buffer");
|
|
}
|
|
|
|
public HardwareBuffer[] newArray(int size) {
|
|
return new HardwareBuffer[size];
|
|
}
|
|
};
|
|
|
|
private static native long nCreateHardwareBuffer(int width, int height, int format, int layers,
|
|
long usage);
|
|
private static native long nCreateFromGraphicBuffer(GraphicBuffer graphicBuffer);
|
|
private static native long nGetNativeFinalizer();
|
|
private static native void nWriteHardwareBufferToParcel(long nativeObject, Parcel dest);
|
|
private static native long nReadHardwareBufferFromParcel(Parcel in);
|
|
@FastNative
|
|
private static native int nGetWidth(long nativeObject);
|
|
@FastNative
|
|
private static native int nGetHeight(long nativeObject);
|
|
@FastNative
|
|
private static native int nGetFormat(long nativeObject);
|
|
@FastNative
|
|
private static native int nGetLayers(long nativeObject);
|
|
@FastNative
|
|
private static native long nGetUsage(long nativeObject);
|
|
private static native boolean nIsSupported(int width, int height, int format, int layers,
|
|
long usage);
|
|
@CriticalNative
|
|
private static native long nEstimateSize(long nativeObject);
|
|
@CriticalNative
|
|
private static native long nGetId(long nativeObject);
|
|
}
|