Bumping gaia.json for 2 gaia revision(s) a=gaia-bump
[gecko.git] / gfx / gl / SharedSurface.cpp
blob5e251ff9ecb08cf46dff57d28010748391e5a6e5
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/. */
6 #include "SharedSurface.h"
8 #include "../2d/2D.h"
9 #include "GLBlitHelper.h"
10 #include "GLContext.h"
11 #include "GLReadTexImageHelper.h"
12 #include "nsThreadUtils.h"
13 #include "ScopedGLHelpers.h"
14 #include "SharedSurfaceGL.h"
16 namespace mozilla {
17 namespace gl {
19 /*static*/ void
20 SharedSurface::ProdCopy(SharedSurface* src, SharedSurface* dest,
21 SurfaceFactory* factory)
23 GLContext* gl = src->mGL;
25 // If `src` begins locked, it must end locked, though we may
26 // temporarily unlock it if we need to.
27 MOZ_ASSERT((src == gl->GetLockedSurface()) == src->IsLocked());
29 gl->MakeCurrent();
31 if (src->mAttachType == AttachmentType::Screen &&
32 dest->mAttachType == AttachmentType::Screen)
34 // Here, we actually need to blit through a temp surface, so let's make one.
35 UniquePtr<SharedSurface_GLTexture> tempSurf;
36 tempSurf = SharedSurface_GLTexture::Create(gl,
37 gl,
38 factory->mFormats,
39 src->mSize,
40 factory->mCaps.alpha);
42 ProdCopy(src, tempSurf.get(), factory);
43 ProdCopy(tempSurf.get(), dest, factory);
44 return;
47 if (src->mAttachType == AttachmentType::Screen) {
48 SharedSurface* origLocked = gl->GetLockedSurface();
49 bool srcNeedsUnlock = false;
50 bool origNeedsRelock = false;
51 if (origLocked != src) {
52 if (origLocked) {
53 origLocked->UnlockProd();
54 origNeedsRelock = true;
57 src->LockProd();
58 srcNeedsUnlock = true;
61 if (dest->mAttachType == AttachmentType::GLTexture) {
62 GLuint destTex = dest->ProdTexture();
63 GLenum destTarget = dest->ProdTextureTarget();
65 gl->BlitHelper()->BlitFramebufferToTexture(0, destTex,
66 src->mSize,
67 dest->mSize,
68 destTarget,
69 true);
70 } else if (dest->mAttachType == AttachmentType::GLRenderbuffer) {
71 GLuint destRB = dest->ProdRenderbuffer();
72 ScopedFramebufferForRenderbuffer destWrapper(gl, destRB);
74 gl->BlitHelper()->BlitFramebufferToFramebuffer(0,
75 destWrapper.FB(),
76 src->mSize,
77 dest->mSize,
78 true);
79 } else {
80 MOZ_CRASH("Unhandled dest->mAttachType.");
83 if (srcNeedsUnlock)
84 src->UnlockProd();
86 if (origNeedsRelock)
87 origLocked->LockProd();
89 return;
92 if (dest->mAttachType == AttachmentType::Screen) {
93 SharedSurface* origLocked = gl->GetLockedSurface();
94 bool destNeedsUnlock = false;
95 bool origNeedsRelock = false;
96 if (origLocked != dest) {
97 if (origLocked) {
98 origLocked->UnlockProd();
99 origNeedsRelock = true;
102 dest->LockProd();
103 destNeedsUnlock = true;
106 if (src->mAttachType == AttachmentType::GLTexture) {
107 GLuint srcTex = src->ProdTexture();
108 GLenum srcTarget = src->ProdTextureTarget();
110 gl->BlitHelper()->BlitTextureToFramebuffer(srcTex, 0,
111 src->mSize,
112 dest->mSize,
113 srcTarget,
114 true);
115 } else if (src->mAttachType == AttachmentType::GLRenderbuffer) {
116 GLuint srcRB = src->ProdRenderbuffer();
117 ScopedFramebufferForRenderbuffer srcWrapper(gl, srcRB);
119 gl->BlitHelper()->BlitFramebufferToFramebuffer(srcWrapper.FB(),
121 src->mSize,
122 dest->mSize,
123 true);
124 } else {
125 MOZ_CRASH("Unhandled src->mAttachType.");
128 if (destNeedsUnlock)
129 dest->UnlockProd();
131 if (origNeedsRelock)
132 origLocked->LockProd();
134 return;
137 // Alright, done with cases involving Screen types.
138 // Only {src,dest}x{texture,renderbuffer} left.
140 if (src->mAttachType == AttachmentType::GLTexture) {
141 GLuint srcTex = src->ProdTexture();
142 GLenum srcTarget = src->ProdTextureTarget();
144 if (dest->mAttachType == AttachmentType::GLTexture) {
145 GLuint destTex = dest->ProdTexture();
146 GLenum destTarget = dest->ProdTextureTarget();
148 gl->BlitHelper()->BlitTextureToTexture(srcTex, destTex,
149 src->mSize, dest->mSize,
150 srcTarget, destTarget);
152 return;
155 if (dest->mAttachType == AttachmentType::GLRenderbuffer) {
156 GLuint destRB = dest->ProdRenderbuffer();
157 ScopedFramebufferForRenderbuffer destWrapper(gl, destRB);
159 gl->BlitHelper()->BlitTextureToFramebuffer(srcTex, destWrapper.FB(),
160 src->mSize, dest->mSize, srcTarget);
162 return;
165 MOZ_CRASH("Unhandled dest->mAttachType.");
168 if (src->mAttachType == AttachmentType::GLRenderbuffer) {
169 GLuint srcRB = src->ProdRenderbuffer();
170 ScopedFramebufferForRenderbuffer srcWrapper(gl, srcRB);
172 if (dest->mAttachType == AttachmentType::GLTexture) {
173 GLuint destTex = dest->ProdTexture();
174 GLenum destTarget = dest->ProdTextureTarget();
176 gl->BlitHelper()->BlitFramebufferToTexture(srcWrapper.FB(), destTex,
177 src->mSize, dest->mSize, destTarget);
179 return;
182 if (dest->mAttachType == AttachmentType::GLRenderbuffer) {
183 GLuint destRB = dest->ProdRenderbuffer();
184 ScopedFramebufferForRenderbuffer destWrapper(gl, destRB);
186 gl->BlitHelper()->BlitFramebufferToFramebuffer(srcWrapper.FB(), destWrapper.FB(),
187 src->mSize, dest->mSize);
189 return;
192 MOZ_CRASH("Unhandled dest->mAttachType.");
195 MOZ_CRASH("Unhandled src->mAttachType.");
198 ////////////////////////////////////////////////////////////////////////
199 // SharedSurface
202 SharedSurface::SharedSurface(SharedSurfaceType type,
203 AttachmentType attachType,
204 GLContext* gl,
205 const gfx::IntSize& size,
206 bool hasAlpha)
207 : mType(type)
208 , mAttachType(attachType)
209 , mGL(gl)
210 , mSize(size)
211 , mHasAlpha(hasAlpha)
212 , mIsLocked(false)
213 , mIsProducerAcquired(false)
214 , mIsConsumerAcquired(false)
215 #ifdef DEBUG
216 , mOwningThread(NS_GetCurrentThread())
217 #endif
221 void
222 SharedSurface::LockProd()
224 MOZ_ASSERT(!mIsLocked);
226 LockProdImpl();
228 mGL->LockSurface(this);
229 mIsLocked = true;
232 void
233 SharedSurface::UnlockProd()
235 if (!mIsLocked)
236 return;
238 UnlockProdImpl();
240 mGL->UnlockSurface(this);
241 mIsLocked = false;
244 void
245 SharedSurface::Fence_ContentThread()
247 MOZ_ASSERT(NS_GetCurrentThread() == mOwningThread);
248 Fence_ContentThread_Impl();
251 bool
252 SharedSurface::WaitSync_ContentThread()
254 MOZ_ASSERT(NS_GetCurrentThread() == mOwningThread);
255 return WaitSync_ContentThread_Impl();
258 bool
259 SharedSurface::PollSync_ContentThread()
261 MOZ_ASSERT(NS_GetCurrentThread() == mOwningThread);
262 return PollSync_ContentThread_Impl();
267 ////////////////////////////////////////////////////////////////////////
268 // SurfaceFactory
270 static void
271 ChooseBufferBits(const SurfaceCaps& caps,
272 SurfaceCaps* const out_drawCaps,
273 SurfaceCaps* const out_readCaps)
275 MOZ_ASSERT(out_drawCaps);
276 MOZ_ASSERT(out_readCaps);
278 SurfaceCaps screenCaps;
280 screenCaps.color = caps.color;
281 screenCaps.alpha = caps.alpha;
282 screenCaps.bpp16 = caps.bpp16;
284 screenCaps.depth = caps.depth;
285 screenCaps.stencil = caps.stencil;
287 screenCaps.antialias = caps.antialias;
288 screenCaps.preserve = caps.preserve;
290 if (caps.antialias) {
291 *out_drawCaps = screenCaps;
292 out_readCaps->Clear();
294 // Color caps need to be duplicated in readCaps.
295 out_readCaps->color = caps.color;
296 out_readCaps->alpha = caps.alpha;
297 out_readCaps->bpp16 = caps.bpp16;
298 } else {
299 out_drawCaps->Clear();
300 *out_readCaps = screenCaps;
304 SurfaceFactory::SurfaceFactory(GLContext* gl,
305 SharedSurfaceType type,
306 const SurfaceCaps& caps)
307 : mGL(gl)
308 , mCaps(caps)
309 , mType(type)
310 , mFormats(gl->ChooseGLFormats(caps))
312 ChooseBufferBits(mCaps, &mDrawCaps, &mReadCaps);
315 SurfaceFactory::~SurfaceFactory()
317 while (!mScraps.Empty()) {
318 mScraps.Pop();
322 UniquePtr<SharedSurface>
323 SurfaceFactory::NewSharedSurface(const gfx::IntSize& size)
325 // Attempt to reuse an old surface.
326 while (!mScraps.Empty()) {
327 UniquePtr<SharedSurface> cur = mScraps.Pop();
329 if (cur->mSize == size)
330 return Move(cur);
332 // Let `cur` be destroyed as it falls out of scope, if it wasn't
333 // moved.
336 return CreateShared(size);
339 TemporaryRef<ShSurfHandle>
340 SurfaceFactory::NewShSurfHandle(const gfx::IntSize& size)
342 auto surf = NewSharedSurface(size);
343 if (!surf)
344 return nullptr;
346 // Before next use, wait until SharedSurface's buffer
347 // is no longer being used.
348 surf->WaitForBufferOwnership();
350 return new ShSurfHandle(this, Move(surf));
353 // Auto-deletes surfs of the wrong type.
354 void
355 SurfaceFactory::Recycle(UniquePtr<SharedSurface> surf)
357 MOZ_ASSERT(surf);
359 if (surf->mType == mType) {
360 mScraps.Push(Move(surf));
364 ////////////////////////////////////////////////////////////////////////////////
365 // ScopedReadbackFB
367 ScopedReadbackFB::ScopedReadbackFB(SharedSurface* src)
368 : mGL(src->mGL)
369 , mAutoFB(mGL)
370 , mTempFB(0)
371 , mTempTex(0)
372 , mSurfToUnlock(nullptr)
373 , mSurfToLock(nullptr)
375 switch (src->mAttachType) {
376 case AttachmentType::GLRenderbuffer:
378 mGL->fGenFramebuffers(1, &mTempFB);
379 mGL->fBindFramebuffer(LOCAL_GL_FRAMEBUFFER, mTempFB);
381 GLuint rb = src->ProdRenderbuffer();
382 mGL->fFramebufferRenderbuffer(LOCAL_GL_FRAMEBUFFER,
383 LOCAL_GL_COLOR_ATTACHMENT0,
384 LOCAL_GL_RENDERBUFFER, rb);
385 break;
387 case AttachmentType::GLTexture:
389 mGL->fGenFramebuffers(1, &mTempFB);
390 mGL->fBindFramebuffer(LOCAL_GL_FRAMEBUFFER, mTempFB);
392 GLuint tex = src->ProdTexture();
393 GLenum texImageTarget = src->ProdTextureTarget();
394 mGL->fFramebufferTexture2D(LOCAL_GL_FRAMEBUFFER,
395 LOCAL_GL_COLOR_ATTACHMENT0,
396 texImageTarget, tex, 0);
397 break;
399 case AttachmentType::Screen:
401 SharedSurface* origLocked = mGL->GetLockedSurface();
402 if (origLocked != src) {
403 if (origLocked) {
404 mSurfToLock = origLocked;
405 mSurfToLock->UnlockProd();
408 mSurfToUnlock = src;
409 mSurfToUnlock->LockProd();
412 // TODO: This should just be BindFB, but we don't have
413 // the patch for this yet. (bug 1045955)
414 MOZ_ASSERT(mGL->Screen());
415 mGL->Screen()->BindReadFB_Internal(0);
416 break;
418 default:
419 MOZ_CRASH("Unhandled `mAttachType`.");
422 if (src->NeedsIndirectReads()) {
423 mGL->fGenTextures(1, &mTempTex);
426 ScopedBindTexture autoTex(mGL, mTempTex);
428 GLenum format = src->mHasAlpha ? LOCAL_GL_RGBA
429 : LOCAL_GL_RGB;
430 auto width = src->mSize.width;
431 auto height = src->mSize.height;
432 mGL->fCopyTexImage2D(LOCAL_GL_TEXTURE_2D, 0, format, 0, 0, width,
433 height, 0);
436 mGL->fFramebufferTexture2D(LOCAL_GL_FRAMEBUFFER,
437 LOCAL_GL_COLOR_ATTACHMENT0,
438 LOCAL_GL_TEXTURE_2D, mTempTex, 0);
442 ScopedReadbackFB::~ScopedReadbackFB()
444 if (mTempFB) {
445 mGL->fDeleteFramebuffers(1, &mTempFB);
447 if (mTempTex) {
448 mGL->fDeleteTextures(1, &mTempTex);
450 if (mSurfToUnlock) {
451 mSurfToUnlock->UnlockProd();
453 if (mSurfToLock) {
454 mSurfToLock->LockProd();
458 ////////////////////////////////////////////////////////////////////////////////
460 class AutoLockBits
462 gfx::DrawTarget* mDT;
463 uint8_t* mLockedBits;
465 public:
466 explicit AutoLockBits(gfx::DrawTarget* dt)
467 : mDT(dt)
468 , mLockedBits(nullptr)
470 MOZ_ASSERT(mDT);
473 bool Lock(uint8_t** data, gfx::IntSize* size, int32_t* stride,
474 gfx::SurfaceFormat* format)
476 if (!mDT->LockBits(data, size, stride, format))
477 return false;
479 mLockedBits = *data;
480 return true;
483 ~AutoLockBits() {
484 if (mLockedBits)
485 mDT->ReleaseBits(mLockedBits);
489 bool
490 ReadbackSharedSurface(SharedSurface* src, gfx::DrawTarget* dst)
492 AutoLockBits lock(dst);
494 uint8_t* dstBytes;
495 gfx::IntSize dstSize;
496 int32_t dstStride;
497 gfx::SurfaceFormat dstFormat;
498 if (!lock.Lock(&dstBytes, &dstSize, &dstStride, &dstFormat))
499 return false;
501 const bool isDstRGBA = (dstFormat == gfx::SurfaceFormat::R8G8B8A8 ||
502 dstFormat == gfx::SurfaceFormat::R8G8B8X8);
503 MOZ_ASSERT_IF(!isDstRGBA, dstFormat == gfx::SurfaceFormat::B8G8R8A8 ||
504 dstFormat == gfx::SurfaceFormat::B8G8R8X8);
506 size_t width = src->mSize.width;
507 size_t height = src->mSize.height;
508 MOZ_ASSERT(width == (size_t)dstSize.width);
509 MOZ_ASSERT(height == (size_t)dstSize.height);
511 GLenum readGLFormat;
512 GLenum readType;
515 ScopedReadbackFB autoReadback(src);
518 // We have a source FB, now we need a format.
519 GLenum dstGLFormat = isDstRGBA ? LOCAL_GL_BGRA : LOCAL_GL_RGBA;
520 GLenum dstType = LOCAL_GL_UNSIGNED_BYTE;
522 // We actually don't care if they match, since we can handle
523 // any read{Format,Type} we get.
524 GLContext* gl = src->mGL;
525 GetActualReadFormats(gl, dstGLFormat, dstType, &readGLFormat,
526 &readType);
528 MOZ_ASSERT(readGLFormat == LOCAL_GL_RGBA ||
529 readGLFormat == LOCAL_GL_BGRA);
530 MOZ_ASSERT(readType == LOCAL_GL_UNSIGNED_BYTE);
532 // ReadPixels from the current FB into lockedBits.
534 size_t alignment = 8;
535 if (dstStride % 4 == 0)
536 alignment = 4;
537 ScopedPackAlignment autoAlign(gl, alignment);
539 gl->raw_fReadPixels(0, 0, width, height, readGLFormat, readType,
540 dstBytes);
544 const bool isReadRGBA = readGLFormat == LOCAL_GL_RGBA;
546 if (isReadRGBA != isDstRGBA) {
547 for (size_t j = 0; j < height; ++j) {
548 uint8_t* rowItr = dstBytes + j*dstStride;
549 uint8_t* rowEnd = rowItr + 4*width;
550 while (rowItr != rowEnd) {
551 Swap(rowItr[0], rowItr[2]);
552 rowItr += 4;
557 return true;
560 } /* namespace gfx */
561 } /* namespace mozilla */