Coverage Report

Created: 2018-09-25 14:53

/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 */