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