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