OLD | NEW |
(Empty) | |
| 1 // Copyright (c) 2012 The Chromium Authors. All rights reserved. |
| 2 // Use of this source code is governed by a BSD-style license that can be |
| 3 // found in the LICENSE file. |
| 4 |
| 5 #include "content/common/android/surface_callback.h" |
| 6 |
| 7 #include <android/native_window_jni.h> |
| 8 |
| 9 #include "base/android/jni_android.h" |
| 10 #include "base/bind.h" |
| 11 #include "base/lazy_instance.h" |
| 12 #include "base/logging.h" |
| 13 #include "base/message_loop.h" |
| 14 #include "base/message_loop_proxy.h" |
| 15 #include "base/synchronization/lock.h" |
| 16 #include "base/synchronization/waitable_event.h" |
| 17 #include "ui/gl/android_native_window.h" |
| 18 #include "jni/surface_callback_jni.h" |
| 19 |
| 20 using base::android::AttachCurrentThread; |
| 21 using base::android::CheckException; |
| 22 using base::android::GetMethodID; |
| 23 using base::WaitableEvent; |
| 24 using content::SurfaceTexturePeer; |
| 25 |
| 26 namespace { |
| 27 |
| 28 struct GlobalState { |
| 29 base::Lock registration_lock; |
| 30 // We hold a reference to a message loop proxy which handles message loop |
| 31 // destruction gracefully, which is important since we post tasks from an |
| 32 // arbitrary binder thread while the main thread might be shutting down. |
| 33 // Also, in single-process mode we have two ChildThread objects for render |
| 34 // and gpu thread, so we need to store the msg loops separately. |
| 35 scoped_refptr<base::MessageLoopProxy> native_window_loop; |
| 36 scoped_refptr<base::MessageLoopProxy> video_surface_loop; |
| 37 content::NativeWindowCallback native_window_callback; |
| 38 content::VideoSurfaceCallback video_surface_callback; |
| 39 }; |
| 40 |
| 41 base::LazyInstance<GlobalState>::Leaky g_state = LAZY_INSTANCE_INITIALIZER; |
| 42 |
| 43 void RunNativeWindowCallback(int32 routing_id, |
| 44 int32 renderer_id, |
| 45 ANativeWindow* native_window, |
| 46 WaitableEvent* completion) { |
| 47 g_state.Pointer()->native_window_callback.Run( |
| 48 routing_id, renderer_id, native_window, completion); |
| 49 } |
| 50 |
| 51 void RunVideoSurfaceCallback(int32 routing_id, |
| 52 int32 renderer_id, |
| 53 jobject surface) { |
| 54 g_state.Pointer()->video_surface_callback.Run( |
| 55 routing_id, renderer_id, surface); |
| 56 } |
| 57 |
| 58 } // namespace <anonymous> |
| 59 |
| 60 static void SetSurface(JNIEnv* env, jclass clazz, |
| 61 jint type, |
| 62 jobject surface, |
| 63 jint primaryID, |
| 64 jint secondaryID) { |
| 65 SetSurfaceAsync(env, surface, |
| 66 static_cast<SurfaceTexturePeer::SurfaceTextureTarget>(type), |
| 67 primaryID, secondaryID, NULL); |
| 68 } |
| 69 |
| 70 |
| 71 namespace content { |
| 72 |
| 73 void ReleaseSurface(jobject surface) { |
| 74 if (surface == NULL) |
| 75 return; |
| 76 |
| 77 JNIEnv* env = AttachCurrentThread(); |
| 78 CHECK(env); |
| 79 |
| 80 jclass cls = env->FindClass("android/view/Surface"); |
| 81 DCHECK(cls); |
| 82 |
| 83 jmethodID method = env->GetMethodID(cls, "release", "()V"); |
| 84 DCHECK(method); |
| 85 |
| 86 env->CallVoidMethod(surface, method); |
| 87 DCHECK(env); |
| 88 |
| 89 env->DeleteLocalRef(cls); |
| 90 } |
| 91 |
| 92 void SetSurfaceAsync(JNIEnv* env, |
| 93 jobject jsurface, |
| 94 SurfaceTexturePeer::SurfaceTextureTarget type, |
| 95 int primary_id, |
| 96 int secondary_id, |
| 97 WaitableEvent* completion) { |
| 98 base::AutoLock lock(g_state.Pointer()->registration_lock); |
| 99 |
| 100 ANativeWindow* native_window = NULL; |
| 101 |
| 102 if (jsurface && |
| 103 type != SurfaceTexturePeer::SET_VIDEO_SURFACE_TEXTURE) { |
| 104 native_window = ANativeWindow_fromSurface(env, jsurface); |
| 105 ReleaseSurface(jsurface); |
| 106 } |
| 107 GlobalState* const global_state = g_state.Pointer(); |
| 108 |
| 109 switch (type) { |
| 110 case SurfaceTexturePeer::SET_GPU_SURFACE_TEXTURE: { |
| 111 // This should only be sent as a reaction to the renderer |
| 112 // activating compositing. If the GPU process crashes, we expect this |
| 113 // to be resent after the new thread is initialized. |
| 114 DCHECK(global_state->native_window_loop); |
| 115 global_state->native_window_loop->PostTask( |
| 116 FROM_HERE, |
| 117 base::Bind(&RunNativeWindowCallback, |
| 118 primary_id, |
| 119 static_cast<uint32_t>(secondary_id), |
| 120 native_window, |
| 121 completion)); |
| 122 // ANativeWindow_release will be called in SetNativeWindow() |
| 123 break; |
| 124 } |
| 125 case SurfaceTexturePeer::SET_VIDEO_SURFACE_TEXTURE: { |
| 126 jobject surface = env->NewGlobalRef(jsurface); |
| 127 DCHECK(global_state->video_surface_loop); |
| 128 global_state->video_surface_loop->PostTask( |
| 129 FROM_HERE, |
| 130 base::Bind(&RunVideoSurfaceCallback, |
| 131 primary_id, |
| 132 secondary_id, |
| 133 surface)); |
| 134 break; |
| 135 } |
| 136 } |
| 137 } |
| 138 |
| 139 void RegisterVideoSurfaceCallback(base::MessageLoopProxy* loop, |
| 140 VideoSurfaceCallback& callback) { |
| 141 GlobalState* const global_state = g_state.Pointer(); |
| 142 base::AutoLock lock(global_state->registration_lock); |
| 143 global_state->video_surface_loop = loop; |
| 144 global_state->video_surface_callback = callback; |
| 145 } |
| 146 |
| 147 void RegisterNativeWindowCallback(base::MessageLoopProxy* loop, |
| 148 NativeWindowCallback& callback) { |
| 149 GlobalState* const global_state = g_state.Pointer(); |
| 150 base::AutoLock lock(global_state->registration_lock); |
| 151 global_state->native_window_loop = loop; |
| 152 global_state->native_window_callback = callback; |
| 153 } |
| 154 |
| 155 bool RegisterSurfaceCallback(JNIEnv* env) { |
| 156 return RegisterNativesImpl(env); |
| 157 } |
| 158 |
| 159 } // namespace content |
OLD | NEW |