michael@0: /* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ michael@0: // vim:set ts=2 sts=2 sw=2 et cin: michael@0: /* This Source Code Form is subject to the terms of the Mozilla Public michael@0: * License, v. 2.0. If a copy of the MPL was not distributed with this michael@0: * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ michael@0: michael@0: #ifdef MOZ_WIDGET_ANDROID michael@0: michael@0: #include michael@0: #include michael@0: #include michael@0: #include "nsSurfaceTexture.h" michael@0: #include "AndroidBridge.h" michael@0: #include "nsThreadUtils.h" michael@0: #include "mozilla/gfx/Matrix.h" michael@0: michael@0: using namespace mozilla; michael@0: michael@0: // UGH michael@0: static std::map sInstances; michael@0: static int sNextID = 0; michael@0: michael@0: static class JNIFunctions { michael@0: public: michael@0: michael@0: JNIFunctions() : mInitialized(false) michael@0: { michael@0: } michael@0: michael@0: bool EnsureInitialized() michael@0: { michael@0: if (mInitialized) michael@0: return true; michael@0: michael@0: JNIEnv* env = GetJNIForThread(); michael@0: michael@0: AutoLocalJNIFrame jniFrame(env); michael@0: michael@0: jSurfaceTextureClass = (jclass)env->NewGlobalRef(env->FindClass("android/graphics/SurfaceTexture")); michael@0: jSurfaceTexture_Ctor = env->GetMethodID(jSurfaceTextureClass, "", "(I)V"); michael@0: jSurfaceTexture_updateTexImage = env->GetMethodID(jSurfaceTextureClass, "updateTexImage", "()V"); michael@0: jSurfaceTexture_getTransformMatrix = env->GetMethodID(jSurfaceTextureClass, "getTransformMatrix", "([F)V"); michael@0: michael@0: mInitialized = true; michael@0: return true; michael@0: } michael@0: michael@0: jobject CreateSurfaceTexture(GLuint aTexture) michael@0: { michael@0: if (!EnsureInitialized()) michael@0: return nullptr; michael@0: michael@0: JNIEnv* env = GetJNIForThread(); michael@0: michael@0: AutoLocalJNIFrame jniFrame(env); michael@0: michael@0: return env->NewGlobalRef(env->NewObject(jSurfaceTextureClass, jSurfaceTexture_Ctor, (int) aTexture)); michael@0: } michael@0: michael@0: void ReleaseSurfaceTexture(jobject aSurfaceTexture) michael@0: { michael@0: JNIEnv* env = GetJNIForThread(); michael@0: michael@0: env->DeleteGlobalRef(aSurfaceTexture); michael@0: } michael@0: michael@0: void UpdateTexImage(jobject aSurfaceTexture) michael@0: { michael@0: JNIEnv* env = GetJNIForThread(); michael@0: michael@0: AutoLocalJNIFrame jniFrame(env); michael@0: env->CallVoidMethod(aSurfaceTexture, jSurfaceTexture_updateTexImage); michael@0: } michael@0: michael@0: bool GetTransformMatrix(jobject aSurfaceTexture, gfx::Matrix4x4& aMatrix) michael@0: { michael@0: JNIEnv* env = GetJNIForThread(); michael@0: michael@0: AutoLocalJNIFrame jniFrame(env); michael@0: michael@0: jfloatArray jarray = env->NewFloatArray(16); michael@0: env->CallVoidMethod(aSurfaceTexture, jSurfaceTexture_getTransformMatrix, jarray); michael@0: michael@0: jfloat* array = env->GetFloatArrayElements(jarray, nullptr); michael@0: michael@0: aMatrix._11 = array[0]; michael@0: aMatrix._12 = array[1]; michael@0: aMatrix._13 = array[2]; michael@0: aMatrix._14 = array[3]; michael@0: michael@0: aMatrix._21 = array[4]; michael@0: aMatrix._22 = array[5]; michael@0: aMatrix._23 = array[6]; michael@0: aMatrix._24 = array[7]; michael@0: michael@0: aMatrix._31 = array[8]; michael@0: aMatrix._32 = array[9]; michael@0: aMatrix._33 = array[10]; michael@0: aMatrix._34 = array[11]; michael@0: michael@0: aMatrix._41 = array[12]; michael@0: aMatrix._42 = array[13]; michael@0: aMatrix._43 = array[14]; michael@0: aMatrix._44 = array[15]; michael@0: michael@0: env->ReleaseFloatArrayElements(jarray, array, 0); michael@0: michael@0: return false; michael@0: } michael@0: michael@0: private: michael@0: bool mInitialized; michael@0: michael@0: jclass jSurfaceTextureClass; michael@0: jmethodID jSurfaceTexture_Ctor; michael@0: jmethodID jSurfaceTexture_updateTexImage; michael@0: jmethodID jSurfaceTexture_getTransformMatrix; michael@0: michael@0: } sJNIFunctions; michael@0: michael@0: nsSurfaceTexture* michael@0: nsSurfaceTexture::Create(GLuint aTexture) michael@0: { michael@0: // Right now we only support creating this on the main thread because michael@0: // of the JNIEnv assumptions in JNIHelper and elsewhere michael@0: if (!NS_IsMainThread()) michael@0: return nullptr; michael@0: michael@0: nsSurfaceTexture* st = new nsSurfaceTexture(); michael@0: if (!st->Init(aTexture)) { michael@0: printf_stderr("Failed to initialize nsSurfaceTexture"); michael@0: delete st; michael@0: st = nullptr; michael@0: } michael@0: michael@0: return st; michael@0: } michael@0: michael@0: nsSurfaceTexture* michael@0: nsSurfaceTexture::Find(int id) michael@0: { michael@0: std::map::iterator it; michael@0: michael@0: it = sInstances.find(id); michael@0: if (it == sInstances.end()) michael@0: return nullptr; michael@0: michael@0: return it->second; michael@0: } michael@0: michael@0: bool michael@0: nsSurfaceTexture::Check() michael@0: { michael@0: return sJNIFunctions.EnsureInitialized(); michael@0: } michael@0: michael@0: bool michael@0: nsSurfaceTexture::Init(GLuint aTexture) michael@0: { michael@0: if (!sJNIFunctions.EnsureInitialized()) michael@0: return false; michael@0: michael@0: JNIEnv* env = GetJNIForThread(); michael@0: michael@0: mSurfaceTexture = sJNIFunctions.CreateSurfaceTexture(aTexture); michael@0: if (!mSurfaceTexture) michael@0: return false; michael@0: michael@0: mNativeWindow = AndroidBridge::Bridge()->AcquireNativeWindowFromSurfaceTexture(env, mSurfaceTexture); michael@0: michael@0: mID = ++sNextID; michael@0: sInstances.insert(std::pair(mID, this)); michael@0: michael@0: return true; michael@0: } michael@0: michael@0: nsSurfaceTexture::nsSurfaceTexture() michael@0: : mSurfaceTexture(nullptr), mNativeWindow(nullptr) michael@0: { michael@0: } michael@0: michael@0: nsSurfaceTexture::~nsSurfaceTexture() michael@0: { michael@0: sInstances.erase(mID); michael@0: michael@0: mFrameAvailableCallback = nullptr; michael@0: michael@0: if (mNativeWindow) { michael@0: AndroidBridge::Bridge()->ReleaseNativeWindowForSurfaceTexture(mSurfaceTexture); michael@0: mNativeWindow = nullptr; michael@0: } michael@0: michael@0: JNIEnv* env = GetJNIForThread(); michael@0: michael@0: if (mSurfaceTexture) { michael@0: mozilla::widget::android::GeckoAppShell::UnregisterSurfaceTextureFrameListener(mSurfaceTexture); michael@0: michael@0: env->DeleteGlobalRef(mSurfaceTexture); michael@0: mSurfaceTexture = nullptr; michael@0: } michael@0: } michael@0: michael@0: void* michael@0: nsSurfaceTexture::GetNativeWindow() michael@0: { michael@0: return mNativeWindow; michael@0: } michael@0: michael@0: void michael@0: nsSurfaceTexture::UpdateTexImage() michael@0: { michael@0: sJNIFunctions.UpdateTexImage(mSurfaceTexture); michael@0: } michael@0: michael@0: bool michael@0: nsSurfaceTexture::GetTransformMatrix(gfx::Matrix4x4& aMatrix) michael@0: { michael@0: return sJNIFunctions.GetTransformMatrix(mSurfaceTexture, aMatrix); michael@0: } michael@0: michael@0: void michael@0: nsSurfaceTexture::SetFrameAvailableCallback(nsIRunnable* aRunnable) michael@0: { michael@0: if (aRunnable) michael@0: mozilla::widget::android::GeckoAppShell::RegisterSurfaceTextureFrameListener(mSurfaceTexture, mID); michael@0: else michael@0: mozilla::widget::android::GeckoAppShell::UnregisterSurfaceTextureFrameListener(mSurfaceTexture); michael@0: michael@0: mFrameAvailableCallback = aRunnable; michael@0: } michael@0: michael@0: void michael@0: nsSurfaceTexture::NotifyFrameAvailable() michael@0: { michael@0: if (mFrameAvailableCallback) { michael@0: // Proxy to main thread if we aren't on it michael@0: if (!NS_IsMainThread()) { michael@0: // Proxy to main thread michael@0: nsCOMPtr event = NS_NewRunnableMethod(this, &nsSurfaceTexture::NotifyFrameAvailable); michael@0: NS_DispatchToCurrentThread(event); michael@0: } else { michael@0: mFrameAvailableCallback->Run(); michael@0: } michael@0: } michael@0: } michael@0: michael@0: #endif // MOZ_WIDGET_ANDROID