1 /*
2  * Copyright (C) 2013 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.graphics;
18 
19 import android.annotation.UnsupportedAppUsage;
20 import android.os.Parcel;
21 import android.os.Parcelable;
22 
23 /**
24  * Simple wrapper for the native GraphicBuffer class.
25  *
26  * @hide
27  */
28 @SuppressWarnings("UnusedDeclaration")
29 public class GraphicBuffer implements Parcelable {
30     // Note: keep usage flags in sync with GraphicBuffer.h and gralloc.h
31     public static final int USAGE_SW_READ_NEVER = 0x0;
32     public static final int USAGE_SW_READ_RARELY = 0x2;
33     public static final int USAGE_SW_READ_OFTEN = 0x3;
34     public static final int USAGE_SW_READ_MASK = 0xF;
35 
36     public static final int USAGE_SW_WRITE_NEVER = 0x0;
37     public static final int USAGE_SW_WRITE_RARELY = 0x20;
38     public static final int USAGE_SW_WRITE_OFTEN = 0x30;
39     public static final int USAGE_SW_WRITE_MASK = 0xF0;
40 
41     public static final int USAGE_SOFTWARE_MASK = USAGE_SW_READ_MASK | USAGE_SW_WRITE_MASK;
42 
43     public static final int USAGE_PROTECTED = 0x4000;
44 
45     public static final int USAGE_HW_TEXTURE = 0x100;
46     public static final int USAGE_HW_RENDER = 0x200;
47     public static final int USAGE_HW_2D = 0x400;
48     public static final int USAGE_HW_COMPOSER = 0x800;
49     public static final int USAGE_HW_VIDEO_ENCODER = 0x10000;
50     public static final int USAGE_HW_MASK = 0x71F00;
51 
52     private final int mWidth;
53     private final int mHeight;
54     private final int mFormat;
55     private final int mUsage;
56     // Note: do not rename, this field is used by native code
57     @UnsupportedAppUsage
58     private final long mNativeObject;
59 
60     // These two fields are only used by lock/unlockCanvas()
61     private Canvas mCanvas;
62     private int mSaveCount;
63 
64     // If set to true, this GraphicBuffer instance cannot be used anymore
65     private boolean mDestroyed;
66 
67     /**
68      * Creates new <code>GraphicBuffer</code> instance. This method will return null
69      * if the buffer cannot be created.
70      *
71      * @param width The width in pixels of the buffer
72      * @param height The height in pixels of the buffer
73      * @param format The format of each pixel as specified in {@link PixelFormat}
74      * @param usage Hint indicating how the buffer will be used
75      *
76      * @return A <code>GraphicBuffer</code> instance or null
77      */
create(int width, int height, int format, int usage)78     public static GraphicBuffer create(int width, int height, int format, int usage) {
79         long nativeObject = nCreateGraphicBuffer(width, height, format, usage);
80         if (nativeObject != 0) {
81             return new GraphicBuffer(width, height, format, usage, nativeObject);
82         }
83         return null;
84     }
85 
86     /**
87      * Private use only. See {@link #create(int, int, int, int)}.
88      */
89     @UnsupportedAppUsage
GraphicBuffer(int width, int height, int format, int usage, long nativeObject)90     private GraphicBuffer(int width, int height, int format, int usage, long nativeObject) {
91         mWidth = width;
92         mHeight = height;
93         mFormat = format;
94         mUsage = usage;
95         mNativeObject = nativeObject;
96     }
97 
98     /**
99      * For SurfaceControl JNI.
100      * @hide
101      */
102     @UnsupportedAppUsage
createFromExisting(int width, int height, int format, int usage, long unwrappedNativeObject)103     public static GraphicBuffer createFromExisting(int width, int height,
104             int format, int usage, long unwrappedNativeObject) {
105         long nativeObject = nWrapGraphicBuffer(unwrappedNativeObject);
106         if (nativeObject != 0) {
107             return new GraphicBuffer(width, height, format, usage, nativeObject);
108         }
109         return null;
110     }
111 
112     /**
113      * Returns the width of this buffer in pixels.
114      */
getWidth()115     public int getWidth() {
116         return mWidth;
117     }
118 
119     /**
120      * Returns the height of this buffer in pixels.
121      */
getHeight()122     public int getHeight() {
123         return mHeight;
124     }
125 
126     /**
127      * Returns the pixel format of this buffer. The pixel format must be one of
128      * the formats defined in {@link PixelFormat}.
129      */
getFormat()130     public int getFormat() {
131         return mFormat;
132     }
133 
134     /**
135      * Returns the usage hint set on this buffer.
136      */
getUsage()137     public int getUsage() {
138         return mUsage;
139     }
140 
141     /**
142      * <p>Start editing the pixels in the buffer. A null is returned if the buffer
143      * cannot be locked for editing.</p>
144      *
145      * <p>The content of the buffer is preserved between unlockCanvas()
146      * and lockCanvas().</p>
147      *
148      * <p>If this method is called after {@link #destroy()}, the return value will
149      * always be null.</p>
150      *
151      * @return A Canvas used to draw into the buffer, or null.
152      *
153      * @see #lockCanvas(android.graphics.Rect)
154      * @see #unlockCanvasAndPost(android.graphics.Canvas)
155      * @see #isDestroyed()
156      */
lockCanvas()157     public Canvas lockCanvas() {
158         return lockCanvas(null);
159     }
160 
161     /**
162      * Just like {@link #lockCanvas()} but allows specification of a dirty
163      * rectangle.
164      *
165      * <p>If this method is called after {@link #destroy()}, the return value will
166      * always be null.</p>
167      *
168      * @param dirty Area of the buffer that may be modified.
169 
170      * @return A Canvas used to draw into the surface, or null.
171      *
172      * @see #lockCanvas()
173      * @see #unlockCanvasAndPost(android.graphics.Canvas)
174      * @see #isDestroyed()
175      */
lockCanvas(Rect dirty)176     public Canvas lockCanvas(Rect dirty) {
177         if (mDestroyed) {
178             return null;
179         }
180 
181         if (mCanvas == null) {
182             mCanvas = new Canvas();
183         }
184 
185         if (nLockCanvas(mNativeObject, mCanvas, dirty)) {
186             mSaveCount = mCanvas.save();
187             return mCanvas;
188         }
189 
190         return null;
191     }
192 
193     /**
194      * Finish editing pixels in the buffer.
195      *
196      * <p>This method doesn't do anything if {@link #destroy()} was
197      * previously called.</p>
198      *
199      * @param canvas The Canvas previously returned by lockCanvas()
200      *
201      * @see #lockCanvas()
202      * @see #lockCanvas(android.graphics.Rect)
203      * @see #isDestroyed()
204      */
unlockCanvasAndPost(Canvas canvas)205     public void unlockCanvasAndPost(Canvas canvas) {
206         if (!mDestroyed && mCanvas != null && canvas == mCanvas) {
207             canvas.restoreToCount(mSaveCount);
208             mSaveCount = 0;
209 
210             nUnlockCanvasAndPost(mNativeObject, mCanvas);
211         }
212     }
213 
214     /**
215      * Destroyes this buffer immediately. Calling this method frees up any
216      * underlying native resources. After calling this method, this buffer
217      * must not be used in any way ({@link #lockCanvas()} must not be called,
218      * etc.)
219      *
220      * @see #isDestroyed()
221      */
destroy()222     public void destroy() {
223         if (!mDestroyed) {
224             mDestroyed = true;
225             nDestroyGraphicBuffer(mNativeObject);
226         }
227     }
228 
229     /**
230      * Indicates whether this buffer has been destroyed. A destroyed buffer
231      * cannot be used in any way: locking a Canvas will return null, the buffer
232      * cannot be written to a parcel, etc.
233      *
234      * @return True if this <code>GraphicBuffer</code> is in a destroyed state,
235      *         false otherwise.
236      *
237      * @see #destroy()
238      */
isDestroyed()239     public boolean isDestroyed() {
240         return mDestroyed;
241     }
242 
243     @Override
finalize()244     protected void finalize() throws Throwable {
245         try {
246             if (!mDestroyed) nDestroyGraphicBuffer(mNativeObject);
247         } finally {
248             super.finalize();
249         }
250     }
251 
252     @Override
describeContents()253     public int describeContents() {
254         return 0;
255     }
256 
257     /**
258      * Flatten this object in to a Parcel.
259      *
260      * <p>Calling this method will throw an <code>IllegalStateException</code> if
261      * {@link #destroy()} has been previously called.</p>
262      *
263      * @param dest The Parcel in which the object should be written.
264      * @param flags Additional flags about how the object should be written.
265      *              May be 0 or {@link #PARCELABLE_WRITE_RETURN_VALUE}.
266      */
267     @Override
writeToParcel(Parcel dest, int flags)268     public void writeToParcel(Parcel dest, int flags) {
269         if (mDestroyed) {
270             throw new IllegalStateException("This GraphicBuffer has been destroyed and cannot be "
271                     + "written to a parcel.");
272         }
273 
274         dest.writeInt(mWidth);
275         dest.writeInt(mHeight);
276         dest.writeInt(mFormat);
277         dest.writeInt(mUsage);
278         nWriteGraphicBufferToParcel(mNativeObject, dest);
279     }
280 
281     @UnsupportedAppUsage
282     public static final @android.annotation.NonNull Parcelable.Creator<GraphicBuffer> CREATOR =
283             new Parcelable.Creator<GraphicBuffer>() {
284         public GraphicBuffer createFromParcel(Parcel in) {
285             int width = in.readInt();
286             int height = in.readInt();
287             int format = in.readInt();
288             int usage = in.readInt();
289             long nativeObject = nReadGraphicBufferFromParcel(in);
290             if (nativeObject != 0) {
291                 return new GraphicBuffer(width, height, format, usage, nativeObject);
292             }
293             return null;
294         }
295 
296         public GraphicBuffer[] newArray(int size) {
297             return new GraphicBuffer[size];
298         }
299     };
300 
nCreateGraphicBuffer(int width, int height, int format, int usage)301     private static native long nCreateGraphicBuffer(int width, int height, int format, int usage);
nDestroyGraphicBuffer(long nativeObject)302     private static native void nDestroyGraphicBuffer(long nativeObject);
nWriteGraphicBufferToParcel(long nativeObject, Parcel dest)303     private static native void nWriteGraphicBufferToParcel(long nativeObject, Parcel dest);
nReadGraphicBufferFromParcel(Parcel in)304     private static native long nReadGraphicBufferFromParcel(Parcel in);
nLockCanvas(long nativeObject, Canvas canvas, Rect dirty)305     private static native boolean nLockCanvas(long nativeObject, Canvas canvas, Rect dirty);
nUnlockCanvasAndPost(long nativeObject, Canvas canvas)306     private static native boolean nUnlockCanvasAndPost(long nativeObject, Canvas canvas);
nWrapGraphicBuffer(long nativeObject)307     private static native long nWrapGraphicBuffer(long nativeObject);
308 }
309