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.
createProcessUniqueId()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.
isProtectedContext()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
SurfaceTexture_setSurfaceTexture(JNIEnv * env,jobject thiz,const sp<GLConsumer> & surfaceTexture)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
SurfaceTexture_setProducer(JNIEnv * env,jobject thiz,const sp<IGraphicBufferProducer> & producer)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
SurfaceTexture_setFrameAvailableListener(JNIEnv * env,jobject thiz,sp<GLConsumer::FrameAvailableListener> listener)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
SurfaceTexture_getSurfaceTexture(JNIEnv * env,jobject thiz)122 sp<GLConsumer> SurfaceTexture_getSurfaceTexture(JNIEnv* env, jobject thiz) {
123 return (GLConsumer*)env->GetLongField(thiz, fields.surfaceTexture);
124 }
125
SurfaceTexture_getProducer(JNIEnv * env,jobject thiz)126 sp<IGraphicBufferProducer> SurfaceTexture_getProducer(JNIEnv* env, jobject thiz) {
127 return (IGraphicBufferProducer*)env->GetLongField(thiz, fields.producer);
128 }
129
android_SurfaceTexture_getNativeWindow(JNIEnv * env,jobject thiz)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
android_SurfaceTexture_isInstanceOf(JNIEnv * env,jobject thiz)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
JNISurfaceTextureContext(JNIEnv * env,jobject weakThiz,jclass clazz)159 JNISurfaceTextureContext::JNISurfaceTextureContext(JNIEnv* env,
160 jobject weakThiz, jclass clazz) :
161 mWeakThiz(env->NewGlobalRef(weakThiz)),
162 mClazz((jclass)env->NewGlobalRef(clazz))
163 {}
164
getJNIEnv(bool * needsDetach)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
detachJNI()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
~JNISurfaceTextureContext()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
onFrameAvailable(const BufferItem &)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
SurfaceTexture_classInit(JNIEnv * env,jclass clazz)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
SurfaceTexture_init(JNIEnv * env,jobject thiz,jboolean isDetached,jint texName,jboolean singleBufferMode,jobject weakThiz)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
SurfaceTexture_finalize(JNIEnv * env,jobject thiz)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
SurfaceTexture_setDefaultBufferSize(JNIEnv * env,jobject thiz,jint width,jint height)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
SurfaceTexture_updateTexImage(JNIEnv * env,jobject thiz)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
SurfaceTexture_releaseTexImage(JNIEnv * env,jobject thiz)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
SurfaceTexture_detachFromGLContext(JNIEnv * env,jobject thiz)345 static jint SurfaceTexture_detachFromGLContext(JNIEnv* env, jobject thiz)
346 {
347 sp<GLConsumer> surfaceTexture(SurfaceTexture_getSurfaceTexture(env, thiz));
348 return surfaceTexture->detachFromContext();
349 }
350
SurfaceTexture_attachToGLContext(JNIEnv * env,jobject thiz,jint tex)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
SurfaceTexture_getTransformMatrix(JNIEnv * env,jobject thiz,jfloatArray jmtx)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
SurfaceTexture_getTimestamp(JNIEnv * env,jobject thiz)366 static jlong SurfaceTexture_getTimestamp(JNIEnv* env, jobject thiz)
367 {
368 sp<GLConsumer> surfaceTexture(SurfaceTexture_getSurfaceTexture(env, thiz));
369 return surfaceTexture->getTimestamp();
370 }
371
SurfaceTexture_release(JNIEnv * env,jobject thiz)372 static void SurfaceTexture_release(JNIEnv* env, jobject thiz)
373 {
374 sp<GLConsumer> surfaceTexture(SurfaceTexture_getSurfaceTexture(env, thiz));
375 surfaceTexture->abandon();
376 }
377
SurfaceTexture_isReleased(JNIEnv * env,jobject thiz)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
register_android_graphics_SurfaceTexture(JNIEnv * env)401 int register_android_graphics_SurfaceTexture(JNIEnv* env)
402 {
403 return RegisterMethodsOrDie(env, kSurfaceTextureClassPathName, gSurfaceTextureMethods,
404 NELEM(gSurfaceTextureMethods));
405 }
406
407 } // namespace android
408