1 /* -*- Mode: c++; c-basic-offset: 2; indent-tabs-mode: nil; tab-width: 4; -*- */
2 /* This Source Code Form is subject to the terms of the Mozilla Public
3  * License, v. 2.0. If a copy of the MPL was not distributed with this
4  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
5 
6 #include "SharedSurfaceEGL.h"
7 
8 #include "GLBlitHelper.h"
9 #include "GLContextEGL.h"
10 #include "GLContextProvider.h"
11 #include "GLLibraryEGL.h"
12 #include "GLReadTexImageHelper.h"
13 #include "MozFramebuffer.h"
14 #include "mozilla/layers/LayersSurfaces.h"  // for SurfaceDescriptor, etc
15 #include "SharedSurface.h"
16 
17 #if defined(MOZ_WIDGET_ANDROID)
18 #  include "AndroidNativeWindow.h"
19 #  include "mozilla/java/SurfaceAllocatorWrappers.h"
20 #  include "mozilla/java/GeckoSurfaceTextureWrappers.h"
21 #endif  // defined(MOZ_WIDGET_ANDROID)
22 
23 namespace mozilla {
24 namespace gl {
25 
HasEglImageExtensions(const GLContextEGL & gl)26 static bool HasEglImageExtensions(const GLContextEGL& gl) {
27   const auto& egl = *(gl.mEgl);
28   return egl.HasKHRImageBase() &&
29          egl.IsExtensionSupported(EGLExtension::KHR_gl_texture_2D_image) &&
30          (gl.IsExtensionSupported(GLContext::OES_EGL_image_external) ||
31           gl.IsExtensionSupported(GLContext::OES_EGL_image));
32 }
33 
34 /*static*/
Create(GLContext & gl_)35 UniquePtr<SurfaceFactory_EGLImage> SurfaceFactory_EGLImage::Create(
36     GLContext& gl_) {
37   auto& gl = *GLContextEGL::Cast(&gl_);
38   if (!HasEglImageExtensions(gl)) return nullptr;
39 
40   const auto partialDesc = PartialSharedSurfaceDesc{
41       &gl, SharedSurfaceType::EGLImageShare, layers::TextureType::EGLImage,
42       false,  // Can't recycle, as mSync changes never update TextureHost.
43   };
44   return AsUnique(new SurfaceFactory_EGLImage(partialDesc));
45 }
46 
47 // -
48 
49 /*static*/
Create(const SharedSurfaceDesc & desc)50 UniquePtr<SharedSurface_EGLImage> SharedSurface_EGLImage::Create(
51     const SharedSurfaceDesc& desc) {
52   const auto& gle = GLContextEGL::Cast(desc.gl);
53   const auto& context = gle->mContext;
54   const auto& egl = *(gle->mEgl);
55 
56   auto fb = MozFramebuffer::Create(desc.gl, desc.size, 0, false);
57   if (!fb) return nullptr;
58 
59   const auto buffer = reinterpret_cast<EGLClientBuffer>(fb->ColorTex());
60   const auto image =
61       egl.fCreateImage(context, LOCAL_EGL_GL_TEXTURE_2D, buffer, nullptr);
62   if (!image) return nullptr;
63 
64   return AsUnique(new SharedSurface_EGLImage(desc, std::move(fb), image));
65 }
66 
SharedSurface_EGLImage(const SharedSurfaceDesc & desc,UniquePtr<MozFramebuffer> && fb,const EGLImage image)67 SharedSurface_EGLImage::SharedSurface_EGLImage(const SharedSurfaceDesc& desc,
68                                                UniquePtr<MozFramebuffer>&& fb,
69                                                const EGLImage image)
70     : SharedSurface(desc, std::move(fb)),
71       mMutex("SharedSurface_EGLImage mutex"),
72       mImage(image) {}
73 
~SharedSurface_EGLImage()74 SharedSurface_EGLImage::~SharedSurface_EGLImage() {
75   const auto& gle = GLContextEGL::Cast(mDesc.gl);
76   const auto& egl = gle->mEgl;
77   egl->fDestroyImage(mImage);
78 
79   if (mSync) {
80     // We can't call this unless we have the ext, but we will always have
81     // the ext if we have something to destroy.
82     egl->fDestroySync(mSync);
83     mSync = 0;
84   }
85 }
86 
ProducerReleaseImpl()87 void SharedSurface_EGLImage::ProducerReleaseImpl() {
88   const auto& gl = GLContextEGL::Cast(mDesc.gl);
89   const auto& egl = gl->mEgl;
90 
91   MutexAutoLock lock(mMutex);
92   gl->MakeCurrent();
93 
94   if (egl->IsExtensionSupported(EGLExtension::KHR_fence_sync) &&
95       gl->IsExtensionSupported(GLContext::OES_EGL_sync)) {
96     if (mSync) {
97       MOZ_RELEASE_ASSERT(false, "GFX: Non-recycleable should not Fence twice.");
98       MOZ_ALWAYS_TRUE(egl->fDestroySync(mSync));
99       mSync = 0;
100     }
101 
102     mSync = egl->fCreateSync(LOCAL_EGL_SYNC_FENCE, nullptr);
103     if (mSync) {
104       gl->fFlush();
105       return;
106     }
107   }
108 
109   MOZ_ASSERT(!mSync);
110   gl->fFinish();
111 }
112 
ProducerReadAcquireImpl()113 void SharedSurface_EGLImage::ProducerReadAcquireImpl() {
114   const auto& gle = GLContextEGL::Cast(mDesc.gl);
115   const auto& egl = gle->mEgl;
116   // Wait on the fence, because presumably we're going to want to read this
117   // surface
118   if (mSync) {
119     egl->fClientWaitSync(mSync, 0, LOCAL_EGL_FOREVER);
120   }
121 }
122 
ToSurfaceDescriptor()123 Maybe<layers::SurfaceDescriptor> SharedSurface_EGLImage::ToSurfaceDescriptor() {
124   return Some(layers::EGLImageDescriptor((uintptr_t)mImage, (uintptr_t)mSync,
125                                          mDesc.size, true));
126 }
127 
128 ////////////////////////////////////////////////////////////////////////
129 
130 #ifdef MOZ_WIDGET_ANDROID
131 
132 /*static*/
Create(const SharedSurfaceDesc & desc)133 UniquePtr<SharedSurface_SurfaceTexture> SharedSurface_SurfaceTexture::Create(
134     const SharedSurfaceDesc& desc) {
135   const auto& size = desc.size;
136 
137   jni::Object::LocalRef surfaceObj;
138   const bool useSingleBuffer =
139       desc.gl->Renderer() != GLRenderer::AndroidEmulator;
140 
141   if (useSingleBuffer) {
142     surfaceObj =
143         java::SurfaceAllocator::AcquireSurface(size.width, size.height, true);
144   }
145 
146   if (!surfaceObj) {
147     // Try multi-buffer mode
148     surfaceObj =
149         java::SurfaceAllocator::AcquireSurface(size.width, size.height, false);
150   }
151 
152   if (!surfaceObj) {
153     // Give up
154     NS_WARNING("Failed to allocate SurfaceTexture!");
155     return nullptr;
156   }
157   const auto surface = java::GeckoSurface::Ref::From(surfaceObj);
158 
159   AndroidNativeWindow window(surface);
160   const auto& gle = GLContextEGL::Cast(desc.gl);
161   MOZ_ASSERT(gle);
162   const auto eglSurface = gle->CreateCompatibleSurface(window.NativeWindow());
163   if (!eglSurface) return nullptr;
164 
165   return AsUnique(new SharedSurface_SurfaceTexture(desc, surface, eglSurface));
166 }
167 
SharedSurface_SurfaceTexture(const SharedSurfaceDesc & desc,java::GeckoSurface::Param surface,const EGLSurface eglSurface)168 SharedSurface_SurfaceTexture::SharedSurface_SurfaceTexture(
169     const SharedSurfaceDesc& desc, java::GeckoSurface::Param surface,
170     const EGLSurface eglSurface)
171     : SharedSurface(desc, nullptr),
172       mSurface(surface),
173       mEglSurface(eglSurface),
174       mEglDisplay(GLContextEGL::Cast(desc.gl)->mEgl) {}
175 
~SharedSurface_SurfaceTexture()176 SharedSurface_SurfaceTexture::~SharedSurface_SurfaceTexture() {
177   if (mOrigEglSurface) {
178     // We are about to destroy mEglSurface.
179     // Make sure gl->SetEGLSurfaceOverride() doesn't keep a reference
180     // to the surface.
181     UnlockProd();
182   }
183 
184   std::shared_ptr<EglDisplay> display = mEglDisplay.lock();
185   if (display) {
186     display->fDestroySurface(mEglSurface);
187   }
188   java::SurfaceAllocator::DisposeSurface(mSurface);
189 }
190 
LockProdImpl()191 void SharedSurface_SurfaceTexture::LockProdImpl() {
192   MOZ_RELEASE_ASSERT(mSurface->GetAvailable());
193 
194   GLContextEGL* gl = GLContextEGL::Cast(mDesc.gl);
195   mOrigEglSurface = gl->GetEGLSurfaceOverride();
196   gl->SetEGLSurfaceOverride(mEglSurface);
197 }
198 
UnlockProdImpl()199 void SharedSurface_SurfaceTexture::UnlockProdImpl() {
200   MOZ_RELEASE_ASSERT(mSurface->GetAvailable());
201 
202   GLContextEGL* gl = GLContextEGL::Cast(mDesc.gl);
203   MOZ_ASSERT(gl->GetEGLSurfaceOverride() == mEglSurface);
204 
205   gl->SetEGLSurfaceOverride(mOrigEglSurface);
206   mOrigEglSurface = nullptr;
207 }
208 
ProducerReadReleaseImpl()209 void SharedSurface_SurfaceTexture::ProducerReadReleaseImpl() {
210   // This GeckoSurfaceTexture is not SurfaceTexture of this class's GeckoSurface
211   // when current process is content process. In this case, SurfaceTexture of
212   // this class's GeckoSurface does not exist in this process. It exists in
213   // compositor's process. Then GeckoSurfaceTexture in this process is a sync
214   // surface that copies back the SurfaceTextrure from compositor's process. It
215   // was added by Bug 1486659. Then SurfaceTexture::UpdateTexImage() becomes
216   // very heavy weight, since it does copy back the SurfaceTextrure from
217   // compositor's process.
218   java::GeckoSurfaceTexture::LocalRef surfaceTexture =
219       java::GeckoSurfaceTexture::Lookup(mSurface->GetHandle());
220   if (!surfaceTexture) {
221     NS_ERROR("Didn't find GeckoSurfaceTexture in ProducerReadReleaseImpl");
222     return;
223   }
224   surfaceTexture->UpdateTexImage();
225   // Non single buffer mode Surface does not need ReleaseTexImage() call.
226   // When SurfaceTexture is sync Surface, it might not be single buffer mode.
227   if (surfaceTexture->IsSingleBuffer()) {
228     surfaceTexture->ReleaseTexImage();
229   }
230 }
231 
Commit()232 void SharedSurface_SurfaceTexture::Commit() {
233   MOZ_RELEASE_ASSERT(mSurface->GetAvailable());
234 
235   LockProdImpl();
236   mDesc.gl->SwapBuffers();
237   UnlockProdImpl();
238   mSurface->SetAvailable(false);
239 }
240 
WaitForBufferOwnership()241 void SharedSurface_SurfaceTexture::WaitForBufferOwnership() {
242   mSurface->SetAvailable(true);
243 }
244 
IsBufferAvailable() const245 bool SharedSurface_SurfaceTexture::IsBufferAvailable() const {
246   return mSurface->GetAvailable();
247 }
248 
249 Maybe<layers::SurfaceDescriptor>
ToSurfaceDescriptor()250 SharedSurface_SurfaceTexture::ToSurfaceDescriptor() {
251   return Some(layers::SurfaceTextureDescriptor(
252       mSurface->GetHandle(), mDesc.size, gfx::SurfaceFormat::R8G8B8A8,
253       false /* NOT continuous */, false /* Do not ignore transform */));
254 }
255 
SurfaceFactory_SurfaceTexture(GLContext & gl)256 SurfaceFactory_SurfaceTexture::SurfaceFactory_SurfaceTexture(GLContext& gl)
257     : SurfaceFactory({&gl, SharedSurfaceType::AndroidSurfaceTexture,
258                       layers::TextureType::AndroidNativeWindow, true}) {}
259 
260 #endif  // MOZ_WIDGET_ANDROID
261 
262 }  // namespace gl
263 
264 } /* namespace mozilla */
265