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 "GraphicBuffer.h" 24#include "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 <hwui/Bitmap.h> 34 35#include <SkCanvas.h> 36#include <SkBitmap.h> 37 38#include <private/gui/ComposerService.h> 39 40#include "core_jni_helpers.h" 41 42namespace android { 43 44// ---------------------------------------------------------------------------- 45// Defines 46// ---------------------------------------------------------------------------- 47 48// Debug 49static const bool kDebugGraphicBuffer = false; 50 51#define LOCK_CANVAS_USAGE (GraphicBuffer::USAGE_SW_READ_OFTEN | GraphicBuffer::USAGE_SW_WRITE_OFTEN) 52 53// ---------------------------------------------------------------------------- 54// JNI Helpers 55// ---------------------------------------------------------------------------- 56 57static struct { 58 jfieldID mNativeObject; 59 jclass mClass; 60 jmethodID mConstructorMethodID; 61} gGraphicBufferClassInfo; 62 63static struct { 64 jmethodID set; 65 jfieldID left; 66 jfieldID top; 67 jfieldID right; 68 jfieldID bottom; 69} gRectClassInfo; 70 71#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 77#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 83#define INVOKEV(object, method, ...) \ 84 env->CallVoidMethod(object, method, __VA_ARGS__) 85 86// ---------------------------------------------------------------------------- 87// Types 88// ---------------------------------------------------------------------------- 89 90class GraphicBufferWrapper { 91public: 92 explicit GraphicBufferWrapper(const sp<GraphicBuffer>& buffer): buffer(buffer) { 93 } 94 95 sp<GraphicBuffer> buffer; 96}; 97 98// ---------------------------------------------------------------------------- 99// GraphicBuffer lifecycle 100// ---------------------------------------------------------------------------- 101 102static jlong android_graphics_GraphicBuffer_wrap(JNIEnv* env, jobject clazz, 103 jlong unwrapped) { 104 sp<GraphicBuffer> b(reinterpret_cast<GraphicBuffer*>(unwrapped)); 105 GraphicBufferWrapper* wrapper = new GraphicBufferWrapper(b); 106 return reinterpret_cast<jlong>(wrapper); 107} 108 109static jlong android_graphics_GraphicBuffer_create(JNIEnv* env, jobject clazz, 110 jint width, jint height, jint format, jint usage) { 111 112 sp<GraphicBuffer> buffer = new GraphicBuffer( 113 uint32_t(width), uint32_t(height), PixelFormat(format), uint32_t(usage), 114 std::string("android_graphics_GraphicBuffer_create pid [") + 115 std::to_string(getpid()) +"]"); 116 117 status_t error = buffer->initCheck(); 118 if (error < 0) { 119 ALOGW_IF(kDebugGraphicBuffer, "createGraphicBuffer() failed in GraphicBuffer.create()"); 120 return NULL; 121 } 122 123 GraphicBufferWrapper* wrapper = new GraphicBufferWrapper(buffer); 124 return reinterpret_cast<jlong>(wrapper); 125} 126 127static void android_graphics_GraphicBuffer_destroy(JNIEnv* env, jobject clazz, 128 jlong wrapperHandle) { 129 GraphicBufferWrapper* wrapper = 130 reinterpret_cast<GraphicBufferWrapper*>(wrapperHandle); 131 delete wrapper; 132} 133 134// ---------------------------------------------------------------------------- 135// Canvas management 136// ---------------------------------------------------------------------------- 137 138static inline SkColorType convertPixelFormat(int32_t format) { 139 switch (format) { 140 case PIXEL_FORMAT_RGBA_8888: 141 return kN32_SkColorType; 142 case PIXEL_FORMAT_RGBX_8888: 143 return kN32_SkColorType; 144 case PIXEL_FORMAT_RGBA_FP16: 145 return kRGBA_F16_SkColorType; 146 case PIXEL_FORMAT_RGB_565: 147 return kRGB_565_SkColorType; 148 default: 149 return kUnknown_SkColorType; 150 } 151} 152 153static jboolean android_graphics_GraphicBuffer_lockCanvas(JNIEnv* env, jobject, 154 jlong wrapperHandle, jobject canvas, jobject dirtyRect) { 155 156 GraphicBufferWrapper* wrapper = 157 reinterpret_cast<GraphicBufferWrapper*>(wrapperHandle); 158 if (!wrapper) { 159 return JNI_FALSE; 160 } 161 162 sp<GraphicBuffer> buffer(wrapper->buffer); 163 164 Rect rect(Rect::EMPTY_RECT); 165 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 177 if (status) return JNI_FALSE; 178 if (!bits) { 179 buffer->unlock(); 180 return JNI_FALSE; 181 } 182 183 ssize_t bytesCount = buffer->getStride() * bytesPerPixel(buffer->getPixelFormat()); 184 185 SkBitmap bitmap; 186 bitmap.setInfo(SkImageInfo::Make(buffer->getWidth(), buffer->getHeight(), 187 convertPixelFormat(buffer->getPixelFormat()), 188 kPremul_SkAlphaType, 189 GraphicsJNI::defaultColorSpace()), 190 bytesCount); 191 192 if (buffer->getWidth() > 0 && buffer->getHeight() > 0) { 193 bitmap.setPixels(bits); 194 } else { 195 bitmap.setPixels(NULL); 196 } 197 198 Canvas* nativeCanvas = GraphicsJNI::getNativeCanvas(env, canvas); 199 nativeCanvas->setBitmap(bitmap); 200 nativeCanvas->clipRect(rect.left, rect.top, rect.right, rect.bottom, 201 SkClipOp::kIntersect); 202 203 if (dirtyRect) { 204 INVOKEV(dirtyRect, gRectClassInfo.set, 205 int(rect.left), int(rect.top), int(rect.right), int(rect.bottom)); 206 } 207 208 return JNI_TRUE; 209} 210 211static jboolean android_graphics_GraphicBuffer_unlockCanvasAndPost(JNIEnv* env, jobject, 212 jlong wrapperHandle, jobject canvas) { 213 214 GraphicBufferWrapper* wrapper = 215 reinterpret_cast<GraphicBufferWrapper*>(wrapperHandle); 216 Canvas* nativeCanvas = GraphicsJNI::getNativeCanvas(env, canvas); 217 nativeCanvas->setBitmap(SkBitmap()); 218 219 if (wrapper) { 220 status_t status = wrapper->buffer->unlock(); 221 return status == 0 ? JNI_TRUE : JNI_FALSE; 222 } 223 224 return JNI_FALSE; 225} 226 227// ---------------------------------------------------------------------------- 228// Serialization 229// ---------------------------------------------------------------------------- 230 231static void android_graphics_GraphicBuffer_write(JNIEnv* env, jobject clazz, 232 jlong wrapperHandle, jobject dest) { 233 GraphicBufferWrapper* wrapper = 234 reinterpret_cast<GraphicBufferWrapper*>(wrapperHandle); 235 Parcel* parcel = parcelForJavaObject(env, dest); 236 if (parcel) { 237 parcel->write(*wrapper->buffer); 238 } 239} 240 241static jlong android_graphics_GraphicBuffer_read(JNIEnv* env, jobject clazz, 242 jobject in) { 243 244 Parcel* parcel = parcelForJavaObject(env, in); 245 if (parcel) { 246 sp<GraphicBuffer> buffer = new GraphicBuffer(); 247 parcel->read(*buffer); 248 return reinterpret_cast<jlong>(new GraphicBufferWrapper(buffer)); 249 } 250 251 return NULL; 252} 253 254// ---------------------------------------------------------------------------- 255// External helpers 256// ---------------------------------------------------------------------------- 257 258sp<GraphicBuffer> graphicBufferForJavaObject(JNIEnv* env, jobject obj) { 259 if (obj) { 260 jlong nativeObject = env->GetLongField(obj, gGraphicBufferClassInfo.mNativeObject); 261 GraphicBufferWrapper* wrapper = (GraphicBufferWrapper*) nativeObject; 262 if (wrapper != NULL) { 263 sp<GraphicBuffer> buffer(wrapper->buffer); 264 return buffer; 265 } 266 } 267 return NULL; 268} 269 270jobject createJavaGraphicBuffer(JNIEnv* env, const sp<GraphicBuffer>& buffer) { 271 GraphicBufferWrapper* wrapper = new GraphicBufferWrapper(buffer); 272 jobject obj = env->NewObject(gGraphicBufferClassInfo.mClass, 273 gGraphicBufferClassInfo.mConstructorMethodID, buffer->getWidth(), buffer->getHeight(), 274 buffer->getPixelFormat(), buffer->getUsage(), reinterpret_cast<jlong>(wrapper)); 275 return obj; 276} 277 278}; 279 280using namespace android; 281// ---------------------------------------------------------------------------- 282// JNI Glue 283// ---------------------------------------------------------------------------- 284 285const char* const kClassPathName = "android/graphics/GraphicBuffer"; 286 287static const JNINativeMethod gMethods[] = { 288 { "nCreateGraphicBuffer", "(IIII)J", (void*) android_graphics_GraphicBuffer_create }, 289 { "nDestroyGraphicBuffer", "(J)V", (void*) android_graphics_GraphicBuffer_destroy }, 290 291 { "nWriteGraphicBufferToParcel", "(JLandroid/os/Parcel;)V", 292 (void*) android_graphics_GraphicBuffer_write }, 293 { "nReadGraphicBufferFromParcel", "(Landroid/os/Parcel;)J", 294 (void*) android_graphics_GraphicBuffer_read }, 295 296 { "nLockCanvas", "(JLandroid/graphics/Canvas;Landroid/graphics/Rect;)Z", 297 (void*) android_graphics_GraphicBuffer_lockCanvas }, 298 { "nUnlockCanvasAndPost", "(JLandroid/graphics/Canvas;)Z", 299 (void*) android_graphics_GraphicBuffer_unlockCanvasAndPost }, 300 { "nWrapGraphicBuffer", "(J)J", 301 (void*) android_graphics_GraphicBuffer_wrap } 302}; 303 304int register_android_graphics_GraphicBuffer(JNIEnv* env) { 305 gGraphicBufferClassInfo.mClass = MakeGlobalRefOrDie(env, FindClassOrDie(env, kClassPathName)); 306 gGraphicBufferClassInfo.mNativeObject = GetFieldIDOrDie(env, gGraphicBufferClassInfo.mClass, 307 "mNativeObject", "J"); 308 gGraphicBufferClassInfo.mConstructorMethodID = env->GetMethodID(gGraphicBufferClassInfo.mClass, 309 "<init>", "(IIIIJ)V"); 310 311 jclass clazz = FindClassOrDie(env, "android/graphics/Rect"); 312 gRectClassInfo.set = GetMethodIDOrDie(env, clazz, "set", "(IIII)V"); 313 gRectClassInfo.left = GetFieldIDOrDie(env, clazz, "left", "I"); 314 gRectClassInfo.top = GetFieldIDOrDie(env, clazz, "top", "I"); 315 gRectClassInfo.right = GetFieldIDOrDie(env, clazz, "right", "I"); 316 gRectClassInfo.bottom = GetFieldIDOrDie(env, clazz, "bottom", "I"); 317 318 return RegisterMethodsOrDie(env, kClassPathName, gMethods, NELEM(gMethods)); 319} 320