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 "mozilla/layers/LayersSurfaces.h" // for SurfaceDescriptor, etc
14 #include "SharedSurface.h"
15
16 #if defined(MOZ_WIDGET_ANDROID)
17 # include "mozilla/java/SurfaceAllocatorWrappers.h"
18 #endif // defined(MOZ_WIDGET_ANDROID)
19
20 namespace mozilla {
21 namespace gl {
22
23 /*static*/
Create(GLContext * prodGL,const GLFormats & formats,const gfx::IntSize & size,bool hasAlpha,EGLContext context)24 UniquePtr<SharedSurface_EGLImage> SharedSurface_EGLImage::Create(
25 GLContext* prodGL, const GLFormats& formats, const gfx::IntSize& size,
26 bool hasAlpha, EGLContext context) {
27 const auto& gle = GLContextEGL::Cast(prodGL);
28 const auto& egl = gle->mEgl;
29 MOZ_ASSERT(egl);
30 MOZ_ASSERT(context);
31
32 UniquePtr<SharedSurface_EGLImage> ret;
33
34 if (!HasExtensions(egl, prodGL)) {
35 return ret;
36 }
37
38 MOZ_ALWAYS_TRUE(prodGL->MakeCurrent());
39 GLuint prodTex = CreateTextureForOffscreen(prodGL, formats, size);
40 if (!prodTex) {
41 return ret;
42 }
43
44 EGLClientBuffer buffer =
45 reinterpret_cast<EGLClientBuffer>(uintptr_t(prodTex));
46 EGLImage image = egl->fCreateImage(egl->Display(), context,
47 LOCAL_EGL_GL_TEXTURE_2D, buffer, nullptr);
48 if (!image) {
49 prodGL->fDeleteTextures(1, &prodTex);
50 return ret;
51 }
52
53 ret.reset(new SharedSurface_EGLImage(prodGL, size, hasAlpha, formats, prodTex,
54 image));
55 return ret;
56 }
57
HasExtensions(GLLibraryEGL * egl,GLContext * gl)58 bool SharedSurface_EGLImage::HasExtensions(GLLibraryEGL* egl, GLContext* gl) {
59 return egl->HasKHRImageBase() &&
60 egl->IsExtensionSupported(GLLibraryEGL::KHR_gl_texture_2D_image) &&
61 (gl->IsExtensionSupported(GLContext::OES_EGL_image_external) ||
62 gl->IsExtensionSupported(GLContext::OES_EGL_image));
63 }
64
SharedSurface_EGLImage(GLContext * gl,const gfx::IntSize & size,bool hasAlpha,const GLFormats & formats,GLuint prodTex,EGLImage image)65 SharedSurface_EGLImage::SharedSurface_EGLImage(GLContext* gl,
66 const gfx::IntSize& size,
67 bool hasAlpha,
68 const GLFormats& formats,
69 GLuint prodTex, EGLImage image)
70 : SharedSurface(
71 SharedSurfaceType::EGLImageShare, AttachmentType::GLTexture, gl, size,
72 hasAlpha,
73 false) // Can't recycle, as mSync changes never update TextureHost.
74 ,
75 mMutex("SharedSurface_EGLImage mutex"),
76 mFormats(formats),
77 mProdTex(prodTex),
78 mImage(image),
79 mSync(0) {}
80
~SharedSurface_EGLImage()81 SharedSurface_EGLImage::~SharedSurface_EGLImage() {
82 const auto& gle = GLContextEGL::Cast(mGL);
83 const auto& egl = gle->mEgl;
84 egl->fDestroyImage(egl->Display(), mImage);
85
86 if (mSync) {
87 // We can't call this unless we have the ext, but we will always have
88 // the ext if we have something to destroy.
89 egl->fDestroySync(egl->Display(), mSync);
90 mSync = 0;
91 }
92
93 if (!mGL || !mGL->MakeCurrent()) return;
94
95 mGL->fDeleteTextures(1, &mProdTex);
96 mProdTex = 0;
97 }
98
ProducerReleaseImpl()99 void SharedSurface_EGLImage::ProducerReleaseImpl() {
100 const auto& gle = GLContextEGL::Cast(mGL);
101 const auto& egl = gle->mEgl;
102
103 MutexAutoLock lock(mMutex);
104 mGL->MakeCurrent();
105
106 if (egl->IsExtensionSupported(GLLibraryEGL::KHR_fence_sync) &&
107 mGL->IsExtensionSupported(GLContext::OES_EGL_sync)) {
108 if (mSync) {
109 MOZ_RELEASE_ASSERT(false, "GFX: Non-recycleable should not Fence twice.");
110 MOZ_ALWAYS_TRUE(egl->fDestroySync(egl->Display(), mSync));
111 mSync = 0;
112 }
113
114 mSync = egl->fCreateSync(egl->Display(), LOCAL_EGL_SYNC_FENCE, nullptr);
115 if (mSync) {
116 mGL->fFlush();
117 return;
118 }
119 }
120
121 MOZ_ASSERT(!mSync);
122 mGL->fFinish();
123 }
124
ProducerReadAcquireImpl()125 void SharedSurface_EGLImage::ProducerReadAcquireImpl() {
126 const auto& gle = GLContextEGL::Cast(mGL);
127 const auto& egl = gle->mEgl;
128 // Wait on the fence, because presumably we're going to want to read this
129 // surface
130 if (mSync) {
131 egl->fClientWaitSync(egl->Display(), mSync, 0, LOCAL_EGL_FOREVER);
132 }
133 }
134
ToSurfaceDescriptor(layers::SurfaceDescriptor * const out_descriptor)135 bool SharedSurface_EGLImage::ToSurfaceDescriptor(
136 layers::SurfaceDescriptor* const out_descriptor) {
137 *out_descriptor = layers::EGLImageDescriptor(
138 (uintptr_t)mImage, (uintptr_t)mSync, mSize, mHasAlpha);
139 return true;
140 }
141
ReadbackBySharedHandle(gfx::DataSourceSurface * out_surface)142 bool SharedSurface_EGLImage::ReadbackBySharedHandle(
143 gfx::DataSourceSurface* out_surface) {
144 const auto& gle = GLContextEGL::Cast(mGL);
145 const auto& egl = gle->mEgl;
146 MOZ_ASSERT(out_surface);
147 MOZ_ASSERT(NS_IsMainThread());
148 return egl->ReadbackEGLImage(mImage, out_surface);
149 }
150
151 ////////////////////////////////////////////////////////////////////////
152
153 /*static*/
Create(GLContext * prodGL,const SurfaceCaps & caps,const RefPtr<layers::LayersIPCChannel> & allocator,const layers::TextureFlags & flags)154 UniquePtr<SurfaceFactory_EGLImage> SurfaceFactory_EGLImage::Create(
155 GLContext* prodGL, const SurfaceCaps& caps,
156 const RefPtr<layers::LayersIPCChannel>& allocator,
157 const layers::TextureFlags& flags) {
158 const auto& gle = GLContextEGL::Cast(prodGL);
159 const auto& egl = gle->mEgl;
160 const auto& context = gle->mContext;
161
162 typedef SurfaceFactory_EGLImage ptrT;
163 UniquePtr<ptrT> ret;
164
165 if (SharedSurface_EGLImage::HasExtensions(egl, prodGL)) {
166 ret.reset(new ptrT(prodGL, caps, allocator, flags, context));
167 }
168
169 return ret;
170 }
171
172 ////////////////////////////////////////////////////////////////////////
173
174 #ifdef MOZ_WIDGET_ANDROID
175
176 /*static*/
Create(GLContext * prodGL,const GLFormats & formats,const gfx::IntSize & size,bool hasAlpha,java::GeckoSurface::Param surface)177 UniquePtr<SharedSurface_SurfaceTexture> SharedSurface_SurfaceTexture::Create(
178 GLContext* prodGL, const GLFormats& formats, const gfx::IntSize& size,
179 bool hasAlpha, java::GeckoSurface::Param surface) {
180 MOZ_ASSERT(surface);
181
182 UniquePtr<SharedSurface_SurfaceTexture> ret;
183
184 AndroidNativeWindow window(surface);
185 const auto& gle = GLContextEGL::Cast(prodGL);
186 MOZ_ASSERT(gle);
187 EGLSurface eglSurface = gle->CreateCompatibleSurface(window.NativeWindow());
188 if (!eglSurface) {
189 return ret;
190 }
191
192 ret.reset(new SharedSurface_SurfaceTexture(prodGL, size, hasAlpha, formats,
193 surface, eglSurface));
194 return ret;
195 }
196
SharedSurface_SurfaceTexture(GLContext * gl,const gfx::IntSize & size,bool hasAlpha,const GLFormats & formats,java::GeckoSurface::Param surface,EGLSurface eglSurface)197 SharedSurface_SurfaceTexture::SharedSurface_SurfaceTexture(
198 GLContext* gl, const gfx::IntSize& size, bool hasAlpha,
199 const GLFormats& formats, java::GeckoSurface::Param surface,
200 EGLSurface eglSurface)
201 : SharedSurface(SharedSurfaceType::AndroidSurfaceTexture,
202 AttachmentType::Screen, gl, size, hasAlpha, true),
203 mSurface(surface),
204 mEglSurface(eglSurface) {}
205
~SharedSurface_SurfaceTexture()206 SharedSurface_SurfaceTexture::~SharedSurface_SurfaceTexture() {
207 if (mOrigEglSurface) {
208 // We are about to destroy mEglSurface.
209 // Make sure gl->SetEGLSurfaceOverride() doesn't keep a reference
210 // to the surface.
211 UnlockProd();
212 }
213 GLContextProviderEGL::DestroyEGLSurface(mEglSurface);
214 java::SurfaceAllocator::DisposeSurface(mSurface);
215 }
216
LockProdImpl()217 void SharedSurface_SurfaceTexture::LockProdImpl() {
218 MOZ_RELEASE_ASSERT(mSurface->GetAvailable());
219
220 GLContextEGL* gl = GLContextEGL::Cast(mGL);
221 mOrigEglSurface = gl->GetEGLSurfaceOverride();
222 gl->SetEGLSurfaceOverride(mEglSurface);
223 }
224
UnlockProdImpl()225 void SharedSurface_SurfaceTexture::UnlockProdImpl() {
226 MOZ_RELEASE_ASSERT(mSurface->GetAvailable());
227
228 GLContextEGL* gl = GLContextEGL::Cast(mGL);
229 MOZ_ASSERT(gl->GetEGLSurfaceOverride() == mEglSurface);
230
231 gl->SetEGLSurfaceOverride(mOrigEglSurface);
232 mOrigEglSurface = nullptr;
233 }
234
Commit()235 void SharedSurface_SurfaceTexture::Commit() {
236 MOZ_RELEASE_ASSERT(mSurface->GetAvailable());
237
238 LockProdImpl();
239 mGL->SwapBuffers();
240 UnlockProdImpl();
241 mSurface->SetAvailable(false);
242 }
243
WaitForBufferOwnership()244 void SharedSurface_SurfaceTexture::WaitForBufferOwnership() {
245 mSurface->SetAvailable(true);
246 }
247
IsBufferAvailable() const248 bool SharedSurface_SurfaceTexture::IsBufferAvailable() const {
249 return mSurface->GetAvailable();
250 }
251
ToSurfaceDescriptor(layers::SurfaceDescriptor * const out_descriptor)252 bool SharedSurface_SurfaceTexture::ToSurfaceDescriptor(
253 layers::SurfaceDescriptor* const out_descriptor) {
254 *out_descriptor = layers::SurfaceTextureDescriptor(
255 mSurface->GetHandle(), mSize, gfx::SurfaceFormat::R8G8B8A8,
256 false /* NOT continuous */, false /* Do not ignore transform */);
257 return true;
258 }
259
260 ////////////////////////////////////////////////////////////////////////
261
262 /*static*/
Create(GLContext * prodGL,const SurfaceCaps & caps,const RefPtr<layers::LayersIPCChannel> & allocator,const layers::TextureFlags & flags)263 UniquePtr<SurfaceFactory_SurfaceTexture> SurfaceFactory_SurfaceTexture::Create(
264 GLContext* prodGL, const SurfaceCaps& caps,
265 const RefPtr<layers::LayersIPCChannel>& allocator,
266 const layers::TextureFlags& flags) {
267 UniquePtr<SurfaceFactory_SurfaceTexture> ret(
268 new SurfaceFactory_SurfaceTexture(prodGL, caps, allocator, flags));
269 return ret;
270 }
271
CreateShared(const gfx::IntSize & size)272 UniquePtr<SharedSurface> SurfaceFactory_SurfaceTexture::CreateShared(
273 const gfx::IntSize& size) {
274 bool hasAlpha = mReadCaps.alpha;
275
276 jni::Object::LocalRef surface =
277 java::SurfaceAllocator::AcquireSurface(size.width, size.height, true);
278 if (!surface) {
279 // Try multi-buffer mode
280 surface =
281 java::SurfaceAllocator::AcquireSurface(size.width, size.height, false);
282 if (!surface) {
283 // Give up
284 NS_WARNING("Failed to allocate SurfaceTexture!");
285 return nullptr;
286 }
287 }
288
289 return SharedSurface_SurfaceTexture::Create(
290 mGL, mFormats, size, hasAlpha, java::GeckoSurface::Ref::From(surface));
291 }
292
293 #endif // MOZ_WIDGET_ANDROID
294
295 } // namespace gl
296
297 } /* namespace mozilla */
298