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