1 /* 2 * Copyright (C) 2007 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 "Surface" 18 19 #include <stdio.h> 20 21 #include "jni.h" 22 #include "JNIHelp.h" 23 #include "android_os_Parcel.h" 24 #include "android/graphics/GraphicsJNI.h" 25 26 #include <android_runtime/AndroidRuntime.h> 27 #include <android_runtime/android_view_Surface.h> 28 #include <android_runtime/android_graphics_SurfaceTexture.h> 29 #include <android_runtime/Log.h> 30 31 #include <binder/Parcel.h> 32 33 #include <gui/Surface.h> 34 #include <gui/SurfaceControl.h> 35 #include <gui/GLConsumer.h> 36 37 #include <ui/Rect.h> 38 #include <ui/Region.h> 39 40 #include <SkCanvas.h> 41 #include <SkBitmap.h> 42 #include <SkRegion.h> 43 44 #include <utils/misc.h> 45 #include <utils/Log.h> 46 47 #include <ScopedUtfChars.h> 48 49 // ---------------------------------------------------------------------------- 50 51 namespace android { 52 53 static const char* const OutOfResourcesException = 54 "android/view/Surface$OutOfResourcesException"; 55 56 static struct { 57 jclass clazz; 58 jfieldID mNativeObject; 59 jfieldID mLock; 60 jmethodID ctor; 61 } gSurfaceClassInfo; 62 63 static struct { 64 jfieldID left; 65 jfieldID top; 66 jfieldID right; 67 jfieldID bottom; 68 } gRectClassInfo; 69 70 static struct { 71 jfieldID mFinalizer; 72 jfieldID mNativeCanvas; 73 jfieldID mSurfaceFormat; 74 } gCanvasClassInfo; 75 76 static struct { 77 jfieldID mNativeCanvas; 78 } gCanvasFinalizerClassInfo; 79 80 // ---------------------------------------------------------------------------- 81 82 // this is just a pointer we use to pass to inc/decStrong 83 static const void *sRefBaseOwner; 84 85 bool android_view_Surface_isInstanceOf(JNIEnv* env, jobject obj) { 86 return env->IsInstanceOf(obj, gSurfaceClassInfo.clazz); 87 } 88 89 sp<ANativeWindow> android_view_Surface_getNativeWindow(JNIEnv* env, jobject surfaceObj) { 90 return android_view_Surface_getSurface(env, surfaceObj); 91 } 92 93 sp<Surface> android_view_Surface_getSurface(JNIEnv* env, jobject surfaceObj) { 94 sp<Surface> sur; 95 jobject lock = env->GetObjectField(surfaceObj, 96 gSurfaceClassInfo.mLock); 97 if (env->MonitorEnter(lock) == JNI_OK) { 98 sur = reinterpret_cast<Surface *>( 99 env->GetIntField(surfaceObj, gSurfaceClassInfo.mNativeObject)); 100 env->MonitorExit(lock); 101 } 102 return sur; 103 } 104 105 jobject android_view_Surface_createFromIGraphicBufferProducer(JNIEnv* env, 106 const sp<IGraphicBufferProducer>& bufferProducer) { 107 if (bufferProducer == NULL) { 108 return NULL; 109 } 110 111 sp<Surface> surface(new Surface(bufferProducer, true)); 112 if (surface == NULL) { 113 return NULL; 114 } 115 116 jobject surfaceObj = env->NewObject(gSurfaceClassInfo.clazz, gSurfaceClassInfo.ctor, surface.get()); 117 if (surfaceObj == NULL) { 118 if (env->ExceptionCheck()) { 119 ALOGE("Could not create instance of Surface from IGraphicBufferProducer."); 120 LOGE_EX(env); 121 env->ExceptionClear(); 122 } 123 return NULL; 124 } 125 surface->incStrong(&sRefBaseOwner); 126 return surfaceObj; 127 } 128 129 // ---------------------------------------------------------------------------- 130 131 static inline bool isSurfaceValid(const sp<Surface>& sur) { 132 return Surface::isValid(sur); 133 } 134 135 // ---------------------------------------------------------------------------- 136 137 static jint nativeCreateFromSurfaceTexture(JNIEnv* env, jclass clazz, 138 jobject surfaceTextureObj) { 139 sp<IGraphicBufferProducer> producer(SurfaceTexture_getProducer(env, surfaceTextureObj)); 140 if (producer == NULL) { 141 jniThrowException(env, "java/lang/IllegalArgumentException", 142 "SurfaceTexture has already been released"); 143 return 0; 144 } 145 146 sp<Surface> surface(new Surface(producer, true)); 147 if (surface == NULL) { 148 jniThrowException(env, OutOfResourcesException, NULL); 149 return 0; 150 } 151 152 surface->incStrong(&sRefBaseOwner); 153 return int(surface.get()); 154 } 155 156 static void nativeRelease(JNIEnv* env, jclass clazz, jint nativeObject) { 157 sp<Surface> sur(reinterpret_cast<Surface *>(nativeObject)); 158 sur->decStrong(&sRefBaseOwner); 159 } 160 161 static jboolean nativeIsValid(JNIEnv* env, jclass clazz, jint nativeObject) { 162 sp<Surface> sur(reinterpret_cast<Surface *>(nativeObject)); 163 return isSurfaceValid(sur) ? JNI_TRUE : JNI_FALSE; 164 } 165 166 static jboolean nativeIsConsumerRunningBehind(JNIEnv* env, jclass clazz, jint nativeObject) { 167 sp<Surface> sur(reinterpret_cast<Surface *>(nativeObject)); 168 if (!isSurfaceValid(sur)) { 169 doThrowIAE(env); 170 return JNI_FALSE; 171 } 172 int value = 0; 173 ANativeWindow* anw = static_cast<ANativeWindow*>(sur.get()); 174 anw->query(anw, NATIVE_WINDOW_CONSUMER_RUNNING_BEHIND, &value); 175 return value; 176 } 177 178 static inline SkBitmap::Config convertPixelFormat(PixelFormat format) { 179 /* note: if PIXEL_FORMAT_RGBX_8888 means that all alpha bytes are 0xFF, then 180 we can map to SkBitmap::kARGB_8888_Config, and optionally call 181 bitmap.setIsOpaque(true) on the resulting SkBitmap (as an accelerator) 182 */ 183 switch (format) { 184 case PIXEL_FORMAT_RGBX_8888: return SkBitmap::kARGB_8888_Config; 185 case PIXEL_FORMAT_RGBA_8888: return SkBitmap::kARGB_8888_Config; 186 case PIXEL_FORMAT_RGB_565: return SkBitmap::kRGB_565_Config; 187 default: return SkBitmap::kNo_Config; 188 } 189 } 190 191 static inline void swapCanvasPtr(JNIEnv* env, jobject canvasObj, SkCanvas* newCanvas) { 192 jobject canvasFinalizerObj = env->GetObjectField(canvasObj, gCanvasClassInfo.mFinalizer); 193 SkCanvas* previousCanvas = reinterpret_cast<SkCanvas*>( 194 env->GetIntField(canvasObj, gCanvasClassInfo.mNativeCanvas)); 195 env->SetIntField(canvasObj, gCanvasClassInfo.mNativeCanvas, (int)newCanvas); 196 env->SetIntField(canvasFinalizerObj, gCanvasFinalizerClassInfo.mNativeCanvas, (int)newCanvas); 197 SkSafeUnref(previousCanvas); 198 } 199 200 static jint nativeLockCanvas(JNIEnv* env, jclass clazz, 201 jint nativeObject, jobject canvasObj, jobject dirtyRectObj) { 202 sp<Surface> surface(reinterpret_cast<Surface *>(nativeObject)); 203 204 if (!isSurfaceValid(surface)) { 205 doThrowIAE(env); 206 return 0; 207 } 208 209 Rect dirtyRect; 210 Rect* dirtyRectPtr = NULL; 211 212 if (dirtyRectObj) { 213 dirtyRect.left = env->GetIntField(dirtyRectObj, gRectClassInfo.left); 214 dirtyRect.top = env->GetIntField(dirtyRectObj, gRectClassInfo.top); 215 dirtyRect.right = env->GetIntField(dirtyRectObj, gRectClassInfo.right); 216 dirtyRect.bottom = env->GetIntField(dirtyRectObj, gRectClassInfo.bottom); 217 dirtyRectPtr = &dirtyRect; 218 } 219 220 ANativeWindow_Buffer outBuffer; 221 status_t err = surface->lock(&outBuffer, dirtyRectPtr); 222 if (err < 0) { 223 const char* const exception = (err == NO_MEMORY) ? 224 OutOfResourcesException : 225 "java/lang/IllegalArgumentException"; 226 jniThrowException(env, exception, NULL); 227 return 0; 228 } 229 230 // Associate a SkCanvas object to this surface 231 env->SetIntField(canvasObj, gCanvasClassInfo.mSurfaceFormat, outBuffer.format); 232 233 SkBitmap bitmap; 234 ssize_t bpr = outBuffer.stride * bytesPerPixel(outBuffer.format); 235 bitmap.setConfig(convertPixelFormat(outBuffer.format), outBuffer.width, outBuffer.height, bpr); 236 if (outBuffer.format == PIXEL_FORMAT_RGBX_8888) { 237 bitmap.setIsOpaque(true); 238 } 239 if (outBuffer.width > 0 && outBuffer.height > 0) { 240 bitmap.setPixels(outBuffer.bits); 241 } else { 242 // be safe with an empty bitmap. 243 bitmap.setPixels(NULL); 244 } 245 246 SkCanvas* nativeCanvas = SkNEW_ARGS(SkCanvas, (bitmap)); 247 swapCanvasPtr(env, canvasObj, nativeCanvas); 248 249 if (dirtyRectPtr) { 250 nativeCanvas->clipRect( SkRect::Make(reinterpret_cast<const SkIRect&>(dirtyRect)) ); 251 } 252 253 if (dirtyRectObj) { 254 env->SetIntField(dirtyRectObj, gRectClassInfo.left, dirtyRect.left); 255 env->SetIntField(dirtyRectObj, gRectClassInfo.top, dirtyRect.top); 256 env->SetIntField(dirtyRectObj, gRectClassInfo.right, dirtyRect.right); 257 env->SetIntField(dirtyRectObj, gRectClassInfo.bottom, dirtyRect.bottom); 258 } 259 260 // Create another reference to the surface and return it. This reference 261 // should be passed to nativeUnlockCanvasAndPost in place of mNativeObject, 262 // because the latter could be replaced while the surface is locked. 263 sp<Surface> lockedSurface(surface); 264 lockedSurface->incStrong(&sRefBaseOwner); 265 return (int) lockedSurface.get(); 266 } 267 268 static void nativeUnlockCanvasAndPost(JNIEnv* env, jclass clazz, 269 jint nativeObject, jobject canvasObj) { 270 sp<Surface> surface(reinterpret_cast<Surface *>(nativeObject)); 271 if (!isSurfaceValid(surface)) { 272 return; 273 } 274 275 // detach the canvas from the surface 276 SkCanvas* nativeCanvas = SkNEW(SkCanvas); 277 swapCanvasPtr(env, canvasObj, nativeCanvas); 278 279 // unlock surface 280 status_t err = surface->unlockAndPost(); 281 if (err < 0) { 282 doThrowIAE(env); 283 } 284 } 285 286 // ---------------------------------------------------------------------------- 287 288 static jint nativeCreateFromSurfaceControl(JNIEnv* env, jclass clazz, 289 jint surfaceControlNativeObj) { 290 /* 291 * This is used by the WindowManagerService just after constructing 292 * a Surface and is necessary for returning the Surface reference to 293 * the caller. At this point, we should only have a SurfaceControl. 294 */ 295 296 sp<SurfaceControl> ctrl(reinterpret_cast<SurfaceControl *>(surfaceControlNativeObj)); 297 sp<Surface> surface(ctrl->getSurface()); 298 if (surface != NULL) { 299 surface->incStrong(&sRefBaseOwner); 300 } 301 return reinterpret_cast<jint>(surface.get()); 302 } 303 304 static jint nativeReadFromParcel(JNIEnv* env, jclass clazz, 305 jint nativeObject, jobject parcelObj) { 306 Parcel* parcel = parcelForJavaObject(env, parcelObj); 307 if (parcel == NULL) { 308 doThrowNPE(env); 309 return 0; 310 } 311 312 sp<Surface> self(reinterpret_cast<Surface *>(nativeObject)); 313 sp<IBinder> binder(parcel->readStrongBinder()); 314 315 // update the Surface only if the underlying IGraphicBufferProducer 316 // has changed. 317 if (self != NULL 318 && (self->getIGraphicBufferProducer()->asBinder() == binder)) { 319 // same IGraphicBufferProducer, return ourselves 320 return int(self.get()); 321 } 322 323 sp<Surface> sur; 324 sp<IGraphicBufferProducer> gbp(interface_cast<IGraphicBufferProducer>(binder)); 325 if (gbp != NULL) { 326 // we have a new IGraphicBufferProducer, create a new Surface for it 327 sur = new Surface(gbp, true); 328 // and keep a reference before passing to java 329 sur->incStrong(&sRefBaseOwner); 330 } 331 332 if (self != NULL) { 333 // and loose the java reference to ourselves 334 self->decStrong(&sRefBaseOwner); 335 } 336 337 return int(sur.get()); 338 } 339 340 static void nativeWriteToParcel(JNIEnv* env, jclass clazz, 341 jint nativeObject, jobject parcelObj) { 342 Parcel* parcel = parcelForJavaObject(env, parcelObj); 343 if (parcel == NULL) { 344 doThrowNPE(env); 345 return; 346 } 347 sp<Surface> self(reinterpret_cast<Surface *>(nativeObject)); 348 parcel->writeStrongBinder( self != 0 ? self->getIGraphicBufferProducer()->asBinder() : NULL); 349 } 350 351 // ---------------------------------------------------------------------------- 352 353 static JNINativeMethod gSurfaceMethods[] = { 354 {"nativeCreateFromSurfaceTexture", "(Landroid/graphics/SurfaceTexture;)I", 355 (void*)nativeCreateFromSurfaceTexture }, 356 {"nativeRelease", "(I)V", 357 (void*)nativeRelease }, 358 {"nativeIsValid", "(I)Z", 359 (void*)nativeIsValid }, 360 {"nativeIsConsumerRunningBehind", "(I)Z", 361 (void*)nativeIsConsumerRunningBehind }, 362 {"nativeLockCanvas", "(ILandroid/graphics/Canvas;Landroid/graphics/Rect;)I", 363 (void*)nativeLockCanvas }, 364 {"nativeUnlockCanvasAndPost", "(ILandroid/graphics/Canvas;)V", 365 (void*)nativeUnlockCanvasAndPost }, 366 {"nativeCreateFromSurfaceControl", "(I)I", 367 (void*)nativeCreateFromSurfaceControl }, 368 {"nativeReadFromParcel", "(ILandroid/os/Parcel;)I", 369 (void*)nativeReadFromParcel }, 370 {"nativeWriteToParcel", "(ILandroid/os/Parcel;)V", 371 (void*)nativeWriteToParcel }, 372 }; 373 374 int register_android_view_Surface(JNIEnv* env) 375 { 376 int err = AndroidRuntime::registerNativeMethods(env, "android/view/Surface", 377 gSurfaceMethods, NELEM(gSurfaceMethods)); 378 379 jclass clazz = env->FindClass("android/view/Surface"); 380 gSurfaceClassInfo.clazz = jclass(env->NewGlobalRef(clazz)); 381 gSurfaceClassInfo.mNativeObject = 382 env->GetFieldID(gSurfaceClassInfo.clazz, "mNativeObject", "I"); 383 gSurfaceClassInfo.mLock = 384 env->GetFieldID(gSurfaceClassInfo.clazz, "mLock", "Ljava/lang/Object;"); 385 gSurfaceClassInfo.ctor = env->GetMethodID(gSurfaceClassInfo.clazz, "<init>", "(I)V"); 386 387 clazz = env->FindClass("android/graphics/Canvas"); 388 gCanvasClassInfo.mFinalizer = env->GetFieldID(clazz, "mFinalizer", "Landroid/graphics/Canvas$CanvasFinalizer;"); 389 gCanvasClassInfo.mNativeCanvas = env->GetFieldID(clazz, "mNativeCanvas", "I"); 390 gCanvasClassInfo.mSurfaceFormat = env->GetFieldID(clazz, "mSurfaceFormat", "I"); 391 392 clazz = env->FindClass("android/graphics/Canvas$CanvasFinalizer"); 393 gCanvasFinalizerClassInfo.mNativeCanvas = env->GetFieldID(clazz, "mNativeCanvas", "I"); 394 395 clazz = env->FindClass("android/graphics/Rect"); 396 gRectClassInfo.left = env->GetFieldID(clazz, "left", "I"); 397 gRectClassInfo.top = env->GetFieldID(clazz, "top", "I"); 398 gRectClassInfo.right = env->GetFieldID(clazz, "right", "I"); 399 gRectClassInfo.bottom = env->GetFieldID(clazz, "bottom", "I"); 400 401 return err; 402 } 403 404 }; 405