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