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