blob: af975fbf7c9cf7864e52ffecf0ee183832b2cf16 [file] [log] [blame]
Romain Guy3b748a42013-04-17 18:54:38 -07001/*
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"
Florin Malita5c3d9272014-05-08 10:35:36 -040024#include "android/graphics/GraphicsJNI.h"
Romain Guy3b748a42013-04-17 18:54:38 -070025
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
Andreas Gampe987f79f2014-11-18 17:29:46 -080041#include "core_jni_helpers.h"
42
Romain Guy3b748a42013-04-17 18:54:38 -070043namespace android {
44
45// ----------------------------------------------------------------------------
46// Defines
47// ----------------------------------------------------------------------------
48
49// Debug
Andreas Gampeed6b9df2014-11-20 22:02:20 -080050static const bool kDebugGraphicBuffer = false;
Romain Guy3b748a42013-04-17 18:54:38 -070051
52#define LOCK_CANVAS_USAGE GraphicBuffer::USAGE_SW_READ_OFTEN | GraphicBuffer::USAGE_SW_WRITE_OFTEN
53
54// ----------------------------------------------------------------------------
55// JNI Helpers
56// ----------------------------------------------------------------------------
57
58static struct {
59 jfieldID mNativeObject;
60} gGraphicBufferClassInfo;
61
62static struct {
63 jmethodID set;
64 jfieldID left;
65 jfieldID top;
66 jfieldID right;
67 jfieldID bottom;
68} gRectClassInfo;
69
Romain Guy3b748a42013-04-17 18:54:38 -070070#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
Ashok Bhat36bef0b2014-01-20 20:08:01 +000076#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
Romain Guy3b748a42013-04-17 18:54:38 -070082#define INVOKEV(object, method, ...) \
83 env->CallVoidMethod(object, method, __VA_ARGS__)
84
85// ----------------------------------------------------------------------------
86// Types
87// ----------------------------------------------------------------------------
88
89class GraphicBufferWrapper {
90public:
Chih-Hung Hsiehc6baf562016-04-27 11:29:23 -070091 explicit GraphicBufferWrapper(const sp<GraphicBuffer>& buffer): buffer(buffer) {
Romain Guy3b748a42013-04-17 18:54:38 -070092 }
93
94 sp<GraphicBuffer> buffer;
95};
96
97// ----------------------------------------------------------------------------
98// GraphicBuffer lifecycle
99// ----------------------------------------------------------------------------
100
Ashok Bhat36bef0b2014-01-20 20:08:01 +0000101static jlong android_view_GraphiceBuffer_create(JNIEnv* env, jobject clazz,
Romain Guy3b748a42013-04-17 18:54:38 -0700102 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) {
Andreas Gampeed6b9df2014-11-20 22:02:20 -0800107 if (kDebugGraphicBuffer) {
108 ALOGW("createGraphicBufferAlloc() failed in GraphicBuffer.create()");
109 }
Romain Guy3b748a42013-04-17 18:54:38 -0700110 return NULL;
111 }
112
113 status_t error;
114 sp<GraphicBuffer> buffer(alloc->createGraphicBuffer(width, height, format, usage, &error));
115 if (buffer == NULL) {
Andreas Gampeed6b9df2014-11-20 22:02:20 -0800116 if (kDebugGraphicBuffer) {
117 ALOGW("createGraphicBuffer() failed in GraphicBuffer.create()");
118 }
Romain Guy3b748a42013-04-17 18:54:38 -0700119 return NULL;
120 }
121
Ashok Bhat36bef0b2014-01-20 20:08:01 +0000122 GraphicBufferWrapper* wrapper = new GraphicBufferWrapper(buffer);
123 return reinterpret_cast<jlong>(wrapper);
Romain Guy3b748a42013-04-17 18:54:38 -0700124}
125
126static void android_view_GraphiceBuffer_destroy(JNIEnv* env, jobject clazz,
Ashok Bhat36bef0b2014-01-20 20:08:01 +0000127 jlong wrapperHandle) {
128 GraphicBufferWrapper* wrapper =
129 reinterpret_cast<GraphicBufferWrapper*>(wrapperHandle);
Romain Guy3b748a42013-04-17 18:54:38 -0700130 delete wrapper;
131}
132
133// ----------------------------------------------------------------------------
134// Canvas management
135// ----------------------------------------------------------------------------
136
Mike Reedb9330552014-06-16 17:31:48 -0400137static inline SkColorType convertPixelFormat(int32_t format) {
Romain Guy3b748a42013-04-17 18:54:38 -0700138 switch (format) {
139 case PIXEL_FORMAT_RGBA_8888:
Mike Reedb9330552014-06-16 17:31:48 -0400140 return kN32_SkColorType;
Romain Guy3b748a42013-04-17 18:54:38 -0700141 case PIXEL_FORMAT_RGBX_8888:
Mike Reedb9330552014-06-16 17:31:48 -0400142 return kN32_SkColorType;
Romain Guy3b748a42013-04-17 18:54:38 -0700143 case PIXEL_FORMAT_RGB_565:
Mike Reedb9330552014-06-16 17:31:48 -0400144 return kRGB_565_SkColorType;
Romain Guy3b748a42013-04-17 18:54:38 -0700145 default:
Mike Reedb9330552014-06-16 17:31:48 -0400146 return kUnknown_SkColorType;
Romain Guy3b748a42013-04-17 18:54:38 -0700147 }
148}
149
150static jboolean android_view_GraphicBuffer_lockCanvas(JNIEnv* env, jobject,
Ashok Bhat36bef0b2014-01-20 20:08:01 +0000151 jlong wrapperHandle, jobject canvas, jobject dirtyRect) {
Romain Guy3b748a42013-04-17 18:54:38 -0700152
Ashok Bhat36bef0b2014-01-20 20:08:01 +0000153 GraphicBufferWrapper* wrapper =
154 reinterpret_cast<GraphicBufferWrapper*>(wrapperHandle);
Romain Guy3b748a42013-04-17 18:54:38 -0700155 if (!wrapper) {
Ashok Bhat36bef0b2014-01-20 20:08:01 +0000156 return JNI_FALSE;
Romain Guy3b748a42013-04-17 18:54:38 -0700157 }
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
Ashok Bhat36bef0b2014-01-20 20:08:01 +0000174 if (status) return JNI_FALSE;
Romain Guy3b748a42013-04-17 18:54:38 -0700175 if (!bits) {
176 buffer->unlock();
Ashok Bhat36bef0b2014-01-20 20:08:01 +0000177 return JNI_FALSE;
Romain Guy3b748a42013-04-17 18:54:38 -0700178 }
179
180 ssize_t bytesCount = buffer->getStride() * bytesPerPixel(buffer->getPixelFormat());
181
182 SkBitmap bitmap;
Mike Reedb9330552014-06-16 17:31:48 -0400183 bitmap.setInfo(SkImageInfo::Make(buffer->getWidth(), buffer->getHeight(),
184 convertPixelFormat(buffer->getPixelFormat()),
185 kPremul_SkAlphaType),
186 bytesCount);
Romain Guy3b748a42013-04-17 18:54:38 -0700187
188 if (buffer->getWidth() > 0 && buffer->getHeight() > 0) {
189 bitmap.setPixels(bits);
190 } else {
191 bitmap.setPixels(NULL);
192 }
193
John Reckc1b33d62015-04-22 09:04:45 -0700194 Canvas* nativeCanvas = GraphicsJNI::getNativeCanvas(env, canvas);
195 nativeCanvas->setBitmap(bitmap);
196 nativeCanvas->clipRect(rect.left, rect.top, rect.right, rect.bottom);
Romain Guy3b748a42013-04-17 18:54:38 -0700197
198 if (dirtyRect) {
199 INVOKEV(dirtyRect, gRectClassInfo.set,
200 int(rect.left), int(rect.top), int(rect.right), int(rect.bottom));
201 }
202
Ashok Bhat36bef0b2014-01-20 20:08:01 +0000203 return JNI_TRUE;
Romain Guy3b748a42013-04-17 18:54:38 -0700204}
205
206static jboolean android_view_GraphicBuffer_unlockCanvasAndPost(JNIEnv* env, jobject,
Ashok Bhat36bef0b2014-01-20 20:08:01 +0000207 jlong wrapperHandle, jobject canvas) {
Romain Guy3b748a42013-04-17 18:54:38 -0700208
Ashok Bhat36bef0b2014-01-20 20:08:01 +0000209 GraphicBufferWrapper* wrapper =
210 reinterpret_cast<GraphicBufferWrapper*>(wrapperHandle);
John Reckc1b33d62015-04-22 09:04:45 -0700211 Canvas* nativeCanvas = GraphicsJNI::getNativeCanvas(env, canvas);
212 nativeCanvas->setBitmap(SkBitmap());
Romain Guy3b748a42013-04-17 18:54:38 -0700213
214 if (wrapper) {
215 status_t status = wrapper->buffer->unlock();
Ashok Bhat36bef0b2014-01-20 20:08:01 +0000216 return status == 0 ? JNI_TRUE : JNI_FALSE;
Romain Guy3b748a42013-04-17 18:54:38 -0700217 }
218
Ashok Bhat36bef0b2014-01-20 20:08:01 +0000219 return JNI_FALSE;
Romain Guy3b748a42013-04-17 18:54:38 -0700220}
221
222// ----------------------------------------------------------------------------
223// Serialization
224// ----------------------------------------------------------------------------
225
226static void android_view_GraphiceBuffer_write(JNIEnv* env, jobject clazz,
Ashok Bhat36bef0b2014-01-20 20:08:01 +0000227 jlong wrapperHandle, jobject dest) {
228 GraphicBufferWrapper* wrapper =
229 reinterpret_cast<GraphicBufferWrapper*>(wrapperHandle);
Romain Guy3b748a42013-04-17 18:54:38 -0700230 Parcel* parcel = parcelForJavaObject(env, dest);
231 if (parcel) {
232 parcel->write(*wrapper->buffer);
233 }
234}
235
Ashok Bhat36bef0b2014-01-20 20:08:01 +0000236static jlong android_view_GraphiceBuffer_read(JNIEnv* env, jobject clazz,
Romain Guy3b748a42013-04-17 18:54:38 -0700237 jobject in) {
238
239 Parcel* parcel = parcelForJavaObject(env, in);
240 if (parcel) {
241 sp<GraphicBuffer> buffer = new GraphicBuffer();
242 parcel->read(*buffer);
Ashok Bhat36bef0b2014-01-20 20:08:01 +0000243 return reinterpret_cast<jlong>(new GraphicBufferWrapper(buffer));
Romain Guy3b748a42013-04-17 18:54:38 -0700244 }
245
246 return NULL;
247}
248
249// ----------------------------------------------------------------------------
250// External helpers
251// ----------------------------------------------------------------------------
252
253sp<GraphicBuffer> graphicBufferForJavaObject(JNIEnv* env, jobject obj) {
254 if (obj) {
Ashok Bhat36bef0b2014-01-20 20:08:01 +0000255 jlong nativeObject = env->GetLongField(obj, gGraphicBufferClassInfo.mNativeObject);
Romain Guy3b748a42013-04-17 18:54:38 -0700256 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
Romain Guy3b748a42013-04-17 18:54:38 -0700269const char* const kClassPathName = "android/view/GraphicBuffer";
270
Daniel Micay76f6a862015-09-19 17:31:01 -0400271static const JNINativeMethod gMethods[] = {
Ashok Bhat36bef0b2014-01-20 20:08:01 +0000272 { "nCreateGraphicBuffer", "(IIII)J", (void*) android_view_GraphiceBuffer_create },
273 { "nDestroyGraphicBuffer", "(J)V", (void*) android_view_GraphiceBuffer_destroy },
Romain Guy3b748a42013-04-17 18:54:38 -0700274
Ashok Bhat36bef0b2014-01-20 20:08:01 +0000275 { "nWriteGraphicBufferToParcel", "(JLandroid/os/Parcel;)V",
Romain Guy3b748a42013-04-17 18:54:38 -0700276 (void*) android_view_GraphiceBuffer_write },
Ashok Bhat36bef0b2014-01-20 20:08:01 +0000277 { "nReadGraphicBufferFromParcel", "(Landroid/os/Parcel;)J",
Romain Guy3b748a42013-04-17 18:54:38 -0700278 (void*) android_view_GraphiceBuffer_read },
279
Ashok Bhat36bef0b2014-01-20 20:08:01 +0000280 { "nLockCanvas", "(JLandroid/graphics/Canvas;Landroid/graphics/Rect;)Z",
Romain Guy3b748a42013-04-17 18:54:38 -0700281 (void*) android_view_GraphicBuffer_lockCanvas },
Ashok Bhat36bef0b2014-01-20 20:08:01 +0000282 { "nUnlockCanvasAndPost", "(JLandroid/graphics/Canvas;)Z",
Romain Guy3b748a42013-04-17 18:54:38 -0700283 (void*) android_view_GraphicBuffer_unlockCanvasAndPost },
284};
285
286int register_android_view_GraphicBuffer(JNIEnv* env) {
Andreas Gampe987f79f2014-11-18 17:29:46 -0800287 jclass clazz = FindClassOrDie(env, "android/view/GraphicBuffer");
288 gGraphicBufferClassInfo.mNativeObject = GetFieldIDOrDie(env, clazz, "mNativeObject", "J");
Romain Guy3b748a42013-04-17 18:54:38 -0700289
Andreas Gampe987f79f2014-11-18 17:29:46 -0800290 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");
Romain Guy3b748a42013-04-17 18:54:38 -0700296
Andreas Gampe987f79f2014-11-18 17:29:46 -0800297 return RegisterMethodsOrDie(env, kClassPathName, gMethods, NELEM(gMethods));
Romain Guy3b748a42013-04-17 18:54:38 -0700298}
299
300};