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 #define LOG_TAG "GraphicBuffer"
18 
19 #include "jni.h"
20 #include "JNIHelp.h"
21 
22 #include "android_os_Parcel.h"
23 #include "android_view_GraphicBuffer.h"
24 #include "android/graphics/GraphicsJNI.h"
25 
26 #include <android_runtime/AndroidRuntime.h>
27 
28 #include <binder/Parcel.h>
29 
30 #include <ui/GraphicBuffer.h>
31 #include <ui/PixelFormat.h>
32 
33 #include <gui/IGraphicBufferAlloc.h>
34 #include <gui/ISurfaceComposer.h>
35 
36 #include <SkCanvas.h>
37 #include <SkBitmap.h>
38 
39 #include <private/gui/ComposerService.h>
40 
41 namespace android {
42 
43 // ----------------------------------------------------------------------------
44 // Defines
45 // ----------------------------------------------------------------------------
46 
47 // Debug
48 #define DEBUG_GRAPHIC_BUFFER 0
49 
50 // Debug
51 #if DEBUG_GRAPHIC_BUFFER
52     #define GB_LOGD(...) ALOGD(__VA_ARGS__)
53     #define GB_LOGW(...) ALOGW(__VA_ARGS__)
54 #else
55     #define GB_LOGD(...)
56     #define GB_LOGW(...)
57 #endif
58 
59 #define LOCK_CANVAS_USAGE GraphicBuffer::USAGE_SW_READ_OFTEN | GraphicBuffer::USAGE_SW_WRITE_OFTEN
60 
61 // ----------------------------------------------------------------------------
62 // JNI Helpers
63 // ----------------------------------------------------------------------------
64 
65 static struct {
66     jfieldID mNativeObject;
67 } gGraphicBufferClassInfo;
68 
69 static struct {
70     jmethodID set;
71     jfieldID left;
72     jfieldID top;
73     jfieldID right;
74     jfieldID bottom;
75 } gRectClassInfo;
76 
77 static struct {
78     jfieldID mSurfaceFormat;
79     jmethodID setNativeBitmap;
80 } gCanvasClassInfo;
81 
82 #define GET_INT(object, field) \
83     env->GetIntField(object, field)
84 
85 #define SET_INT(object, field, value) \
86     env->SetIntField(object, field, value)
87 
88 #define GET_LONG(object, field) \
89     env->GetLongField(object, field)
90 
91 #define SET_LONG(object, field, value) \
92     env->SetLongField(object, field, value)
93 
94 #define INVOKEV(object, method, ...) \
95     env->CallVoidMethod(object, method, __VA_ARGS__)
96 
97 // ----------------------------------------------------------------------------
98 // Types
99 // ----------------------------------------------------------------------------
100 
101 class GraphicBufferWrapper {
102 public:
GraphicBufferWrapper(const sp<GraphicBuffer> & buffer)103     GraphicBufferWrapper(const sp<GraphicBuffer>& buffer): buffer(buffer) {
104     }
105 
106     sp<GraphicBuffer> buffer;
107 };
108 
109 // ----------------------------------------------------------------------------
110 // GraphicBuffer lifecycle
111 // ----------------------------------------------------------------------------
112 
android_view_GraphiceBuffer_create(JNIEnv * env,jobject clazz,jint width,jint height,jint format,jint usage)113 static jlong android_view_GraphiceBuffer_create(JNIEnv* env, jobject clazz,
114         jint width, jint height, jint format, jint usage) {
115 
116     sp<ISurfaceComposer> composer(ComposerService::getComposerService());
117     sp<IGraphicBufferAlloc> alloc(composer->createGraphicBufferAlloc());
118     if (alloc == NULL) {
119         GB_LOGW("createGraphicBufferAlloc() failed in GraphicBuffer.create()");
120         return NULL;
121     }
122 
123     status_t error;
124     sp<GraphicBuffer> buffer(alloc->createGraphicBuffer(width, height, format, usage, &error));
125     if (buffer == NULL) {
126         GB_LOGW("createGraphicBuffer() failed in GraphicBuffer.create()");
127         return NULL;
128     }
129 
130     GraphicBufferWrapper* wrapper = new GraphicBufferWrapper(buffer);
131     return reinterpret_cast<jlong>(wrapper);
132 }
133 
android_view_GraphiceBuffer_destroy(JNIEnv * env,jobject clazz,jlong wrapperHandle)134 static void android_view_GraphiceBuffer_destroy(JNIEnv* env, jobject clazz,
135         jlong wrapperHandle) {
136     GraphicBufferWrapper* wrapper =
137                 reinterpret_cast<GraphicBufferWrapper*>(wrapperHandle);
138     delete wrapper;
139 }
140 
141 // ----------------------------------------------------------------------------
142 // Canvas management
143 // ----------------------------------------------------------------------------
144 
convertPixelFormat(int32_t format)145 static inline SkColorType convertPixelFormat(int32_t format) {
146     switch (format) {
147         case PIXEL_FORMAT_RGBA_8888:
148             return kN32_SkColorType;
149         case PIXEL_FORMAT_RGBX_8888:
150             return kN32_SkColorType;
151         case PIXEL_FORMAT_RGB_565:
152             return kRGB_565_SkColorType;
153         default:
154             return kUnknown_SkColorType;
155     }
156 }
157 
android_view_GraphicBuffer_lockCanvas(JNIEnv * env,jobject,jlong wrapperHandle,jobject canvas,jobject dirtyRect)158 static jboolean android_view_GraphicBuffer_lockCanvas(JNIEnv* env, jobject,
159         jlong wrapperHandle, jobject canvas, jobject dirtyRect) {
160 
161     GraphicBufferWrapper* wrapper =
162                 reinterpret_cast<GraphicBufferWrapper*>(wrapperHandle);
163     if (!wrapper) {
164         return JNI_FALSE;
165     }
166 
167     sp<GraphicBuffer> buffer(wrapper->buffer);
168 
169     Rect rect;
170     if (dirtyRect) {
171         rect.left = GET_INT(dirtyRect, gRectClassInfo.left);
172         rect.top = GET_INT(dirtyRect, gRectClassInfo.top);
173         rect.right = GET_INT(dirtyRect, gRectClassInfo.right);
174         rect.bottom = GET_INT(dirtyRect, gRectClassInfo.bottom);
175     } else {
176         rect.set(Rect(buffer->getWidth(), buffer->getHeight()));
177     }
178 
179     void* bits = NULL;
180     status_t status = buffer->lock(LOCK_CANVAS_USAGE, rect, &bits);
181 
182     if (status) return JNI_FALSE;
183     if (!bits) {
184         buffer->unlock();
185         return JNI_FALSE;
186     }
187 
188     ssize_t bytesCount = buffer->getStride() * bytesPerPixel(buffer->getPixelFormat());
189 
190     SkBitmap bitmap;
191     bitmap.setInfo(SkImageInfo::Make(buffer->getWidth(), buffer->getHeight(),
192                                      convertPixelFormat(buffer->getPixelFormat()),
193                                      kPremul_SkAlphaType),
194                    bytesCount);
195 
196     if (buffer->getWidth() > 0 && buffer->getHeight() > 0) {
197         bitmap.setPixels(bits);
198     } else {
199         bitmap.setPixels(NULL);
200     }
201 
202     SET_INT(canvas, gCanvasClassInfo.mSurfaceFormat, buffer->getPixelFormat());
203     INVOKEV(canvas, gCanvasClassInfo.setNativeBitmap, reinterpret_cast<jlong>(&bitmap));
204 
205     SkRect clipRect;
206     clipRect.set(rect.left, rect.top, rect.right, rect.bottom);
207     SkCanvas* nativeCanvas = GraphicsJNI::getNativeCanvas(env, canvas);
208     nativeCanvas->clipRect(clipRect);
209 
210     if (dirtyRect) {
211         INVOKEV(dirtyRect, gRectClassInfo.set,
212                 int(rect.left), int(rect.top), int(rect.right), int(rect.bottom));
213     }
214 
215     return JNI_TRUE;
216 }
217 
android_view_GraphicBuffer_unlockCanvasAndPost(JNIEnv * env,jobject,jlong wrapperHandle,jobject canvas)218 static jboolean android_view_GraphicBuffer_unlockCanvasAndPost(JNIEnv* env, jobject,
219         jlong wrapperHandle, jobject canvas) {
220 
221     GraphicBufferWrapper* wrapper =
222                 reinterpret_cast<GraphicBufferWrapper*>(wrapperHandle);
223     INVOKEV(canvas, gCanvasClassInfo.setNativeBitmap, (jlong)0);
224 
225     if (wrapper) {
226         status_t status = wrapper->buffer->unlock();
227         return status == 0 ? JNI_TRUE : JNI_FALSE;
228     }
229 
230     return JNI_FALSE;
231 }
232 
233 // ----------------------------------------------------------------------------
234 // Serialization
235 // ----------------------------------------------------------------------------
236 
android_view_GraphiceBuffer_write(JNIEnv * env,jobject clazz,jlong wrapperHandle,jobject dest)237 static void android_view_GraphiceBuffer_write(JNIEnv* env, jobject clazz,
238         jlong wrapperHandle, jobject dest) {
239     GraphicBufferWrapper* wrapper =
240                 reinterpret_cast<GraphicBufferWrapper*>(wrapperHandle);
241     Parcel* parcel = parcelForJavaObject(env, dest);
242     if (parcel) {
243         parcel->write(*wrapper->buffer);
244     }
245 }
246 
android_view_GraphiceBuffer_read(JNIEnv * env,jobject clazz,jobject in)247 static jlong android_view_GraphiceBuffer_read(JNIEnv* env, jobject clazz,
248         jobject in) {
249 
250     Parcel* parcel = parcelForJavaObject(env, in);
251     if (parcel) {
252         sp<GraphicBuffer> buffer = new GraphicBuffer();
253         parcel->read(*buffer);
254         return reinterpret_cast<jlong>(new GraphicBufferWrapper(buffer));
255     }
256 
257     return NULL;
258 }
259 
260 // ----------------------------------------------------------------------------
261 // External helpers
262 // ----------------------------------------------------------------------------
263 
graphicBufferForJavaObject(JNIEnv * env,jobject obj)264 sp<GraphicBuffer> graphicBufferForJavaObject(JNIEnv* env, jobject obj) {
265     if (obj) {
266         jlong nativeObject = env->GetLongField(obj, gGraphicBufferClassInfo.mNativeObject);
267         GraphicBufferWrapper* wrapper = (GraphicBufferWrapper*) nativeObject;
268         if (wrapper != NULL) {
269             sp<GraphicBuffer> buffer(wrapper->buffer);
270             return buffer;
271         }
272     }
273     return NULL;
274 }
275 
276 // ----------------------------------------------------------------------------
277 // JNI Glue
278 // ----------------------------------------------------------------------------
279 
280 #define FIND_CLASS(var, className) \
281         var = env->FindClass(className); \
282         LOG_FATAL_IF(! var, "Unable to find class " className);
283 
284 #define GET_FIELD_ID(var, clazz, fieldName, fieldDescriptor) \
285         var = env->GetFieldID(clazz, fieldName, fieldDescriptor); \
286         LOG_FATAL_IF(! var, "Unable to find field " fieldName);
287 
288 #define GET_METHOD_ID(var, clazz, methodName, methodDescriptor) \
289         var = env->GetMethodID(clazz, methodName, methodDescriptor); \
290         LOG_FATAL_IF(!var, "Unable to find method " methodName);
291 
292 const char* const kClassPathName = "android/view/GraphicBuffer";
293 
294 static JNINativeMethod gMethods[] = {
295     { "nCreateGraphicBuffer",  "(IIII)J", (void*) android_view_GraphiceBuffer_create },
296     { "nDestroyGraphicBuffer", "(J)V",    (void*) android_view_GraphiceBuffer_destroy },
297 
298     { "nWriteGraphicBufferToParcel",  "(JLandroid/os/Parcel;)V",
299             (void*) android_view_GraphiceBuffer_write },
300     { "nReadGraphicBufferFromParcel", "(Landroid/os/Parcel;)J",
301             (void*) android_view_GraphiceBuffer_read },
302 
303     { "nLockCanvas", "(JLandroid/graphics/Canvas;Landroid/graphics/Rect;)Z",
304             (void*) android_view_GraphicBuffer_lockCanvas },
305     { "nUnlockCanvasAndPost", "(JLandroid/graphics/Canvas;)Z",
306             (void*) android_view_GraphicBuffer_unlockCanvasAndPost },
307 };
308 
register_android_view_GraphicBuffer(JNIEnv * env)309 int register_android_view_GraphicBuffer(JNIEnv* env) {
310     jclass clazz;
311     FIND_CLASS(clazz, "android/view/GraphicBuffer");
312     GET_FIELD_ID(gGraphicBufferClassInfo.mNativeObject, clazz, "mNativeObject", "J");
313 
314     FIND_CLASS(clazz, "android/graphics/Rect");
315     GET_METHOD_ID(gRectClassInfo.set, clazz, "set", "(IIII)V");
316     GET_FIELD_ID(gRectClassInfo.left, clazz, "left", "I");
317     GET_FIELD_ID(gRectClassInfo.top, clazz, "top", "I");
318     GET_FIELD_ID(gRectClassInfo.right, clazz, "right", "I");
319     GET_FIELD_ID(gRectClassInfo.bottom, clazz, "bottom", "I");
320 
321     FIND_CLASS(clazz, "android/graphics/Canvas");
322     GET_FIELD_ID(gCanvasClassInfo.mSurfaceFormat, clazz, "mSurfaceFormat", "I");
323     GET_METHOD_ID(gCanvasClassInfo.setNativeBitmap, clazz, "setNativeBitmap", "(J)V");
324 
325     return AndroidRuntime::registerNativeMethods(env, kClassPathName, gMethods, NELEM(gMethods));
326 }
327 
328 };
329