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