File: HardwareBuffer.java

package info (click to toggle)
android-platform-frameworks-base 1%3A10.0.0%2Br36-3
  • links: PTS, VCS
  • area: main
  • in suites: bullseye
  • size: 321,788 kB
  • sloc: java: 962,234; cpp: 274,314; xml: 242,770; python: 5,060; sh: 1,432; ansic: 494; makefile: 47; sed: 19
file content (440 lines) | stat: -rw-r--r-- 16,985 bytes parent folder | download | duplicates (2)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
/*
 * 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.IntDef;
import android.annotation.IntRange;
import android.annotation.LongDef;
import android.annotation.NonNull;
import android.annotation.UnsupportedAppUsage;
import android.graphics.GraphicBuffer;
import android.os.Build;
import android.os.Parcel;
import android.os.Parcelable;

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 accessibly 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", "D_", "DS_", "S_" }, value = {
            RGBA_8888,
            RGBA_FP16,
            RGBA_1010102,
            RGBX_8888,
            RGB_888,
            RGB_565,
            BLOB,
            D_16,
            D_24,
            DS_24UI8,
            D_FP32,
            DS_FP32UI8,
            S_UI8,
    })
    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: 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;

    // Note: do not rename, this field is used by native code
    @UnsupportedAppUsage
    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_PROTECTED_CONTENT, USAGE_VIDEO_ENCODE,
            USAGE_GPU_DATA_BUFFER, USAGE_SENSOR_DIRECT_DATA, USAGE_GPU_CUBE_MAP,
            USAGE_GPU_MIPMAP_COMPLETE})
    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;
    /** 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;

    // The approximate size of a native AHardwareBuffer object.
    private static final long NATIVE_HARDWARE_BUFFER_SIZE = 232;
    /**
     * 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 (!HardwareBuffer.isSupportedFormat(format)) {
            throw new IllegalArgumentException("Invalid pixel format " + format);
        }
        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 (!HardwareBuffer.isSupportedFormat(format)) {
            throw new IllegalArgumentException("Invalid pixel format " + format);
        }
        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;

        ClassLoader loader = HardwareBuffer.class.getClassLoader();
        NativeAllocationRegistry registry = new NativeAllocationRegistry(
                loader, nGetNativeFinalizer(), NATIVE_HARDWARE_BUFFER_SIZE);
        mCleaner = registry.registerNativeAllocation(this, mNativeObject);
        mCloseGuard.open("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() {
        if (isClosed()) {
            throw new IllegalStateException("This HardwareBuffer has been closed and its width "
                    + "cannot be obtained.");
        }
        return nGetWidth(mNativeObject);
    }

    /**
     * Returns the height of this buffer in pixels.
     */
    public int getHeight() {
        if (isClosed()) {
            throw new IllegalStateException("This HardwareBuffer has been closed and its height "
                    + "cannot be obtained.");
        }
        return nGetHeight(mNativeObject);
    }

    /**
     * Returns the @Format of this buffer.
     */
    @Format
    public int getFormat() {
        if (isClosed()) {
            throw new IllegalStateException("This HardwareBuffer has been closed and its format "
                    + "cannot be obtained.");
        }
        return nGetFormat(mNativeObject);
    }

    /**
     * Returns the number of layers in this buffer.
     */
    public int getLayers() {
        if (isClosed()) {
            throw new IllegalStateException("This HardwareBuffer has been closed and its layer "
                    + "count cannot be obtained.");
        }
        return nGetLayers(mNativeObject);
    }

    /**
     * Returns the usage flags of the usage hints set on this buffer.
     */
    public long getUsage() {
        if (isClosed()) {
            throw new IllegalStateException("This HardwareBuffer has been closed and its usage "
                    + "cannot be obtained.");
        }
        return nGetUsage(mNativeObject);
    }

    /** @removed replaced by {@link #close()} */
    @Deprecated
    public void destroy() {
        close();
    }

    /** @removed replaced by {@link #isClosed()} */
    @Deprecated
    public boolean isDestroyed() {
        return isClosed();
    }

    /**
     * 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) {
            long nativeObject = nReadHardwareBufferFromParcel(in);
            if (nativeObject != 0) {
                return new HardwareBuffer(nativeObject);
            }
            return null;
        }

        public HardwareBuffer[] newArray(int size) {
            return new HardwareBuffer[size];
        }
    };

    /**
     * Validates whether a particular format is supported by HardwareBuffer.
     *
     * @param format The format to validate.
     *
     * @return True if <code>format</code> is a supported format. false otherwise.
     * See {@link #create(int, int, int, int, long)}.
     */
    private static boolean isSupportedFormat(@Format int format) {
        switch(format) {
            case RGBA_8888:
            case RGBA_FP16:
            case RGBA_1010102:
            case RGBX_8888:
            case RGB_565:
            case RGB_888:
            case BLOB:
            case D_16:
            case D_24:
            case DS_24UI8:
            case D_FP32:
            case DS_FP32UI8:
            case S_UI8:
                return true;
        }
        return false;
    }

    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);
}