blob: 6cc71096405012e28ca0d96fcb5f2b36ebf23513 [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"
sergeyv0a0f2312017-01-04 13:58:52 -080023#include "GraphicBuffer.h"
24#include "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>
sergeyv9a029872016-11-29 10:13:28 -080035#include <hwui/Bitmap.h>
Romain Guy3b748a42013-04-17 18:54:38 -070036
37#include <SkCanvas.h>
38#include <SkBitmap.h>
39
40#include <private/gui/ComposerService.h>
41
Andreas Gampe987f79f2014-11-18 17:29:46 -080042#include "core_jni_helpers.h"
43
Romain Guy3b748a42013-04-17 18:54:38 -070044namespace android {
45
46// ----------------------------------------------------------------------------
47// Defines
48// ----------------------------------------------------------------------------
49
50// Debug
Andreas Gampeed6b9df2014-11-20 22:02:20 -080051static const bool kDebugGraphicBuffer = false;
Romain Guy3b748a42013-04-17 18:54:38 -070052
Chih-Hung Hsiehcef190d2016-05-19 15:25:50 -070053#define LOCK_CANVAS_USAGE (GraphicBuffer::USAGE_SW_READ_OFTEN | GraphicBuffer::USAGE_SW_WRITE_OFTEN)
Romain Guy3b748a42013-04-17 18:54:38 -070054
55// ----------------------------------------------------------------------------
56// JNI Helpers
57// ----------------------------------------------------------------------------
58
59static struct {
60 jfieldID mNativeObject;
61} gGraphicBufferClassInfo;
62
63static struct {
64 jmethodID set;
65 jfieldID left;
66 jfieldID top;
67 jfieldID right;
68 jfieldID bottom;
69} gRectClassInfo;
70
Romain Guy3b748a42013-04-17 18:54:38 -070071#define GET_INT(object, field) \
72 env->GetIntField(object, field)
73
74#define SET_INT(object, field, value) \
75 env->SetIntField(object, field, value)
76
Ashok Bhat36bef0b2014-01-20 20:08:01 +000077#define GET_LONG(object, field) \
78 env->GetLongField(object, field)
79
80#define SET_LONG(object, field, value) \
81 env->SetLongField(object, field, value)
82
Romain Guy3b748a42013-04-17 18:54:38 -070083#define INVOKEV(object, method, ...) \
84 env->CallVoidMethod(object, method, __VA_ARGS__)
85
86// ----------------------------------------------------------------------------
87// Types
88// ----------------------------------------------------------------------------
89
90class GraphicBufferWrapper {
91public:
Chih-Hung Hsiehc6baf562016-04-27 11:29:23 -070092 explicit GraphicBufferWrapper(const sp<GraphicBuffer>& buffer): buffer(buffer) {
Romain Guy3b748a42013-04-17 18:54:38 -070093 }
94
95 sp<GraphicBuffer> buffer;
96};
97
98// ----------------------------------------------------------------------------
99// GraphicBuffer lifecycle
100// ----------------------------------------------------------------------------
101
sergeyv0a0f2312017-01-04 13:58:52 -0800102static jlong android_graphics_GraphicBuffer_create(JNIEnv* env, jobject clazz,
Romain Guy3b748a42013-04-17 18:54:38 -0700103 jint width, jint height, jint format, jint usage) {
104
105 sp<ISurfaceComposer> composer(ComposerService::getComposerService());
106 sp<IGraphicBufferAlloc> alloc(composer->createGraphicBufferAlloc());
107 if (alloc == NULL) {
Andreas Gampeed6b9df2014-11-20 22:02:20 -0800108 if (kDebugGraphicBuffer) {
109 ALOGW("createGraphicBufferAlloc() failed in GraphicBuffer.create()");
110 }
Romain Guy3b748a42013-04-17 18:54:38 -0700111 return NULL;
112 }
113
114 status_t error;
Craig Donner850054c2016-10-26 11:47:23 -0700115 sp<GraphicBuffer> buffer(alloc->createGraphicBuffer(width, height, format, 1, usage, &error));
Romain Guy3b748a42013-04-17 18:54:38 -0700116 if (buffer == NULL) {
Andreas Gampeed6b9df2014-11-20 22:02:20 -0800117 if (kDebugGraphicBuffer) {
118 ALOGW("createGraphicBuffer() failed in GraphicBuffer.create()");
119 }
Romain Guy3b748a42013-04-17 18:54:38 -0700120 return NULL;
121 }
122
Ashok Bhat36bef0b2014-01-20 20:08:01 +0000123 GraphicBufferWrapper* wrapper = new GraphicBufferWrapper(buffer);
124 return reinterpret_cast<jlong>(wrapper);
Romain Guy3b748a42013-04-17 18:54:38 -0700125}
126
sergeyv0a0f2312017-01-04 13:58:52 -0800127static void android_graphics_GraphicBuffer_destroy(JNIEnv* env, jobject clazz,
Ashok Bhat36bef0b2014-01-20 20:08:01 +0000128 jlong wrapperHandle) {
129 GraphicBufferWrapper* wrapper =
130 reinterpret_cast<GraphicBufferWrapper*>(wrapperHandle);
Romain Guy3b748a42013-04-17 18:54:38 -0700131 delete wrapper;
132}
133
134// ----------------------------------------------------------------------------
135// Canvas management
136// ----------------------------------------------------------------------------
137
Mike Reedb9330552014-06-16 17:31:48 -0400138static inline SkColorType convertPixelFormat(int32_t format) {
Romain Guy3b748a42013-04-17 18:54:38 -0700139 switch (format) {
140 case PIXEL_FORMAT_RGBA_8888:
Mike Reedb9330552014-06-16 17:31:48 -0400141 return kN32_SkColorType;
Romain Guy3b748a42013-04-17 18:54:38 -0700142 case PIXEL_FORMAT_RGBX_8888:
Mike Reedb9330552014-06-16 17:31:48 -0400143 return kN32_SkColorType;
Romain Guy9505a652016-12-14 09:43:50 -0800144 case PIXEL_FORMAT_RGBA_FP16:
145 return kRGBA_F16_SkColorType;
Romain Guy3b748a42013-04-17 18:54:38 -0700146 case PIXEL_FORMAT_RGB_565:
Mike Reedb9330552014-06-16 17:31:48 -0400147 return kRGB_565_SkColorType;
Romain Guy3b748a42013-04-17 18:54:38 -0700148 default:
Mike Reedb9330552014-06-16 17:31:48 -0400149 return kUnknown_SkColorType;
Romain Guy3b748a42013-04-17 18:54:38 -0700150 }
151}
152
sergeyv0a0f2312017-01-04 13:58:52 -0800153static jboolean android_graphics_GraphicBuffer_lockCanvas(JNIEnv* env, jobject,
Ashok Bhat36bef0b2014-01-20 20:08:01 +0000154 jlong wrapperHandle, jobject canvas, jobject dirtyRect) {
Romain Guy3b748a42013-04-17 18:54:38 -0700155
Ashok Bhat36bef0b2014-01-20 20:08:01 +0000156 GraphicBufferWrapper* wrapper =
157 reinterpret_cast<GraphicBufferWrapper*>(wrapperHandle);
Romain Guy3b748a42013-04-17 18:54:38 -0700158 if (!wrapper) {
Ashok Bhat36bef0b2014-01-20 20:08:01 +0000159 return JNI_FALSE;
Romain Guy3b748a42013-04-17 18:54:38 -0700160 }
161
162 sp<GraphicBuffer> buffer(wrapper->buffer);
163
Pablo Ceballos82702922015-08-07 17:28:03 -0700164 Rect rect(Rect::EMPTY_RECT);
Romain Guy3b748a42013-04-17 18:54:38 -0700165 if (dirtyRect) {
166 rect.left = GET_INT(dirtyRect, gRectClassInfo.left);
167 rect.top = GET_INT(dirtyRect, gRectClassInfo.top);
168 rect.right = GET_INT(dirtyRect, gRectClassInfo.right);
169 rect.bottom = GET_INT(dirtyRect, gRectClassInfo.bottom);
170 } else {
171 rect.set(Rect(buffer->getWidth(), buffer->getHeight()));
172 }
173
174 void* bits = NULL;
175 status_t status = buffer->lock(LOCK_CANVAS_USAGE, rect, &bits);
176
Ashok Bhat36bef0b2014-01-20 20:08:01 +0000177 if (status) return JNI_FALSE;
Romain Guy3b748a42013-04-17 18:54:38 -0700178 if (!bits) {
179 buffer->unlock();
Ashok Bhat36bef0b2014-01-20 20:08:01 +0000180 return JNI_FALSE;
Romain Guy3b748a42013-04-17 18:54:38 -0700181 }
182
183 ssize_t bytesCount = buffer->getStride() * bytesPerPixel(buffer->getPixelFormat());
184
185 SkBitmap bitmap;
Mike Reedb9330552014-06-16 17:31:48 -0400186 bitmap.setInfo(SkImageInfo::Make(buffer->getWidth(), buffer->getHeight(),
187 convertPixelFormat(buffer->getPixelFormat()),
Romain Guy253f2c22016-09-28 17:34:42 -0700188 kPremul_SkAlphaType,
189 GraphicsJNI::defaultColorSpace()),
Mike Reedb9330552014-06-16 17:31:48 -0400190 bytesCount);
Romain Guy3b748a42013-04-17 18:54:38 -0700191
192 if (buffer->getWidth() > 0 && buffer->getHeight() > 0) {
193 bitmap.setPixels(bits);
194 } else {
195 bitmap.setPixels(NULL);
196 }
197
John Reckc1b33d62015-04-22 09:04:45 -0700198 Canvas* nativeCanvas = GraphicsJNI::getNativeCanvas(env, canvas);
199 nativeCanvas->setBitmap(bitmap);
Mike Reed6e49c9f2016-12-02 15:36:59 -0500200 nativeCanvas->clipRect(rect.left, rect.top, rect.right, rect.bottom,
Mike Reed6c67f1d2016-12-14 10:29:54 -0500201 SkClipOp::kIntersect);
Romain Guy3b748a42013-04-17 18:54:38 -0700202
203 if (dirtyRect) {
204 INVOKEV(dirtyRect, gRectClassInfo.set,
205 int(rect.left), int(rect.top), int(rect.right), int(rect.bottom));
206 }
207
Ashok Bhat36bef0b2014-01-20 20:08:01 +0000208 return JNI_TRUE;
Romain Guy3b748a42013-04-17 18:54:38 -0700209}
210
sergeyv0a0f2312017-01-04 13:58:52 -0800211static jboolean android_graphics_GraphicBuffer_unlockCanvasAndPost(JNIEnv* env, jobject,
Ashok Bhat36bef0b2014-01-20 20:08:01 +0000212 jlong wrapperHandle, jobject canvas) {
Romain Guy3b748a42013-04-17 18:54:38 -0700213
Ashok Bhat36bef0b2014-01-20 20:08:01 +0000214 GraphicBufferWrapper* wrapper =
215 reinterpret_cast<GraphicBufferWrapper*>(wrapperHandle);
John Reckc1b33d62015-04-22 09:04:45 -0700216 Canvas* nativeCanvas = GraphicsJNI::getNativeCanvas(env, canvas);
217 nativeCanvas->setBitmap(SkBitmap());
Romain Guy3b748a42013-04-17 18:54:38 -0700218
219 if (wrapper) {
220 status_t status = wrapper->buffer->unlock();
Ashok Bhat36bef0b2014-01-20 20:08:01 +0000221 return status == 0 ? JNI_TRUE : JNI_FALSE;
Romain Guy3b748a42013-04-17 18:54:38 -0700222 }
223
Ashok Bhat36bef0b2014-01-20 20:08:01 +0000224 return JNI_FALSE;
Romain Guy3b748a42013-04-17 18:54:38 -0700225}
226
227// ----------------------------------------------------------------------------
228// Serialization
229// ----------------------------------------------------------------------------
230
sergeyv0a0f2312017-01-04 13:58:52 -0800231static void android_graphics_GraphicBuffer_write(JNIEnv* env, jobject clazz,
Ashok Bhat36bef0b2014-01-20 20:08:01 +0000232 jlong wrapperHandle, jobject dest) {
233 GraphicBufferWrapper* wrapper =
234 reinterpret_cast<GraphicBufferWrapper*>(wrapperHandle);
Romain Guy3b748a42013-04-17 18:54:38 -0700235 Parcel* parcel = parcelForJavaObject(env, dest);
236 if (parcel) {
237 parcel->write(*wrapper->buffer);
238 }
239}
240
sergeyv0a0f2312017-01-04 13:58:52 -0800241static jlong android_graphics_GraphicBuffer_read(JNIEnv* env, jobject clazz,
Romain Guy3b748a42013-04-17 18:54:38 -0700242 jobject in) {
243
244 Parcel* parcel = parcelForJavaObject(env, in);
245 if (parcel) {
246 sp<GraphicBuffer> buffer = new GraphicBuffer();
247 parcel->read(*buffer);
Ashok Bhat36bef0b2014-01-20 20:08:01 +0000248 return reinterpret_cast<jlong>(new GraphicBufferWrapper(buffer));
Romain Guy3b748a42013-04-17 18:54:38 -0700249 }
250
251 return NULL;
252}
253
254// ----------------------------------------------------------------------------
255// External helpers
256// ----------------------------------------------------------------------------
257
258sp<GraphicBuffer> graphicBufferForJavaObject(JNIEnv* env, jobject obj) {
259 if (obj) {
Ashok Bhat36bef0b2014-01-20 20:08:01 +0000260 jlong nativeObject = env->GetLongField(obj, gGraphicBufferClassInfo.mNativeObject);
Romain Guy3b748a42013-04-17 18:54:38 -0700261 GraphicBufferWrapper* wrapper = (GraphicBufferWrapper*) nativeObject;
262 if (wrapper != NULL) {
263 sp<GraphicBuffer> buffer(wrapper->buffer);
264 return buffer;
265 }
266 }
267 return NULL;
268}
sergeyv0a0f2312017-01-04 13:58:52 -0800269};
Romain Guy3b748a42013-04-17 18:54:38 -0700270
sergeyv0a0f2312017-01-04 13:58:52 -0800271using namespace android;
Romain Guy3b748a42013-04-17 18:54:38 -0700272// ----------------------------------------------------------------------------
273// JNI Glue
274// ----------------------------------------------------------------------------
275
sergeyv0a0f2312017-01-04 13:58:52 -0800276const char* const kClassPathName = "android/graphics/GraphicBuffer";
Romain Guy3b748a42013-04-17 18:54:38 -0700277
Daniel Micay76f6a862015-09-19 17:31:01 -0400278static const JNINativeMethod gMethods[] = {
sergeyv0a0f2312017-01-04 13:58:52 -0800279 { "nCreateGraphicBuffer", "(IIII)J", (void*) android_graphics_GraphicBuffer_create },
280 { "nDestroyGraphicBuffer", "(J)V", (void*) android_graphics_GraphicBuffer_destroy },
Romain Guy3b748a42013-04-17 18:54:38 -0700281
Ashok Bhat36bef0b2014-01-20 20:08:01 +0000282 { "nWriteGraphicBufferToParcel", "(JLandroid/os/Parcel;)V",
sergeyv0a0f2312017-01-04 13:58:52 -0800283 (void*) android_graphics_GraphicBuffer_write },
Ashok Bhat36bef0b2014-01-20 20:08:01 +0000284 { "nReadGraphicBufferFromParcel", "(Landroid/os/Parcel;)J",
sergeyv0a0f2312017-01-04 13:58:52 -0800285 (void*) android_graphics_GraphicBuffer_read },
Romain Guy3b748a42013-04-17 18:54:38 -0700286
Ashok Bhat36bef0b2014-01-20 20:08:01 +0000287 { "nLockCanvas", "(JLandroid/graphics/Canvas;Landroid/graphics/Rect;)Z",
sergeyv0a0f2312017-01-04 13:58:52 -0800288 (void*) android_graphics_GraphicBuffer_lockCanvas },
Ashok Bhat36bef0b2014-01-20 20:08:01 +0000289 { "nUnlockCanvasAndPost", "(JLandroid/graphics/Canvas;)Z",
sergeyv0a0f2312017-01-04 13:58:52 -0800290 (void*) android_graphics_GraphicBuffer_unlockCanvasAndPost }
Romain Guy3b748a42013-04-17 18:54:38 -0700291};
292
sergeyv0a0f2312017-01-04 13:58:52 -0800293int register_android_graphics_GraphicBuffer(JNIEnv* env) {
294 jclass clazz = FindClassOrDie(env, "android/graphics/GraphicBuffer");
Andreas Gampe987f79f2014-11-18 17:29:46 -0800295 gGraphicBufferClassInfo.mNativeObject = GetFieldIDOrDie(env, clazz, "mNativeObject", "J");
Romain Guy3b748a42013-04-17 18:54:38 -0700296
Andreas Gampe987f79f2014-11-18 17:29:46 -0800297 clazz = FindClassOrDie(env, "android/graphics/Rect");
298 gRectClassInfo.set = GetMethodIDOrDie(env, clazz, "set", "(IIII)V");
299 gRectClassInfo.left = GetFieldIDOrDie(env, clazz, "left", "I");
300 gRectClassInfo.top = GetFieldIDOrDie(env, clazz, "top", "I");
301 gRectClassInfo.right = GetFieldIDOrDie(env, clazz, "right", "I");
302 gRectClassInfo.bottom = GetFieldIDOrDie(env, clazz, "bottom", "I");
Romain Guy3b748a42013-04-17 18:54:38 -0700303
Andreas Gampe987f79f2014-11-18 17:29:46 -0800304 return RegisterMethodsOrDie(env, kClassPathName, gMethods, NELEM(gMethods));
sergeyv0a0f2312017-01-04 13:58:52 -0800305}