michael@0: /* -*- Mode: c++; c-basic-offset: 4; indent-tabs-mode: nil; tab-width: 40; -*- */ michael@0: /* This Source Code Form is subject to the terms of the Mozilla Public michael@0: * License, v. 2.0. If a copy of the MPL was not distributed with this michael@0: * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ michael@0: michael@0: #include "GLScreenBuffer.h" michael@0: michael@0: #include michael@0: #include "gfxImageSurface.h" michael@0: #include "GLContext.h" michael@0: #include "GLBlitHelper.h" michael@0: #include "GLReadTexImageHelper.h" michael@0: #include "SharedSurfaceGL.h" michael@0: #include "SurfaceStream.h" michael@0: #ifdef MOZ_WIDGET_GONK michael@0: #include "SharedSurfaceGralloc.h" michael@0: #include "nsXULAppAPI.h" michael@0: #endif michael@0: #ifdef XP_MACOSX michael@0: #include "SharedSurfaceIO.h" michael@0: #endif michael@0: #include "ScopedGLHelpers.h" michael@0: #include "gfx2DGlue.h" michael@0: michael@0: using namespace mozilla::gfx; michael@0: michael@0: namespace mozilla { michael@0: namespace gl { michael@0: michael@0: GLScreenBuffer* michael@0: GLScreenBuffer::Create(GLContext* gl, michael@0: const gfx::IntSize& size, michael@0: const SurfaceCaps& caps) michael@0: { michael@0: if (caps.antialias && michael@0: !gl->IsSupported(GLFeature::framebuffer_multisample)) michael@0: { michael@0: return nullptr; michael@0: } michael@0: michael@0: SurfaceFactory_GL* factory = nullptr; michael@0: michael@0: #ifdef MOZ_WIDGET_GONK michael@0: /* On B2G, we want a Gralloc factory, and we want one right at the start */ michael@0: if (!factory && michael@0: caps.surfaceAllocator && michael@0: XRE_GetProcessType() != GeckoProcessType_Default) michael@0: { michael@0: factory = new SurfaceFactory_Gralloc(gl, caps); michael@0: } michael@0: #endif michael@0: #ifdef XP_MACOSX michael@0: /* On OSX, we want an IOSurface factory, and we want one right at the start */ michael@0: if (!factory) michael@0: { michael@0: factory = new SurfaceFactory_IOSurface(gl, caps); michael@0: } michael@0: #endif michael@0: michael@0: if (!factory) michael@0: factory = new SurfaceFactory_Basic(gl, caps); michael@0: michael@0: SurfaceStream* stream = SurfaceStream::CreateForType( michael@0: SurfaceStream::ChooseGLStreamType(SurfaceStream::MainThread, michael@0: caps.preserve), michael@0: gl, michael@0: nullptr); michael@0: michael@0: return new GLScreenBuffer(gl, caps, factory, stream); michael@0: } michael@0: michael@0: GLScreenBuffer::~GLScreenBuffer() michael@0: { michael@0: delete mDraw; michael@0: delete mRead; michael@0: michael@0: // bug 914823: it is crucial to destroy the Factory _after_ we destroy michael@0: // the SharedSurfaces around here! Reason: the shared surfaces will want michael@0: // to ask the Allocator (e.g. the ClientLayerManager) to destroy their michael@0: // buffers, but that Allocator may be kept alive by the Factory, michael@0: // as it currently the case in SurfaceFactory_Gralloc holding a nsRefPtr michael@0: // to the Allocator! michael@0: delete mFactory; michael@0: } michael@0: michael@0: michael@0: void michael@0: GLScreenBuffer::BindAsFramebuffer(GLContext* const gl, GLenum target) const michael@0: { michael@0: GLuint drawFB = DrawFB(); michael@0: GLuint readFB = ReadFB(); michael@0: michael@0: if (!gl->IsSupported(GLFeature::framebuffer_blit)) { michael@0: MOZ_ASSERT(drawFB == readFB); michael@0: gl->raw_fBindFramebuffer(target, readFB); michael@0: return; michael@0: } michael@0: michael@0: switch (target) { michael@0: case LOCAL_GL_FRAMEBUFFER: michael@0: gl->raw_fBindFramebuffer(LOCAL_GL_DRAW_FRAMEBUFFER_EXT, drawFB); michael@0: gl->raw_fBindFramebuffer(LOCAL_GL_READ_FRAMEBUFFER_EXT, readFB); michael@0: break; michael@0: michael@0: case LOCAL_GL_DRAW_FRAMEBUFFER_EXT: michael@0: if (!gl->IsSupported(GLFeature::framebuffer_blit)) michael@0: NS_WARNING("DRAW_FRAMEBUFFER requested but unavailable."); michael@0: michael@0: gl->raw_fBindFramebuffer(LOCAL_GL_DRAW_FRAMEBUFFER_EXT, drawFB); michael@0: break; michael@0: michael@0: case LOCAL_GL_READ_FRAMEBUFFER_EXT: michael@0: if (!gl->IsSupported(GLFeature::framebuffer_blit)) michael@0: NS_WARNING("READ_FRAMEBUFFER requested but unavailable."); michael@0: michael@0: gl->raw_fBindFramebuffer(LOCAL_GL_READ_FRAMEBUFFER_EXT, readFB); michael@0: break; michael@0: michael@0: default: michael@0: MOZ_CRASH("Bad `target` for BindFramebuffer."); michael@0: } michael@0: } michael@0: michael@0: void michael@0: GLScreenBuffer::BindFB(GLuint fb) michael@0: { michael@0: GLuint drawFB = DrawFB(); michael@0: GLuint readFB = ReadFB(); michael@0: michael@0: mUserDrawFB = fb; michael@0: mUserReadFB = fb; michael@0: mInternalDrawFB = (fb == 0) ? drawFB : fb; michael@0: mInternalReadFB = (fb == 0) ? readFB : fb; michael@0: michael@0: if (mInternalDrawFB == mInternalReadFB) { michael@0: mGL->raw_fBindFramebuffer(LOCAL_GL_FRAMEBUFFER, mInternalDrawFB); michael@0: } else { michael@0: MOZ_ASSERT(mGL->IsSupported(GLFeature::framebuffer_blit)); michael@0: mGL->raw_fBindFramebuffer(LOCAL_GL_DRAW_FRAMEBUFFER_EXT, mInternalDrawFB); michael@0: mGL->raw_fBindFramebuffer(LOCAL_GL_READ_FRAMEBUFFER_EXT, mInternalReadFB); michael@0: } michael@0: michael@0: #ifdef DEBUG michael@0: mInInternalMode_DrawFB = false; michael@0: mInInternalMode_ReadFB = false; michael@0: #endif michael@0: } michael@0: michael@0: void michael@0: GLScreenBuffer::BindDrawFB(GLuint fb) michael@0: { michael@0: if (!mGL->IsSupported(GLFeature::framebuffer_blit)) { michael@0: NS_WARNING("DRAW_FRAMEBUFFER requested, but unsupported."); michael@0: michael@0: mGL->raw_fBindFramebuffer(LOCAL_GL_DRAW_FRAMEBUFFER_EXT, fb); michael@0: } else { michael@0: GLuint drawFB = DrawFB(); michael@0: mUserDrawFB = fb; michael@0: mInternalDrawFB = (fb == 0) ? drawFB : fb; michael@0: michael@0: mGL->raw_fBindFramebuffer(LOCAL_GL_DRAW_FRAMEBUFFER_EXT, mInternalDrawFB); michael@0: } michael@0: michael@0: #ifdef DEBUG michael@0: mInInternalMode_DrawFB = false; michael@0: #endif michael@0: } michael@0: michael@0: void michael@0: GLScreenBuffer::BindReadFB(GLuint fb) michael@0: { michael@0: if (!mGL->IsSupported(GLFeature::framebuffer_blit)) { michael@0: NS_WARNING("READ_FRAMEBUFFER requested, but unsupported."); michael@0: michael@0: mGL->raw_fBindFramebuffer(LOCAL_GL_READ_FRAMEBUFFER_EXT, fb); michael@0: } else { michael@0: GLuint readFB = ReadFB(); michael@0: mUserReadFB = fb; michael@0: mInternalReadFB = (fb == 0) ? readFB : fb; michael@0: michael@0: mGL->raw_fBindFramebuffer(LOCAL_GL_READ_FRAMEBUFFER_EXT, mInternalReadFB); michael@0: } michael@0: michael@0: #ifdef DEBUG michael@0: mInInternalMode_ReadFB = false; michael@0: #endif michael@0: } michael@0: michael@0: void michael@0: GLScreenBuffer::BindDrawFB_Internal(GLuint fb) michael@0: { michael@0: mInternalDrawFB = mUserDrawFB = fb; michael@0: mGL->raw_fBindFramebuffer(LOCAL_GL_DRAW_FRAMEBUFFER_EXT, mInternalDrawFB); michael@0: michael@0: #ifdef DEBUG michael@0: mInInternalMode_DrawFB = true; michael@0: #endif michael@0: } michael@0: michael@0: void michael@0: GLScreenBuffer::BindReadFB_Internal(GLuint fb) michael@0: { michael@0: mInternalReadFB = mUserReadFB = fb; michael@0: mGL->raw_fBindFramebuffer(LOCAL_GL_READ_FRAMEBUFFER_EXT, mInternalReadFB); michael@0: michael@0: #ifdef DEBUG michael@0: mInInternalMode_ReadFB = true; michael@0: #endif michael@0: } michael@0: michael@0: michael@0: GLuint michael@0: GLScreenBuffer::GetDrawFB() const michael@0: { michael@0: #ifdef DEBUG michael@0: MOZ_ASSERT(mGL->IsCurrent()); michael@0: MOZ_ASSERT(!mInInternalMode_DrawFB); michael@0: michael@0: // Don't need a branch here, because: michael@0: // LOCAL_GL_DRAW_FRAMEBUFFER_BINDING_EXT == LOCAL_GL_FRAMEBUFFER_BINDING == 0x8CA6 michael@0: // We use raw_ here because this is debug code and we need to see what michael@0: // the driver thinks. michael@0: GLuint actual = 0; michael@0: mGL->raw_fGetIntegerv(LOCAL_GL_DRAW_FRAMEBUFFER_BINDING_EXT, (GLint*)&actual); michael@0: michael@0: GLuint predicted = mInternalDrawFB; michael@0: if (predicted != actual) { michael@0: printf_stderr("Misprediction: Bound draw FB predicted: %d. Was: %d.\n", michael@0: predicted, actual); michael@0: MOZ_ASSERT(false, "Draw FB binding misprediction!"); michael@0: } michael@0: #endif michael@0: michael@0: return mUserDrawFB; michael@0: } michael@0: michael@0: GLuint michael@0: GLScreenBuffer::GetReadFB() const michael@0: { michael@0: #ifdef DEBUG michael@0: MOZ_ASSERT(mGL->IsCurrent()); michael@0: MOZ_ASSERT(!mInInternalMode_ReadFB); michael@0: michael@0: // We use raw_ here because this is debug code and we need to see what michael@0: // the driver thinks. michael@0: GLuint actual = 0; michael@0: if (mGL->IsSupported(GLFeature::framebuffer_blit)) michael@0: mGL->raw_fGetIntegerv(LOCAL_GL_READ_FRAMEBUFFER_BINDING_EXT, (GLint*)&actual); michael@0: else michael@0: mGL->raw_fGetIntegerv(LOCAL_GL_FRAMEBUFFER_BINDING, (GLint*)&actual); michael@0: michael@0: GLuint predicted = mInternalReadFB; michael@0: if (predicted != actual) { michael@0: printf_stderr("Misprediction: Bound read FB predicted: %d. Was: %d.\n", michael@0: predicted, actual); michael@0: MOZ_ASSERT(false, "Read FB binding misprediction!"); michael@0: } michael@0: #endif michael@0: michael@0: return mUserReadFB; michael@0: } michael@0: michael@0: GLuint michael@0: GLScreenBuffer::GetFB() const michael@0: { michael@0: MOZ_ASSERT(GetDrawFB() == GetReadFB()); michael@0: return GetDrawFB(); michael@0: } michael@0: michael@0: michael@0: void michael@0: GLScreenBuffer::DeletingFB(GLuint fb) michael@0: { michael@0: if (fb == mInternalDrawFB) { michael@0: mInternalDrawFB = 0; michael@0: mUserDrawFB = 0; michael@0: } michael@0: if (fb == mInternalReadFB) { michael@0: mInternalReadFB = 0; michael@0: mUserReadFB = 0; michael@0: } michael@0: } michael@0: michael@0: michael@0: void michael@0: GLScreenBuffer::AfterDrawCall() michael@0: { michael@0: if (mUserDrawFB != 0) michael@0: return; michael@0: michael@0: RequireBlit(); michael@0: } michael@0: michael@0: void michael@0: GLScreenBuffer::BeforeReadCall() michael@0: { michael@0: if (mUserReadFB != 0) michael@0: return; michael@0: michael@0: AssureBlitted(); michael@0: } michael@0: michael@0: bool michael@0: GLScreenBuffer::ReadPixels(GLint x, GLint y, GLsizei width, GLsizei height, michael@0: GLenum format, GLenum type, GLvoid *pixels) michael@0: { michael@0: // If the currently bound framebuffer is backed by a SharedSurface_GL michael@0: // then it might want to override how we read pixel data from it. michael@0: // This is normally only the default framebuffer, but we can also michael@0: // have SharedSurfaces bound to other framebuffers when doing michael@0: // readback for BasicLayers. michael@0: SharedSurface_GL* surf; michael@0: if (GetReadFB() == 0) { michael@0: surf = SharedSurf(); michael@0: } else { michael@0: surf = mGL->mFBOMapping[GetReadFB()]; michael@0: } michael@0: if (surf) { michael@0: return surf->ReadPixels(x, y, width, height, format, type, pixels); michael@0: } michael@0: michael@0: return false; michael@0: } michael@0: michael@0: void michael@0: GLScreenBuffer::RequireBlit() michael@0: { michael@0: mNeedsBlit = true; michael@0: } michael@0: michael@0: void michael@0: GLScreenBuffer::AssureBlitted() michael@0: { michael@0: if (!mNeedsBlit) michael@0: return; michael@0: michael@0: if (mDraw) { michael@0: GLuint drawFB = DrawFB(); michael@0: GLuint readFB = ReadFB(); michael@0: michael@0: MOZ_ASSERT(drawFB != 0); michael@0: MOZ_ASSERT(drawFB != readFB); michael@0: MOZ_ASSERT(mGL->IsSupported(GLFeature::framebuffer_blit)); michael@0: MOZ_ASSERT(mDraw->Size() == mRead->Size()); michael@0: michael@0: ScopedBindFramebuffer boundFB(mGL); michael@0: ScopedGLState scissor(mGL, LOCAL_GL_SCISSOR_TEST, false); michael@0: michael@0: BindReadFB_Internal(drawFB); michael@0: BindDrawFB_Internal(readFB); michael@0: michael@0: const gfx::IntSize& srcSize = mDraw->Size(); michael@0: const gfx::IntSize& destSize = mRead->Size(); michael@0: michael@0: mGL->raw_fBlitFramebuffer(0, 0, srcSize.width, srcSize.height, michael@0: 0, 0, destSize.width, destSize.height, michael@0: LOCAL_GL_COLOR_BUFFER_BIT, michael@0: LOCAL_GL_NEAREST); michael@0: // Done! michael@0: } michael@0: michael@0: mNeedsBlit = false; michael@0: } michael@0: michael@0: void michael@0: GLScreenBuffer::Morph(SurfaceFactory_GL* newFactory, SurfaceStreamType streamType) michael@0: { michael@0: MOZ_ASSERT(mStream); michael@0: michael@0: if (newFactory) { michael@0: delete mFactory; michael@0: mFactory = newFactory; michael@0: } michael@0: michael@0: if (mStream->mType == streamType) michael@0: return; michael@0: michael@0: SurfaceStream* newStream = SurfaceStream::CreateForType(streamType, mGL, mStream); michael@0: MOZ_ASSERT(newStream); michael@0: michael@0: mStream = newStream; michael@0: } michael@0: michael@0: void michael@0: GLScreenBuffer::Attach(SharedSurface* surface, const gfx::IntSize& size) michael@0: { michael@0: ScopedBindFramebuffer autoFB(mGL); michael@0: michael@0: SharedSurface_GL* surf = SharedSurface_GL::Cast(surface); michael@0: if (mRead && SharedSurf()) michael@0: SharedSurf()->UnlockProd(); michael@0: michael@0: surf->LockProd(); michael@0: michael@0: if (mRead && michael@0: surf->AttachType() == SharedSurf()->AttachType() && michael@0: size == Size()) michael@0: { michael@0: // Same size, same type, ready for reuse! michael@0: mRead->Attach(surf); michael@0: } else { michael@0: // Else something changed, so resize: michael@0: DrawBuffer* draw = CreateDraw(size); // Can be null. michael@0: ReadBuffer* read = CreateRead(surf); michael@0: MOZ_ASSERT(read); // Should never fail if SwapProd succeeded. michael@0: michael@0: delete mDraw; michael@0: delete mRead; michael@0: michael@0: mDraw = draw; michael@0: mRead = read; michael@0: } michael@0: michael@0: // Check that we're all set up. michael@0: MOZ_ASSERT(SharedSurf() == surf); michael@0: michael@0: if (!PreserveBuffer()) { michael@0: // DiscardFramebuffer here could help perf on some mobile platforms. michael@0: } michael@0: } michael@0: michael@0: bool michael@0: GLScreenBuffer::Swap(const gfx::IntSize& size) michael@0: { michael@0: SharedSurface* nextSurf = mStream->SwapProducer(mFactory, size); michael@0: if (!nextSurf) { michael@0: SurfaceFactory_Basic basicFactory(mGL, mFactory->Caps()); michael@0: nextSurf = mStream->SwapProducer(&basicFactory, size); michael@0: if (!nextSurf) michael@0: return false; michael@0: michael@0: NS_WARNING("SwapProd failed for sophisticated Factory type, fell back to Basic."); michael@0: } michael@0: MOZ_ASSERT(nextSurf); michael@0: michael@0: Attach(nextSurf, size); michael@0: michael@0: return true; michael@0: } michael@0: michael@0: bool michael@0: GLScreenBuffer::PublishFrame(const gfx::IntSize& size) michael@0: { michael@0: AssureBlitted(); michael@0: michael@0: bool good = Swap(size); michael@0: return good; michael@0: } michael@0: michael@0: bool michael@0: GLScreenBuffer::Resize(const gfx::IntSize& size) michael@0: { michael@0: SharedSurface* surface = mStream->Resize(mFactory, size); michael@0: if (!surface) michael@0: return false; michael@0: michael@0: Attach(surface, size); michael@0: return true; michael@0: } michael@0: michael@0: DrawBuffer* michael@0: GLScreenBuffer::CreateDraw(const gfx::IntSize& size) michael@0: { michael@0: GLContext* gl = mFactory->GL(); michael@0: const GLFormats& formats = mFactory->Formats(); michael@0: const SurfaceCaps& caps = mFactory->DrawCaps(); michael@0: michael@0: return DrawBuffer::Create(gl, caps, formats, size); michael@0: } michael@0: michael@0: ReadBuffer* michael@0: GLScreenBuffer::CreateRead(SharedSurface_GL* surf) michael@0: { michael@0: GLContext* gl = mFactory->GL(); michael@0: const GLFormats& formats = mFactory->Formats(); michael@0: const SurfaceCaps& caps = mFactory->ReadCaps(); michael@0: michael@0: return ReadBuffer::Create(gl, caps, formats, surf); michael@0: } michael@0: michael@0: void michael@0: GLScreenBuffer::Readback(SharedSurface_GL* src, DataSourceSurface* dest) michael@0: { michael@0: MOZ_ASSERT(src && dest); michael@0: DataSourceSurface::MappedSurface ms; michael@0: dest->Map(DataSourceSurface::MapType::READ, &ms); michael@0: nsRefPtr wrappedDest = michael@0: new gfxImageSurface(ms.mData, michael@0: ThebesIntSize(dest->GetSize()), michael@0: ms.mStride, michael@0: SurfaceFormatToImageFormat(dest->GetFormat())); michael@0: DeprecatedReadback(src, wrappedDest); michael@0: dest->Unmap(); michael@0: } michael@0: michael@0: void michael@0: GLScreenBuffer::DeprecatedReadback(SharedSurface_GL* src, gfxImageSurface* dest) michael@0: { michael@0: MOZ_ASSERT(src && dest); michael@0: MOZ_ASSERT(ToIntSize(dest->GetSize()) == src->Size()); michael@0: MOZ_ASSERT(dest->Format() == (src->HasAlpha() ? gfxImageFormat::ARGB32 michael@0: : gfxImageFormat::RGB24)); michael@0: michael@0: mGL->MakeCurrent(); michael@0: michael@0: bool needsSwap = src != SharedSurf(); michael@0: if (needsSwap) { michael@0: SharedSurf()->UnlockProd(); michael@0: src->LockProd(); michael@0: } michael@0: michael@0: ReadBuffer* buffer = CreateRead(src); michael@0: MOZ_ASSERT(buffer); michael@0: michael@0: ScopedBindFramebuffer autoFB(mGL, buffer->FB()); michael@0: ReadPixelsIntoImageSurface(mGL, dest); michael@0: michael@0: delete buffer; michael@0: michael@0: if (needsSwap) { michael@0: src->UnlockProd(); michael@0: SharedSurf()->LockProd(); michael@0: } michael@0: } michael@0: michael@0: DrawBuffer* michael@0: DrawBuffer::Create(GLContext* const gl, michael@0: const SurfaceCaps& caps, michael@0: const GLFormats& formats, michael@0: const gfx::IntSize& size) michael@0: { michael@0: if (!caps.color) { michael@0: MOZ_ASSERT(!caps.alpha && !caps.depth && !caps.stencil); michael@0: michael@0: // Nothing is needed. michael@0: return nullptr; michael@0: } michael@0: michael@0: GLuint colorMSRB = 0; michael@0: GLuint depthRB = 0; michael@0: GLuint stencilRB = 0; michael@0: michael@0: GLuint* pColorMSRB = caps.antialias ? &colorMSRB : nullptr; michael@0: GLuint* pDepthRB = caps.depth ? &depthRB : nullptr; michael@0: GLuint* pStencilRB = caps.stencil ? &stencilRB : nullptr; michael@0: michael@0: if (!formats.color_rbFormat) michael@0: pColorMSRB = nullptr; michael@0: michael@0: if (pDepthRB && pStencilRB) { michael@0: if (!formats.depth && !formats.depthStencil) michael@0: pDepthRB = nullptr; michael@0: michael@0: if (!formats.stencil && !formats.depthStencil) michael@0: pStencilRB = nullptr; michael@0: } else { michael@0: if (!formats.depth) michael@0: pDepthRB = nullptr; michael@0: michael@0: if (!formats.stencil) michael@0: pStencilRB = nullptr; michael@0: } michael@0: michael@0: CreateRenderbuffersForOffscreen(gl, formats, size, caps.antialias, michael@0: pColorMSRB, pDepthRB, pStencilRB); michael@0: michael@0: GLuint fb = 0; michael@0: gl->fGenFramebuffers(1, &fb); michael@0: gl->AttachBuffersToFB(0, colorMSRB, depthRB, stencilRB, fb); michael@0: MOZ_ASSERT(gl->IsFramebufferComplete(fb)); michael@0: michael@0: return new DrawBuffer(gl, size, fb, colorMSRB, depthRB, stencilRB); michael@0: } michael@0: michael@0: DrawBuffer::~DrawBuffer() michael@0: { michael@0: mGL->MakeCurrent(); michael@0: michael@0: GLuint fb = mFB; michael@0: GLuint rbs[] = { michael@0: mColorMSRB, michael@0: mDepthRB, michael@0: mStencilRB michael@0: }; michael@0: michael@0: mGL->fDeleteFramebuffers(1, &fb); michael@0: mGL->fDeleteRenderbuffers(3, rbs); michael@0: } michael@0: michael@0: michael@0: michael@0: michael@0: michael@0: michael@0: ReadBuffer* michael@0: ReadBuffer::Create(GLContext* gl, michael@0: const SurfaceCaps& caps, michael@0: const GLFormats& formats, michael@0: SharedSurface_GL* surf) michael@0: { michael@0: MOZ_ASSERT(surf); michael@0: michael@0: if (surf->AttachType() == AttachmentType::Screen) { michael@0: // Don't need anything. Our read buffer will be the 'screen'. michael@0: michael@0: return new ReadBuffer(gl, michael@0: 0, 0, 0, michael@0: surf); michael@0: } michael@0: michael@0: GLuint depthRB = 0; michael@0: GLuint stencilRB = 0; michael@0: michael@0: GLuint* pDepthRB = caps.depth ? &depthRB : nullptr; michael@0: GLuint* pStencilRB = caps.stencil ? &stencilRB : nullptr; michael@0: michael@0: CreateRenderbuffersForOffscreen(gl, formats, surf->Size(), caps.antialias, michael@0: nullptr, pDepthRB, pStencilRB); michael@0: michael@0: GLuint colorTex = 0; michael@0: GLuint colorRB = 0; michael@0: GLenum target = 0; michael@0: michael@0: switch (surf->AttachType()) { michael@0: case AttachmentType::GLTexture: michael@0: colorTex = surf->ProdTexture(); michael@0: target = surf->ProdTextureTarget(); michael@0: break; michael@0: case AttachmentType::GLRenderbuffer: michael@0: colorRB = surf->ProdRenderbuffer(); michael@0: break; michael@0: default: michael@0: MOZ_CRASH("Unknown attachment type?"); michael@0: } michael@0: MOZ_ASSERT(colorTex || colorRB); michael@0: michael@0: GLuint fb = 0; michael@0: gl->fGenFramebuffers(1, &fb); michael@0: gl->AttachBuffersToFB(colorTex, colorRB, depthRB, stencilRB, fb, target); michael@0: gl->mFBOMapping[fb] = surf; michael@0: michael@0: MOZ_ASSERT(gl->IsFramebufferComplete(fb)); michael@0: michael@0: return new ReadBuffer(gl, michael@0: fb, depthRB, stencilRB, michael@0: surf); michael@0: } michael@0: michael@0: ReadBuffer::~ReadBuffer() michael@0: { michael@0: mGL->MakeCurrent(); michael@0: michael@0: GLuint fb = mFB; michael@0: GLuint rbs[] = { michael@0: mDepthRB, michael@0: mStencilRB michael@0: }; michael@0: michael@0: mGL->fDeleteFramebuffers(1, &fb); michael@0: mGL->fDeleteRenderbuffers(2, rbs); michael@0: mGL->mFBOMapping.erase(mFB); michael@0: } michael@0: michael@0: void michael@0: ReadBuffer::Attach(SharedSurface_GL* surf) michael@0: { michael@0: MOZ_ASSERT(surf && mSurf); michael@0: MOZ_ASSERT(surf->AttachType() == mSurf->AttachType()); michael@0: MOZ_ASSERT(surf->Size() == mSurf->Size()); michael@0: michael@0: // Nothing else is needed for AttachType Screen. michael@0: if (surf->AttachType() != AttachmentType::Screen) { michael@0: GLuint colorTex = 0; michael@0: GLuint colorRB = 0; michael@0: GLenum target = 0; michael@0: michael@0: switch (surf->AttachType()) { michael@0: case AttachmentType::GLTexture: michael@0: colorTex = surf->ProdTexture(); michael@0: target = surf->ProdTextureTarget(); michael@0: break; michael@0: case AttachmentType::GLRenderbuffer: michael@0: colorRB = surf->ProdRenderbuffer(); michael@0: break; michael@0: default: michael@0: MOZ_CRASH("Unknown attachment type?"); michael@0: } michael@0: michael@0: mGL->AttachBuffersToFB(colorTex, colorRB, 0, 0, mFB, target); michael@0: mGL->mFBOMapping[mFB] = surf; michael@0: MOZ_ASSERT(mGL->IsFramebufferComplete(mFB)); michael@0: } michael@0: michael@0: mSurf = surf; michael@0: } michael@0: michael@0: const gfx::IntSize& michael@0: ReadBuffer::Size() const michael@0: { michael@0: return mSurf->Size(); michael@0: } michael@0: michael@0: } /* namespace gl */ michael@0: } /* namespace mozilla */