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