1 /* 2 * Copyright (C) 2010 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 "SurfaceTexture" 18 19 #include <stdio.h> 20 21 #include <EGL/egl.h> 22 #include <EGL/eglext.h> 23 #include <GLES2/gl2.h> 24 #include <GLES2/gl2ext.h> 25 26 #include <gui/GLConsumer.h> 27 #include <gui/Surface.h> 28 #include <gui/BufferQueue.h> 29 30 #include "core_jni_helpers.h" 31 32 #include <cutils/atomic.h> 33 #include <utils/Log.h> 34 #include <utils/misc.h> 35 36 #include "jni.h" 37 #include "JNIHelp.h" 38 #include "ScopedLocalRef.h" 39 40 // ---------------------------------------------------------------------------- 41 42 #define EGL_PROTECTED_CONTENT_EXT 0x32C0 43 44 namespace android { 45 46 static const char* const OutOfResourcesException = 47 "android/view/Surface$OutOfResourcesException"; 48 static const char* const IllegalStateException = "java/lang/IllegalStateException"; 49 const char* const kSurfaceTextureClassPathName = "android/graphics/SurfaceTexture"; 50 51 struct fields_t { 52 jfieldID surfaceTexture; 53 jfieldID producer; 54 jfieldID frameAvailableListener; 55 jmethodID postEvent; 56 }; 57 static fields_t fields; 58 59 // Get an ID that's unique within this process. 60 static int32_t createProcessUniqueId() { 61 static volatile int32_t globalCounter = 0; 62 return android_atomic_inc(&globalCounter); 63 } 64 65 // Check whether the current EGL context is protected. 66 static bool isProtectedContext() { 67 EGLDisplay dpy = eglGetCurrentDisplay(); 68 EGLContext ctx = eglGetCurrentContext(); 69 70 if (dpy == EGL_NO_DISPLAY || ctx == EGL_NO_CONTEXT) { 71 return false; 72 } 73 74 EGLint isProtected = EGL_FALSE; 75 eglQueryContext(dpy, ctx, EGL_PROTECTED_CONTENT_EXT, &isProtected); 76 77 return isProtected; 78 } 79 80 // ---------------------------------------------------------------------------- 81 82 static void SurfaceTexture_setSurfaceTexture(JNIEnv* env, jobject thiz, 83 const sp<GLConsumer>& surfaceTexture) 84 { 85 GLConsumer* const p = 86 (GLConsumer*)env->GetLongField(thiz, fields.surfaceTexture); 87 if (surfaceTexture.get()) { 88 surfaceTexture->incStrong((void*)SurfaceTexture_setSurfaceTexture); 89 } 90 if (p) { 91 p->decStrong((void*)SurfaceTexture_setSurfaceTexture); 92 } 93 env->SetLongField(thiz, fields.surfaceTexture, (jlong)surfaceTexture.get()); 94 } 95 96 static void SurfaceTexture_setProducer(JNIEnv* env, jobject thiz, 97 const sp<IGraphicBufferProducer>& producer) 98 { 99 IGraphicBufferProducer* const p = 100 (IGraphicBufferProducer*)env->GetLongField(thiz, fields.producer); 101 if (producer.get()) { 102 producer->incStrong((void*)SurfaceTexture_setProducer); 103 } 104 if (p) { 105 p->decStrong((void*)SurfaceTexture_setProducer); 106 } 107 env->SetLongField(thiz, fields.producer, (jlong)producer.get()); 108 } 109 110 static void SurfaceTexture_setFrameAvailableListener(JNIEnv* env, 111 jobject thiz, sp<GLConsumer::FrameAvailableListener> listener) 112 { 113 GLConsumer::FrameAvailableListener* const p = 114 (GLConsumer::FrameAvailableListener*) 115 env->GetLongField(thiz, fields.frameAvailableListener); 116 if (listener.get()) { 117 listener->incStrong((void*)SurfaceTexture_setSurfaceTexture); 118 } 119 if (p) { 120 p->decStrong((void*)SurfaceTexture_setSurfaceTexture); 121 } 122 env->SetLongField(thiz, fields.frameAvailableListener, (jlong)listener.get()); 123 } 124 125 sp<GLConsumer> SurfaceTexture_getSurfaceTexture(JNIEnv* env, jobject thiz) { 126 return (GLConsumer*)env->GetLongField(thiz, fields.surfaceTexture); 127 } 128 129 sp<IGraphicBufferProducer> SurfaceTexture_getProducer(JNIEnv* env, jobject thiz) { 130 return (IGraphicBufferProducer*)env->GetLongField(thiz, fields.producer); 131 } 132 133 sp<ANativeWindow> android_SurfaceTexture_getNativeWindow(JNIEnv* env, jobject thiz) { 134 sp<GLConsumer> surfaceTexture(SurfaceTexture_getSurfaceTexture(env, thiz)); 135 sp<IGraphicBufferProducer> producer(SurfaceTexture_getProducer(env, thiz)); 136 sp<Surface> surfaceTextureClient(surfaceTexture != NULL ? new Surface(producer) : NULL); 137 return surfaceTextureClient; 138 } 139 140 bool android_SurfaceTexture_isInstanceOf(JNIEnv* env, jobject thiz) { 141 jclass surfaceTextureClass = env->FindClass(kSurfaceTextureClassPathName); 142 return env->IsInstanceOf(thiz, surfaceTextureClass); 143 } 144 145 // ---------------------------------------------------------------------------- 146 147 class JNISurfaceTextureContext : public GLConsumer::FrameAvailableListener 148 { 149 public: 150 JNISurfaceTextureContext(JNIEnv* env, jobject weakThiz, jclass clazz); 151 virtual ~JNISurfaceTextureContext(); 152 virtual void onFrameAvailable(const BufferItem& item); 153 154 private: 155 static JNIEnv* getJNIEnv(bool* needsDetach); 156 static void detachJNI(); 157 158 jobject mWeakThiz; 159 jclass mClazz; 160 }; 161 162 JNISurfaceTextureContext::JNISurfaceTextureContext(JNIEnv* env, 163 jobject weakThiz, jclass clazz) : 164 mWeakThiz(env->NewGlobalRef(weakThiz)), 165 mClazz((jclass)env->NewGlobalRef(clazz)) 166 {} 167 168 JNIEnv* JNISurfaceTextureContext::getJNIEnv(bool* needsDetach) { 169 *needsDetach = false; 170 JNIEnv* env = AndroidRuntime::getJNIEnv(); 171 if (env == NULL) { 172 JavaVMAttachArgs args = { 173 JNI_VERSION_1_4, "JNISurfaceTextureContext", NULL }; 174 JavaVM* vm = AndroidRuntime::getJavaVM(); 175 int result = vm->AttachCurrentThread(&env, (void*) &args); 176 if (result != JNI_OK) { 177 ALOGE("thread attach failed: %#x", result); 178 return NULL; 179 } 180 *needsDetach = true; 181 } 182 return env; 183 } 184 185 void JNISurfaceTextureContext::detachJNI() { 186 JavaVM* vm = AndroidRuntime::getJavaVM(); 187 int result = vm->DetachCurrentThread(); 188 if (result != JNI_OK) { 189 ALOGE("thread detach failed: %#x", result); 190 } 191 } 192 193 JNISurfaceTextureContext::~JNISurfaceTextureContext() 194 { 195 bool needsDetach = false; 196 JNIEnv* env = getJNIEnv(&needsDetach); 197 if (env != NULL) { 198 env->DeleteGlobalRef(mWeakThiz); 199 env->DeleteGlobalRef(mClazz); 200 } else { 201 ALOGW("leaking JNI object references"); 202 } 203 if (needsDetach) { 204 detachJNI(); 205 } 206 } 207 208 void JNISurfaceTextureContext::onFrameAvailable(const BufferItem& /* item */) 209 { 210 bool needsDetach = false; 211 JNIEnv* env = getJNIEnv(&needsDetach); 212 if (env != NULL) { 213 env->CallStaticVoidMethod(mClazz, fields.postEvent, mWeakThiz); 214 } else { 215 ALOGW("onFrameAvailable event will not posted"); 216 } 217 if (needsDetach) { 218 detachJNI(); 219 } 220 } 221 222 // ---------------------------------------------------------------------------- 223 224 225 #define ANDROID_GRAPHICS_SURFACETEXTURE_JNI_ID "mSurfaceTexture" 226 #define ANDROID_GRAPHICS_PRODUCER_JNI_ID "mProducer" 227 #define ANDROID_GRAPHICS_FRAMEAVAILABLELISTENER_JNI_ID \ 228 "mFrameAvailableListener" 229 230 static void SurfaceTexture_classInit(JNIEnv* env, jclass clazz) 231 { 232 fields.surfaceTexture = env->GetFieldID(clazz, 233 ANDROID_GRAPHICS_SURFACETEXTURE_JNI_ID, "J"); 234 if (fields.surfaceTexture == NULL) { 235 ALOGE("can't find android/graphics/SurfaceTexture.%s", 236 ANDROID_GRAPHICS_SURFACETEXTURE_JNI_ID); 237 } 238 fields.producer = env->GetFieldID(clazz, 239 ANDROID_GRAPHICS_PRODUCER_JNI_ID, "J"); 240 if (fields.producer == NULL) { 241 ALOGE("can't find android/graphics/SurfaceTexture.%s", 242 ANDROID_GRAPHICS_PRODUCER_JNI_ID); 243 } 244 fields.frameAvailableListener = env->GetFieldID(clazz, 245 ANDROID_GRAPHICS_FRAMEAVAILABLELISTENER_JNI_ID, "J"); 246 if (fields.frameAvailableListener == NULL) { 247 ALOGE("can't find android/graphics/SurfaceTexture.%s", 248 ANDROID_GRAPHICS_FRAMEAVAILABLELISTENER_JNI_ID); 249 } 250 251 fields.postEvent = env->GetStaticMethodID(clazz, "postEventFromNative", 252 "(Ljava/lang/ref/WeakReference;)V"); 253 if (fields.postEvent == NULL) { 254 ALOGE("can't find android/graphics/SurfaceTexture.postEventFromNative"); 255 } 256 } 257 258 static void SurfaceTexture_init(JNIEnv* env, jobject thiz, jboolean isDetached, 259 jint texName, jboolean singleBufferMode, jobject weakThiz) 260 { 261 sp<IGraphicBufferProducer> producer; 262 sp<IGraphicBufferConsumer> consumer; 263 BufferQueue::createBufferQueue(&producer, &consumer); 264 265 if (singleBufferMode) { 266 consumer->setMaxBufferCount(1); 267 } 268 269 sp<GLConsumer> surfaceTexture; 270 if (isDetached) { 271 surfaceTexture = new GLConsumer(consumer, GL_TEXTURE_EXTERNAL_OES, 272 true, !singleBufferMode); 273 } else { 274 surfaceTexture = new GLConsumer(consumer, texName, 275 GL_TEXTURE_EXTERNAL_OES, true, !singleBufferMode); 276 } 277 278 if (surfaceTexture == 0) { 279 jniThrowException(env, OutOfResourcesException, 280 "Unable to create native SurfaceTexture"); 281 return; 282 } 283 surfaceTexture->setName(String8::format("SurfaceTexture-%d-%d-%d", 284 (isDetached ? 0 : texName), 285 getpid(), 286 createProcessUniqueId())); 287 288 // If the current context is protected, inform the producer. 289 consumer->setConsumerIsProtected(isProtectedContext()); 290 291 SurfaceTexture_setSurfaceTexture(env, thiz, surfaceTexture); 292 SurfaceTexture_setProducer(env, thiz, producer); 293 294 jclass clazz = env->GetObjectClass(thiz); 295 if (clazz == NULL) { 296 jniThrowRuntimeException(env, 297 "Can't find android/graphics/SurfaceTexture"); 298 return; 299 } 300 301 sp<JNISurfaceTextureContext> ctx(new JNISurfaceTextureContext(env, weakThiz, 302 clazz)); 303 surfaceTexture->setFrameAvailableListener(ctx); 304 SurfaceTexture_setFrameAvailableListener(env, thiz, ctx); 305 } 306 307 static void SurfaceTexture_finalize(JNIEnv* env, jobject thiz) 308 { 309 sp<GLConsumer> surfaceTexture(SurfaceTexture_getSurfaceTexture(env, thiz)); 310 surfaceTexture->setFrameAvailableListener(0); 311 SurfaceTexture_setFrameAvailableListener(env, thiz, 0); 312 SurfaceTexture_setSurfaceTexture(env, thiz, 0); 313 SurfaceTexture_setProducer(env, thiz, 0); 314 } 315 316 static void SurfaceTexture_setDefaultBufferSize( 317 JNIEnv* env, jobject thiz, jint width, jint height) { 318 sp<GLConsumer> surfaceTexture(SurfaceTexture_getSurfaceTexture(env, thiz)); 319 surfaceTexture->setDefaultBufferSize(width, height); 320 } 321 322 static void SurfaceTexture_updateTexImage(JNIEnv* env, jobject thiz) 323 { 324 sp<GLConsumer> surfaceTexture(SurfaceTexture_getSurfaceTexture(env, thiz)); 325 status_t err = surfaceTexture->updateTexImage(); 326 if (err == INVALID_OPERATION) { 327 jniThrowException(env, IllegalStateException, "Unable to update texture contents (see " 328 "logcat for details)"); 329 } else if (err < 0) { 330 jniThrowRuntimeException(env, "Error during updateTexImage (see logcat for details)"); 331 } 332 } 333 334 static void SurfaceTexture_releaseTexImage(JNIEnv* env, jobject thiz) 335 { 336 sp<GLConsumer> surfaceTexture(SurfaceTexture_getSurfaceTexture(env, thiz)); 337 status_t err = surfaceTexture->releaseTexImage(); 338 if (err == INVALID_OPERATION) { 339 jniThrowException(env, IllegalStateException, "Unable to release texture contents (see " 340 "logcat for details)"); 341 } else if (err < 0) { 342 jniThrowRuntimeException(env, "Error during updateTexImage (see logcat for details)"); 343 } 344 } 345 346 static jint SurfaceTexture_detachFromGLContext(JNIEnv* env, jobject thiz) 347 { 348 sp<GLConsumer> surfaceTexture(SurfaceTexture_getSurfaceTexture(env, thiz)); 349 return surfaceTexture->detachFromContext(); 350 } 351 352 static jint SurfaceTexture_attachToGLContext(JNIEnv* env, jobject thiz, jint tex) 353 { 354 sp<GLConsumer> surfaceTexture(SurfaceTexture_getSurfaceTexture(env, thiz)); 355 return surfaceTexture->attachToContext((GLuint)tex); 356 } 357 358 static void SurfaceTexture_getTransformMatrix(JNIEnv* env, jobject thiz, 359 jfloatArray jmtx) 360 { 361 sp<GLConsumer> surfaceTexture(SurfaceTexture_getSurfaceTexture(env, thiz)); 362 float* mtx = env->GetFloatArrayElements(jmtx, NULL); 363 surfaceTexture->getTransformMatrix(mtx); 364 env->ReleaseFloatArrayElements(jmtx, mtx, 0); 365 } 366 367 static jlong SurfaceTexture_getTimestamp(JNIEnv* env, jobject thiz) 368 { 369 sp<GLConsumer> surfaceTexture(SurfaceTexture_getSurfaceTexture(env, thiz)); 370 return surfaceTexture->getTimestamp(); 371 } 372 373 static void SurfaceTexture_release(JNIEnv* env, jobject thiz) 374 { 375 sp<GLConsumer> surfaceTexture(SurfaceTexture_getSurfaceTexture(env, thiz)); 376 surfaceTexture->abandon(); 377 } 378 379 static jboolean SurfaceTexture_isReleased(JNIEnv* env, jobject thiz) 380 { 381 sp<GLConsumer> surfaceTexture(SurfaceTexture_getSurfaceTexture(env, thiz)); 382 return surfaceTexture->isAbandoned(); 383 } 384 385 // ---------------------------------------------------------------------------- 386 387 static const JNINativeMethod gSurfaceTextureMethods[] = { 388 {"nativeInit", "(ZIZLjava/lang/ref/WeakReference;)V", (void*)SurfaceTexture_init }, 389 {"nativeFinalize", "()V", (void*)SurfaceTexture_finalize }, 390 {"nativeSetDefaultBufferSize", "(II)V", (void*)SurfaceTexture_setDefaultBufferSize }, 391 {"nativeUpdateTexImage", "()V", (void*)SurfaceTexture_updateTexImage }, 392 {"nativeReleaseTexImage", "()V", (void*)SurfaceTexture_releaseTexImage }, 393 {"nativeDetachFromGLContext", "()I", (void*)SurfaceTexture_detachFromGLContext }, 394 {"nativeAttachToGLContext", "(I)I", (void*)SurfaceTexture_attachToGLContext }, 395 {"nativeGetTransformMatrix", "([F)V", (void*)SurfaceTexture_getTransformMatrix }, 396 {"nativeGetTimestamp", "()J", (void*)SurfaceTexture_getTimestamp }, 397 {"nativeRelease", "()V", (void*)SurfaceTexture_release }, 398 {"nativeIsReleased", "()Z", (void*)SurfaceTexture_isReleased }, 399 }; 400 401 int register_android_graphics_SurfaceTexture(JNIEnv* env) 402 { 403 // Cache some fields. 404 ScopedLocalRef<jclass> klass(env, FindClassOrDie(env, kSurfaceTextureClassPathName)); 405 SurfaceTexture_classInit(env, klass.get()); 406 407 return RegisterMethodsOrDie(env, kSurfaceTextureClassPathName, gSurfaceTextureMethods, 408 NELEM(gSurfaceTextureMethods)); 409 } 410 411 } // namespace android 412