xref: /aosp_15_r20/frameworks/base/core/jni/android_graphics_SurfaceTexture.cpp (revision d57664e9bc4670b3ecf6748a746a57c557b6bc9e)
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 #undef LOG_TAG
18 #define LOG_TAG "SurfaceTexture"
19 
20 #include <EGL/egl.h>
21 #include <EGL/eglext.h>
22 #include <GLES2/gl2.h>
23 #include <GLES2/gl2ext.h>
24 #include <com_android_graphics_libgui_flags.h>
25 #include <cutils/atomic.h>
26 #include <gui/BufferQueue.h>
27 #include <gui/Surface.h>
28 #include <nativehelper/JNIHelp.h>
29 #include <nativehelper/ScopedLocalRef.h>
30 #include <stdio.h>
31 #include <surfacetexture/SurfaceTexture.h>
32 #include <surfacetexture/surface_texture_platform.h>
33 #include <utils/Log.h>
34 #include <utils/misc.h>
35 
36 #include "core_jni_helpers.h"
37 #include "jni.h"
38 
39 // ----------------------------------------------------------------------------
40 
41 #define EGL_PROTECTED_CONTENT_EXT 0x32C0
42 
43 namespace android {
44 
45 static const char* const OutOfResourcesException =
46     "android/view/Surface$OutOfResourcesException";
47 static const char* const IllegalStateException = "java/lang/IllegalStateException";
48 const char* const kSurfaceTextureClassPathName = "android/graphics/SurfaceTexture";
49 
50 struct fields_t {
51     jfieldID  surfaceTexture;
52     jfieldID  producer;
53     jfieldID  frameAvailableListener;
54     jmethodID postEvent;
55     jmethodID postOnSetFrameRateEvent;
56 };
57 static fields_t fields;
58 
59 // Get an ID that's unique within this process.
createProcessUniqueId()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.
isProtectedContext()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 
SurfaceTexture_setSurfaceTexture(JNIEnv * env,jobject thiz,const sp<SurfaceTexture> & surfaceTexture)82 static void SurfaceTexture_setSurfaceTexture(JNIEnv* env, jobject thiz,
83         const sp<SurfaceTexture>& surfaceTexture)
84 {
85     SurfaceTexture* const p =
86         (SurfaceTexture*)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 
SurfaceTexture_setProducer(JNIEnv * env,jobject thiz,const sp<IGraphicBufferProducer> & producer)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 
SurfaceTexture_setFrameAvailableListener(JNIEnv * env,jobject thiz,sp<SurfaceTexture::FrameAvailableListener> listener)110 static void SurfaceTexture_setFrameAvailableListener(JNIEnv* env,
111         jobject thiz, sp<SurfaceTexture::FrameAvailableListener> listener)
112 {
113     SurfaceTexture::FrameAvailableListener* const p =
114         (SurfaceTexture::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 
SurfaceTexture_getSurfaceTexture(JNIEnv * env,jobject thiz)125 sp<SurfaceTexture> SurfaceTexture_getSurfaceTexture(JNIEnv* env, jobject thiz) {
126     return (SurfaceTexture*)env->GetLongField(thiz, fields.surfaceTexture);
127 }
128 
SurfaceTexture_getProducer(JNIEnv * env,jobject thiz)129 sp<IGraphicBufferProducer> SurfaceTexture_getProducer(JNIEnv* env, jobject thiz) {
130     return (IGraphicBufferProducer*)env->GetLongField(thiz, fields.producer);
131 }
132 
android_SurfaceTexture_isInstanceOf(JNIEnv * env,jobject thiz)133 bool android_SurfaceTexture_isInstanceOf(JNIEnv* env, jobject thiz) {
134     jclass surfaceTextureClass = env->FindClass(kSurfaceTextureClassPathName);
135     return env->IsInstanceOf(thiz, surfaceTextureClass);
136 }
137 
138 // ----------------------------------------------------------------------------
139 
140 class JNISurfaceTextureContextCommon {
141 public:
JNISurfaceTextureContextCommon(JNIEnv * env,jobject weakThiz,jclass clazz)142     JNISurfaceTextureContextCommon(JNIEnv* env, jobject weakThiz, jclass clazz)
143           : mWeakThiz(env->NewGlobalRef(weakThiz)), mClazz((jclass)env->NewGlobalRef(clazz)) {}
144 
~JNISurfaceTextureContextCommon()145     virtual ~JNISurfaceTextureContextCommon() {
146         JNIEnv* env = getJNIEnv();
147         if (env != NULL) {
148             env->DeleteGlobalRef(mWeakThiz);
149             env->DeleteGlobalRef(mClazz);
150         } else {
151             ALOGW("leaking JNI object references");
152         }
153     }
154 
onFrameAvailable(const BufferItem & item)155     void onFrameAvailable(const BufferItem& item) {
156         JNIEnv* env = getJNIEnv();
157         if (env != NULL) {
158             env->CallStaticVoidMethod(mClazz, fields.postEvent, mWeakThiz);
159         } else {
160             ALOGW("onFrameAvailable event will not posted");
161         }
162     }
163 
164 protected:
getJNIEnv()165     static JNIEnv* getJNIEnv() {
166         JNIEnv* env = AndroidRuntime::getJNIEnv();
167         if (env == NULL) {
168             JavaVMAttachArgs args = {JNI_VERSION_1_4, "JNISurfaceTextureContext", NULL};
169             JavaVM* vm = AndroidRuntime::getJavaVM();
170             int result = vm->AttachCurrentThreadAsDaemon(&env, (void*)&args);
171             if (result != JNI_OK) {
172                 ALOGE("thread attach failed: %#x", result);
173                 return NULL;
174             }
175         }
176         return env;
177     }
178 
179     jobject mWeakThiz;
180     jclass mClazz;
181 };
182 
183 class JNISurfaceTextureContextFrameAvailableListener
184       : public JNISurfaceTextureContextCommon,
185         public SurfaceTexture::FrameAvailableListener {
186 public:
JNISurfaceTextureContextFrameAvailableListener(JNIEnv * env,jobject weakThiz,jclass clazz)187     JNISurfaceTextureContextFrameAvailableListener(JNIEnv* env, jobject weakThiz, jclass clazz)
188           : JNISurfaceTextureContextCommon(env, weakThiz, clazz) {}
onFrameAvailable(const BufferItem & item)189     void onFrameAvailable(const BufferItem& item) override {
190         JNISurfaceTextureContextCommon::onFrameAvailable(item);
191     }
192 };
193 
194 class JNISurfaceTextureContextListener : public JNISurfaceTextureContextCommon,
195                                          public SurfaceTexture::SurfaceTextureListener {
196 public:
JNISurfaceTextureContextListener(JNIEnv * env,jobject weakThiz,jclass clazz)197     JNISurfaceTextureContextListener(JNIEnv* env, jobject weakThiz, jclass clazz)
198           : JNISurfaceTextureContextCommon(env, weakThiz, clazz) {}
199 
onFrameAvailable(const BufferItem & item)200     void onFrameAvailable(const BufferItem& item) override {
201         JNISurfaceTextureContextCommon::onFrameAvailable(item);
202     }
203 
onSetFrameRate(float frameRate,int8_t compatibility,int8_t changeFrameRateStrategy)204     void onSetFrameRate(float frameRate, int8_t compatibility,
205                         int8_t changeFrameRateStrategy) override {
206         JNIEnv* env = getJNIEnv();
207         if (env != NULL) {
208             env->CallStaticVoidMethod(mClazz, fields.postOnSetFrameRateEvent, mWeakThiz, frameRate,
209                                       compatibility, changeFrameRateStrategy);
210         } else {
211             ALOGW("onSetFrameRate event will not posted");
212         }
213     }
214 };
215 
216 // ----------------------------------------------------------------------------
217 
218 
219 #define ANDROID_GRAPHICS_SURFACETEXTURE_JNI_ID "mSurfaceTexture"
220 #define ANDROID_GRAPHICS_PRODUCER_JNI_ID "mProducer"
221 #define ANDROID_GRAPHICS_FRAMEAVAILABLELISTENER_JNI_ID \
222                                          "mFrameAvailableListener"
223 
SurfaceTexture_classInit(JNIEnv * env,jclass clazz)224 static void SurfaceTexture_classInit(JNIEnv* env, jclass clazz)
225 {
226     fields.surfaceTexture = env->GetFieldID(clazz,
227             ANDROID_GRAPHICS_SURFACETEXTURE_JNI_ID, "J");
228     if (fields.surfaceTexture == NULL) {
229         ALOGE("can't find android/graphics/SurfaceTexture.%s",
230                 ANDROID_GRAPHICS_SURFACETEXTURE_JNI_ID);
231     }
232     fields.producer = env->GetFieldID(clazz,
233             ANDROID_GRAPHICS_PRODUCER_JNI_ID, "J");
234     if (fields.producer == NULL) {
235         ALOGE("can't find android/graphics/SurfaceTexture.%s",
236                 ANDROID_GRAPHICS_PRODUCER_JNI_ID);
237     }
238     fields.frameAvailableListener = env->GetFieldID(clazz,
239             ANDROID_GRAPHICS_FRAMEAVAILABLELISTENER_JNI_ID, "J");
240     if (fields.frameAvailableListener == NULL) {
241         ALOGE("can't find android/graphics/SurfaceTexture.%s",
242                 ANDROID_GRAPHICS_FRAMEAVAILABLELISTENER_JNI_ID);
243     }
244 
245     fields.postEvent = env->GetStaticMethodID(clazz, "postEventFromNative",
246             "(Ljava/lang/ref/WeakReference;)V");
247     if (fields.postEvent == NULL) {
248         ALOGE("can't find android/graphics/SurfaceTexture.postEventFromNative");
249     }
250 
251     fields.postOnSetFrameRateEvent =
252             env->GetStaticMethodID(clazz, "postOnSetFrameRateEventFromNative",
253                                    "(Ljava/lang/ref/WeakReference;FII)V");
254     if (fields.postOnSetFrameRateEvent == NULL) {
255         ALOGE("can't find android/graphics/SurfaceTexture.postOnSetFrameRateEventFromNative");
256     }
257 }
258 
SurfaceTexture_init(JNIEnv * env,jobject thiz,jboolean isDetached,jint texName,jboolean singleBufferMode,jobject weakThiz)259 static void SurfaceTexture_init(JNIEnv* env, jobject thiz, jboolean isDetached, jint texName,
260                                 jboolean singleBufferMode, jobject weakThiz) {
261 #if COM_ANDROID_GRAPHICS_LIBGUI_FLAGS(WB_CONSUMER_BASE_OWNS_BQ)
262     sp<SurfaceTexture> surfaceTexture;
263     if (isDetached) {
264         surfaceTexture = new SurfaceTexture(GL_TEXTURE_EXTERNAL_OES, true, !singleBufferMode);
265     } else {
266         surfaceTexture =
267                 new SurfaceTexture(texName, GL_TEXTURE_EXTERNAL_OES, true, !singleBufferMode);
268     }
269 
270     if (singleBufferMode) {
271         surfaceTexture->setMaxBufferCount(1);
272     }
273 #else
274     sp<IGraphicBufferProducer> producer;
275     sp<IGraphicBufferConsumer> consumer;
276     BufferQueue::createBufferQueue(&producer, &consumer);
277 
278     if (singleBufferMode) {
279         consumer->setMaxBufferCount(1);
280     }
281 
282     sp<SurfaceTexture> surfaceTexture;
283     if (isDetached) {
284         surfaceTexture = new SurfaceTexture(consumer, GL_TEXTURE_EXTERNAL_OES,
285                 true, !singleBufferMode);
286     } else {
287         surfaceTexture = new SurfaceTexture(consumer, texName,
288                 GL_TEXTURE_EXTERNAL_OES, true, !singleBufferMode);
289     }
290 #endif // COM_ANDROID_GRAPHICS_LIBGUI_FLAGS(WB_CONSUMER_BASE_OWNS_BQ)
291 
292     if (surfaceTexture == 0) {
293         jniThrowException(env, OutOfResourcesException,
294                 "Unable to create native SurfaceTexture");
295         return;
296     }
297     surfaceTexture->setName(String8::format("SurfaceTexture-%d-%d-%d",
298             (isDetached ? 0 : texName),
299             getpid(),
300             createProcessUniqueId()));
301 
302     // If the current context is protected, inform the producer.
303 #if COM_ANDROID_GRAPHICS_LIBGUI_FLAGS(WB_CONSUMER_BASE_OWNS_BQ)
304     surfaceTexture->setConsumerIsProtected(isProtectedContext());
305 
306     SurfaceTexture_setSurfaceTexture(env, thiz, surfaceTexture);
307     sp<Surface> surface = surfaceTexture->getSurface();
308     if (nullptr == surface) {
309         jniThrowException(env, IllegalStateException, "Unable to get surface from SurfaceTexture");
310         return;
311     }
312     sp<IGraphicBufferProducer> igbp = surface->getIGraphicBufferProducer();
313     if (nullptr == igbp) {
314         jniThrowException(env, IllegalStateException, "Unable to get IGBP from Surface");
315         return;
316     }
317     SurfaceTexture_setProducer(env, thiz, igbp);
318 #else
319     consumer->setConsumerIsProtected(isProtectedContext());
320 
321     SurfaceTexture_setSurfaceTexture(env, thiz, surfaceTexture);
322     SurfaceTexture_setProducer(env, thiz, producer);
323 #endif // COM_ANDROID_GRAPHICS_LIBGUI_FLAGS(WB_CONSUMER_BASE_OWNS_BQ)
324     jclass clazz = env->GetObjectClass(thiz);
325     if (clazz == NULL) {
326         jniThrowRuntimeException(env,
327                 "Can't find android/graphics/SurfaceTexture");
328         return;
329     }
330 
331     if (com::android::graphics::libgui::flags::bq_setframerate()) {
332         sp<JNISurfaceTextureContextListener> ctx(
333                 new JNISurfaceTextureContextListener(env, weakThiz, clazz));
334         surfaceTexture->setSurfaceTextureListener(ctx);
335     } else {
336         sp<JNISurfaceTextureContextFrameAvailableListener> ctx(
337                 new JNISurfaceTextureContextFrameAvailableListener(env, weakThiz, clazz));
338         surfaceTexture->setFrameAvailableListener(ctx);
339         SurfaceTexture_setFrameAvailableListener(env, thiz, ctx);
340     }
341 }
342 
SurfaceTexture_finalize(JNIEnv * env,jobject thiz)343 static void SurfaceTexture_finalize(JNIEnv* env, jobject thiz)
344 {
345     sp<SurfaceTexture> surfaceTexture(SurfaceTexture_getSurfaceTexture(env, thiz));
346     if (com::android::graphics::libgui::flags::bq_setframerate()) {
347         surfaceTexture->setSurfaceTextureListener(0);
348     } else {
349         surfaceTexture->setFrameAvailableListener(0);
350         SurfaceTexture_setFrameAvailableListener(env, thiz, 0);
351     }
352     SurfaceTexture_setSurfaceTexture(env, thiz, 0);
353     SurfaceTexture_setProducer(env, thiz, 0);
354 }
355 
SurfaceTexture_setDefaultBufferSize(JNIEnv * env,jobject thiz,jint width,jint height)356 static void SurfaceTexture_setDefaultBufferSize(
357         JNIEnv* env, jobject thiz, jint width, jint height) {
358     sp<SurfaceTexture> surfaceTexture(SurfaceTexture_getSurfaceTexture(env, thiz));
359     surfaceTexture->setDefaultBufferSize(width, height);
360 }
361 
SurfaceTexture_updateTexImage(JNIEnv * env,jobject thiz)362 static void SurfaceTexture_updateTexImage(JNIEnv* env, jobject thiz)
363 {
364     sp<SurfaceTexture> surfaceTexture(SurfaceTexture_getSurfaceTexture(env, thiz));
365     status_t err = surfaceTexture->updateTexImage();
366     if (err == INVALID_OPERATION) {
367         jniThrowException(env, IllegalStateException, "Unable to update texture contents (see "
368                 "logcat for details)");
369     } else if (err < 0) {
370         jniThrowRuntimeException(env, "Error during updateTexImage (see logcat for details)");
371     }
372 }
373 
SurfaceTexture_releaseTexImage(JNIEnv * env,jobject thiz)374 static void SurfaceTexture_releaseTexImage(JNIEnv* env, jobject thiz)
375 {
376     sp<SurfaceTexture> surfaceTexture(SurfaceTexture_getSurfaceTexture(env, thiz));
377     status_t err = surfaceTexture->releaseTexImage();
378     if (err == INVALID_OPERATION) {
379         jniThrowException(env, IllegalStateException, "Unable to release texture contents (see "
380                 "logcat for details)");
381     } else if (err < 0) {
382         jniThrowRuntimeException(env, "Error during updateTexImage (see logcat for details)");
383     }
384 }
385 
SurfaceTexture_detachFromGLContext(JNIEnv * env,jobject thiz)386 static jint SurfaceTexture_detachFromGLContext(JNIEnv* env, jobject thiz)
387 {
388     sp<SurfaceTexture> surfaceTexture(SurfaceTexture_getSurfaceTexture(env, thiz));
389     return surfaceTexture->detachFromContext();
390 }
391 
SurfaceTexture_attachToGLContext(JNIEnv * env,jobject thiz,jint tex)392 static jint SurfaceTexture_attachToGLContext(JNIEnv* env, jobject thiz, jint tex)
393 {
394     sp<SurfaceTexture> surfaceTexture(SurfaceTexture_getSurfaceTexture(env, thiz));
395     return surfaceTexture->attachToContext((GLuint)tex);
396 }
397 
SurfaceTexture_getTransformMatrix(JNIEnv * env,jobject thiz,jfloatArray jmtx)398 static void SurfaceTexture_getTransformMatrix(JNIEnv* env, jobject thiz,
399         jfloatArray jmtx)
400 {
401     sp<SurfaceTexture> surfaceTexture(SurfaceTexture_getSurfaceTexture(env, thiz));
402     float* mtx = env->GetFloatArrayElements(jmtx, NULL);
403     surfaceTexture->getTransformMatrix(mtx);
404     env->ReleaseFloatArrayElements(jmtx, mtx, 0);
405 }
406 
SurfaceTexture_getTimestamp(JNIEnv * env,jobject thiz)407 static jlong SurfaceTexture_getTimestamp(JNIEnv* env, jobject thiz)
408 {
409     sp<SurfaceTexture> surfaceTexture(SurfaceTexture_getSurfaceTexture(env, thiz));
410     return surfaceTexture->getTimestamp();
411 }
412 
SurfaceTexture_getDataSpace(JNIEnv * env,jobject thiz)413 static jint SurfaceTexture_getDataSpace(JNIEnv* env, jobject thiz) {
414     sp<SurfaceTexture> surfaceTexture(SurfaceTexture_getSurfaceTexture(env, thiz));
415     return surfaceTexture->getCurrentDataSpace();
416 }
417 
SurfaceTexture_release(JNIEnv * env,jobject thiz)418 static void SurfaceTexture_release(JNIEnv* env, jobject thiz)
419 {
420     sp<SurfaceTexture> surfaceTexture(SurfaceTexture_getSurfaceTexture(env, thiz));
421     surfaceTexture->abandon();
422 }
423 
SurfaceTexture_isReleased(JNIEnv * env,jobject thiz)424 static jboolean SurfaceTexture_isReleased(JNIEnv* env, jobject thiz)
425 {
426     sp<SurfaceTexture> surfaceTexture(SurfaceTexture_getSurfaceTexture(env, thiz));
427     return surfaceTexture->isAbandoned();
428 }
429 
430 // ----------------------------------------------------------------------------
431 
432 static const JNINativeMethod gSurfaceTextureMethods[] = {
433         {"nativeInit", "(ZIZLjava/lang/ref/WeakReference;)V", (void*)SurfaceTexture_init},
434         {"nativeFinalize", "()V", (void*)SurfaceTexture_finalize},
435         {"nativeSetDefaultBufferSize", "(II)V", (void*)SurfaceTexture_setDefaultBufferSize},
436         {"nativeUpdateTexImage", "()V", (void*)SurfaceTexture_updateTexImage},
437         {"nativeReleaseTexImage", "()V", (void*)SurfaceTexture_releaseTexImage},
438         {"nativeDetachFromGLContext", "()I", (void*)SurfaceTexture_detachFromGLContext},
439         {"nativeAttachToGLContext", "(I)I", (void*)SurfaceTexture_attachToGLContext},
440         {"nativeGetTransformMatrix", "([F)V", (void*)SurfaceTexture_getTransformMatrix},
441         {"nativeGetTimestamp", "()J", (void*)SurfaceTexture_getTimestamp},
442         {"nativeGetDataSpace", "()I", (void*)SurfaceTexture_getDataSpace},
443         {"nativeRelease", "()V", (void*)SurfaceTexture_release},
444         {"nativeIsReleased", "()Z", (void*)SurfaceTexture_isReleased},
445 };
446 
register_android_graphics_SurfaceTexture(JNIEnv * env)447 int register_android_graphics_SurfaceTexture(JNIEnv* env)
448 {
449     // Cache some fields.
450     ScopedLocalRef<jclass> klass(env, FindClassOrDie(env, kSurfaceTextureClassPathName));
451     SurfaceTexture_classInit(env, klass.get());
452 
453     return RegisterMethodsOrDie(env, kSurfaceTextureClassPathName, gSurfaceTextureMethods,
454                                 NELEM(gSurfaceTextureMethods));
455 }
456 
457 } // namespace android
458 
459 //TODO: Move this file to frameworks/base/core/jni/android_graphics_SurfaceTexture.cpp. See
460 //TODO: android_view_Surface.cpp for example.
461