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