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 
     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