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