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