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/. */
6 #include "SharedSurfaceEGL.h"
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"
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)
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
));
35 UniquePtr
<SurfaceFactory_EGLImage
> SurfaceFactory_EGLImage::Create(
37 auto& gl
= *GLContextEGL::Cast(&gl_
);
38 if (!HasEglImageExtensions(gl
)) return nullptr;
40 const auto partialDesc
= PartialSharedSurfaceDesc
{
41 &gl
, SharedSurfaceType::EGLImageShare
, layers::TextureType::EGLImage
,
42 false, // Can't recycle, as mSync changes never update TextureHost.
44 return AsUnique(new SurfaceFactory_EGLImage(partialDesc
));
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
);
56 auto fb
= MozFramebuffer::Create(desc
.gl
, desc
.size
, 0, false);
57 if (!fb
) return nullptr;
59 const auto buffer
= reinterpret_cast<EGLClientBuffer
>(fb
->ColorTex());
61 egl
.fCreateImage(context
, LOCAL_EGL_GL_TEXTURE_2D
, buffer
, nullptr);
62 if (!image
) return nullptr;
64 return AsUnique(new SharedSurface_EGLImage(desc
, std::move(fb
), image
));
67 SharedSurface_EGLImage::SharedSurface_EGLImage(const SharedSurfaceDesc
& desc
,
68 UniquePtr
<MozFramebuffer
>&& fb
,
70 : SharedSurface(desc
, std::move(fb
)),
71 mMutex("SharedSurface_EGLImage mutex"),
74 SharedSurface_EGLImage::~SharedSurface_EGLImage() {
75 const auto& gle
= GLContextEGL::Cast(mDesc
.gl
);
76 const auto& egl
= gle
->mEgl
;
77 egl
->fDestroyImage(mImage
);
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
);
87 void SharedSurface_EGLImage::ProducerReleaseImpl() {
88 const auto& gl
= GLContextEGL::Cast(mDesc
.gl
);
89 const auto& egl
= gl
->mEgl
;
91 MutexAutoLock
lock(mMutex
);
94 if (egl
->IsExtensionSupported(EGLExtension::KHR_fence_sync
) &&
95 gl
->IsExtensionSupported(GLContext::OES_EGL_sync
)) {
97 MOZ_RELEASE_ASSERT(false, "GFX: Non-recycleable should not Fence twice.");
98 MOZ_ALWAYS_TRUE(egl
->fDestroySync(mSync
));
102 mSync
= egl
->fCreateSync(LOCAL_EGL_SYNC_FENCE
, nullptr);
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
119 egl
->fClientWaitSync(mSync
, 0, LOCAL_EGL_FOREVER
);
123 Maybe
<layers::SurfaceDescriptor
> SharedSurface_EGLImage::ToSurfaceDescriptor() {
124 return Some(layers::EGLImageDescriptor((uintptr_t)mImage
, (uintptr_t)mSync
,
128 ////////////////////////////////////////////////////////////////////////
130 #ifdef MOZ_WIDGET_ANDROID
133 UniquePtr
<SharedSurface_SurfaceTexture
> SharedSurface_SurfaceTexture::Create(
134 const SharedSurfaceDesc
& desc
) {
135 const auto& size
= desc
.size
;
137 jni::Object::LocalRef surfaceObj
;
138 const bool useSingleBuffer
=
139 desc
.gl
->Renderer() != GLRenderer::AndroidEmulator
;
141 if (useSingleBuffer
) {
143 java::SurfaceAllocator::AcquireSurface(size
.width
, size
.height
, true);
147 // Try multi-buffer mode
149 java::SurfaceAllocator::AcquireSurface(size
.width
, size
.height
, false);
154 NS_WARNING("Failed to allocate SurfaceTexture!");
157 const auto surface
= java::GeckoSurface::Ref::From(surfaceObj
);
159 AndroidNativeWindow
window(surface
);
160 const auto& gle
= GLContextEGL::Cast(desc
.gl
);
162 const auto eglSurface
= gle
->CreateCompatibleSurface(window
.NativeWindow());
163 if (!eglSurface
) return nullptr;
165 return AsUnique(new SharedSurface_SurfaceTexture(desc
, surface
, eglSurface
));
168 SharedSurface_SurfaceTexture::SharedSurface_SurfaceTexture(
169 const SharedSurfaceDesc
& desc
, java::GeckoSurface::Param surface
,
170 const EGLSurface eglSurface
)
171 : SharedSurface(desc
, nullptr),
173 mEglSurface(eglSurface
),
174 mEglDisplay(GLContextEGL::Cast(desc
.gl
)->mEgl
) {}
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
184 std::shared_ptr
<EglDisplay
> display
= mEglDisplay
.lock();
186 display
->fDestroySurface(mEglSurface
);
188 java::SurfaceAllocator::DisposeSurface(mSurface
);
191 void SharedSurface_SurfaceTexture::LockProdImpl() {
192 MOZ_RELEASE_ASSERT(mSurface
->GetAvailable());
194 GLContextEGL
* gl
= GLContextEGL::Cast(mDesc
.gl
);
195 mOrigEglSurface
= gl
->GetEGLSurfaceOverride();
196 gl
->SetEGLSurfaceOverride(mEglSurface
);
199 void SharedSurface_SurfaceTexture::UnlockProdImpl() {
200 MOZ_RELEASE_ASSERT(mSurface
->GetAvailable());
202 GLContextEGL
* gl
= GLContextEGL::Cast(mDesc
.gl
);
203 MOZ_ASSERT(gl
->GetEGLSurfaceOverride() == mEglSurface
);
205 gl
->SetEGLSurfaceOverride(mOrigEglSurface
);
206 mOrigEglSurface
= nullptr;
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");
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();
232 void SharedSurface_SurfaceTexture::Commit() {
233 MOZ_RELEASE_ASSERT(mSurface
->GetAvailable());
236 mDesc
.gl
->SwapBuffers();
238 mSurface
->SetAvailable(false);
241 void SharedSurface_SurfaceTexture::WaitForBufferOwnership() {
242 mSurface
->SetAvailable(true);
245 bool SharedSurface_SurfaceTexture::IsBufferAvailable() const {
246 return mSurface
->GetAvailable();
249 Maybe
<layers::SurfaceDescriptor
>
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 */));
256 SurfaceFactory_SurfaceTexture::SurfaceFactory_SurfaceTexture(GLContext
& gl
)
257 : SurfaceFactory({&gl
, SharedSurfaceType::AndroidSurfaceTexture
,
258 layers::TextureType::AndroidNativeWindow
, true}) {}
260 #endif // MOZ_WIDGET_ANDROID
264 } /* namespace mozilla */