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