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