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 "GLScreenBuffer.h"
9 #include "CompositorTypes.h"
10 #include "GLContext.h"
11 #include "GLBlitHelper.h"
12 #include "GLReadTexImageHelper.h"
13 #include "SharedSurfaceGL.h"
14 #ifdef MOZ_WIDGET_GONK
15 #include "SharedSurfaceGralloc.h"
16 #include "nsXULAppAPI.h"
19 #include "SharedSurfaceIO.h"
21 #include "ScopedGLHelpers.h"
22 #include "gfx2DGlue.h"
23 #include "../layers/ipc/ShadowLayers.h"
28 using gfx::SurfaceFormat
;
30 UniquePtr
<GLScreenBuffer
>
31 GLScreenBuffer::Create(GLContext
* gl
,
32 const gfx::IntSize
& size
,
33 const SurfaceCaps
& caps
)
35 UniquePtr
<GLScreenBuffer
> ret
;
37 !gl
->IsSupported(GLFeature::framebuffer_multisample
))
42 UniquePtr
<SurfaceFactory
> factory
;
44 #ifdef MOZ_WIDGET_GONK
45 /* On B2G, we want a Gralloc factory, and we want one right at the start */
46 layers::ISurfaceAllocator
* allocator
= caps
.surfaceAllocator
;
49 XRE_GetProcessType() != GeckoProcessType_Default
)
51 layers::TextureFlags flags
= layers::TextureFlags::DEALLOCATE_CLIENT
|
52 layers::TextureFlags::ORIGIN_BOTTOM_LEFT
;
53 if (!caps
.premultAlpha
) {
54 flags
|= layers::TextureFlags::NON_PREMULTIPLIED
;
57 factory
= MakeUnique
<SurfaceFactory_Gralloc
>(gl
, caps
, flags
,
62 /* On OSX, we want an IOSurface factory, and we want one right at the start */
64 factory
= SurfaceFactory_IOSurface::Create(gl
, caps
);
69 factory
= MakeUnique
<SurfaceFactory_Basic
>(gl
, caps
);
72 ret
.reset( new GLScreenBuffer(gl
, caps
, Move(factory
)) );
76 GLScreenBuffer::~GLScreenBuffer()
81 // bug 914823: it is crucial to destroy the Factory _after_ we destroy
82 // the SharedSurfaces around here! Reason: the shared surfaces will want
83 // to ask the Allocator (e.g. the ClientLayerManager) to destroy their
84 // buffers, but that Allocator may be kept alive by the Factory,
85 // as it currently the case in SurfaceFactory_Gralloc holding a nsRefPtr
92 GLScreenBuffer::BindAsFramebuffer(GLContext
* const gl
, GLenum target
) const
94 GLuint drawFB
= DrawFB();
95 GLuint readFB
= ReadFB();
97 if (!gl
->IsSupported(GLFeature::framebuffer_blit
)) {
98 MOZ_ASSERT(drawFB
== readFB
);
99 gl
->raw_fBindFramebuffer(target
, readFB
);
104 case LOCAL_GL_FRAMEBUFFER
:
105 gl
->raw_fBindFramebuffer(LOCAL_GL_DRAW_FRAMEBUFFER_EXT
, drawFB
);
106 gl
->raw_fBindFramebuffer(LOCAL_GL_READ_FRAMEBUFFER_EXT
, readFB
);
109 case LOCAL_GL_DRAW_FRAMEBUFFER_EXT
:
110 if (!gl
->IsSupported(GLFeature::framebuffer_blit
))
111 NS_WARNING("DRAW_FRAMEBUFFER requested but unavailable.");
113 gl
->raw_fBindFramebuffer(LOCAL_GL_DRAW_FRAMEBUFFER_EXT
, drawFB
);
116 case LOCAL_GL_READ_FRAMEBUFFER_EXT
:
117 if (!gl
->IsSupported(GLFeature::framebuffer_blit
))
118 NS_WARNING("READ_FRAMEBUFFER requested but unavailable.");
120 gl
->raw_fBindFramebuffer(LOCAL_GL_READ_FRAMEBUFFER_EXT
, readFB
);
124 MOZ_CRASH("Bad `target` for BindFramebuffer.");
129 GLScreenBuffer::BindFB(GLuint fb
)
131 GLuint drawFB
= DrawFB();
132 GLuint readFB
= ReadFB();
136 mInternalDrawFB
= (fb
== 0) ? drawFB
: fb
;
137 mInternalReadFB
= (fb
== 0) ? readFB
: fb
;
139 if (mInternalDrawFB
== mInternalReadFB
) {
140 mGL
->raw_fBindFramebuffer(LOCAL_GL_FRAMEBUFFER
, mInternalDrawFB
);
142 MOZ_ASSERT(mGL
->IsSupported(GLFeature::framebuffer_blit
));
143 mGL
->raw_fBindFramebuffer(LOCAL_GL_DRAW_FRAMEBUFFER_EXT
, mInternalDrawFB
);
144 mGL
->raw_fBindFramebuffer(LOCAL_GL_READ_FRAMEBUFFER_EXT
, mInternalReadFB
);
148 mInInternalMode_DrawFB
= false;
149 mInInternalMode_ReadFB
= false;
154 GLScreenBuffer::BindDrawFB(GLuint fb
)
156 MOZ_ASSERT(mGL
->IsSupported(GLFeature::framebuffer_blit
));
158 GLuint drawFB
= DrawFB();
160 mInternalDrawFB
= (fb
== 0) ? drawFB
: fb
;
162 mGL
->raw_fBindFramebuffer(LOCAL_GL_DRAW_FRAMEBUFFER_EXT
, mInternalDrawFB
);
165 mInInternalMode_DrawFB
= false;
170 GLScreenBuffer::BindReadFB(GLuint fb
)
172 MOZ_ASSERT(mGL
->IsSupported(GLFeature::framebuffer_blit
));
174 GLuint readFB
= ReadFB();
176 mInternalReadFB
= (fb
== 0) ? readFB
: fb
;
178 mGL
->raw_fBindFramebuffer(LOCAL_GL_READ_FRAMEBUFFER_EXT
, mInternalReadFB
);
181 mInInternalMode_ReadFB
= false;
186 GLScreenBuffer::BindFB_Internal(GLuint fb
)
188 mInternalDrawFB
= mUserDrawFB
= fb
;
189 mInternalReadFB
= mUserReadFB
= fb
;
190 mGL
->raw_fBindFramebuffer(LOCAL_GL_FRAMEBUFFER
, mInternalDrawFB
);
193 mInInternalMode_DrawFB
= true;
194 mInInternalMode_ReadFB
= true;
199 GLScreenBuffer::BindDrawFB_Internal(GLuint fb
)
201 MOZ_ASSERT(mGL
->IsSupported(GLFeature::framebuffer_blit
));
203 mInternalDrawFB
= mUserDrawFB
= fb
;
204 mGL
->raw_fBindFramebuffer(LOCAL_GL_DRAW_FRAMEBUFFER_EXT
, mInternalDrawFB
);
207 mInInternalMode_DrawFB
= true;
212 GLScreenBuffer::BindReadFB_Internal(GLuint fb
)
214 MOZ_ASSERT(mGL
->IsSupported(GLFeature::framebuffer_blit
));
216 mInternalReadFB
= mUserReadFB
= fb
;
217 mGL
->raw_fBindFramebuffer(LOCAL_GL_READ_FRAMEBUFFER_EXT
, mInternalReadFB
);
220 mInInternalMode_ReadFB
= true;
226 GLScreenBuffer::GetDrawFB() const
229 MOZ_ASSERT(mGL
->IsCurrent());
230 MOZ_ASSERT(!mInInternalMode_DrawFB
);
232 // Don't need a branch here, because:
233 // LOCAL_GL_DRAW_FRAMEBUFFER_BINDING_EXT == LOCAL_GL_FRAMEBUFFER_BINDING == 0x8CA6
234 // We use raw_ here because this is debug code and we need to see what
235 // the driver thinks.
237 mGL
->raw_fGetIntegerv(LOCAL_GL_DRAW_FRAMEBUFFER_BINDING_EXT
, (GLint
*)&actual
);
239 GLuint predicted
= mInternalDrawFB
;
240 if (predicted
!= actual
) {
241 printf_stderr("Misprediction: Bound draw FB predicted: %d. Was: %d.\n",
243 MOZ_ASSERT(false, "Draw FB binding misprediction!");
251 GLScreenBuffer::GetReadFB() const
254 MOZ_ASSERT(mGL
->IsCurrent());
255 MOZ_ASSERT(!mInInternalMode_ReadFB
);
257 // We use raw_ here because this is debug code and we need to see what
258 // the driver thinks.
260 if (mGL
->IsSupported(GLFeature::framebuffer_blit
))
261 mGL
->raw_fGetIntegerv(LOCAL_GL_READ_FRAMEBUFFER_BINDING_EXT
, (GLint
*)&actual
);
263 mGL
->raw_fGetIntegerv(LOCAL_GL_FRAMEBUFFER_BINDING
, (GLint
*)&actual
);
265 GLuint predicted
= mInternalReadFB
;
266 if (predicted
!= actual
) {
267 printf_stderr("Misprediction: Bound read FB predicted: %d. Was: %d.\n",
269 MOZ_ASSERT(false, "Read FB binding misprediction!");
277 GLScreenBuffer::GetFB() const
279 MOZ_ASSERT(GetDrawFB() == GetReadFB());
285 GLScreenBuffer::DeletingFB(GLuint fb
)
287 if (fb
== mInternalDrawFB
) {
291 if (fb
== mInternalReadFB
) {
299 GLScreenBuffer::AfterDrawCall()
301 if (mUserDrawFB
!= 0)
308 GLScreenBuffer::BeforeReadCall()
310 if (mUserReadFB
!= 0)
317 GLScreenBuffer::ReadPixels(GLint x
, GLint y
,
318 GLsizei width
, GLsizei height
,
319 GLenum format
, GLenum type
,
322 // If the currently bound framebuffer is backed by a SharedSurface
323 // then it might want to override how we read pixel data from it.
324 // This is normally only the default framebuffer, but we can also
325 // have SharedSurfaces bound to other framebuffers when doing
326 // readback for BasicLayers.
328 if (GetReadFB() == 0) {
331 surf
= mGL
->mFBOMapping
[GetReadFB()];
334 return surf
->ReadPixels(x
, y
, width
, height
, format
, type
, pixels
);
341 GLScreenBuffer::RequireBlit()
347 GLScreenBuffer::AssureBlitted()
353 GLuint drawFB
= DrawFB();
354 GLuint readFB
= ReadFB();
356 MOZ_ASSERT(drawFB
!= 0);
357 MOZ_ASSERT(drawFB
!= readFB
);
358 MOZ_ASSERT(mGL
->IsSupported(GLFeature::framebuffer_blit
));
359 MOZ_ASSERT(mDraw
->mSize
== mRead
->Size());
361 ScopedBindFramebuffer
boundFB(mGL
);
362 ScopedGLState
scissor(mGL
, LOCAL_GL_SCISSOR_TEST
, false);
364 BindReadFB_Internal(drawFB
);
365 BindDrawFB_Internal(readFB
);
367 const gfx::IntSize
& srcSize
= mDraw
->mSize
;
368 const gfx::IntSize
& destSize
= mRead
->Size();
370 mGL
->raw_fBlitFramebuffer(0, 0, srcSize
.width
, srcSize
.height
,
371 0, 0, destSize
.width
, destSize
.height
,
372 LOCAL_GL_COLOR_BUFFER_BIT
,
381 GLScreenBuffer::Morph(UniquePtr
<SurfaceFactory
> newFactory
)
383 MOZ_ASSERT(newFactory
);
384 mFactory
= Move(newFactory
);
388 GLScreenBuffer::Attach(SharedSurface
* surf
, const gfx::IntSize
& size
)
390 ScopedBindFramebuffer
autoFB(mGL
);
392 if (mRead
&& SharedSurf())
393 SharedSurf()->UnlockProd();
398 surf
->mAttachType
== SharedSurf()->mAttachType
&&
401 // Same size, same type, ready for reuse!
404 // Else something changed, so resize:
405 UniquePtr
<DrawBuffer
> draw
;
406 bool drawOk
= CreateDraw(size
, &draw
); // Can be null.
408 UniquePtr
<ReadBuffer
> read
= CreateRead(surf
);
409 bool readOk
= !!read
;
411 if (!drawOk
|| !readOk
) {
421 // Check that we're all set up.
422 MOZ_ASSERT(SharedSurf() == surf
);
428 GLScreenBuffer::Swap(const gfx::IntSize
& size
)
430 RefPtr
<ShSurfHandle
> newBack
= mFactory
->NewShSurfHandle(size
);
434 if (!Attach(newBack
->Surf(), size
))
436 // Attach was successful.
442 mBack
->Surf()->ProducerAcquire();
445 if (ShouldPreserveBuffer() &&
449 auto src
= mFront
->Surf();
450 auto dest
= mBack
->Surf();
451 SharedSurface::ProdCopy(src
, dest
, mFactory
.get());
454 // XXX: We would prefer to fence earlier on platforms that don't need
455 // the full ProducerAcquire/ProducerRelease semantics, so that the fence
456 // doesn't include the copy operation. Unfortunately, the current API
457 // doesn't expose a good way to do that.
459 mFront
->Surf()->ProducerRelease();
466 GLScreenBuffer::PublishFrame(const gfx::IntSize
& size
)
470 bool good
= Swap(size
);
475 GLScreenBuffer::Resize(const gfx::IntSize
& size
)
477 RefPtr
<ShSurfHandle
> newBack
= mFactory
->NewShSurfHandle(size
);
481 if (!Attach(newBack
->Surf(), size
))
485 mBack
->Surf()->ProducerRelease();
489 mBack
->Surf()->ProducerAcquire();
495 GLScreenBuffer::CreateDraw(const gfx::IntSize
& size
,
496 UniquePtr
<DrawBuffer
>* out_buffer
)
498 GLContext
* gl
= mFactory
->mGL
;
499 const GLFormats
& formats
= mFactory
->mFormats
;
500 const SurfaceCaps
& caps
= mFactory
->DrawCaps();
502 return DrawBuffer::Create(gl
, caps
, formats
, size
, out_buffer
);
505 UniquePtr
<ReadBuffer
>
506 GLScreenBuffer::CreateRead(SharedSurface
* surf
)
508 GLContext
* gl
= mFactory
->mGL
;
509 const GLFormats
& formats
= mFactory
->mFormats
;
510 const SurfaceCaps
& caps
= mFactory
->ReadCaps();
512 return ReadBuffer::Create(gl
, caps
, formats
, surf
);
516 GLScreenBuffer::Readback(SharedSurface
* src
, gfx::DataSourceSurface
* dest
)
518 MOZ_ASSERT(src
&& dest
);
519 MOZ_ASSERT(dest
->GetSize() == src
->mSize
);
520 MOZ_ASSERT(dest
->GetFormat() == (src
->mHasAlpha
? SurfaceFormat::B8G8R8A8
521 : SurfaceFormat::B8G8R8X8
));
525 bool needsSwap
= src
!= SharedSurf();
527 SharedSurf()->UnlockProd();
532 // Even though we're reading. We're doing it on
533 // the producer side. So we call ProducerAcquire
534 // instead of ConsumerAcquire.
535 src
->ProducerAcquire();
537 UniquePtr
<ReadBuffer
> buffer
= CreateRead(src
);
540 ScopedBindFramebuffer
autoFB(mGL
, buffer
->mFB
);
541 ReadPixelsIntoDataSurface(mGL
, dest
);
543 src
->ProducerRelease();
548 SharedSurf()->LockProd();
553 GLScreenBuffer::IsDrawFramebufferDefault() const
556 return IsReadFramebufferDefault();
557 return mDraw
->mFB
== 0;
561 GLScreenBuffer::IsReadFramebufferDefault() const
563 return SharedSurf()->mAttachType
== AttachmentType::Screen
;
566 ////////////////////////////////////////////////////////////////////////
570 DrawBuffer::Create(GLContext
* const gl
,
571 const SurfaceCaps
& caps
,
572 const GLFormats
& formats
,
573 const gfx::IntSize
& size
,
574 UniquePtr
<DrawBuffer
>* out_buffer
)
576 MOZ_ASSERT(out_buffer
);
577 *out_buffer
= nullptr;
580 MOZ_ASSERT(!caps
.alpha
&& !caps
.depth
&& !caps
.stencil
);
582 // Nothing is needed.
586 if (caps
.antialias
) {
587 if (formats
.samples
== 0)
588 return false; // Can't create it.
590 MOZ_ASSERT(formats
.samples
<= gl
->MaxSamples());
593 GLuint colorMSRB
= 0;
595 GLuint stencilRB
= 0;
597 GLuint
* pColorMSRB
= caps
.antialias
? &colorMSRB
: nullptr;
598 GLuint
* pDepthRB
= caps
.depth
? &depthRB
: nullptr;
599 GLuint
* pStencilRB
= caps
.stencil
? &stencilRB
: nullptr;
601 if (!formats
.color_rbFormat
)
602 pColorMSRB
= nullptr;
604 if (pDepthRB
&& pStencilRB
) {
605 if (!formats
.depth
&& !formats
.depthStencil
)
608 if (!formats
.stencil
&& !formats
.depthStencil
)
609 pStencilRB
= nullptr;
614 if (!formats
.stencil
)
615 pStencilRB
= nullptr;
618 GLContext::LocalErrorScope
localError(*gl
);
620 CreateRenderbuffersForOffscreen(gl
, formats
, size
, caps
.antialias
,
621 pColorMSRB
, pDepthRB
, pStencilRB
);
624 gl
->fGenFramebuffers(1, &fb
);
625 gl
->AttachBuffersToFB(0, colorMSRB
, depthRB
, stencilRB
, fb
);
627 UniquePtr
<DrawBuffer
> ret( new DrawBuffer(gl
, size
, fb
, colorMSRB
,
628 depthRB
, stencilRB
) );
630 GLenum err
= localError
.GetError();
631 MOZ_ASSERT_IF(err
!= LOCAL_GL_NO_ERROR
, err
== LOCAL_GL_OUT_OF_MEMORY
);
632 if (err
|| !gl
->IsFramebufferComplete(fb
))
635 *out_buffer
= Move(ret
);
639 DrawBuffer::~DrawBuffer()
650 mGL
->fDeleteFramebuffers(1, &fb
);
651 mGL
->fDeleteRenderbuffers(3, rbs
);
654 ////////////////////////////////////////////////////////////////////////
657 UniquePtr
<ReadBuffer
>
658 ReadBuffer::Create(GLContext
* gl
,
659 const SurfaceCaps
& caps
,
660 const GLFormats
& formats
,
665 if (surf
->mAttachType
== AttachmentType::Screen
) {
666 // Don't need anything. Our read buffer will be the 'screen'.
668 return UniquePtr
<ReadBuffer
>( new ReadBuffer(gl
, 0, 0, 0,
673 GLuint stencilRB
= 0;
675 GLuint
* pDepthRB
= caps
.depth
? &depthRB
: nullptr;
676 GLuint
* pStencilRB
= caps
.stencil
? &stencilRB
: nullptr;
678 GLContext::LocalErrorScope
localError(*gl
);
680 CreateRenderbuffersForOffscreen(gl
, formats
, surf
->mSize
, caps
.antialias
,
681 nullptr, pDepthRB
, pStencilRB
);
687 switch (surf
->mAttachType
) {
688 case AttachmentType::GLTexture
:
689 colorTex
= surf
->ProdTexture();
690 target
= surf
->ProdTextureTarget();
692 case AttachmentType::GLRenderbuffer
:
693 colorRB
= surf
->ProdRenderbuffer();
696 MOZ_CRASH("Unknown attachment type?");
698 MOZ_ASSERT(colorTex
|| colorRB
);
701 gl
->fGenFramebuffers(1, &fb
);
702 gl
->AttachBuffersToFB(colorTex
, colorRB
, depthRB
, stencilRB
, fb
, target
);
703 gl
->mFBOMapping
[fb
] = surf
;
705 UniquePtr
<ReadBuffer
> ret( new ReadBuffer(gl
, fb
, depthRB
,
708 GLenum err
= localError
.GetError();
709 MOZ_ASSERT_IF(err
!= LOCAL_GL_NO_ERROR
, err
== LOCAL_GL_OUT_OF_MEMORY
);
710 if (err
|| !gl
->IsFramebufferComplete(fb
)) {
717 ReadBuffer::~ReadBuffer()
727 mGL
->fDeleteFramebuffers(1, &fb
);
728 mGL
->fDeleteRenderbuffers(2, rbs
);
729 mGL
->mFBOMapping
.erase(mFB
);
733 ReadBuffer::Attach(SharedSurface
* surf
)
735 MOZ_ASSERT(surf
&& mSurf
);
736 MOZ_ASSERT(surf
->mAttachType
== mSurf
->mAttachType
);
737 MOZ_ASSERT(surf
->mSize
== mSurf
->mSize
);
739 // Nothing else is needed for AttachType Screen.
740 if (surf
->mAttachType
!= AttachmentType::Screen
) {
745 switch (surf
->mAttachType
) {
746 case AttachmentType::GLTexture
:
747 colorTex
= surf
->ProdTexture();
748 target
= surf
->ProdTextureTarget();
750 case AttachmentType::GLRenderbuffer
:
751 colorRB
= surf
->ProdRenderbuffer();
754 MOZ_CRASH("Unknown attachment type?");
757 mGL
->AttachBuffersToFB(colorTex
, colorRB
, 0, 0, mFB
, target
);
758 mGL
->mFBOMapping
[mFB
] = surf
;
759 MOZ_ASSERT(mGL
->IsFramebufferComplete(mFB
));
766 ReadBuffer::Size() const
772 } /* namespace mozilla */