Coverage Report

Created: 2018-09-25 14:53

/src/mozilla-central/gfx/gl/GLScreenBuffer.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 "GLScreenBuffer.h"
7
8
#include <cstring>
9
#include "CompositorTypes.h"
10
#include "gfxPrefs.h"
11
#include "GLContext.h"
12
#include "GLBlitHelper.h"
13
#include "GLReadTexImageHelper.h"
14
#include "SharedSurfaceEGL.h"
15
#include "SharedSurfaceGL.h"
16
#include "ScopedGLHelpers.h"
17
#include "gfx2DGlue.h"
18
#include "../layers/ipc/ShadowLayers.h"
19
#include "mozilla/layers/TextureForwarder.h"
20
#include "mozilla/layers/TextureClientSharedSurface.h"
21
22
#ifdef XP_WIN
23
#include "SharedSurfaceANGLE.h"         // for SurfaceFactory_ANGLEShareHandle
24
#include "SharedSurfaceD3D11Interop.h"  // for SurfaceFactory_D3D11Interop
25
#include "mozilla/gfx/DeviceManagerDx.h"
26
#endif
27
28
#ifdef XP_MACOSX
29
#include "SharedSurfaceIO.h"
30
#endif
31
32
#ifdef MOZ_X11
33
#include "GLXLibrary.h"
34
#include "SharedSurfaceGLX.h"
35
#endif
36
37
namespace mozilla {
38
namespace gl {
39
40
using gfx::SurfaceFormat;
41
42
UniquePtr<GLScreenBuffer>
43
GLScreenBuffer::Create(GLContext* gl,
44
                       const gfx::IntSize& size,
45
                       const SurfaceCaps& caps)
46
0
{
47
0
    UniquePtr<GLScreenBuffer> ret;
48
0
    if (caps.antialias &&
49
0
        !gl->IsSupported(GLFeature::framebuffer_multisample))
50
0
    {
51
0
        return ret;
52
0
    }
53
0
54
0
    layers::TextureFlags flags = layers::TextureFlags::ORIGIN_BOTTOM_LEFT;
55
0
    if (!caps.premultAlpha) {
56
0
        flags |= layers::TextureFlags::NON_PREMULTIPLIED;
57
0
    }
58
0
59
0
    UniquePtr<SurfaceFactory> factory = MakeUnique<SurfaceFactory_Basic>(gl, caps, flags);
60
0
61
0
    ret.reset( new GLScreenBuffer(gl, caps, std::move(factory)) );
62
0
    return ret;
63
0
}
64
65
/* static */ UniquePtr<SurfaceFactory>
66
GLScreenBuffer::CreateFactory(GLContext* gl,
67
                              const SurfaceCaps& caps,
68
                              KnowsCompositor* compositorConnection,
69
                              const layers::TextureFlags& flags)
70
0
{
71
0
    LayersIPCChannel* ipcChannel = compositorConnection->GetTextureForwarder();
72
0
    const layers::LayersBackend backend = compositorConnection->GetCompositorBackendType();
73
0
    const bool useANGLE = compositorConnection->GetCompositorUseANGLE();
74
0
75
0
    const bool useGl = !gfxPrefs::WebGLForceLayersReadback() &&
76
0
                       (backend == layers::LayersBackend::LAYERS_OPENGL ||
77
0
                       (backend == layers::LayersBackend::LAYERS_WR && !useANGLE));
78
0
    const bool useD3D = !gfxPrefs::WebGLForceLayersReadback() &&
79
0
                        (backend == layers::LayersBackend::LAYERS_D3D11 ||
80
0
                        (backend == layers::LayersBackend::LAYERS_WR && useANGLE));
81
0
82
0
    UniquePtr<SurfaceFactory> factory = nullptr;
83
0
    if (useGl) {
84
#if defined(XP_MACOSX)
85
        factory = SurfaceFactory_IOSurface::Create(gl, caps, ipcChannel, flags);
86
#elif defined(MOZ_X11)
87
0
        if (sGLXLibrary.UseTextureFromPixmap())
88
0
            factory = SurfaceFactory_GLXDrawable::Create(gl, caps, ipcChannel, flags);
89
#elif defined(MOZ_WIDGET_UIKIT)
90
        factory = MakeUnique<SurfaceFactory_GLTexture>(mGLContext, caps, ipcChannel, mFlags);
91
#elif defined(MOZ_WIDGET_ANDROID)
92
        if (XRE_IsParentProcess() && !gfxPrefs::WebGLSurfaceTextureEnabled()) {
93
            factory = SurfaceFactory_EGLImage::Create(gl, caps, ipcChannel, flags);
94
        } else {
95
            factory = SurfaceFactory_SurfaceTexture::Create(gl, caps, ipcChannel, flags);
96
        }
97
#else
98
        if (gl->GetContextType() == GLContextType::EGL) {
99
            if (XRE_IsParentProcess()) {
100
                factory = SurfaceFactory_EGLImage::Create(gl, caps, ipcChannel, flags);
101
            }
102
        }
103
#endif
104
0
    } else if (useD3D) {
105
#ifdef XP_WIN
106
        // Enable surface sharing only if ANGLE and compositing devices
107
        // are both WARP or both not WARP
108
        gfx::DeviceManagerDx* dm = gfx::DeviceManagerDx::Get();
109
        if (gl->IsANGLE() &&
110
            (gl->IsWARP() == dm->IsWARP()) &&
111
             dm->TextureSharingWorks())
112
        {
113
            factory = SurfaceFactory_ANGLEShareHandle::Create(gl, caps, ipcChannel, flags);
114
        }
115
116
        if (!factory && gfxPrefs::WebGLDXGLEnabled()) {
117
            factory = SurfaceFactory_D3D11Interop::Create(gl, caps, ipcChannel, flags);
118
        }
119
#endif
120
    }
121
0
122
0
#ifdef MOZ_X11
123
0
    if (!factory && sGLXLibrary.UseTextureFromPixmap()) {
124
0
        factory = SurfaceFactory_GLXDrawable::Create(gl, caps, ipcChannel, flags);
125
0
    }
126
0
#endif
127
0
128
0
    return factory;
129
0
}
130
131
GLScreenBuffer::GLScreenBuffer(GLContext* gl,
132
                               const SurfaceCaps& caps,
133
                               UniquePtr<SurfaceFactory> factory)
134
    : mGL(gl)
135
    , mCaps(caps)
136
    , mFactory(std::move(factory))
137
    , mNeedsBlit(true)
138
    , mUserReadBufferMode(LOCAL_GL_BACK)
139
    , mUserDrawBufferMode(LOCAL_GL_BACK)
140
    , mUserDrawFB(0)
141
    , mUserReadFB(0)
142
    , mInternalDrawFB(0)
143
    , mInternalReadFB(0)
144
#ifdef DEBUG
145
    , mInInternalMode_DrawFB(true)
146
    , mInInternalMode_ReadFB(true)
147
#endif
148
0
{ }
149
150
GLScreenBuffer::~GLScreenBuffer()
151
0
{
152
0
    mFactory = nullptr;
153
0
    mDraw = nullptr;
154
0
    mRead = nullptr;
155
0
156
0
    if (!mBack)
157
0
        return;
158
0
159
0
    // Detach mBack cleanly.
160
0
    mBack->Surf()->ProducerRelease();
161
0
}
162
163
void
164
GLScreenBuffer::BindAsFramebuffer(GLContext* const gl, GLenum target) const
165
0
{
166
0
    GLuint drawFB = DrawFB();
167
0
    GLuint readFB = ReadFB();
168
0
169
0
    if (!gl->IsSupported(GLFeature::split_framebuffer)) {
170
0
        MOZ_ASSERT(drawFB == readFB);
171
0
        gl->raw_fBindFramebuffer(target, readFB);
172
0
        return;
173
0
    }
174
0
175
0
    switch (target) {
176
0
    case LOCAL_GL_FRAMEBUFFER:
177
0
        gl->raw_fBindFramebuffer(LOCAL_GL_DRAW_FRAMEBUFFER_EXT, drawFB);
178
0
        gl->raw_fBindFramebuffer(LOCAL_GL_READ_FRAMEBUFFER_EXT, readFB);
179
0
        break;
180
0
181
0
    case LOCAL_GL_DRAW_FRAMEBUFFER_EXT:
182
0
        gl->raw_fBindFramebuffer(LOCAL_GL_DRAW_FRAMEBUFFER_EXT, drawFB);
183
0
        break;
184
0
185
0
    case LOCAL_GL_READ_FRAMEBUFFER_EXT:
186
0
        gl->raw_fBindFramebuffer(LOCAL_GL_READ_FRAMEBUFFER_EXT, readFB);
187
0
        break;
188
0
189
0
    default:
190
0
        MOZ_CRASH("GFX: Bad `target` for BindFramebuffer.");
191
0
    }
192
0
}
193
194
void
195
GLScreenBuffer::BindFB(GLuint fb)
196
0
{
197
0
    GLuint drawFB = DrawFB();
198
0
    GLuint readFB = ReadFB();
199
0
200
0
    mUserDrawFB = fb;
201
0
    mUserReadFB = fb;
202
0
    mInternalDrawFB = (fb == 0) ? drawFB : fb;
203
0
    mInternalReadFB = (fb == 0) ? readFB : fb;
204
0
205
0
    if (mInternalDrawFB == mInternalReadFB) {
206
0
        mGL->raw_fBindFramebuffer(LOCAL_GL_FRAMEBUFFER, mInternalDrawFB);
207
0
    } else {
208
0
        MOZ_ASSERT(mGL->IsSupported(GLFeature::split_framebuffer));
209
0
        mGL->raw_fBindFramebuffer(LOCAL_GL_DRAW_FRAMEBUFFER_EXT, mInternalDrawFB);
210
0
        mGL->raw_fBindFramebuffer(LOCAL_GL_READ_FRAMEBUFFER_EXT, mInternalReadFB);
211
0
    }
212
0
213
#ifdef DEBUG
214
    mInInternalMode_DrawFB = false;
215
    mInInternalMode_ReadFB = false;
216
#endif
217
}
218
219
void
220
GLScreenBuffer::BindDrawFB(GLuint fb)
221
0
{
222
0
    MOZ_ASSERT(mGL->IsSupported(GLFeature::split_framebuffer));
223
0
224
0
    GLuint drawFB = DrawFB();
225
0
    mUserDrawFB = fb;
226
0
    mInternalDrawFB = (fb == 0) ? drawFB : fb;
227
0
228
0
    mGL->raw_fBindFramebuffer(LOCAL_GL_DRAW_FRAMEBUFFER_EXT, mInternalDrawFB);
229
0
230
#ifdef DEBUG
231
    mInInternalMode_DrawFB = false;
232
#endif
233
}
234
235
void
236
GLScreenBuffer::BindReadFB(GLuint fb)
237
0
{
238
0
    MOZ_ASSERT(mGL->IsSupported(GLFeature::split_framebuffer));
239
0
240
0
    GLuint readFB = ReadFB();
241
0
    mUserReadFB = fb;
242
0
    mInternalReadFB = (fb == 0) ? readFB : fb;
243
0
244
0
    mGL->raw_fBindFramebuffer(LOCAL_GL_READ_FRAMEBUFFER_EXT, mInternalReadFB);
245
0
246
#ifdef DEBUG
247
    mInInternalMode_ReadFB = false;
248
#endif
249
}
250
251
void
252
GLScreenBuffer::BindFB_Internal(GLuint fb)
253
0
{
254
0
    mInternalDrawFB = mUserDrawFB = fb;
255
0
    mInternalReadFB = mUserReadFB = fb;
256
0
    mGL->raw_fBindFramebuffer(LOCAL_GL_FRAMEBUFFER, mInternalDrawFB);
257
0
258
#ifdef DEBUG
259
    mInInternalMode_DrawFB = true;
260
    mInInternalMode_ReadFB = true;
261
#endif
262
}
263
264
void
265
GLScreenBuffer::BindDrawFB_Internal(GLuint fb)
266
0
{
267
0
    MOZ_ASSERT(mGL->IsSupported(GLFeature::split_framebuffer));
268
0
269
0
    mInternalDrawFB = mUserDrawFB = fb;
270
0
    mGL->raw_fBindFramebuffer(LOCAL_GL_DRAW_FRAMEBUFFER_EXT, mInternalDrawFB);
271
0
272
#ifdef DEBUG
273
    mInInternalMode_DrawFB = true;
274
#endif
275
}
276
277
void
278
GLScreenBuffer::BindReadFB_Internal(GLuint fb)
279
0
{
280
0
    MOZ_ASSERT(mGL->IsSupported(GLFeature::split_framebuffer));
281
0
282
0
    mInternalReadFB = mUserReadFB = fb;
283
0
    mGL->raw_fBindFramebuffer(LOCAL_GL_READ_FRAMEBUFFER_EXT, mInternalReadFB);
284
0
285
#ifdef DEBUG
286
    mInInternalMode_ReadFB = true;
287
#endif
288
}
289
290
291
GLuint
292
GLScreenBuffer::GetDrawFB() const
293
0
{
294
#ifdef DEBUG
295
    MOZ_ASSERT(mGL->IsCurrent());
296
    MOZ_ASSERT(!mInInternalMode_DrawFB);
297
298
    // Don't need a branch here, because:
299
    // LOCAL_GL_DRAW_FRAMEBUFFER_BINDING_EXT == LOCAL_GL_FRAMEBUFFER_BINDING == 0x8CA6
300
    // We use raw_ here because this is debug code and we need to see what
301
    // the driver thinks.
302
    GLuint actual = 0;
303
    mGL->raw_fGetIntegerv(LOCAL_GL_DRAW_FRAMEBUFFER_BINDING_EXT, (GLint*)&actual);
304
305
    GLuint predicted = mInternalDrawFB;
306
    if (predicted != actual) {
307
        printf_stderr("Misprediction: Bound draw FB predicted: %d. Was: %d.\n",
308
                      predicted, actual);
309
        MOZ_ASSERT(false, "Draw FB binding misprediction!");
310
    }
311
#endif
312
313
0
    return mUserDrawFB;
314
0
}
315
316
GLuint
317
GLScreenBuffer::GetReadFB() const
318
0
{
319
#ifdef DEBUG
320
    MOZ_ASSERT(mGL->IsCurrent());
321
    MOZ_ASSERT(!mInInternalMode_ReadFB);
322
323
    // We use raw_ here because this is debug code and we need to see what
324
    // the driver thinks.
325
    GLuint actual = 0;
326
    if (mGL->IsSupported(GLFeature::split_framebuffer))
327
        mGL->raw_fGetIntegerv(LOCAL_GL_READ_FRAMEBUFFER_BINDING_EXT, (GLint*)&actual);
328
    else
329
        mGL->raw_fGetIntegerv(LOCAL_GL_FRAMEBUFFER_BINDING, (GLint*)&actual);
330
331
    GLuint predicted = mInternalReadFB;
332
    if (predicted != actual) {
333
        printf_stderr("Misprediction: Bound read FB predicted: %d. Was: %d.\n",
334
                      predicted, actual);
335
        MOZ_ASSERT(false, "Read FB binding misprediction!");
336
    }
337
#endif
338
339
0
    return mUserReadFB;
340
0
}
341
342
GLuint
343
GLScreenBuffer::GetFB() const
344
0
{
345
0
    MOZ_ASSERT(GetDrawFB() == GetReadFB());
346
0
    return GetDrawFB();
347
0
}
348
349
350
void
351
GLScreenBuffer::DeletingFB(GLuint fb)
352
0
{
353
0
    if (fb == mInternalDrawFB) {
354
0
        mInternalDrawFB = 0;
355
0
        mUserDrawFB = 0;
356
0
    }
357
0
    if (fb == mInternalReadFB) {
358
0
        mInternalReadFB = 0;
359
0
        mUserReadFB = 0;
360
0
    }
361
0
}
362
363
364
void
365
GLScreenBuffer::AfterDrawCall()
366
0
{
367
0
    if (mUserDrawFB != 0)
368
0
        return;
369
0
370
0
    RequireBlit();
371
0
}
372
373
void
374
GLScreenBuffer::BeforeReadCall()
375
0
{
376
0
    if (mUserReadFB != 0)
377
0
        return;
378
0
379
0
    AssureBlitted();
380
0
}
381
382
bool
383
GLScreenBuffer::CopyTexImage2D(GLenum target, GLint level, GLenum internalformat, GLint x,
384
                               GLint y, GLsizei width, GLsizei height, GLint border)
385
0
{
386
0
    SharedSurface* surf;
387
0
    if (GetReadFB() == 0) {
388
0
        surf = SharedSurf();
389
0
    } else {
390
0
        surf = mGL->mFBOMapping[GetReadFB()];
391
0
    }
392
0
    if (surf) {
393
0
        return surf->CopyTexImage2D(target, level, internalformat,  x, y, width, height, border);
394
0
    }
395
0
396
0
    return false;
397
0
}
398
399
bool
400
GLScreenBuffer::ReadPixels(GLint x, GLint y,
401
                           GLsizei width, GLsizei height,
402
                           GLenum format, GLenum type,
403
                           GLvoid* pixels)
404
0
{
405
0
    // If the currently bound framebuffer is backed by a SharedSurface
406
0
    // then it might want to override how we read pixel data from it.
407
0
    // This is normally only the default framebuffer, but we can also
408
0
    // have SharedSurfaces bound to other framebuffers when doing
409
0
    // readback for BasicLayers.
410
0
    SharedSurface* surf;
411
0
    if (GetReadFB() == 0) {
412
0
        surf = SharedSurf();
413
0
    } else {
414
0
        surf = mGL->mFBOMapping[GetReadFB()];
415
0
    }
416
0
    if (surf) {
417
0
        return surf->ReadPixels(x, y, width, height, format, type, pixels);
418
0
    }
419
0
420
0
    return false;
421
0
}
422
423
void
424
GLScreenBuffer::RequireBlit()
425
0
{
426
0
    mNeedsBlit = true;
427
0
}
428
429
void
430
GLScreenBuffer::AssureBlitted()
431
0
{
432
0
    if (!mNeedsBlit)
433
0
        return;
434
0
435
0
    if (mDraw) {
436
0
        GLuint drawFB = DrawFB();
437
0
        GLuint readFB = ReadFB();
438
0
439
0
        MOZ_ASSERT(drawFB != 0);
440
0
        MOZ_ASSERT(drawFB != readFB);
441
0
        MOZ_ASSERT(mGL->IsSupported(GLFeature::split_framebuffer));
442
0
        MOZ_ASSERT(mDraw->mSize == mRead->Size());
443
0
444
0
        ScopedBindFramebuffer boundFB(mGL);
445
0
        ScopedGLState scissor(mGL, LOCAL_GL_SCISSOR_TEST, false);
446
0
447
0
        BindReadFB_Internal(drawFB);
448
0
        BindDrawFB_Internal(readFB);
449
0
450
0
        if (mGL->IsSupported(GLFeature::framebuffer_blit)) {
451
0
            const gfx::IntSize&  srcSize = mDraw->mSize;
452
0
            const gfx::IntSize& destSize = mRead->Size();
453
0
454
0
            mGL->raw_fBlitFramebuffer(0, 0,  srcSize.width,  srcSize.height,
455
0
                                      0, 0, destSize.width, destSize.height,
456
0
                                      LOCAL_GL_COLOR_BUFFER_BIT,
457
0
                                      LOCAL_GL_NEAREST);
458
0
        } else if (mGL->IsExtensionSupported(GLContext::APPLE_framebuffer_multisample)) {
459
0
            mGL->fResolveMultisampleFramebufferAPPLE();
460
0
        } else {
461
0
            MOZ_CRASH("GFX: No available blit methods.");
462
0
        }
463
0
        // Done!
464
0
    }
465
0
466
0
    mNeedsBlit = false;
467
0
}
468
469
void
470
GLScreenBuffer::Morph(UniquePtr<SurfaceFactory> newFactory)
471
0
{
472
0
    MOZ_RELEASE_ASSERT(newFactory, "newFactory must not be null");
473
0
    mFactory = std::move(newFactory);
474
0
}
475
476
bool
477
GLScreenBuffer::Attach(SharedSurface* surf, const gfx::IntSize& size)
478
0
{
479
0
    ScopedBindFramebuffer autoFB(mGL);
480
0
481
0
    const bool readNeedsUnlock = (mRead && SharedSurf());
482
0
    if (readNeedsUnlock) {
483
0
        SharedSurf()->UnlockProd();
484
0
    }
485
0
486
0
    surf->LockProd();
487
0
488
0
    if (mRead &&
489
0
        surf->mAttachType == SharedSurf()->mAttachType &&
490
0
        size == Size())
491
0
    {
492
0
        // Same size, same type, ready for reuse!
493
0
        mRead->Attach(surf);
494
0
    } else {
495
0
        // Else something changed, so resize:
496
0
        UniquePtr<DrawBuffer> draw;
497
0
        bool drawOk = true;
498
0
499
0
        /* Don't change out the draw buffer unless we resize. In the
500
0
         * preserveDrawingBuffer:true case, prior contents of the buffer must
501
0
         * be retained. If we're using a draw buffer, it's an MSAA buffer, so
502
0
         * even if we copy the previous frame into the (single-sampled) read
503
0
         * buffer, if we need to re-resolve from draw to read (as triggered by
504
0
         * drawing), we'll need the old MSAA content to still be in the draw
505
0
         * buffer.
506
0
         */
507
0
        if (!mDraw || size != Size())
508
0
            drawOk = CreateDraw(size, &draw);  // Can be null.
509
0
510
0
        UniquePtr<ReadBuffer> read = CreateRead(surf);
511
0
        bool readOk = !!read;
512
0
513
0
        if (!drawOk || !readOk) {
514
0
            surf->UnlockProd();
515
0
            if (readNeedsUnlock) {
516
0
                SharedSurf()->LockProd();
517
0
            }
518
0
            return false;
519
0
        }
520
0
521
0
        if (draw)
522
0
            mDraw = std::move(draw);
523
0
524
0
        mRead = std::move(read);
525
0
    }
526
0
527
0
    // Check that we're all set up.
528
0
    MOZ_ASSERT(SharedSurf() == surf);
529
0
530
0
    // Update the ReadBuffer mode.
531
0
    if (mGL->IsSupported(gl::GLFeature::read_buffer)) {
532
0
        BindFB(0);
533
0
        mRead->SetReadBuffer(mUserReadBufferMode);
534
0
    }
535
0
536
0
    // Update the DrawBuffer mode.
537
0
    if (mGL->IsSupported(gl::GLFeature::draw_buffers)) {
538
0
        BindFB(0);
539
0
        SetDrawBuffer(mUserDrawBufferMode);
540
0
    }
541
0
542
0
    RequireBlit();
543
0
544
0
    return true;
545
0
}
546
547
bool
548
GLScreenBuffer::Swap(const gfx::IntSize& size)
549
0
{
550
0
    RefPtr<SharedSurfaceTextureClient> newBack = mFactory->NewTexClient(size);
551
0
    if (!newBack)
552
0
        return false;
553
0
554
0
    // In the case of DXGL interop, the new surface needs to be acquired before
555
0
    // it is attached so that the interop surface is locked, which populates
556
0
    // the GL renderbuffer. This results in the renderbuffer being ready and
557
0
    // attachment to framebuffer succeeds in Attach() call.
558
0
    newBack->Surf()->ProducerAcquire();
559
0
560
0
    if (!Attach(newBack->Surf(), size)) {
561
0
        newBack->Surf()->ProducerRelease();
562
0
        return false;
563
0
    }
564
0
    // Attach was successful.
565
0
566
0
    mFront = mBack;
567
0
    mBack = newBack;
568
0
569
0
    if (ShouldPreserveBuffer() &&
570
0
        mFront &&
571
0
        mBack &&
572
0
        !mDraw)
573
0
    {
574
0
        auto src  = mFront->Surf();
575
0
        auto dest = mBack->Surf();
576
0
577
0
        //uint32_t srcPixel = ReadPixel(src);
578
0
        //uint32_t destPixel = ReadPixel(dest);
579
0
        //printf_stderr("Before: src: 0x%08x, dest: 0x%08x\n", srcPixel, destPixel);
580
#ifdef DEBUG
581
        GLContext::LocalErrorScope errorScope(*mGL);
582
#endif
583
584
0
        SharedSurface::ProdCopy(src, dest, mFactory.get());
585
0
586
#ifdef DEBUG
587
        MOZ_ASSERT(!errorScope.GetError());
588
#endif
589
590
0
        //srcPixel = ReadPixel(src);
591
0
        //destPixel = ReadPixel(dest);
592
0
        //printf_stderr("After: src: 0x%08x, dest: 0x%08x\n", srcPixel, destPixel);
593
0
    }
594
0
595
0
    // XXX: We would prefer to fence earlier on platforms that don't need
596
0
    // the full ProducerAcquire/ProducerRelease semantics, so that the fence
597
0
    // doesn't include the copy operation. Unfortunately, the current API
598
0
    // doesn't expose a good way to do that.
599
0
    if (mFront) {
600
0
        mFront->Surf()->ProducerRelease();
601
0
    }
602
0
603
0
    return true;
604
0
}
605
606
bool
607
GLScreenBuffer::PublishFrame(const gfx::IntSize& size)
608
0
{
609
0
    AssureBlitted();
610
0
611
0
    bool good = Swap(size);
612
0
    return good;
613
0
}
614
615
bool
616
GLScreenBuffer::Resize(const gfx::IntSize& size)
617
0
{
618
0
    RefPtr<SharedSurfaceTextureClient> newBack = mFactory->NewTexClient(size);
619
0
    if (!newBack)
620
0
        return false;
621
0
622
0
    if (!Attach(newBack->Surf(), size))
623
0
        return false;
624
0
625
0
    if (mBack)
626
0
        mBack->Surf()->ProducerRelease();
627
0
628
0
    mBack = newBack;
629
0
630
0
    mBack->Surf()->ProducerAcquire();
631
0
632
0
    return true;
633
0
}
634
635
bool
636
GLScreenBuffer::CreateDraw(const gfx::IntSize& size,
637
                           UniquePtr<DrawBuffer>* out_buffer)
638
0
{
639
0
    GLContext* gl = mFactory->mGL;
640
0
    const GLFormats& formats = mFactory->mFormats;
641
0
    const SurfaceCaps& caps = mFactory->DrawCaps();
642
0
643
0
    return DrawBuffer::Create(gl, caps, formats, size, out_buffer);
644
0
}
645
646
UniquePtr<ReadBuffer>
647
GLScreenBuffer::CreateRead(SharedSurface* surf)
648
0
{
649
0
    GLContext* gl = mFactory->mGL;
650
0
    const GLFormats& formats = mFactory->mFormats;
651
0
    const SurfaceCaps& caps = mFactory->ReadCaps();
652
0
653
0
    return ReadBuffer::Create(gl, caps, formats, surf);
654
0
}
655
656
void
657
GLScreenBuffer::SetDrawBuffer(GLenum mode)
658
0
{
659
0
    MOZ_ASSERT(mGL->IsSupported(gl::GLFeature::draw_buffers));
660
0
    MOZ_ASSERT(GetDrawFB() == 0);
661
0
662
0
    if (!mGL->IsSupported(GLFeature::draw_buffers))
663
0
        return;
664
0
665
0
    mUserDrawBufferMode = mode;
666
0
667
0
    GLuint fb = mDraw ? mDraw->mFB : mRead->mFB;
668
0
    GLenum internalMode;
669
0
670
0
    switch (mode) {
671
0
    case LOCAL_GL_BACK:
672
0
        internalMode = (fb == 0) ? LOCAL_GL_BACK
673
0
                                 : LOCAL_GL_COLOR_ATTACHMENT0;
674
0
        break;
675
0
676
0
    case LOCAL_GL_NONE:
677
0
        internalMode = LOCAL_GL_NONE;
678
0
        break;
679
0
680
0
    default:
681
0
        MOZ_CRASH("GFX: Bad value.");
682
0
    }
683
0
684
0
    mGL->MakeCurrent();
685
0
    mGL->fDrawBuffers(1, &internalMode);
686
0
}
687
688
void
689
GLScreenBuffer::SetReadBuffer(GLenum mode)
690
0
{
691
0
    MOZ_ASSERT(mGL->IsSupported(gl::GLFeature::read_buffer));
692
0
    MOZ_ASSERT(GetReadFB() == 0);
693
0
694
0
    mUserReadBufferMode = mode;
695
0
    mRead->SetReadBuffer(mUserReadBufferMode);
696
0
}
697
698
bool
699
GLScreenBuffer::IsDrawFramebufferDefault() const
700
0
{
701
0
    if (!mDraw)
702
0
        return IsReadFramebufferDefault();
703
0
    return mDraw->mFB == 0;
704
0
}
705
706
bool
707
GLScreenBuffer::IsReadFramebufferDefault() const
708
0
{
709
0
    return SharedSurf()->mAttachType == AttachmentType::Screen;
710
0
}
711
712
uint32_t
713
GLScreenBuffer::DepthBits() const
714
0
{
715
0
    const GLFormats& formats = mFactory->mFormats;
716
0
717
0
    if (formats.depth == LOCAL_GL_DEPTH_COMPONENT16)
718
0
        return 16;
719
0
720
0
    return 24;
721
0
}
722
723
////////////////////////////////////////////////////////////////////////
724
// Utils
725
726
static void
727
RenderbufferStorageBySamples(GLContext* aGL, GLsizei aSamples,
728
                             GLenum aInternalFormat, const gfx::IntSize& aSize)
729
0
{
730
0
    if (aSamples) {
731
0
        aGL->fRenderbufferStorageMultisample(LOCAL_GL_RENDERBUFFER,
732
0
                                             aSamples,
733
0
                                             aInternalFormat,
734
0
                                             aSize.width, aSize.height);
735
0
    } else {
736
0
        aGL->fRenderbufferStorage(LOCAL_GL_RENDERBUFFER,
737
0
                                  aInternalFormat,
738
0
                                  aSize.width, aSize.height);
739
0
    }
740
0
}
741
742
static GLuint
743
CreateRenderbuffer(GLContext* aGL, GLenum aFormat, GLsizei aSamples,
744
                   const gfx::IntSize& aSize)
745
0
{
746
0
    GLuint rb = 0;
747
0
    aGL->fGenRenderbuffers(1, &rb);
748
0
    ScopedBindRenderbuffer autoRB(aGL, rb);
749
0
750
0
    RenderbufferStorageBySamples(aGL, aSamples, aFormat, aSize);
751
0
752
0
    return rb;
753
0
}
754
755
static void
756
CreateRenderbuffersForOffscreen(GLContext* aGL, const GLFormats& aFormats,
757
                                const gfx::IntSize& aSize, bool aMultisample,
758
                                GLuint* aColorMSRB, GLuint* aDepthRB,
759
                                GLuint* aStencilRB)
760
0
{
761
0
    GLsizei samples = aMultisample ? aFormats.samples : 0;
762
0
    if (aColorMSRB) {
763
0
        MOZ_ASSERT(aFormats.samples > 0);
764
0
        MOZ_ASSERT(aFormats.color_rbFormat);
765
0
766
0
        GLenum colorFormat = aFormats.color_rbFormat;
767
0
        if (aGL->IsANGLE()) {
768
0
            MOZ_ASSERT(colorFormat == LOCAL_GL_RGBA8);
769
0
            colorFormat = LOCAL_GL_BGRA8_EXT;
770
0
        }
771
0
772
0
        *aColorMSRB = CreateRenderbuffer(aGL, colorFormat, samples, aSize);
773
0
    }
774
0
775
0
    if (aDepthRB &&
776
0
        aStencilRB &&
777
0
        aFormats.depthStencil)
778
0
    {
779
0
        *aDepthRB = CreateRenderbuffer(aGL, aFormats.depthStencil, samples, aSize);
780
0
        *aStencilRB = *aDepthRB;
781
0
    } else {
782
0
        if (aDepthRB) {
783
0
            MOZ_ASSERT(aFormats.depth);
784
0
785
0
            *aDepthRB = CreateRenderbuffer(aGL, aFormats.depth, samples, aSize);
786
0
        }
787
0
788
0
        if (aStencilRB) {
789
0
            MOZ_ASSERT(aFormats.stencil);
790
0
791
0
            *aStencilRB = CreateRenderbuffer(aGL, aFormats.stencil, samples, aSize);
792
0
        }
793
0
    }
794
0
}
795
796
////////////////////////////////////////////////////////////////////////
797
// DrawBuffer
798
799
bool
800
DrawBuffer::Create(GLContext* const gl,
801
                   const SurfaceCaps& caps,
802
                   const GLFormats& formats,
803
                   const gfx::IntSize& size,
804
                   UniquePtr<DrawBuffer>* out_buffer)
805
0
{
806
0
    MOZ_ASSERT(out_buffer);
807
0
    *out_buffer = nullptr;
808
0
809
0
    if (!caps.color) {
810
0
        MOZ_ASSERT(!caps.alpha && !caps.depth && !caps.stencil);
811
0
812
0
        // Nothing is needed.
813
0
        return true;
814
0
    }
815
0
816
0
    if (caps.antialias) {
817
0
        if (formats.samples == 0)
818
0
            return false; // Can't create it.
819
0
820
0
        MOZ_ASSERT(uint32_t(formats.samples) <= gl->MaxSamples());
821
0
    }
822
0
823
0
    GLuint colorMSRB = 0;
824
0
    GLuint depthRB   = 0;
825
0
    GLuint stencilRB = 0;
826
0
827
0
    GLuint* pColorMSRB = caps.antialias ? &colorMSRB : nullptr;
828
0
    GLuint* pDepthRB   = caps.depth     ? &depthRB   : nullptr;
829
0
    GLuint* pStencilRB = caps.stencil   ? &stencilRB : nullptr;
830
0
831
0
    if (!formats.color_rbFormat)
832
0
        pColorMSRB = nullptr;
833
0
834
0
    if (pDepthRB && pStencilRB) {
835
0
        if (!formats.depth && !formats.depthStencil)
836
0
            pDepthRB = nullptr;
837
0
838
0
        if (!formats.stencil && !formats.depthStencil)
839
0
            pStencilRB = nullptr;
840
0
    } else {
841
0
        if (!formats.depth)
842
0
            pDepthRB = nullptr;
843
0
844
0
        if (!formats.stencil)
845
0
            pStencilRB = nullptr;
846
0
    }
847
0
848
0
    GLContext::LocalErrorScope localError(*gl);
849
0
850
0
    CreateRenderbuffersForOffscreen(gl, formats, size, caps.antialias,
851
0
                                    pColorMSRB, pDepthRB, pStencilRB);
852
0
853
0
    GLuint fb = 0;
854
0
    gl->fGenFramebuffers(1, &fb);
855
0
    gl->AttachBuffersToFB(0, colorMSRB, depthRB, stencilRB, fb);
856
0
857
0
    const GLsizei samples = formats.samples;
858
0
    UniquePtr<DrawBuffer> ret( new DrawBuffer(gl, size, samples, fb, colorMSRB,
859
0
                                              depthRB, stencilRB) );
860
0
861
0
    GLenum err = localError.GetError();
862
0
    MOZ_ASSERT_IF(err != LOCAL_GL_NO_ERROR, err == LOCAL_GL_OUT_OF_MEMORY);
863
0
    if (err || !gl->IsFramebufferComplete(fb))
864
0
        return false;
865
0
866
0
    *out_buffer = std::move(ret);
867
0
    return true;
868
0
}
869
870
DrawBuffer::~DrawBuffer()
871
0
{
872
0
    if (!mGL->MakeCurrent())
873
0
        return;
874
0
875
0
    GLuint fb = mFB;
876
0
    GLuint rbs[] = {
877
0
        mColorMSRB,
878
0
        mDepthRB,
879
0
        (mStencilRB != mDepthRB) ? mStencilRB : 0, // Don't double-delete DEPTH_STENCIL RBs.
880
0
    };
881
0
882
0
    mGL->fDeleteFramebuffers(1, &fb);
883
0
    mGL->fDeleteRenderbuffers(3, rbs);
884
0
}
885
886
////////////////////////////////////////////////////////////////////////
887
// ReadBuffer
888
889
UniquePtr<ReadBuffer>
890
ReadBuffer::Create(GLContext* gl,
891
                   const SurfaceCaps& caps,
892
                   const GLFormats& formats,
893
                   SharedSurface* surf)
894
0
{
895
0
    MOZ_ASSERT(surf);
896
0
897
0
    if (surf->mAttachType == AttachmentType::Screen) {
898
0
        // Don't need anything. Our read buffer will be the 'screen'.
899
0
        return UniquePtr<ReadBuffer>( new ReadBuffer(gl, 0, 0, 0,
900
0
                                                     surf) );
901
0
    }
902
0
903
0
    GLuint depthRB = 0;
904
0
    GLuint stencilRB = 0;
905
0
906
0
    GLuint* pDepthRB   = caps.depth   ? &depthRB   : nullptr;
907
0
    GLuint* pStencilRB = caps.stencil ? &stencilRB : nullptr;
908
0
909
0
    GLContext::LocalErrorScope localError(*gl);
910
0
911
0
    CreateRenderbuffersForOffscreen(gl, formats, surf->mSize, caps.antialias,
912
0
                                    nullptr, pDepthRB, pStencilRB);
913
0
914
0
    GLuint colorTex = 0;
915
0
    GLuint colorRB = 0;
916
0
    GLenum target = 0;
917
0
918
0
    switch (surf->mAttachType) {
919
0
    case AttachmentType::GLTexture:
920
0
        colorTex = surf->ProdTexture();
921
0
        target = surf->ProdTextureTarget();
922
0
        break;
923
0
    case AttachmentType::GLRenderbuffer:
924
0
        colorRB = surf->ProdRenderbuffer();
925
0
        break;
926
0
    default:
927
0
        MOZ_CRASH("GFX: Unknown attachment type, create?");
928
0
    }
929
0
    MOZ_ASSERT(colorTex || colorRB);
930
0
931
0
    GLuint fb = 0;
932
0
    gl->fGenFramebuffers(1, &fb);
933
0
    gl->AttachBuffersToFB(colorTex, colorRB, depthRB, stencilRB, fb, target);
934
0
    gl->mFBOMapping[fb] = surf;
935
0
936
0
    UniquePtr<ReadBuffer> ret( new ReadBuffer(gl, fb, depthRB,
937
0
                                              stencilRB, surf) );
938
0
939
0
    GLenum err = localError.GetError();
940
0
    MOZ_ASSERT_IF(err != LOCAL_GL_NO_ERROR, err == LOCAL_GL_OUT_OF_MEMORY);
941
0
    if (err)
942
0
        return nullptr;
943
0
944
0
    const bool needsAcquire = !surf->IsProducerAcquired();
945
0
    if (needsAcquire) {
946
0
        surf->ProducerReadAcquire();
947
0
    }
948
0
    const bool isComplete = gl->IsFramebufferComplete(fb);
949
0
    if (needsAcquire) {
950
0
        surf->ProducerReadRelease();
951
0
    }
952
0
953
0
    if (!isComplete)
954
0
        return nullptr;
955
0
956
0
    return ret;
957
0
}
958
959
ReadBuffer::~ReadBuffer()
960
0
{
961
0
    if (!mGL->MakeCurrent())
962
0
        return;
963
0
964
0
    GLuint fb = mFB;
965
0
    GLuint rbs[] = {
966
0
        mDepthRB,
967
0
        (mStencilRB != mDepthRB) ? mStencilRB : 0, // Don't double-delete DEPTH_STENCIL RBs.
968
0
    };
969
0
970
0
    mGL->fDeleteFramebuffers(1, &fb);
971
0
    mGL->fDeleteRenderbuffers(2, rbs);
972
0
973
0
    mGL->mFBOMapping.erase(mFB);
974
0
}
975
976
void
977
ReadBuffer::Attach(SharedSurface* surf)
978
0
{
979
0
    MOZ_ASSERT(surf && mSurf);
980
0
    MOZ_ASSERT(surf->mAttachType == mSurf->mAttachType);
981
0
    MOZ_ASSERT(surf->mSize == mSurf->mSize);
982
0
983
0
    // Nothing else is needed for AttachType Screen.
984
0
    if (surf->mAttachType != AttachmentType::Screen) {
985
0
        GLuint colorTex = 0;
986
0
        GLuint colorRB = 0;
987
0
        GLenum target = 0;
988
0
989
0
        switch (surf->mAttachType) {
990
0
        case AttachmentType::GLTexture:
991
0
            colorTex = surf->ProdTexture();
992
0
            target = surf->ProdTextureTarget();
993
0
            break;
994
0
        case AttachmentType::GLRenderbuffer:
995
0
            colorRB = surf->ProdRenderbuffer();
996
0
            break;
997
0
        default:
998
0
            MOZ_CRASH("GFX: Unknown attachment type, attach?");
999
0
        }
1000
0
1001
0
        mGL->AttachBuffersToFB(colorTex, colorRB, 0, 0, mFB, target);
1002
0
        mGL->mFBOMapping[mFB] = surf;
1003
0
        MOZ_ASSERT(mGL->IsFramebufferComplete(mFB));
1004
0
    }
1005
0
1006
0
    mSurf = surf;
1007
0
}
1008
1009
const gfx::IntSize&
1010
ReadBuffer::Size() const
1011
0
{
1012
0
    return mSurf->mSize;
1013
0
}
1014
1015
void
1016
ReadBuffer::SetReadBuffer(GLenum userMode) const
1017
0
{
1018
0
    if (!mGL->IsSupported(GLFeature::read_buffer))
1019
0
        return;
1020
0
1021
0
    GLenum internalMode;
1022
0
1023
0
    switch (userMode) {
1024
0
    case LOCAL_GL_BACK:
1025
0
    case LOCAL_GL_FRONT:
1026
0
        internalMode = (mFB == 0) ? userMode
1027
0
                                  : LOCAL_GL_COLOR_ATTACHMENT0;
1028
0
        break;
1029
0
1030
0
    case LOCAL_GL_NONE:
1031
0
        internalMode = LOCAL_GL_NONE;
1032
0
        break;
1033
0
1034
0
    default:
1035
0
        MOZ_CRASH("GFX: Bad value.");
1036
0
    }
1037
0
1038
0
    mGL->MakeCurrent();
1039
0
    mGL->fReadBuffer(internalMode);
1040
0
}
1041
1042
} /* namespace gl */
1043
} /* namespace mozilla */