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 bytesCount); 201 202 if (buffer->getWidth() > 0 && buffer->getHeight() > 0) { 203 bitmap.setPixels(bits); 204 } else { 205 bitmap.setPixels(NULL); 206 } 207 208 Canvas* nativeCanvas = GraphicsJNI::getNativeCanvas(env, canvas); 209 nativeCanvas->setBitmap(bitmap); 210 nativeCanvas->clipRect(rect.left, rect.top, rect.right, rect.bottom, 211 SkClipOp::kIntersect); 212 213 if (dirtyRect) { 214 INVOKEV(dirtyRect, gRectClassInfo.set, 215 int(rect.left), int(rect.top), int(rect.right), int(rect.bottom)); 216 } 217 218 return JNI_TRUE; 219 } 220 221 static jboolean android_graphics_GraphicBuffer_unlockCanvasAndPost(JNIEnv* env, jobject, 222 jlong wrapperHandle, jobject canvas) { 223 224 GraphicBufferWrapper* wrapper = 225 reinterpret_cast<GraphicBufferWrapper*>(wrapperHandle); 226 Canvas* nativeCanvas = GraphicsJNI::getNativeCanvas(env, canvas); 227 nativeCanvas->setBitmap(SkBitmap()); 228 229 if (wrapper) { 230 status_t status = wrapper->get()->unlock(); 231 return status == 0 ? JNI_TRUE : JNI_FALSE; 232 } 233 234 return JNI_FALSE; 235 } 236 237 // ---------------------------------------------------------------------------- 238 // Serialization 239 // ---------------------------------------------------------------------------- 240 241 static void android_graphics_GraphicBuffer_write(JNIEnv* env, jobject clazz, 242 jlong wrapperHandle, jobject dest) { 243 244 GraphicBufferWrapper* wrapper = 245 reinterpret_cast<GraphicBufferWrapper*>(wrapperHandle); 246 Parcel* parcel = parcelForJavaObject(env, dest); 247 if (parcel) { 248 parcel->write(*wrapper->get()); 249 } 250 } 251 252 static jlong android_graphics_GraphicBuffer_read(JNIEnv* env, jobject clazz, 253 jobject in) { 254 255 Parcel* parcel = parcelForJavaObject(env, in); 256 if (parcel) { 257 sp<GraphicBuffer> buffer = new GraphicBuffer(); 258 parcel->read(*buffer); 259 return reinterpret_cast<jlong>(new GraphicBufferWrapper(buffer)); 260 } 261 262 return NULL; 263 } 264 265 // ---------------------------------------------------------------------------- 266 // External helpers 267 // ---------------------------------------------------------------------------- 268 269 sp<GraphicBuffer> graphicBufferForJavaObject(JNIEnv* env, jobject obj) { 270 if (obj) { 271 jlong nativeObject = env->GetLongField(obj, gGraphicBufferClassInfo.mNativeObject); 272 GraphicBufferWrapper* wrapper = (GraphicBufferWrapper*) nativeObject; 273 if (wrapper != NULL) { 274 sp<GraphicBuffer> buffer(wrapper->get()); 275 return buffer; 276 } 277 } 278 return NULL; 279 } 280 281 jobject createJavaGraphicBuffer(JNIEnv* env, const sp<GraphicBuffer>& buffer) { 282 GraphicBufferWrapper* wrapper = new GraphicBufferWrapper(buffer); 283 jobject obj = env->NewObject(gGraphicBufferClassInfo.mClass, 284 gGraphicBufferClassInfo.mConstructorMethodID, buffer->getWidth(), buffer->getHeight(), 285 buffer->getPixelFormat(), (jint)buffer->getUsage(), reinterpret_cast<jlong>(wrapper)); 286 return obj; 287 } 288 289 }; 290 291 using namespace android; 292 // ---------------------------------------------------------------------------- 293 // JNI Glue 294 // ---------------------------------------------------------------------------- 295 296 const char* const kClassPathName = "android/graphics/GraphicBuffer"; 297 298 static const JNINativeMethod gMethods[] = { 299 { "nCreateGraphicBuffer", "(IIII)J", (void*) android_graphics_GraphicBuffer_create }, 300 { "nDestroyGraphicBuffer", "(J)V", (void*) android_graphics_GraphicBuffer_destroy }, 301 302 { "nWriteGraphicBufferToParcel", "(JLandroid/os/Parcel;)V", 303 (void*) android_graphics_GraphicBuffer_write }, 304 { "nReadGraphicBufferFromParcel", "(Landroid/os/Parcel;)J", 305 (void*) android_graphics_GraphicBuffer_read }, 306 307 { "nLockCanvas", "(JLandroid/graphics/Canvas;Landroid/graphics/Rect;)Z", 308 (void*) android_graphics_GraphicBuffer_lockCanvas }, 309 { "nUnlockCanvasAndPost", "(JLandroid/graphics/Canvas;)Z", 310 (void*) android_graphics_GraphicBuffer_unlockCanvasAndPost }, 311 { "nWrapGraphicBuffer", "(J)J", 312 (void*) android_graphics_GraphicBuffer_wrap } 313 }; 314 315 int register_android_graphics_GraphicBuffer(JNIEnv* env) { 316 gGraphicBufferClassInfo.mClass = MakeGlobalRefOrDie(env, FindClassOrDie(env, kClassPathName)); 317 gGraphicBufferClassInfo.mNativeObject = GetFieldIDOrDie(env, gGraphicBufferClassInfo.mClass, 318 "mNativeObject", "J"); 319 gGraphicBufferClassInfo.mConstructorMethodID = env->GetMethodID(gGraphicBufferClassInfo.mClass, 320 "<init>", "(IIIIJ)V"); 321 322 jclass clazz = FindClassOrDie(env, "android/graphics/Rect"); 323 gRectClassInfo.set = GetMethodIDOrDie(env, clazz, "set", "(IIII)V"); 324 gRectClassInfo.left = GetFieldIDOrDie(env, clazz, "left", "I"); 325 gRectClassInfo.top = GetFieldIDOrDie(env, clazz, "top", "I"); 326 gRectClassInfo.right = GetFieldIDOrDie(env, clazz, "right", "I"); 327 gRectClassInfo.bottom = GetFieldIDOrDie(env, clazz, "bottom", "I"); 328 329 return RegisterMethodsOrDie(env, kClassPathName, gMethods, NELEM(gMethods)); 330 } 331