HardwareBuffer.java revision 1a4d07d9193f843ebf4403ef49bac4cd61d34165
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
17package android.hardware;
18
19import android.annotation.IntDef;
20import android.annotation.NonNull;
21import android.os.Parcel;
22import android.os.Parcelable;
23
24import dalvik.annotation.optimization.FastNative;
25
26import java.lang.annotation.Retention;
27import java.lang.annotation.RetentionPolicy;
28
29import libcore.util.NativeAllocationRegistry;
30
31/**
32 * HardwareBuffer wraps a native <code>AHardwareBuffer</code> object, which is a low-level object
33 * representing a memory buffer accessible by various hardware units. HardwareBuffer allows sharing
34 * buffers across different application processes. In particular, HardwareBuffers may be mappable
35 * to memory accessibly to various hardware systems, such as the GPU, a sensor or context hub, or
36 * other auxiliary processing units.
37 *
38 * For more information, see the NDK documentation for <code>AHardwareBuffer</code>.
39 */
40public final class HardwareBuffer implements Parcelable {
41    /** @hide */
42    @Retention(RetentionPolicy.SOURCE)
43    @IntDef({RGBA_8888, RGBA_FP16, RGBX_8888, RGB_888, RGB_565})
44    public @interface Format {};
45
46    /** Format: 8 bits each red, green, blue, alpha */
47    public static final int RGBA_8888   = 1;
48    /** Format: 8 bits each red, green, blue, alpha, alpha is always 0xFF */
49    public static final int RGBX_8888   = 2;
50    /** Format: 8 bits each red, green, blue, no alpha */
51    public static final int RGB_888     = 3;
52    /** Format: 5 bits each red and blue, 6 bits green, no alpha */
53    public static final int RGB_565     = 4;
54    /** Format: 16 bits each red, green, blue, alpha */
55    public static final int RGBA_FP16   = 5;
56
57    // Note: do not rename, this field is used by native code
58    private long mNativeObject;
59
60    // Invoked on destruction
61    private Runnable mCleaner;
62
63    /** @hide */
64    @Retention(RetentionPolicy.SOURCE)
65    @IntDef(flag = true, value = {USAGE0_CPU_READ, USAGE0_CPU_READ_OFTEN, USAGE0_CPU_WRITE,
66            USAGE0_CPU_WRITE_OFTEN, USAGE0_GPU_SAMPLED_IMAGE, USAGE0_GPU_COLOR_OUTPUT,
67            USAGE0_GPU_STORAGE_IMAGE, USAGE0_GPU_CUBEMAP, USAGE0_GPU_DATA_BUFFER,
68            USAGE0_PROTECTED_CONTENT, USAGE0_SENSOR_DIRECT_DATA, USAGE0_VIDEO_ENCODE})
69    public @interface Usage0 {};
70
71    /** Usage0: the buffer will sometimes be read by the CPU */
72    public static final long USAGE0_CPU_READ               = (1 << 1);
73    /** Usage0: the buffer will often be read by the CPU*/
74    public static final long USAGE0_CPU_READ_OFTEN         = (1 << 2 | USAGE0_CPU_READ);
75    /** Usage0: the buffer will sometimes be written to by the CPU */
76    public static final long USAGE0_CPU_WRITE              = (1 << 5);
77    /** Usage0: the buffer will often be written to by the CPU */
78    public static final long USAGE0_CPU_WRITE_OFTEN        = (1 << 6 | USAGE0_CPU_WRITE);
79    /** Usage0: the buffer will be read from by the GPU */
80    public static final long USAGE0_GPU_SAMPLED_IMAGE      = (1 << 10);
81    /** Usage0: the buffer will be written to by the GPU */
82    public static final long USAGE0_GPU_COLOR_OUTPUT       = (1 << 11);
83    /** Usage0: the buffer will be read from and written to by the GPU */
84    public static final long USAGE0_GPU_STORAGE_IMAGE      = (USAGE0_GPU_SAMPLED_IMAGE |
85            USAGE0_GPU_COLOR_OUTPUT);
86    /** Usage0: the buffer will be used as a cubemap texture */
87    public static final long USAGE0_GPU_CUBEMAP            = (1 << 13);
88    /** Usage0: the buffer will be used as a shader storage or uniform buffer object*/
89    public static final long USAGE0_GPU_DATA_BUFFER        = (1 << 14);
90    /** Usage0: the buffer must not be used outside of a protected hardware path */
91    public static final long USAGE0_PROTECTED_CONTENT      = (1 << 18);
92    /** Usage0: the buffer will be used for sensor direct data */
93    public static final long USAGE0_SENSOR_DIRECT_DATA     = (1 << 29);
94    /** Usage0: the buffer will be read by a hardware video encoder */
95    public static final long USAGE0_VIDEO_ENCODE           = (1 << 21);
96
97    // The approximate size of a native AHardwareBuffer object.
98    private static final long NATIVE_HARDWARE_BUFFER_SIZE = 232;
99    /**
100     * Creates a new <code>HardwareBuffer</code> instance.
101     *
102     * <p>Calling this method will throw an <code>IllegalStateException</code> if
103     * format is not a supported Format type.</p>
104     *
105     * @param width The width in pixels of the buffer
106     * @param height The height in pixels of the buffer
107     * @param format The format of each pixel, one of {@link #RGBA_8888}, {@link #RGBA_FP16},
108     * {@link #RGBX_8888}, {@link #RGB_565}, {@link #RGB_888}
109     * @param layers The number of layers in the buffer
110     * @param usage Flags describing how the buffer will be used, one of
111     *     {@link #USAGE0_CPU_READ}, {@link #USAGE0_CPU_READ_OFTEN}, {@link #USAGE0_CPU_WRITE},
112     *     {@link #USAGE0_CPU_WRITE_OFTEN}, {@link #USAGE0_GPU_SAMPLED_IMAGE},
113     *     {@link #USAGE0_GPU_COLOR_OUTPUT},{@link #USAGE0_GPU_STORAGE_IMAGE},
114     *     {@link #USAGE0_GPU_CUBEMAP}, {@link #USAGE0_GPU_DATA_BUFFER},
115     *     {@link #USAGE0_PROTECTED_CONTENT}, {@link #USAGE0_SENSOR_DIRECT_DATA},
116     *     {@link #USAGE0_VIDEO_ENCODE}
117     *
118     * @return A <code>HardwareBuffer</code> instance if successful, or throws an
119     *     IllegalArgumentException if the dimensions passed are invalid (either zero, negative, or
120     *     too large to allocate), if the format is not supported, if the requested number of layers
121     *     is less than one or not supported, or if the passed usage flags are not a supported set.
122     */
123    @NonNull
124    public static HardwareBuffer create(int width, int height, @Format int format, int layers,
125            @Usage0 long usage) {
126        if (!HardwareBuffer.isSupportedFormat(format)) {
127            throw new IllegalArgumentException("Invalid pixel format " + format);
128        }
129        if (width <= 0) {
130            throw new IllegalArgumentException("Invalid width " + width);
131        }
132        if (height <= 0) {
133            throw new IllegalArgumentException("Invalid height " + height);
134        }
135        if (layers <= 0) {
136            throw new IllegalArgumentException("Invalid layer count " + layers);
137        }
138        long nativeObject = nCreateHardwareBuffer(width, height, format, layers, usage);
139        if (nativeObject == 0) {
140            throw new IllegalArgumentException("Unable to create a HardwareBuffer, either the " +
141                    "dimensions passed were too large, too many image layers were requested, " +
142                    "or an invalid set of usage flags was passed");
143        }
144        return new HardwareBuffer(nativeObject);
145    }
146
147    /**
148     * Private use only. See {@link #create(int, int, int, int, int, long, long)}. May also be
149     * called from JNI using an already allocated native <code>HardwareBuffer</code>.
150     */
151    private HardwareBuffer(long nativeObject) {
152        mNativeObject = nativeObject;
153
154        long nativeSize = NATIVE_HARDWARE_BUFFER_SIZE;
155        NativeAllocationRegistry registry = new NativeAllocationRegistry(
156            HardwareBuffer.class.getClassLoader(), nGetNativeFinalizer(), nativeSize);
157        mCleaner = registry.registerNativeAllocation(this, mNativeObject);
158    }
159
160    /**
161     * Returns the width of this buffer in pixels.
162     */
163    public int getWidth() {
164        if (mNativeObject == 0) {
165            throw new IllegalStateException("This HardwareBuffer has been destroyed and its width "
166                    + "cannot be obtained.");
167        }
168        return nGetWidth(mNativeObject);
169    }
170
171    /**
172     * Returns the height of this buffer in pixels.
173     */
174    public int getHeight() {
175        if (mNativeObject == 0) {
176            throw new IllegalStateException("This HardwareBuffer has been destroyed and its height "
177                    + "cannot be obtained.");
178        }
179        return nGetHeight(mNativeObject);
180    }
181
182    /**
183     * Returns the format of this buffer, one of {@link #RGBA_8888}, {@link #RGBA_FP16},
184     * {@link #RGBX_8888}, {@link #RGB_565}, or {@link #RGB_888}.
185     */
186    public int getFormat() {
187        if (mNativeObject == 0) {
188            throw new IllegalStateException("This HardwareBuffer has been destroyed and its format "
189                    + "cannot be obtained.");
190        }
191        return nGetFormat(mNativeObject);
192    }
193
194    /**
195     * Returns the number of layers in this buffer.
196     */
197    public int getLayers() {
198        if (mNativeObject == 0) {
199            throw new IllegalStateException("This HardwareBuffer has been destroyed and its layer "
200                    + "count cannot be obtained.");
201        }
202        return nGetLayers(mNativeObject);
203    }
204
205    /**
206     * Returns the usage flags of the usage hints set on this buffer.
207     */
208    public long getUsage() {
209        if (mNativeObject == 0) {
210            throw new IllegalStateException("This HardwareBuffer has been destroyed and its usage "
211                    + "cannot be obtained.");
212        }
213        return nGetUsage(mNativeObject);
214    }
215
216    /**
217     * Destroys this buffer immediately. Calling this method frees up any
218     * underlying native resources. After calling this method, this buffer
219     * must not be used in any way.
220     *
221     * @see #isDestroyed()
222     */
223    public void destroy() {
224        if (mNativeObject != 0) {
225            mNativeObject = 0;
226            mCleaner.run();
227            mCleaner = null;
228        }
229    }
230
231    /**
232     * Indicates whether this buffer has been destroyed. A destroyed buffer
233     * cannot be used in any way: the buffer cannot be written to a parcel, etc.
234     *
235     * @return True if this <code>HardwareBuffer</code> is in a destroyed state,
236     *         false otherwise.
237     *
238     * @see #destroy()
239     */
240    public boolean isDestroyed() {
241        return mNativeObject == 0;
242    }
243
244    @Override
245    public int describeContents() {
246        return Parcelable.CONTENTS_FILE_DESCRIPTOR;
247    }
248
249    /**
250     * Flatten this object in to a Parcel.
251     *
252     * <p>Calling this method will throw an <code>IllegalStateException</code> if
253     * {@link #destroy()} has been previously called.</p>
254     *
255     * @param dest The Parcel in which the object should be written.
256     * @param flags Additional flags about how the object should be written.
257     *              May be 0 or {@link #PARCELABLE_WRITE_RETURN_VALUE}.
258     */
259    @Override
260    public void writeToParcel(Parcel dest, int flags) {
261        if (mNativeObject == 0) {
262            throw new IllegalStateException("This HardwareBuffer has been destroyed and cannot be "
263                    + "written to a parcel.");
264        }
265        nWriteHardwareBufferToParcel(mNativeObject, dest);
266    }
267
268    public static final Parcelable.Creator<HardwareBuffer> CREATOR =
269            new Parcelable.Creator<HardwareBuffer>() {
270        public HardwareBuffer createFromParcel(Parcel in) {
271            long nativeObject = nReadHardwareBufferFromParcel(in);
272            if (nativeObject != 0) {
273                return new HardwareBuffer(nativeObject);
274            }
275            return null;
276        }
277
278        public HardwareBuffer[] newArray(int size) {
279            return new HardwareBuffer[size];
280        }
281    };
282
283    /**
284     * Validates whether a particular format is supported by HardwareBuffer.
285     *
286     * @param format The format to validate.
287     *
288     * @return True if <code>format</code> is a supported format. false otherwise.
289     * See {@link #create(int, int, int, int, int, long, long)}.a
290     */
291    private static boolean isSupportedFormat(@Format int format) {
292        switch(format) {
293            case RGBA_8888:
294            case RGBA_FP16:
295            case RGBX_8888:
296            case RGB_565:
297            case RGB_888:
298                return true;
299        }
300        return false;
301    }
302
303    private static native long nCreateHardwareBuffer(int width, int height, int format, int layers,
304            long usage);
305    private static native long nGetNativeFinalizer();
306    private static native void nWriteHardwareBufferToParcel(long nativeObject, Parcel dest);
307    private static native long nReadHardwareBufferFromParcel(Parcel in);
308    @FastNative
309    private static native int nGetWidth(long nativeObject);
310    @FastNative
311    private static native int nGetHeight(long nativeObject);
312    @FastNative
313    private static native int nGetFormat(long nativeObject);
314    @FastNative
315    private static native int nGetLayers(long nativeObject);
316    @FastNative
317    private static native long nGetUsage(long nativeObject);
318}
319