1 /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
2 /* vim: set ts=8 sts=2 et sw=2 tw=80: */
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 #include "AndroidSurfaceTexture.h"
8 
9 #include "GLContextEGL.h"
10 #include "GLBlitHelper.h"
11 #include "GLImages.h"
12 
13 #ifdef MOZ_WIDGET_ANDROID
14 #  include "mozilla/java/GeckoSurfaceTextureNatives.h"
15 #  include "AndroidNativeWindow.h"
16 #endif  // MOZ_WIDGET_ANDROID
17 
18 namespace mozilla {
19 namespace gl {
20 
21 class AndroidSharedBlitGL final {
22  public:
AndroidSharedBlitGL(const EGLNativeWindowType window)23   explicit AndroidSharedBlitGL(const EGLNativeWindowType window) {
24     StaticMutexAutoLock lock(sMutex);
25 
26     if (!sContext) {
27       MOZ_ASSERT(sInstanceCount == 0);
28       sContext = CreateContext();
29       if (!sContext) {
30         return;
31       }
32     }
33 
34     const auto& egl = *(sContext->mEgl);
35     mTargetSurface = egl.fCreateWindowSurface(sContext->mConfig, window, 0);
36 
37     ++sInstanceCount;
38   }
39 
~AndroidSharedBlitGL()40   ~AndroidSharedBlitGL() {
41     StaticMutexAutoLock lock(sMutex);
42 
43     if (mTargetSurface != EGL_NO_SURFACE) {
44       const auto& egl = *(sContext->mEgl);
45       egl.fDestroySurface(mTargetSurface);
46     }
47 
48     // Destroy shared GL context when no one uses it.
49     if (--sInstanceCount == 0) {
50       sContext = nullptr;
51     }
52   }
53 
Blit(layers::SurfaceTextureImage * img,const gfx::IntSize & imageSize)54   void Blit(layers::SurfaceTextureImage* img, const gfx::IntSize& imageSize) {
55     StaticMutexAutoLock lock(sMutex);
56     MOZ_ASSERT(sContext);
57 
58     // Setting overide also makes conext and surface current.
59     sContext->SetEGLSurfaceOverride(mTargetSurface);
60 #ifdef MOZ_WIDGET_ANDROID
61     sContext->BlitHelper()->BlitImage(img, imageSize, OriginPos::BottomLeft);
62 #else
63     MOZ_CRASH("bad platform");
64 #endif
65     sContext->SwapBuffers();
66     // This method is called through binder IPC and could run on any thread in
67     // the pool. Release the context and surface from this thread after use so
68     // they can be bound to another thread later.
69     UnmakeCurrent(sContext);
70   }
71 
72  private:
CreateContextImpl(bool aUseGles)73   static already_AddRefed<GLContextEGL> CreateContextImpl(bool aUseGles) {
74     sMutex.AssertCurrentThreadOwns();
75     MOZ_ASSERT(!sContext);
76 
77     nsCString ignored;
78     const auto egl = gl::DefaultEglDisplay(&ignored);
79     EGLConfig eglConfig;
80     CreateConfig(*egl, &eglConfig, /* bpp */ 24, /* depth buffer? */ false,
81                  aUseGles);
82     auto gl = GLContextEGL::CreateGLContext(egl, {}, eglConfig, EGL_NO_SURFACE,
83                                             true, &ignored);
84     if (!gl) {
85       NS_WARNING("Fail to create GL context for native blitter.");
86       return nullptr;
87     }
88 
89     // Yield the current state made in constructor.
90     UnmakeCurrent(gl);
91     return gl.forget();
92   }
93 
CreateContext()94   static already_AddRefed<GLContextEGL> CreateContext() {
95     RefPtr<GLContextEGL> gl;
96 #if !defined(MOZ_WIDGET_ANDROID)
97     gl = CreateContextImpl(/* aUseGles */ false);
98 #endif  // !defined(MOZ_WIDGET_ANDROID)
99 
100     if (!gl) {
101       gl = CreateContextImpl(/* aUseGles */ true);
102     }
103     return gl.forget();
104   }
105 
UnmakeCurrent(GLContextEGL * const gl)106   static bool UnmakeCurrent(GLContextEGL* const gl) {
107     sMutex.AssertCurrentThreadOwns();
108     MOZ_ASSERT(gl);
109 
110     if (!gl->IsCurrent()) {
111       return true;
112     }
113     const auto& egl = *(gl->mEgl);
114     return egl.fMakeCurrent(EGL_NO_SURFACE, EGL_NO_SURFACE, EGL_NO_CONTEXT);
115   }
116 
117   static StaticMutex sMutex;
118   static StaticRefPtr<GLContextEGL> sContext;
119   static size_t sInstanceCount;
120 
121   EGLSurface mTargetSurface;
122 };
123 
124 StaticMutex AndroidSharedBlitGL::sMutex;
125 StaticRefPtr<GLContextEGL> AndroidSharedBlitGL::sContext;
126 size_t AndroidSharedBlitGL::sInstanceCount = 0;
127 
128 // -
129 #ifdef MOZ_WIDGET_ANDROID
130 
GetTransformMatrix(java::sdk::SurfaceTexture::Param surfaceTexture,gfx::Matrix4x4 * outMatrix)131 void AndroidSurfaceTexture::GetTransformMatrix(
132     java::sdk::SurfaceTexture::Param surfaceTexture,
133     gfx::Matrix4x4* outMatrix) {
134   JNIEnv* const env = jni::GetEnvForThread();
135 
136   auto jarray = jni::FloatArray::LocalRef::Adopt(env, env->NewFloatArray(16));
137   surfaceTexture->GetTransformMatrix(jarray);
138 
139   jfloat* array = env->GetFloatArrayElements(jarray.Get(), nullptr);
140 
141   memcpy(&(outMatrix->_11), array, sizeof(float) * 16);
142 
143   env->ReleaseFloatArrayElements(jarray.Get(), array, 0);
144 }
145 
146 class GLBlitterSupport final
147     : public java::GeckoSurfaceTexture::NativeGLBlitHelper::Natives<
148           GLBlitterSupport> {
149  public:
150   using Base =
151       java::GeckoSurfaceTexture::NativeGLBlitHelper::Natives<GLBlitterSupport>;
152   using Base::AttachNative;
153   using Base::DisposeNative;
154   using Base::GetNative;
155 
NativeCreate(jint sourceTextureHandle,jni::Object::Param targetSurface,jint width,jint height)156   static java::GeckoSurfaceTexture::NativeGLBlitHelper::LocalRef NativeCreate(
157       jint sourceTextureHandle, jni::Object::Param targetSurface, jint width,
158       jint height) {
159     AndroidNativeWindow win(java::GeckoSurface::Ref::From(targetSurface));
160     auto helper = java::GeckoSurfaceTexture::NativeGLBlitHelper::New();
161     const auto& eglWindow = win.NativeWindow();
162     GLBlitterSupport::AttachNative(
163         helper,
164         MakeUnique<GLBlitterSupport>(MakeUnique<AndroidSharedBlitGL>(eglWindow),
165                                      sourceTextureHandle, width, height));
166     return helper;
167   }
168 
GLBlitterSupport(UniquePtr<AndroidSharedBlitGL> && gl,jint sourceTextureHandle,jint width,jint height)169   GLBlitterSupport(UniquePtr<AndroidSharedBlitGL>&& gl,
170                    jint sourceTextureHandle, jint width, jint height)
171       : mGl(std::move(gl)),
172         mSourceTextureHandle(sourceTextureHandle),
173         mSize(width, height) {}
174 
Blit()175   void Blit() {
176     RefPtr<layers::SurfaceTextureImage> img = new layers::SurfaceTextureImage(
177         mSourceTextureHandle, mSize, false, OriginPos::TopLeft);
178     mGl->Blit(img, mSize);
179   }
180 
181  private:
182   const UniquePtr<AndroidSharedBlitGL> mGl;
183   const AndroidSurfaceTextureHandle mSourceTextureHandle;
184   const gfx::IntSize mSize;
185 };
186 
Init()187 void AndroidSurfaceTexture::Init() { GLBlitterSupport::Init(); }
188 
189 #endif  // MOZ_WIDGET_ANDROID
190 
191 }  // namespace gl
192 }  // namespace mozilla
193