summaryrefslogtreecommitdiffstats
path: root/gfx/gl/AndroidSurfaceTexture.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'gfx/gl/AndroidSurfaceTexture.cpp')
-rw-r--r--gfx/gl/AndroidSurfaceTexture.cpp260
1 files changed, 260 insertions, 0 deletions
diff --git a/gfx/gl/AndroidSurfaceTexture.cpp b/gfx/gl/AndroidSurfaceTexture.cpp
new file mode 100644
index 000000000..3c8c81974
--- /dev/null
+++ b/gfx/gl/AndroidSurfaceTexture.cpp
@@ -0,0 +1,260 @@
+/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+// vim:set ts=2 sts=2 sw=2 et cin:
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+#ifdef MOZ_WIDGET_ANDROID
+
+#include <map>
+#include <android/native_window_jni.h>
+#include <android/log.h>
+#include "AndroidSurfaceTexture.h"
+#include "gfxImageSurface.h"
+#include "gfxPrefs.h"
+#include "AndroidBridge.h"
+#include "nsThreadUtils.h"
+#include "mozilla/gfx/Matrix.h"
+#include "GeneratedJNINatives.h"
+#include "GLContext.h"
+
+using namespace mozilla;
+
+namespace mozilla {
+namespace gl {
+
+class AndroidSurfaceTexture::Listener
+ : public java::SurfaceTextureListener::Natives<Listener>
+{
+ using Base = java::SurfaceTextureListener::Natives<Listener>;
+
+ const nsCOMPtr<nsIRunnable> mCallback;
+
+public:
+ using Base::AttachNative;
+ using Base::DisposeNative;
+
+ Listener(nsIRunnable* aCallback) : mCallback(aCallback) {}
+
+ void OnFrameAvailable()
+ {
+ if (NS_IsMainThread()) {
+ mCallback->Run();
+ return;
+ }
+ NS_DispatchToMainThread(mCallback);
+ }
+};
+
+already_AddRefed<AndroidSurfaceTexture>
+AndroidSurfaceTexture::Create()
+{
+ return Create(nullptr, 0);
+}
+
+already_AddRefed<AndroidSurfaceTexture>
+AndroidSurfaceTexture::Create(GLContext* aContext, GLuint aTexture)
+{
+ RefPtr<AndroidSurfaceTexture> st = new AndroidSurfaceTexture();
+ if (!st->Init(aContext, aTexture)) {
+ printf_stderr("Failed to initialize AndroidSurfaceTexture");
+ st = nullptr;
+ }
+
+ return st.forget();
+}
+
+nsresult
+AndroidSurfaceTexture::Attach(GLContext* aContext, PRIntervalTime aTimeout)
+{
+ MonitorAutoLock lock(mMonitor);
+
+ if (mAttachedContext == aContext) {
+ NS_WARNING("Tried to attach same GLContext to AndroidSurfaceTexture");
+ return NS_OK;
+ }
+
+ if (!CanDetach()) {
+ return NS_ERROR_NOT_AVAILABLE;
+ }
+
+ while (mAttachedContext) {
+ // Wait until it's detached (or we time out)
+ if (NS_FAILED(lock.Wait(aTimeout))) {
+ return NS_ERROR_NOT_AVAILABLE;
+ }
+ }
+
+ MOZ_ASSERT(aContext->IsOwningThreadCurrent(), "Trying to attach GLContext from different thread");
+
+ aContext->fGenTextures(1, &mTexture);
+
+ if (NS_FAILED(mSurfaceTexture->AttachToGLContext(mTexture))) {
+ return NS_ERROR_NOT_AVAILABLE;
+ }
+ mAttachedContext = aContext;
+ mAttachedContext->MakeCurrent();
+
+ return NS_OK;
+}
+
+nsresult
+AndroidSurfaceTexture::Detach()
+{
+ MonitorAutoLock lock(mMonitor);
+
+ if (!CanDetach() ||
+ !mAttachedContext ||
+ !mAttachedContext->IsOwningThreadCurrent())
+ {
+ return NS_ERROR_FAILURE;
+ }
+
+ mAttachedContext->MakeCurrent();
+
+ mSurfaceTexture->DetachFromGLContext();
+
+ mTexture = 0;
+ mAttachedContext = nullptr;
+ lock.NotifyAll();
+ return NS_OK;
+}
+
+bool
+AndroidSurfaceTexture::CanDetach() const
+{
+ // The API for attach/detach only exists on 16+, and PowerVR has some sort of
+ // fencing issue. Additionally, attach/detach seems to be busted on at least
+ // some Mali adapters (400MP2 for sure, bug 1131793)
+ return AndroidBridge::Bridge()->GetAPIVersion() >= 16 &&
+ (!mAttachedContext || mAttachedContext->Vendor() != GLVendor::Imagination) &&
+ (!mAttachedContext || mAttachedContext->Vendor() != GLVendor::ARM /* Mali */) &&
+ gfxPrefs::SurfaceTextureDetachEnabled();
+}
+
+bool
+AndroidSurfaceTexture::Init(GLContext* aContext, GLuint aTexture)
+{
+
+ if (!aTexture && !CanDetach()) {
+ // We have no texture and cannot initialize detached, bail out
+ return false;
+ }
+
+ if (NS_WARN_IF(NS_FAILED(
+ java::sdk::SurfaceTexture::New(aTexture, ReturnTo(&mSurfaceTexture))))) {
+ return false;
+ }
+
+ if (!aTexture) {
+ mSurfaceTexture->DetachFromGLContext();
+ }
+
+ mAttachedContext = aContext;
+
+ if (NS_WARN_IF(NS_FAILED(
+ java::sdk::Surface::New(mSurfaceTexture, ReturnTo(&mSurface))))) {
+ return false;
+ }
+
+ mNativeWindow = ANativeWindow_fromSurface(jni::GetEnvForThread(),
+ mSurface.Get());
+ MOZ_ASSERT(mNativeWindow, "Failed to create native window from surface");
+
+ return true;
+}
+
+AndroidSurfaceTexture::AndroidSurfaceTexture()
+ : mTexture(0)
+ , mSurfaceTexture()
+ , mSurface()
+ , mAttachedContext(nullptr)
+ , mMonitor("AndroidSurfaceTexture")
+{
+}
+
+AndroidSurfaceTexture::~AndroidSurfaceTexture()
+{
+ if (mSurfaceTexture) {
+ SetFrameAvailableCallback(nullptr);
+ mSurfaceTexture = nullptr;
+ }
+
+ if (mNativeWindow) {
+ ANativeWindow_release(mNativeWindow);
+ mNativeWindow = nullptr;
+ }
+}
+
+void
+AndroidSurfaceTexture::UpdateTexImage()
+{
+ mSurfaceTexture->UpdateTexImage();
+}
+
+void
+AndroidSurfaceTexture::GetTransformMatrix(gfx::Matrix4x4& aMatrix) const
+{
+ JNIEnv* const env = jni::GetEnvForThread();
+
+ auto jarray = jni::FloatArray::LocalRef::Adopt(env, env->NewFloatArray(16));
+ mSurfaceTexture->GetTransformMatrix(jarray);
+
+ jfloat* array = env->GetFloatArrayElements(jarray.Get(), nullptr);
+
+ aMatrix._11 = array[0];
+ aMatrix._12 = array[1];
+ aMatrix._13 = array[2];
+ aMatrix._14 = array[3];
+
+ aMatrix._21 = array[4];
+ aMatrix._22 = array[5];
+ aMatrix._23 = array[6];
+ aMatrix._24 = array[7];
+
+ aMatrix._31 = array[8];
+ aMatrix._32 = array[9];
+ aMatrix._33 = array[10];
+ aMatrix._34 = array[11];
+
+ aMatrix._41 = array[12];
+ aMatrix._42 = array[13];
+ aMatrix._43 = array[14];
+ aMatrix._44 = array[15];
+
+ env->ReleaseFloatArrayElements(jarray.Get(), array, 0);
+}
+
+void
+AndroidSurfaceTexture::SetFrameAvailableCallback(nsIRunnable* aRunnable)
+{
+ java::SurfaceTextureListener::LocalRef newListener;
+
+ if (aRunnable) {
+ newListener = java::SurfaceTextureListener::New();
+ Listener::AttachNative(newListener, MakeUnique<Listener>(aRunnable));
+ }
+
+ if (aRunnable || mListener) {
+ MOZ_ALWAYS_TRUE(NS_SUCCEEDED(
+ mSurfaceTexture->SetOnFrameAvailableListener(newListener)));
+ }
+
+ if (mListener) {
+ Listener::DisposeNative(java::SurfaceTextureListener::LocalRef(
+ newListener.Env(), mListener));
+ }
+
+ mListener = newListener;
+}
+
+void
+AndroidSurfaceTexture::SetDefaultSize(mozilla::gfx::IntSize size)
+{
+ mSurfaceTexture->SetDefaultBufferSize(size.width, size.height);
+}
+
+} // gl
+} // mozilla
+
+#endif // MOZ_WIDGET_ANDROID