Coverage Report

Created: 2018-09-25 14:53

/src/mozilla-central/gfx/gl/SharedSurface.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 "SharedSurface.h"
7
8
#include "../2d/2D.h"
9
#include "GLBlitHelper.h"
10
#include "GLContext.h"
11
#include "GLReadTexImageHelper.h"
12
#include "GLScreenBuffer.h"
13
#include "nsThreadUtils.h"
14
#include "ScopedGLHelpers.h"
15
#include "SharedSurfaceGL.h"
16
#include "mozilla/layers/CompositorTypes.h"
17
#include "mozilla/layers/TextureClientSharedSurface.h"
18
#include "mozilla/layers/TextureForwarder.h"
19
#include "mozilla/Unused.h"
20
#include "VRManagerChild.h"
21
22
namespace mozilla {
23
namespace gl {
24
25
/*static*/ void
26
SharedSurface::ProdCopy(SharedSurface* src, SharedSurface* dest,
27
                        SurfaceFactory* factory)
28
0
{
29
0
    GLContext* gl = src->mGL;
30
0
31
0
    // If `src` begins locked, it must end locked, though we may
32
0
    // temporarily unlock it if we need to.
33
0
    MOZ_ASSERT((src == gl->GetLockedSurface()) == src->IsLocked());
34
0
35
0
    gl->MakeCurrent();
36
0
37
0
    if (src->mAttachType  == AttachmentType::Screen &&
38
0
        dest->mAttachType == AttachmentType::Screen)
39
0
    {
40
0
        // Here, we actually need to blit through a temp surface, so let's make one.
41
0
        UniquePtr<SharedSurface_Basic> tempSurf;
42
0
        tempSurf = SharedSurface_Basic::Create(gl, factory->mFormats, src->mSize,
43
0
                                               factory->mCaps.alpha);
44
0
45
0
        ProdCopy(src, tempSurf.get(), factory);
46
0
        ProdCopy(tempSurf.get(), dest, factory);
47
0
        return;
48
0
    }
49
0
50
0
    if (src->mAttachType == AttachmentType::Screen) {
51
0
        SharedSurface* origLocked = gl->GetLockedSurface();
52
0
        bool srcNeedsUnlock = false;
53
0
        bool origNeedsRelock = false;
54
0
        if (origLocked != src) {
55
0
            if (origLocked) {
56
0
                origLocked->UnlockProd();
57
0
                origNeedsRelock = true;
58
0
            }
59
0
60
0
            src->LockProd();
61
0
            srcNeedsUnlock = true;
62
0
        }
63
0
64
0
        if (dest->mAttachType == AttachmentType::GLTexture) {
65
0
            GLuint destTex = dest->ProdTexture();
66
0
            GLenum destTarget = dest->ProdTextureTarget();
67
0
68
0
            const ScopedBindFramebuffer bindFB(gl, 0);
69
0
70
0
            gl->BlitHelper()->BlitFramebufferToTexture(destTex,
71
0
                                                       src->mSize,
72
0
                                                       dest->mSize,
73
0
                                                       destTarget);
74
0
        } else if (dest->mAttachType == AttachmentType::GLRenderbuffer) {
75
0
            GLuint destRB = dest->ProdRenderbuffer();
76
0
            ScopedFramebufferForRenderbuffer destWrapper(gl, destRB);
77
0
78
0
            gl->BlitHelper()->BlitFramebufferToFramebuffer(0,
79
0
                                                           destWrapper.FB(),
80
0
                                                           src->mSize,
81
0
                                                           dest->mSize);
82
0
        } else {
83
0
            MOZ_CRASH("GFX: Unhandled dest->mAttachType 1.");
84
0
        }
85
0
86
0
        if (srcNeedsUnlock)
87
0
            src->UnlockProd();
88
0
89
0
        if (origNeedsRelock)
90
0
            origLocked->LockProd();
91
0
92
0
        return;
93
0
    }
94
0
95
0
    if (dest->mAttachType == AttachmentType::Screen) {
96
0
        SharedSurface* origLocked = gl->GetLockedSurface();
97
0
        bool destNeedsUnlock = false;
98
0
        bool origNeedsRelock = false;
99
0
        if (origLocked != dest) {
100
0
            if (origLocked) {
101
0
                origLocked->UnlockProd();
102
0
                origNeedsRelock = true;
103
0
            }
104
0
105
0
            dest->LockProd();
106
0
            destNeedsUnlock = true;
107
0
        }
108
0
109
0
        if (src->mAttachType == AttachmentType::GLTexture) {
110
0
            GLuint srcTex = src->ProdTexture();
111
0
            GLenum srcTarget = src->ProdTextureTarget();
112
0
113
0
            const ScopedBindFramebuffer bindFB(gl, 0);
114
0
115
0
            gl->BlitHelper()->BlitTextureToFramebuffer(srcTex,
116
0
                                                       src->mSize,
117
0
                                                       dest->mSize,
118
0
                                                       srcTarget);
119
0
        } else if (src->mAttachType == AttachmentType::GLRenderbuffer) {
120
0
            GLuint srcRB = src->ProdRenderbuffer();
121
0
            ScopedFramebufferForRenderbuffer srcWrapper(gl, srcRB);
122
0
123
0
            gl->BlitHelper()->BlitFramebufferToFramebuffer(srcWrapper.FB(),
124
0
                                                           0,
125
0
                                                           src->mSize,
126
0
                                                           dest->mSize);
127
0
        } else {
128
0
            MOZ_CRASH("GFX: Unhandled src->mAttachType 2.");
129
0
        }
130
0
131
0
        if (destNeedsUnlock)
132
0
            dest->UnlockProd();
133
0
134
0
        if (origNeedsRelock)
135
0
            origLocked->LockProd();
136
0
137
0
        return;
138
0
    }
139
0
140
0
    // Alright, done with cases involving Screen types.
141
0
    // Only {src,dest}x{texture,renderbuffer} left.
142
0
143
0
    if (src->mAttachType == AttachmentType::GLTexture) {
144
0
        GLuint srcTex = src->ProdTexture();
145
0
        GLenum srcTarget = src->ProdTextureTarget();
146
0
147
0
        if (dest->mAttachType == AttachmentType::GLTexture) {
148
0
            GLuint destTex = dest->ProdTexture();
149
0
            GLenum destTarget = dest->ProdTextureTarget();
150
0
151
0
            gl->BlitHelper()->BlitTextureToTexture(srcTex, destTex,
152
0
                                                   src->mSize, dest->mSize,
153
0
                                                   srcTarget, destTarget);
154
0
155
0
            return;
156
0
        }
157
0
158
0
        if (dest->mAttachType == AttachmentType::GLRenderbuffer) {
159
0
            GLuint destRB = dest->ProdRenderbuffer();
160
0
            ScopedFramebufferForRenderbuffer destWrapper(gl, destRB);
161
0
            const ScopedBindFramebuffer bindFB(gl, destWrapper.FB());
162
0
            gl->BlitHelper()->BlitTextureToFramebuffer(srcTex, src->mSize, dest->mSize,
163
0
                                                       srcTarget);
164
0
165
0
            return;
166
0
        }
167
0
168
0
        MOZ_CRASH("GFX: Unhandled dest->mAttachType 3.");
169
0
    }
170
0
171
0
    if (src->mAttachType == AttachmentType::GLRenderbuffer) {
172
0
        GLuint srcRB = src->ProdRenderbuffer();
173
0
        ScopedFramebufferForRenderbuffer srcWrapper(gl, srcRB);
174
0
175
0
        if (dest->mAttachType == AttachmentType::GLTexture) {
176
0
            GLuint destTex = dest->ProdTexture();
177
0
            GLenum destTarget = dest->ProdTextureTarget();
178
0
            const ScopedBindFramebuffer bindFB(gl, srcWrapper.FB());
179
0
180
0
            gl->BlitHelper()->BlitFramebufferToTexture(destTex, src->mSize, dest->mSize,
181
0
                                                       destTarget);
182
0
183
0
            return;
184
0
        }
185
0
186
0
        if (dest->mAttachType == AttachmentType::GLRenderbuffer) {
187
0
            GLuint destRB = dest->ProdRenderbuffer();
188
0
            ScopedFramebufferForRenderbuffer destWrapper(gl, destRB);
189
0
190
0
            gl->BlitHelper()->BlitFramebufferToFramebuffer(srcWrapper.FB(), destWrapper.FB(),
191
0
                                                           src->mSize, dest->mSize);
192
0
193
0
            return;
194
0
        }
195
0
196
0
        MOZ_CRASH("GFX: Unhandled dest->mAttachType 4.");
197
0
    }
198
0
199
0
    MOZ_CRASH("GFX: Unhandled src->mAttachType 5.");
200
0
}
201
202
////////////////////////////////////////////////////////////////////////
203
// SharedSurface
204
205
206
SharedSurface::SharedSurface(SharedSurfaceType type,
207
                             AttachmentType attachType,
208
                             GLContext* gl,
209
                             const gfx::IntSize& size,
210
                             bool hasAlpha,
211
                             bool canRecycle)
212
    : mType(type)
213
    , mAttachType(attachType)
214
    , mGL(gl)
215
    , mSize(size)
216
    , mHasAlpha(hasAlpha)
217
    , mCanRecycle(canRecycle)
218
    , mIsLocked(false)
219
    , mIsProducerAcquired(false)
220
0
{ }
221
222
0
SharedSurface::~SharedSurface() = default;
223
224
layers::TextureFlags
225
SharedSurface::GetTextureFlags() const
226
0
{
227
0
    return layers::TextureFlags::NO_FLAGS;
228
0
}
229
230
void
231
SharedSurface::LockProd()
232
0
{
233
0
    MOZ_ASSERT(!mIsLocked);
234
0
235
0
    LockProdImpl();
236
0
237
0
    mGL->LockSurface(this);
238
0
    mIsLocked = true;
239
0
}
240
241
void
242
SharedSurface::UnlockProd()
243
0
{
244
0
    if (!mIsLocked)
245
0
        return;
246
0
247
0
    UnlockProdImpl();
248
0
249
0
    mGL->UnlockSurface(this);
250
0
    mIsLocked = false;
251
0
}
252
253
////////////////////////////////////////////////////////////////////////
254
// SurfaceFactory
255
256
static void
257
ChooseBufferBits(const SurfaceCaps& caps,
258
                 SurfaceCaps* const out_drawCaps,
259
                 SurfaceCaps* const out_readCaps)
260
0
{
261
0
    MOZ_ASSERT(out_drawCaps);
262
0
    MOZ_ASSERT(out_readCaps);
263
0
264
0
    SurfaceCaps screenCaps;
265
0
266
0
    screenCaps.color = caps.color;
267
0
    screenCaps.alpha = caps.alpha;
268
0
    screenCaps.bpp16 = caps.bpp16;
269
0
270
0
    screenCaps.depth = caps.depth;
271
0
    screenCaps.stencil = caps.stencil;
272
0
273
0
    screenCaps.antialias = caps.antialias;
274
0
    screenCaps.preserve = caps.preserve;
275
0
276
0
    if (caps.antialias) {
277
0
        *out_drawCaps = screenCaps;
278
0
        out_readCaps->Clear();
279
0
280
0
        // Color caps need to be duplicated in readCaps.
281
0
        out_readCaps->color = caps.color;
282
0
        out_readCaps->alpha = caps.alpha;
283
0
        out_readCaps->bpp16 = caps.bpp16;
284
0
    } else {
285
0
        out_drawCaps->Clear();
286
0
        *out_readCaps = screenCaps;
287
0
    }
288
0
}
289
290
SurfaceFactory::SurfaceFactory(SharedSurfaceType type, GLContext* gl,
291
                               const SurfaceCaps& caps,
292
                               const RefPtr<layers::LayersIPCChannel>& allocator,
293
                               const layers::TextureFlags& flags)
294
    : mType(type)
295
    , mGL(gl)
296
    , mCaps(caps)
297
    , mAllocator(allocator)
298
    , mFlags(flags)
299
    , mFormats(gl->ChooseGLFormats(caps))
300
    , mMutex("SurfaceFactor::mMutex")
301
0
{
302
0
    ChooseBufferBits(mCaps, &mDrawCaps, &mReadCaps);
303
0
}
304
305
SurfaceFactory::~SurfaceFactory()
306
0
{
307
0
    while (!mRecycleTotalPool.empty()) {
308
0
        RefPtr<layers::SharedSurfaceTextureClient> tex = *mRecycleTotalPool.begin();
309
0
        StopRecycling(tex);
310
0
        tex->CancelWaitForRecycle();
311
0
    }
312
0
313
0
    MOZ_RELEASE_ASSERT(mRecycleTotalPool.empty(),"GFX: Surface recycle pool not empty.");
314
0
315
0
    // If we mRecycleFreePool.clear() before StopRecycling(), we may try to recycle it,
316
0
    // fail, call StopRecycling(), then return here and call it again.
317
0
    mRecycleFreePool.clear();
318
0
}
319
320
already_AddRefed<layers::SharedSurfaceTextureClient>
321
SurfaceFactory::NewTexClient(const gfx::IntSize& size)
322
0
{
323
0
    while (!mRecycleFreePool.empty()) {
324
0
        RefPtr<layers::SharedSurfaceTextureClient> cur = mRecycleFreePool.front();
325
0
        mRecycleFreePool.pop();
326
0
327
0
        if (cur->Surf()->mSize == size) {
328
0
            cur->Surf()->WaitForBufferOwnership();
329
0
            return cur.forget();
330
0
        }
331
0
332
0
        StopRecycling(cur);
333
0
    }
334
0
335
0
    UniquePtr<SharedSurface> surf = CreateShared(size);
336
0
    if (!surf)
337
0
        return nullptr;
338
0
339
0
    RefPtr<layers::SharedSurfaceTextureClient> ret;
340
0
    ret = layers::SharedSurfaceTextureClient::Create(std::move(surf), this, mAllocator, mFlags);
341
0
342
0
    StartRecycling(ret);
343
0
344
0
    return ret.forget();
345
0
}
346
347
void
348
SurfaceFactory::StartRecycling(layers::SharedSurfaceTextureClient* tc)
349
0
{
350
0
    tc->SetRecycleCallback(&SurfaceFactory::RecycleCallback, static_cast<void*>(this));
351
0
352
0
    bool didInsert = mRecycleTotalPool.insert(tc);
353
0
    MOZ_RELEASE_ASSERT(didInsert, "GFX: Shared surface texture client was not inserted to recycle.");
354
0
    mozilla::Unused << didInsert;
355
0
}
356
357
void
358
SurfaceFactory::StopRecycling(layers::SharedSurfaceTextureClient* tc)
359
0
{
360
0
    MutexAutoLock autoLock(mMutex);
361
0
    // Must clear before releasing ref.
362
0
    tc->ClearRecycleCallback();
363
0
364
0
    bool didErase = mRecycleTotalPool.erase(tc);
365
0
    MOZ_RELEASE_ASSERT(didErase, "GFX: Shared texture surface client was not erased.");
366
0
    mozilla::Unused << didErase;
367
0
}
368
369
/*static*/ void
370
SurfaceFactory::RecycleCallback(layers::TextureClient* rawTC, void* rawFactory)
371
0
{
372
0
    RefPtr<layers::SharedSurfaceTextureClient> tc;
373
0
    tc = static_cast<layers::SharedSurfaceTextureClient*>(rawTC);
374
0
    SurfaceFactory* factory = static_cast<SurfaceFactory*>(rawFactory);
375
0
376
0
    if (tc->Surf()->mCanRecycle) {
377
0
        if (factory->Recycle(tc))
378
0
            return;
379
0
    }
380
0
381
0
    // Did not recover the tex client. End the (re)cycle!
382
0
    factory->StopRecycling(tc);
383
0
}
384
385
bool
386
SurfaceFactory::Recycle(layers::SharedSurfaceTextureClient* texClient)
387
0
{
388
0
    MOZ_ASSERT(texClient);
389
0
    MutexAutoLock autoLock(mMutex);
390
0
391
0
    if (mRecycleFreePool.size() >= 2) {
392
0
        return false;
393
0
    }
394
0
395
0
    RefPtr<layers::SharedSurfaceTextureClient> texClientRef = texClient;
396
0
    mRecycleFreePool.push(texClientRef);
397
0
    return true;
398
0
}
399
400
////////////////////////////////////////////////////////////////////////////////
401
// ScopedReadbackFB
402
403
ScopedReadbackFB::ScopedReadbackFB(SharedSurface* src)
404
    : mGL(src->mGL)
405
    , mAutoFB(mGL)
406
0
{
407
0
    switch (src->mAttachType) {
408
0
    case AttachmentType::GLRenderbuffer:
409
0
        {
410
0
            mGL->fGenFramebuffers(1, &mTempFB);
411
0
            mGL->fBindFramebuffer(LOCAL_GL_FRAMEBUFFER, mTempFB);
412
0
413
0
            GLuint rb = src->ProdRenderbuffer();
414
0
            mGL->fFramebufferRenderbuffer(LOCAL_GL_FRAMEBUFFER,
415
0
                                          LOCAL_GL_COLOR_ATTACHMENT0,
416
0
                                          LOCAL_GL_RENDERBUFFER, rb);
417
0
            break;
418
0
        }
419
0
    case AttachmentType::GLTexture:
420
0
        {
421
0
            mGL->fGenFramebuffers(1, &mTempFB);
422
0
            mGL->fBindFramebuffer(LOCAL_GL_FRAMEBUFFER, mTempFB);
423
0
424
0
            GLuint tex = src->ProdTexture();
425
0
            GLenum texImageTarget = src->ProdTextureTarget();
426
0
            mGL->fFramebufferTexture2D(LOCAL_GL_FRAMEBUFFER,
427
0
                                       LOCAL_GL_COLOR_ATTACHMENT0,
428
0
                                       texImageTarget, tex, 0);
429
0
            break;
430
0
        }
431
0
    case AttachmentType::Screen:
432
0
        {
433
0
            SharedSurface* origLocked = mGL->GetLockedSurface();
434
0
            if (origLocked != src) {
435
0
                if (origLocked) {
436
0
                    mSurfToLock = origLocked;
437
0
                    mSurfToLock->UnlockProd();
438
0
                }
439
0
440
0
                mSurfToUnlock = src;
441
0
                mSurfToUnlock->LockProd();
442
0
            }
443
0
444
0
            // TODO: This should just be BindFB, but we don't have
445
0
            // the patch for this yet. (bug 1045955)
446
0
            MOZ_ASSERT(mGL->Screen());
447
0
            mGL->Screen()->BindReadFB_Internal(0);
448
0
            break;
449
0
        }
450
0
    default:
451
0
        MOZ_CRASH("GFX: Unhandled `mAttachType`.");
452
0
    }
453
0
454
0
    if (src->NeedsIndirectReads()) {
455
0
        mGL->fGenTextures(1, &mTempTex);
456
0
457
0
        {
458
0
            ScopedBindTexture autoTex(mGL, mTempTex);
459
0
460
0
            GLenum format = src->mHasAlpha ? LOCAL_GL_RGBA
461
0
                                           : LOCAL_GL_RGB;
462
0
            auto width = src->mSize.width;
463
0
            auto height = src->mSize.height;
464
0
            mGL->fCopyTexImage2D(LOCAL_GL_TEXTURE_2D, 0, format, 0, 0, width,
465
0
                                 height, 0);
466
0
        }
467
0
468
0
        mGL->fFramebufferTexture2D(LOCAL_GL_FRAMEBUFFER,
469
0
                                   LOCAL_GL_COLOR_ATTACHMENT0,
470
0
                                   LOCAL_GL_TEXTURE_2D, mTempTex, 0);
471
0
    }
472
0
}
473
474
ScopedReadbackFB::~ScopedReadbackFB()
475
0
{
476
0
    if (mTempFB) {
477
0
        mGL->fDeleteFramebuffers(1, &mTempFB);
478
0
    }
479
0
    if (mTempTex) {
480
0
        mGL->fDeleteTextures(1, &mTempTex);
481
0
    }
482
0
    if (mSurfToUnlock) {
483
0
        mSurfToUnlock->UnlockProd();
484
0
    }
485
0
    if (mSurfToLock) {
486
0
        mSurfToLock->LockProd();
487
0
    }
488
0
}
489
490
////////////////////////////////////////////////////////////////////////////////
491
492
class AutoLockBits
493
{
494
    gfx::DrawTarget* mDT;
495
    uint8_t* mLockedBits;
496
497
public:
498
    explicit AutoLockBits(gfx::DrawTarget* dt)
499
        : mDT(dt)
500
        , mLockedBits(nullptr)
501
0
    {
502
0
        MOZ_ASSERT(mDT);
503
0
    }
504
505
    bool Lock(uint8_t** data, gfx::IntSize* size, int32_t* stride,
506
              gfx::SurfaceFormat* format)
507
0
    {
508
0
        if (!mDT->LockBits(data, size, stride, format))
509
0
            return false;
510
0
511
0
        mLockedBits = *data;
512
0
        return true;
513
0
    }
514
515
0
    ~AutoLockBits() {
516
0
        if (mLockedBits)
517
0
            mDT->ReleaseBits(mLockedBits);
518
0
    }
519
};
520
521
bool
522
ReadbackSharedSurface(SharedSurface* src, gfx::DrawTarget* dst)
523
0
{
524
0
    AutoLockBits lock(dst);
525
0
526
0
    uint8_t* dstBytes;
527
0
    gfx::IntSize dstSize;
528
0
    int32_t dstStride;
529
0
    gfx::SurfaceFormat dstFormat;
530
0
    if (!lock.Lock(&dstBytes, &dstSize, &dstStride, &dstFormat))
531
0
        return false;
532
0
533
0
    const bool isDstRGBA = (dstFormat == gfx::SurfaceFormat::R8G8B8A8 ||
534
0
                            dstFormat == gfx::SurfaceFormat::R8G8B8X8);
535
0
    MOZ_ASSERT_IF(!isDstRGBA, dstFormat == gfx::SurfaceFormat::B8G8R8A8 ||
536
0
                              dstFormat == gfx::SurfaceFormat::B8G8R8X8);
537
0
538
0
    size_t width = src->mSize.width;
539
0
    size_t height = src->mSize.height;
540
0
    MOZ_ASSERT(width == (size_t)dstSize.width);
541
0
    MOZ_ASSERT(height == (size_t)dstSize.height);
542
0
543
0
    GLenum readGLFormat;
544
0
    GLenum readType;
545
0
546
0
    {
547
0
        ScopedReadbackFB autoReadback(src);
548
0
549
0
550
0
        // We have a source FB, now we need a format.
551
0
        GLenum dstGLFormat = isDstRGBA ? LOCAL_GL_BGRA : LOCAL_GL_RGBA;
552
0
        GLenum dstType = LOCAL_GL_UNSIGNED_BYTE;
553
0
554
0
        // We actually don't care if they match, since we can handle
555
0
        // any read{Format,Type} we get.
556
0
        GLContext* gl = src->mGL;
557
0
        GetActualReadFormats(gl, dstGLFormat, dstType, &readGLFormat,
558
0
                             &readType);
559
0
560
0
        MOZ_ASSERT(readGLFormat == LOCAL_GL_RGBA ||
561
0
                   readGLFormat == LOCAL_GL_BGRA);
562
0
        MOZ_ASSERT(readType == LOCAL_GL_UNSIGNED_BYTE);
563
0
564
0
        // ReadPixels from the current FB into lockedBits.
565
0
        {
566
0
            size_t alignment = 8;
567
0
            if (dstStride % 4 == 0)
568
0
                alignment = 4;
569
0
570
0
            ScopedPackState scopedPackState(gl);
571
0
            if (alignment != 4) {
572
0
                gl->fPixelStorei(LOCAL_GL_PACK_ALIGNMENT, alignment);
573
0
            }
574
0
575
0
            gl->raw_fReadPixels(0, 0, width, height, readGLFormat, readType,
576
0
                                dstBytes);
577
0
        }
578
0
    }
579
0
580
0
    const bool isReadRGBA = readGLFormat == LOCAL_GL_RGBA;
581
0
582
0
    if (isReadRGBA != isDstRGBA) {
583
0
        for (size_t j = 0; j < height; ++j) {
584
0
            uint8_t* rowItr = dstBytes + j*dstStride;
585
0
            uint8_t* rowEnd = rowItr + 4*width;
586
0
            while (rowItr != rowEnd) {
587
0
                Swap(rowItr[0], rowItr[2]);
588
0
                rowItr += 4;
589
0
            }
590
0
        }
591
0
    }
592
0
593
0
    return true;
594
0
}
595
596
uint32_t
597
ReadPixel(SharedSurface* src)
598
0
{
599
0
    GLContext* gl = src->mGL;
600
0
601
0
    uint32_t pixel;
602
0
603
0
    ScopedReadbackFB a(src);
604
0
    {
605
0
        ScopedPackState scopedPackState(gl);
606
0
607
0
        UniquePtr<uint8_t[]> bytes(new uint8_t[4]);
608
0
        gl->raw_fReadPixels(0, 0, 1, 1, LOCAL_GL_RGBA, LOCAL_GL_UNSIGNED_BYTE,
609
0
                            bytes.get());
610
0
        memcpy(&pixel, bytes.get(), 4);
611
0
    }
612
0
613
0
    return pixel;
614
0
}
615
616
} // namespace gl
617
618
} /* namespace mozilla */