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