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