|
1 /* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ |
|
2 // vim:set ts=2 sts=2 sw=2 et cin: |
|
3 /* This Source Code Form is subject to the terms of the Mozilla Public |
|
4 * License, v. 2.0. If a copy of the MPL was not distributed with this |
|
5 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ |
|
6 |
|
7 #ifdef MOZ_WIDGET_ANDROID |
|
8 |
|
9 #include <set> |
|
10 #include <map> |
|
11 #include <android/log.h> |
|
12 #include "nsSurfaceTexture.h" |
|
13 #include "AndroidBridge.h" |
|
14 #include "nsThreadUtils.h" |
|
15 #include "mozilla/gfx/Matrix.h" |
|
16 |
|
17 using namespace mozilla; |
|
18 |
|
19 // UGH |
|
20 static std::map<int, nsSurfaceTexture*> sInstances; |
|
21 static int sNextID = 0; |
|
22 |
|
23 static class JNIFunctions { |
|
24 public: |
|
25 |
|
26 JNIFunctions() : mInitialized(false) |
|
27 { |
|
28 } |
|
29 |
|
30 bool EnsureInitialized() |
|
31 { |
|
32 if (mInitialized) |
|
33 return true; |
|
34 |
|
35 JNIEnv* env = GetJNIForThread(); |
|
36 |
|
37 AutoLocalJNIFrame jniFrame(env); |
|
38 |
|
39 jSurfaceTextureClass = (jclass)env->NewGlobalRef(env->FindClass("android/graphics/SurfaceTexture")); |
|
40 jSurfaceTexture_Ctor = env->GetMethodID(jSurfaceTextureClass, "<init>", "(I)V"); |
|
41 jSurfaceTexture_updateTexImage = env->GetMethodID(jSurfaceTextureClass, "updateTexImage", "()V"); |
|
42 jSurfaceTexture_getTransformMatrix = env->GetMethodID(jSurfaceTextureClass, "getTransformMatrix", "([F)V"); |
|
43 |
|
44 mInitialized = true; |
|
45 return true; |
|
46 } |
|
47 |
|
48 jobject CreateSurfaceTexture(GLuint aTexture) |
|
49 { |
|
50 if (!EnsureInitialized()) |
|
51 return nullptr; |
|
52 |
|
53 JNIEnv* env = GetJNIForThread(); |
|
54 |
|
55 AutoLocalJNIFrame jniFrame(env); |
|
56 |
|
57 return env->NewGlobalRef(env->NewObject(jSurfaceTextureClass, jSurfaceTexture_Ctor, (int) aTexture)); |
|
58 } |
|
59 |
|
60 void ReleaseSurfaceTexture(jobject aSurfaceTexture) |
|
61 { |
|
62 JNIEnv* env = GetJNIForThread(); |
|
63 |
|
64 env->DeleteGlobalRef(aSurfaceTexture); |
|
65 } |
|
66 |
|
67 void UpdateTexImage(jobject aSurfaceTexture) |
|
68 { |
|
69 JNIEnv* env = GetJNIForThread(); |
|
70 |
|
71 AutoLocalJNIFrame jniFrame(env); |
|
72 env->CallVoidMethod(aSurfaceTexture, jSurfaceTexture_updateTexImage); |
|
73 } |
|
74 |
|
75 bool GetTransformMatrix(jobject aSurfaceTexture, gfx::Matrix4x4& aMatrix) |
|
76 { |
|
77 JNIEnv* env = GetJNIForThread(); |
|
78 |
|
79 AutoLocalJNIFrame jniFrame(env); |
|
80 |
|
81 jfloatArray jarray = env->NewFloatArray(16); |
|
82 env->CallVoidMethod(aSurfaceTexture, jSurfaceTexture_getTransformMatrix, jarray); |
|
83 |
|
84 jfloat* array = env->GetFloatArrayElements(jarray, nullptr); |
|
85 |
|
86 aMatrix._11 = array[0]; |
|
87 aMatrix._12 = array[1]; |
|
88 aMatrix._13 = array[2]; |
|
89 aMatrix._14 = array[3]; |
|
90 |
|
91 aMatrix._21 = array[4]; |
|
92 aMatrix._22 = array[5]; |
|
93 aMatrix._23 = array[6]; |
|
94 aMatrix._24 = array[7]; |
|
95 |
|
96 aMatrix._31 = array[8]; |
|
97 aMatrix._32 = array[9]; |
|
98 aMatrix._33 = array[10]; |
|
99 aMatrix._34 = array[11]; |
|
100 |
|
101 aMatrix._41 = array[12]; |
|
102 aMatrix._42 = array[13]; |
|
103 aMatrix._43 = array[14]; |
|
104 aMatrix._44 = array[15]; |
|
105 |
|
106 env->ReleaseFloatArrayElements(jarray, array, 0); |
|
107 |
|
108 return false; |
|
109 } |
|
110 |
|
111 private: |
|
112 bool mInitialized; |
|
113 |
|
114 jclass jSurfaceTextureClass; |
|
115 jmethodID jSurfaceTexture_Ctor; |
|
116 jmethodID jSurfaceTexture_updateTexImage; |
|
117 jmethodID jSurfaceTexture_getTransformMatrix; |
|
118 |
|
119 } sJNIFunctions; |
|
120 |
|
121 nsSurfaceTexture* |
|
122 nsSurfaceTexture::Create(GLuint aTexture) |
|
123 { |
|
124 // Right now we only support creating this on the main thread because |
|
125 // of the JNIEnv assumptions in JNIHelper and elsewhere |
|
126 if (!NS_IsMainThread()) |
|
127 return nullptr; |
|
128 |
|
129 nsSurfaceTexture* st = new nsSurfaceTexture(); |
|
130 if (!st->Init(aTexture)) { |
|
131 printf_stderr("Failed to initialize nsSurfaceTexture"); |
|
132 delete st; |
|
133 st = nullptr; |
|
134 } |
|
135 |
|
136 return st; |
|
137 } |
|
138 |
|
139 nsSurfaceTexture* |
|
140 nsSurfaceTexture::Find(int id) |
|
141 { |
|
142 std::map<int, nsSurfaceTexture*>::iterator it; |
|
143 |
|
144 it = sInstances.find(id); |
|
145 if (it == sInstances.end()) |
|
146 return nullptr; |
|
147 |
|
148 return it->second; |
|
149 } |
|
150 |
|
151 bool |
|
152 nsSurfaceTexture::Check() |
|
153 { |
|
154 return sJNIFunctions.EnsureInitialized(); |
|
155 } |
|
156 |
|
157 bool |
|
158 nsSurfaceTexture::Init(GLuint aTexture) |
|
159 { |
|
160 if (!sJNIFunctions.EnsureInitialized()) |
|
161 return false; |
|
162 |
|
163 JNIEnv* env = GetJNIForThread(); |
|
164 |
|
165 mSurfaceTexture = sJNIFunctions.CreateSurfaceTexture(aTexture); |
|
166 if (!mSurfaceTexture) |
|
167 return false; |
|
168 |
|
169 mNativeWindow = AndroidBridge::Bridge()->AcquireNativeWindowFromSurfaceTexture(env, mSurfaceTexture); |
|
170 |
|
171 mID = ++sNextID; |
|
172 sInstances.insert(std::pair<int, nsSurfaceTexture*>(mID, this)); |
|
173 |
|
174 return true; |
|
175 } |
|
176 |
|
177 nsSurfaceTexture::nsSurfaceTexture() |
|
178 : mSurfaceTexture(nullptr), mNativeWindow(nullptr) |
|
179 { |
|
180 } |
|
181 |
|
182 nsSurfaceTexture::~nsSurfaceTexture() |
|
183 { |
|
184 sInstances.erase(mID); |
|
185 |
|
186 mFrameAvailableCallback = nullptr; |
|
187 |
|
188 if (mNativeWindow) { |
|
189 AndroidBridge::Bridge()->ReleaseNativeWindowForSurfaceTexture(mSurfaceTexture); |
|
190 mNativeWindow = nullptr; |
|
191 } |
|
192 |
|
193 JNIEnv* env = GetJNIForThread(); |
|
194 |
|
195 if (mSurfaceTexture) { |
|
196 mozilla::widget::android::GeckoAppShell::UnregisterSurfaceTextureFrameListener(mSurfaceTexture); |
|
197 |
|
198 env->DeleteGlobalRef(mSurfaceTexture); |
|
199 mSurfaceTexture = nullptr; |
|
200 } |
|
201 } |
|
202 |
|
203 void* |
|
204 nsSurfaceTexture::GetNativeWindow() |
|
205 { |
|
206 return mNativeWindow; |
|
207 } |
|
208 |
|
209 void |
|
210 nsSurfaceTexture::UpdateTexImage() |
|
211 { |
|
212 sJNIFunctions.UpdateTexImage(mSurfaceTexture); |
|
213 } |
|
214 |
|
215 bool |
|
216 nsSurfaceTexture::GetTransformMatrix(gfx::Matrix4x4& aMatrix) |
|
217 { |
|
218 return sJNIFunctions.GetTransformMatrix(mSurfaceTexture, aMatrix); |
|
219 } |
|
220 |
|
221 void |
|
222 nsSurfaceTexture::SetFrameAvailableCallback(nsIRunnable* aRunnable) |
|
223 { |
|
224 if (aRunnable) |
|
225 mozilla::widget::android::GeckoAppShell::RegisterSurfaceTextureFrameListener(mSurfaceTexture, mID); |
|
226 else |
|
227 mozilla::widget::android::GeckoAppShell::UnregisterSurfaceTextureFrameListener(mSurfaceTexture); |
|
228 |
|
229 mFrameAvailableCallback = aRunnable; |
|
230 } |
|
231 |
|
232 void |
|
233 nsSurfaceTexture::NotifyFrameAvailable() |
|
234 { |
|
235 if (mFrameAvailableCallback) { |
|
236 // Proxy to main thread if we aren't on it |
|
237 if (!NS_IsMainThread()) { |
|
238 // Proxy to main thread |
|
239 nsCOMPtr<nsIRunnable> event = NS_NewRunnableMethod(this, &nsSurfaceTexture::NotifyFrameAvailable); |
|
240 NS_DispatchToCurrentThread(event); |
|
241 } else { |
|
242 mFrameAvailableCallback->Run(); |
|
243 } |
|
244 } |
|
245 } |
|
246 |
|
247 #endif // MOZ_WIDGET_ANDROID |