android_view_GraphicBuffer.cpp revision 18b4cbeedef21c1fa666a110a157bab66edff976
1326e0ddf89e8df2837752fbfd7a014814b32082cJason Sams/*
2326e0ddf89e8df2837752fbfd7a014814b32082cJason Sams * Copyright (C) 2013 The Android Open Source Project
3326e0ddf89e8df2837752fbfd7a014814b32082cJason Sams *
4326e0ddf89e8df2837752fbfd7a014814b32082cJason Sams * Licensed under the Apache License, Version 2.0 (the "License");
5326e0ddf89e8df2837752fbfd7a014814b32082cJason Sams * you may not use this file except in compliance with the License.
6326e0ddf89e8df2837752fbfd7a014814b32082cJason Sams * You may obtain a copy of the License at
7326e0ddf89e8df2837752fbfd7a014814b32082cJason Sams *
8326e0ddf89e8df2837752fbfd7a014814b32082cJason Sams *      http://www.apache.org/licenses/LICENSE-2.0
9326e0ddf89e8df2837752fbfd7a014814b32082cJason Sams *
10326e0ddf89e8df2837752fbfd7a014814b32082cJason Sams * Unless required by applicable law or agreed to in writing, software
11326e0ddf89e8df2837752fbfd7a014814b32082cJason Sams * distributed under the License is distributed on an "AS IS" BASIS,
12326e0ddf89e8df2837752fbfd7a014814b32082cJason Sams * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13326e0ddf89e8df2837752fbfd7a014814b32082cJason Sams * See the License for the specific language governing permissions and
14326e0ddf89e8df2837752fbfd7a014814b32082cJason Sams * limitations under the License.
15326e0ddf89e8df2837752fbfd7a014814b32082cJason Sams */
16326e0ddf89e8df2837752fbfd7a014814b32082cJason Sams
17326e0ddf89e8df2837752fbfd7a014814b32082cJason Sams#define LOG_TAG "GraphicBuffer"
18326e0ddf89e8df2837752fbfd7a014814b32082cJason Sams
19326e0ddf89e8df2837752fbfd7a014814b32082cJason Sams#include "jni.h"
20326e0ddf89e8df2837752fbfd7a014814b32082cJason Sams#include "JNIHelp.h"
21326e0ddf89e8df2837752fbfd7a014814b32082cJason Sams
22326e0ddf89e8df2837752fbfd7a014814b32082cJason Sams#include "android_os_Parcel.h"
23326e0ddf89e8df2837752fbfd7a014814b32082cJason Sams#include "android_view_GraphicBuffer.h"
24326e0ddf89e8df2837752fbfd7a014814b32082cJason Sams
25326e0ddf89e8df2837752fbfd7a014814b32082cJason Sams#include <android_runtime/AndroidRuntime.h>
26326e0ddf89e8df2837752fbfd7a014814b32082cJason Sams
27326e0ddf89e8df2837752fbfd7a014814b32082cJason Sams#include <binder/Parcel.h>
28326e0ddf89e8df2837752fbfd7a014814b32082cJason Sams
29326e0ddf89e8df2837752fbfd7a014814b32082cJason Sams#include <ui/GraphicBuffer.h>
30326e0ddf89e8df2837752fbfd7a014814b32082cJason Sams#include <ui/PixelFormat.h>
31326e0ddf89e8df2837752fbfd7a014814b32082cJason Sams
32326e0ddf89e8df2837752fbfd7a014814b32082cJason Sams#include <gui/IGraphicBufferAlloc.h>
33326e0ddf89e8df2837752fbfd7a014814b32082cJason Sams#include <gui/ISurfaceComposer.h>
34326e0ddf89e8df2837752fbfd7a014814b32082cJason Sams
35326e0ddf89e8df2837752fbfd7a014814b32082cJason Sams#include <SkCanvas.h>
36a0a1b6fbece2eb8d72d788422ab3e5f58d5a9216Jason Sams#include <SkBitmap.h>
37a0a1b6fbece2eb8d72d788422ab3e5f58d5a9216Jason Sams
38a0a1b6fbece2eb8d72d788422ab3e5f58d5a9216Jason Sams#include <private/gui/ComposerService.h>
39a0a1b6fbece2eb8d72d788422ab3e5f58d5a9216Jason Sams
40a0a1b6fbece2eb8d72d788422ab3e5f58d5a9216Jason Samsnamespace android {
41326e0ddf89e8df2837752fbfd7a014814b32082cJason Sams
42a0a1b6fbece2eb8d72d788422ab3e5f58d5a9216Jason Sams// ----------------------------------------------------------------------------
43326e0ddf89e8df2837752fbfd7a014814b32082cJason Sams// Defines
44326e0ddf89e8df2837752fbfd7a014814b32082cJason Sams// ----------------------------------------------------------------------------
45326e0ddf89e8df2837752fbfd7a014814b32082cJason Sams
46326e0ddf89e8df2837752fbfd7a014814b32082cJason Sams// Debug
47326e0ddf89e8df2837752fbfd7a014814b32082cJason Sams#define DEBUG_GRAPHIC_BUFFER 0
48326e0ddf89e8df2837752fbfd7a014814b32082cJason Sams
49326e0ddf89e8df2837752fbfd7a014814b32082cJason Sams// Debug
50326e0ddf89e8df2837752fbfd7a014814b32082cJason Sams#if DEBUG_GRAPHIC_BUFFER
51326e0ddf89e8df2837752fbfd7a014814b32082cJason Sams    #define GB_LOGD(...) ALOGD(__VA_ARGS__)
52326e0ddf89e8df2837752fbfd7a014814b32082cJason Sams    #define GB_LOGW(...) ALOGW(__VA_ARGS__)
53326e0ddf89e8df2837752fbfd7a014814b32082cJason Sams#else
54326e0ddf89e8df2837752fbfd7a014814b32082cJason Sams    #define GB_LOGD(...)
55326e0ddf89e8df2837752fbfd7a014814b32082cJason Sams    #define GB_LOGW(...)
561030893d9b99b72468034da13df025bda479bb97Jason Sams#endif
571030893d9b99b72468034da13df025bda479bb97Jason Sams
58a0a1b6fbece2eb8d72d788422ab3e5f58d5a9216Jason Sams#define LOCK_CANVAS_USAGE GraphicBuffer::USAGE_SW_READ_OFTEN | GraphicBuffer::USAGE_SW_WRITE_OFTEN
59a0a1b6fbece2eb8d72d788422ab3e5f58d5a9216Jason Sams
60a0a1b6fbece2eb8d72d788422ab3e5f58d5a9216Jason Sams// ----------------------------------------------------------------------------
611030893d9b99b72468034da13df025bda479bb97Jason Sams// JNI Helpers
621030893d9b99b72468034da13df025bda479bb97Jason Sams// ----------------------------------------------------------------------------
631030893d9b99b72468034da13df025bda479bb97Jason Sams
641030893d9b99b72468034da13df025bda479bb97Jason Samsstatic struct {
65a0a1b6fbece2eb8d72d788422ab3e5f58d5a9216Jason Sams    jfieldID mNativeObject;
66a0a1b6fbece2eb8d72d788422ab3e5f58d5a9216Jason Sams} gGraphicBufferClassInfo;
67a0a1b6fbece2eb8d72d788422ab3e5f58d5a9216Jason Sams
681030893d9b99b72468034da13df025bda479bb97Jason Samsstatic struct {
691030893d9b99b72468034da13df025bda479bb97Jason Sams    jmethodID set;
70326e0ddf89e8df2837752fbfd7a014814b32082cJason Sams    jfieldID left;
71326e0ddf89e8df2837752fbfd7a014814b32082cJason Sams    jfieldID top;
72326e0ddf89e8df2837752fbfd7a014814b32082cJason Sams    jfieldID right;
73326e0ddf89e8df2837752fbfd7a014814b32082cJason Sams    jfieldID bottom;
74326e0ddf89e8df2837752fbfd7a014814b32082cJason Sams} gRectClassInfo;
75326e0ddf89e8df2837752fbfd7a014814b32082cJason Sams
76326e0ddf89e8df2837752fbfd7a014814b32082cJason Samsstatic struct {
77326e0ddf89e8df2837752fbfd7a014814b32082cJason Sams    jfieldID mFinalizer;
78a0a1b6fbece2eb8d72d788422ab3e5f58d5a9216Jason Sams    jfieldID mNativeCanvas;
79a0a1b6fbece2eb8d72d788422ab3e5f58d5a9216Jason Sams    jfieldID mSurfaceFormat;
80a0a1b6fbece2eb8d72d788422ab3e5f58d5a9216Jason Sams} gCanvasClassInfo;
81326e0ddf89e8df2837752fbfd7a014814b32082cJason Sams
82326e0ddf89e8df2837752fbfd7a014814b32082cJason Samsstatic struct {
83326e0ddf89e8df2837752fbfd7a014814b32082cJason Sams    jfieldID mNativeCanvas;
84a0a1b6fbece2eb8d72d788422ab3e5f58d5a9216Jason Sams} gCanvasFinalizerClassInfo;
85a0a1b6fbece2eb8d72d788422ab3e5f58d5a9216Jason Sams
86a0a1b6fbece2eb8d72d788422ab3e5f58d5a9216Jason Sams#define GET_INT(object, field) \
87a0a1b6fbece2eb8d72d788422ab3e5f58d5a9216Jason Sams    env->GetIntField(object, field)
88326e0ddf89e8df2837752fbfd7a014814b32082cJason Sams
89326e0ddf89e8df2837752fbfd7a014814b32082cJason Sams#define SET_INT(object, field, value) \
90326e0ddf89e8df2837752fbfd7a014814b32082cJason Sams    env->SetIntField(object, field, value)
91326e0ddf89e8df2837752fbfd7a014814b32082cJason Sams
92326e0ddf89e8df2837752fbfd7a014814b32082cJason Sams#define GET_LONG(object, field) \
93326e0ddf89e8df2837752fbfd7a014814b32082cJason Sams    env->GetLongField(object, field)
94326e0ddf89e8df2837752fbfd7a014814b32082cJason Sams
95326e0ddf89e8df2837752fbfd7a014814b32082cJason Sams#define SET_LONG(object, field, value) \
96326e0ddf89e8df2837752fbfd7a014814b32082cJason Sams    env->SetLongField(object, field, value)
97326e0ddf89e8df2837752fbfd7a014814b32082cJason Sams
98326e0ddf89e8df2837752fbfd7a014814b32082cJason Sams#define INVOKEV(object, method, ...) \
99326e0ddf89e8df2837752fbfd7a014814b32082cJason Sams    env->CallVoidMethod(object, method, __VA_ARGS__)
100326e0ddf89e8df2837752fbfd7a014814b32082cJason Sams
101326e0ddf89e8df2837752fbfd7a014814b32082cJason Sams// ----------------------------------------------------------------------------
102326e0ddf89e8df2837752fbfd7a014814b32082cJason Sams// Types
103326e0ddf89e8df2837752fbfd7a014814b32082cJason Sams// ----------------------------------------------------------------------------
104326e0ddf89e8df2837752fbfd7a014814b32082cJason Sams
105326e0ddf89e8df2837752fbfd7a014814b32082cJason Samsclass GraphicBufferWrapper {
106326e0ddf89e8df2837752fbfd7a014814b32082cJason Samspublic:
107326e0ddf89e8df2837752fbfd7a014814b32082cJason Sams    GraphicBufferWrapper(const sp<GraphicBuffer>& buffer): buffer(buffer) {
108326e0ddf89e8df2837752fbfd7a014814b32082cJason Sams    }
109326e0ddf89e8df2837752fbfd7a014814b32082cJason Sams
110326e0ddf89e8df2837752fbfd7a014814b32082cJason Sams    sp<GraphicBuffer> buffer;
111326e0ddf89e8df2837752fbfd7a014814b32082cJason Sams};
112326e0ddf89e8df2837752fbfd7a014814b32082cJason Sams
113326e0ddf89e8df2837752fbfd7a014814b32082cJason Sams// ----------------------------------------------------------------------------
114// GraphicBuffer lifecycle
115// ----------------------------------------------------------------------------
116
117static jlong android_view_GraphiceBuffer_create(JNIEnv* env, jobject clazz,
118        jint width, jint height, jint format, jint usage) {
119
120    sp<ISurfaceComposer> composer(ComposerService::getComposerService());
121    sp<IGraphicBufferAlloc> alloc(composer->createGraphicBufferAlloc());
122    if (alloc == NULL) {
123        GB_LOGW("createGraphicBufferAlloc() failed in GraphicBuffer.create()");
124        return NULL;
125    }
126
127    status_t error;
128    sp<GraphicBuffer> buffer(alloc->createGraphicBuffer(width, height, format, usage, &error));
129    if (buffer == NULL) {
130        GB_LOGW("createGraphicBuffer() failed in GraphicBuffer.create()");
131        return NULL;
132    }
133
134    GraphicBufferWrapper* wrapper = new GraphicBufferWrapper(buffer);
135    return reinterpret_cast<jlong>(wrapper);
136}
137
138static void android_view_GraphiceBuffer_destroy(JNIEnv* env, jobject clazz,
139        jlong wrapperHandle) {
140    GraphicBufferWrapper* wrapper =
141                reinterpret_cast<GraphicBufferWrapper*>(wrapperHandle);
142    delete wrapper;
143}
144
145// ----------------------------------------------------------------------------
146// Canvas management
147// ----------------------------------------------------------------------------
148
149static inline void swapCanvasPtr(JNIEnv* env, jobject canvasObj, SkCanvas* newCanvas) {
150    jobject canvasFinalizerObj = env->GetObjectField(canvasObj, gCanvasClassInfo.mFinalizer);
151    SkCanvas* previousCanvas = reinterpret_cast<SkCanvas*>(
152            GET_LONG(canvasObj, gCanvasClassInfo.mNativeCanvas));
153    SET_LONG(canvasObj, gCanvasClassInfo.mNativeCanvas, (long) newCanvas);
154    SET_LONG(canvasFinalizerObj, gCanvasFinalizerClassInfo.mNativeCanvas, (long) newCanvas);
155    SkSafeUnref(previousCanvas);
156}
157
158static inline SkBitmap::Config convertPixelFormat(int32_t format) {
159    switch (format) {
160        case PIXEL_FORMAT_RGBA_8888:
161            return SkBitmap::kARGB_8888_Config;
162        case PIXEL_FORMAT_RGBX_8888:
163            return SkBitmap::kARGB_8888_Config;
164        case PIXEL_FORMAT_RGB_565:
165            return SkBitmap::kRGB_565_Config;
166        default:
167            return SkBitmap::kNo_Config;
168    }
169}
170
171static jboolean android_view_GraphicBuffer_lockCanvas(JNIEnv* env, jobject,
172        jlong wrapperHandle, jobject canvas, jobject dirtyRect) {
173
174    GraphicBufferWrapper* wrapper =
175                reinterpret_cast<GraphicBufferWrapper*>(wrapperHandle);
176    if (!wrapper) {
177        return JNI_FALSE;
178    }
179
180    sp<GraphicBuffer> buffer(wrapper->buffer);
181
182    Rect rect;
183    if (dirtyRect) {
184        rect.left = GET_INT(dirtyRect, gRectClassInfo.left);
185        rect.top = GET_INT(dirtyRect, gRectClassInfo.top);
186        rect.right = GET_INT(dirtyRect, gRectClassInfo.right);
187        rect.bottom = GET_INT(dirtyRect, gRectClassInfo.bottom);
188    } else {
189        rect.set(Rect(buffer->getWidth(), buffer->getHeight()));
190    }
191
192    void* bits = NULL;
193    status_t status = buffer->lock(LOCK_CANVAS_USAGE, rect, &bits);
194
195    if (status) return JNI_FALSE;
196    if (!bits) {
197        buffer->unlock();
198        return JNI_FALSE;
199    }
200
201    ssize_t bytesCount = buffer->getStride() * bytesPerPixel(buffer->getPixelFormat());
202
203    SkBitmap bitmap;
204    bitmap.setConfig(convertPixelFormat(buffer->getPixelFormat()),
205            buffer->getWidth(), buffer->getHeight(), bytesCount);
206
207    if (buffer->getWidth() > 0 && buffer->getHeight() > 0) {
208        bitmap.setPixels(bits);
209    } else {
210        bitmap.setPixels(NULL);
211    }
212
213    SET_INT(canvas, gCanvasClassInfo.mSurfaceFormat, buffer->getPixelFormat());
214
215    SkCanvas* nativeCanvas = SkNEW_ARGS(SkCanvas, (bitmap));
216    swapCanvasPtr(env, canvas, nativeCanvas);
217
218    SkRect clipRect;
219    clipRect.set(rect.left, rect.top, rect.right, rect.bottom);
220    nativeCanvas->clipRect(clipRect);
221
222    if (dirtyRect) {
223        INVOKEV(dirtyRect, gRectClassInfo.set,
224                int(rect.left), int(rect.top), int(rect.right), int(rect.bottom));
225    }
226
227    return JNI_TRUE;
228}
229
230static jboolean android_view_GraphicBuffer_unlockCanvasAndPost(JNIEnv* env, jobject,
231        jlong wrapperHandle, jobject canvas) {
232
233    GraphicBufferWrapper* wrapper =
234                reinterpret_cast<GraphicBufferWrapper*>(wrapperHandle);
235    SkCanvas* nativeCanvas = SkNEW(SkCanvas);
236    swapCanvasPtr(env, canvas, nativeCanvas);
237
238    if (wrapper) {
239        status_t status = wrapper->buffer->unlock();
240        return status == 0 ? JNI_TRUE : JNI_FALSE;
241    }
242
243    return JNI_FALSE;
244}
245
246// ----------------------------------------------------------------------------
247// Serialization
248// ----------------------------------------------------------------------------
249
250static void android_view_GraphiceBuffer_write(JNIEnv* env, jobject clazz,
251        jlong wrapperHandle, jobject dest) {
252    GraphicBufferWrapper* wrapper =
253                reinterpret_cast<GraphicBufferWrapper*>(wrapperHandle);
254    Parcel* parcel = parcelForJavaObject(env, dest);
255    if (parcel) {
256        parcel->write(*wrapper->buffer);
257    }
258}
259
260static jlong android_view_GraphiceBuffer_read(JNIEnv* env, jobject clazz,
261        jobject in) {
262
263    Parcel* parcel = parcelForJavaObject(env, in);
264    if (parcel) {
265        sp<GraphicBuffer> buffer = new GraphicBuffer();
266        parcel->read(*buffer);
267        return reinterpret_cast<jlong>(new GraphicBufferWrapper(buffer));
268    }
269
270    return NULL;
271}
272
273// ----------------------------------------------------------------------------
274// External helpers
275// ----------------------------------------------------------------------------
276
277sp<GraphicBuffer> graphicBufferForJavaObject(JNIEnv* env, jobject obj) {
278    if (obj) {
279        jlong nativeObject = env->GetLongField(obj, gGraphicBufferClassInfo.mNativeObject);
280        GraphicBufferWrapper* wrapper = (GraphicBufferWrapper*) nativeObject;
281        if (wrapper != NULL) {
282            sp<GraphicBuffer> buffer(wrapper->buffer);
283            return buffer;
284        }
285    }
286    return NULL;
287}
288
289// ----------------------------------------------------------------------------
290// JNI Glue
291// ----------------------------------------------------------------------------
292
293#define FIND_CLASS(var, className) \
294        var = env->FindClass(className); \
295        LOG_FATAL_IF(! var, "Unable to find class " className);
296
297#define GET_FIELD_ID(var, clazz, fieldName, fieldDescriptor) \
298        var = env->GetFieldID(clazz, fieldName, fieldDescriptor); \
299        LOG_FATAL_IF(! var, "Unable to find field " fieldName);
300
301#define GET_METHOD_ID(var, clazz, methodName, methodDescriptor) \
302        var = env->GetMethodID(clazz, methodName, methodDescriptor); \
303        LOG_FATAL_IF(!var, "Unable to find method " methodName);
304
305const char* const kClassPathName = "android/view/GraphicBuffer";
306
307static JNINativeMethod gMethods[] = {
308    { "nCreateGraphicBuffer",  "(IIII)J", (void*) android_view_GraphiceBuffer_create },
309    { "nDestroyGraphicBuffer", "(J)V",    (void*) android_view_GraphiceBuffer_destroy },
310
311    { "nWriteGraphicBufferToParcel",  "(JLandroid/os/Parcel;)V",
312            (void*) android_view_GraphiceBuffer_write },
313    { "nReadGraphicBufferFromParcel", "(Landroid/os/Parcel;)J",
314            (void*) android_view_GraphiceBuffer_read },
315
316    { "nLockCanvas", "(JLandroid/graphics/Canvas;Landroid/graphics/Rect;)Z",
317            (void*) android_view_GraphicBuffer_lockCanvas },
318    { "nUnlockCanvasAndPost", "(JLandroid/graphics/Canvas;)Z",
319            (void*) android_view_GraphicBuffer_unlockCanvasAndPost },
320};
321
322int register_android_view_GraphicBuffer(JNIEnv* env) {
323    jclass clazz;
324    FIND_CLASS(clazz, "android/view/GraphicBuffer");
325    GET_FIELD_ID(gGraphicBufferClassInfo.mNativeObject, clazz, "mNativeObject", "J");
326
327    FIND_CLASS(clazz, "android/graphics/Rect");
328    GET_METHOD_ID(gRectClassInfo.set, clazz, "set", "(IIII)V");
329    GET_FIELD_ID(gRectClassInfo.left, clazz, "left", "I");
330    GET_FIELD_ID(gRectClassInfo.top, clazz, "top", "I");
331    GET_FIELD_ID(gRectClassInfo.right, clazz, "right", "I");
332    GET_FIELD_ID(gRectClassInfo.bottom, clazz, "bottom", "I");
333
334    FIND_CLASS(clazz, "android/graphics/Canvas");
335    GET_FIELD_ID(gCanvasClassInfo.mFinalizer, clazz, "mFinalizer",
336            "Landroid/graphics/Canvas$CanvasFinalizer;");
337    GET_FIELD_ID(gCanvasClassInfo.mNativeCanvas, clazz, "mNativeCanvas", "J");
338    GET_FIELD_ID(gCanvasClassInfo.mSurfaceFormat, clazz, "mSurfaceFormat", "I");
339
340    FIND_CLASS(clazz, "android/graphics/Canvas$CanvasFinalizer");
341    GET_FIELD_ID(gCanvasFinalizerClassInfo.mNativeCanvas, clazz, "mNativeCanvas", "J");
342
343    return AndroidRuntime::registerNativeMethods(env, kClassPathName, gMethods, NELEM(gMethods));
344}
345
346};
347