1 /* -*- Mode: c++; c-basic-offset: 4; indent-tabs-mode: nil; tab-width: 40; -*- */
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 "GLLibraryEGL.h"
11 #include "GLReadTexImageHelper.h"
12 #include "mozilla/layers/LayersSurfaces.h"  // for SurfaceDescriptor, etc
13 #include "SharedSurface.h"
14 #include "TextureGarbageBin.h"
15 
16 namespace mozilla {
17 namespace gl {
18 
19 /*static*/ UniquePtr<SharedSurface_EGLImage>
Create(GLContext * prodGL,const GLFormats & formats,const gfx::IntSize & size,bool hasAlpha,EGLContext context)20 SharedSurface_EGLImage::Create(GLContext* prodGL,
21                                const GLFormats& formats,
22                                const gfx::IntSize& size,
23                                bool hasAlpha,
24                                EGLContext context)
25 {
26     GLLibraryEGL* egl = &sEGLLibrary;
27     MOZ_ASSERT(egl);
28     MOZ_ASSERT(context);
29 
30     UniquePtr<SharedSurface_EGLImage> ret;
31 
32     if (!HasExtensions(egl, prodGL)) {
33         return Move(ret);
34     }
35 
36     MOZ_ALWAYS_TRUE(prodGL->MakeCurrent());
37     GLuint prodTex = CreateTextureForOffscreen(prodGL, formats, size);
38     if (!prodTex) {
39         return Move(ret);
40     }
41 
42     EGLClientBuffer buffer = reinterpret_cast<EGLClientBuffer>(uintptr_t(prodTex));
43     EGLImage image = egl->fCreateImage(egl->Display(), context,
44                                        LOCAL_EGL_GL_TEXTURE_2D, buffer,
45                                        nullptr);
46     if (!image) {
47         prodGL->fDeleteTextures(1, &prodTex);
48         return Move(ret);
49     }
50 
51     ret.reset( new SharedSurface_EGLImage(prodGL, egl, size, hasAlpha,
52                                           formats, prodTex, image) );
53     return Move(ret);
54 }
55 
56 bool
HasExtensions(GLLibraryEGL * egl,GLContext * gl)57 SharedSurface_EGLImage::HasExtensions(GLLibraryEGL* egl, GLContext* gl)
58 {
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,GLLibraryEGL * egl,const gfx::IntSize & size,bool hasAlpha,const GLFormats & formats,GLuint prodTex,EGLImage image)65 SharedSurface_EGLImage::SharedSurface_EGLImage(GLContext* gl,
66                                                GLLibraryEGL* egl,
67                                                const gfx::IntSize& size,
68                                                bool hasAlpha,
69                                                const GLFormats& formats,
70                                                GLuint prodTex,
71                                                EGLImage image)
72     : SharedSurface(SharedSurfaceType::EGLImageShare,
73                     AttachmentType::GLTexture,
74                     gl,
75                     size,
76                     hasAlpha,
77                     false) // Can't recycle, as mSync changes never update TextureHost.
78     , mMutex("SharedSurface_EGLImage mutex")
79     , mEGL(egl)
80     , mFormats(formats)
81     , mProdTex(prodTex)
82     , mImage(image)
83     , mSync(0)
84 {}
85 
~SharedSurface_EGLImage()86 SharedSurface_EGLImage::~SharedSurface_EGLImage()
87 {
88     mEGL->fDestroyImage(Display(), mImage);
89 
90     if (mSync) {
91         // We can't call this unless we have the ext, but we will always have
92         // the ext if we have something to destroy.
93         mEGL->fDestroySync(Display(), mSync);
94         mSync = 0;
95     }
96 
97     if (!mGL || !mGL->MakeCurrent())
98         return;
99 
100     mGL->fDeleteTextures(1, &mProdTex);
101     mProdTex = 0;
102 }
103 
104 layers::TextureFlags
GetTextureFlags() const105 SharedSurface_EGLImage::GetTextureFlags() const
106 {
107     return layers::TextureFlags::DEALLOCATE_CLIENT;
108 }
109 
110 void
ProducerReleaseImpl()111 SharedSurface_EGLImage::ProducerReleaseImpl()
112 {
113     MutexAutoLock lock(mMutex);
114     mGL->MakeCurrent();
115 
116     if (mEGL->IsExtensionSupported(GLLibraryEGL::KHR_fence_sync) &&
117         mGL->IsExtensionSupported(GLContext::OES_EGL_sync))
118     {
119         if (mSync) {
120             MOZ_RELEASE_ASSERT(false, "GFX: Non-recycleable should not Fence twice.");
121             MOZ_ALWAYS_TRUE( mEGL->fDestroySync(Display(), mSync) );
122             mSync = 0;
123         }
124 
125         mSync = mEGL->fCreateSync(Display(),
126                                   LOCAL_EGL_SYNC_FENCE,
127                                   nullptr);
128         if (mSync) {
129             mGL->fFlush();
130             return;
131         }
132     }
133 
134     MOZ_ASSERT(!mSync);
135     mGL->fFinish();
136 }
137 
138 void
ProducerReadAcquireImpl()139 SharedSurface_EGLImage::ProducerReadAcquireImpl()
140 {
141     // Wait on the fence, because presumably we're going to want to read this surface
142     if (mSync) {
143         mEGL->fClientWaitSync(Display(), mSync, 0, LOCAL_EGL_FOREVER);
144     }
145 }
146 
147 EGLDisplay
Display() const148 SharedSurface_EGLImage::Display() const
149 {
150     return mEGL->Display();
151 }
152 
153 bool
ToSurfaceDescriptor(layers::SurfaceDescriptor * const out_descriptor)154 SharedSurface_EGLImage::ToSurfaceDescriptor(layers::SurfaceDescriptor* const out_descriptor)
155 {
156     *out_descriptor = layers::EGLImageDescriptor((uintptr_t)mImage, (uintptr_t)mSync,
157                                                  mSize, mHasAlpha);
158     return true;
159 }
160 
161 bool
ReadbackBySharedHandle(gfx::DataSourceSurface * out_surface)162 SharedSurface_EGLImage::ReadbackBySharedHandle(gfx::DataSourceSurface* out_surface)
163 {
164     MOZ_ASSERT(out_surface);
165     MOZ_ASSERT(NS_IsMainThread());
166     return sEGLLibrary.ReadbackEGLImage(mImage, out_surface);
167 }
168 
169 ////////////////////////////////////////////////////////////////////////
170 
171 /*static*/ UniquePtr<SurfaceFactory_EGLImage>
Create(GLContext * prodGL,const SurfaceCaps & caps,const RefPtr<layers::LayersIPCChannel> & allocator,const layers::TextureFlags & flags)172 SurfaceFactory_EGLImage::Create(GLContext* prodGL, const SurfaceCaps& caps,
173                                 const RefPtr<layers::LayersIPCChannel>& allocator,
174                                 const layers::TextureFlags& flags)
175 {
176     EGLContext context = GLContextEGL::Cast(prodGL)->mContext;
177 
178     typedef SurfaceFactory_EGLImage ptrT;
179     UniquePtr<ptrT> ret;
180 
181     GLLibraryEGL* egl = &sEGLLibrary;
182     if (SharedSurface_EGLImage::HasExtensions(egl, prodGL)) {
183         ret.reset( new ptrT(prodGL, caps, allocator, flags, context) );
184     }
185 
186     return Move(ret);
187 }
188 
189 } // namespace gl
190 
191 } /* namespace mozilla */
192