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