/* -*- Mode: c++; c-basic-offset: 2; indent-tabs-mode: nil; tab-width: 4; -*- */ /* This Source Code Form is subject to the terms of the Mozilla Public * License, v. 2.0. If a copy of the MPL was not distributed with this * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ /* GLScreenBuffer is the abstraction for the "default framebuffer" used * by an offscreen GLContext. Since it's only for offscreen GLContext's, * it's only useful for things like WebGL, and is NOT used by the * compositor's GLContext. Remember that GLContext provides an abstraction * so that even if you want to draw to the 'screen', even if that's not * actually the screen, just draw to 0. This GLScreenBuffer class takes the * logic handling out of GLContext. */ #ifndef SCREEN_BUFFER_H_ #define SCREEN_BUFFER_H_ #include "GLContextTypes.h" #include "GLDefs.h" #include "mozilla/gfx/2D.h" #include "mozilla/gfx/Point.h" #include "mozilla/UniquePtr.h" #include "SharedSurface.h" #include "SurfaceTypes.h" namespace mozilla { namespace layers { class KnowsCompositor; class LayersIPCChannel; class SharedSurfaceTextureClient; } // namespace layers namespace gl { class GLContext; class SharedSurface; class ShSurfHandle; class SurfaceFactory; class ReadBuffer { public: // Infallible, always non-null. static UniquePtr Create(GLContext* gl, const SurfaceCaps& caps, const GLFormats& formats, SharedSurface* surf); protected: GLContext* const mGL; public: const GLuint mFB; protected: // mFB has the following attachments: const GLuint mDepthRB; const GLuint mStencilRB; // note no mColorRB here: this is provided by mSurf. SharedSurface* mSurf; ReadBuffer(GLContext* gl, GLuint fb, GLuint depthRB, GLuint stencilRB, SharedSurface* surf) : mGL(gl), mFB(fb), mDepthRB(depthRB), mStencilRB(stencilRB), mSurf(surf) {} public: virtual ~ReadBuffer(); // Cannot attach a surf of a different AttachType or Size than before. void Attach(SharedSurface* surf); const gfx::IntSize& Size() const; SharedSurface* SharedSurf() const { return mSurf; } void SetReadBuffer(GLenum mode) const; }; class GLScreenBuffer { public: // Infallible. static UniquePtr Create(GLContext* gl, const gfx::IntSize& size, const SurfaceCaps& caps); static UniquePtr CreateFactory( GLContext* gl, const SurfaceCaps& caps, layers::KnowsCompositor* compositorConnection, const layers::TextureFlags& flags); protected: GLContext* const mGL; // Owns us. public: const SurfaceCaps mCaps; protected: UniquePtr mFactory; RefPtr mBack; RefPtr mFront; UniquePtr mRead; bool mNeedsBlit; GLenum mUserReadBufferMode; GLenum mUserDrawBufferMode; // Below are the parts that help us pretend to be framebuffer 0: GLuint mUserDrawFB; GLuint mUserReadFB; GLuint mInternalDrawFB; GLuint mInternalReadFB; #ifdef DEBUG bool mInInternalMode_DrawFB; bool mInInternalMode_ReadFB; #endif GLScreenBuffer(GLContext* gl, const SurfaceCaps& caps, UniquePtr factory); public: virtual ~GLScreenBuffer(); SurfaceFactory* Factory() const { return mFactory.get(); } const RefPtr& Front() const { return mFront; } SharedSurface* SharedSurf() const { MOZ_ASSERT(mRead); return mRead->SharedSurf(); } bool ShouldPreserveBuffer() const { return mCaps.preserve; } GLuint DrawFB() const { return ReadFB(); } GLuint ReadFB() const { return mRead->mFB; } uint32_t DepthBits() const; void DeletingFB(GLuint fb); const gfx::IntSize& Size() const { MOZ_ASSERT(mRead); return mRead->Size(); } bool IsReadBufferReady() const { return mRead.get() != nullptr; } void BindAsFramebuffer(GLContext* const gl, GLenum target) const; void RequireBlit(); void AssureBlitted(); void AfterDrawCall(); void BeforeReadCall(); bool CopyTexImage2D(GLenum target, GLint level, GLenum internalformat, GLint x, GLint y, GLsizei width, GLsizei height, GLint border); void SetReadBuffer(GLenum userMode); void SetDrawBuffer(GLenum userMode); GLenum GetReadBufferMode() const { return mUserReadBufferMode; } GLenum GetDrawBufferMode() const { return mUserDrawBufferMode; } /** * Attempts to read pixels from the current bound framebuffer, if * it is backed by a SharedSurface. * * Returns true if the pixel data has been read back, false * otherwise. */ bool ReadPixels(GLint x, GLint y, GLsizei width, GLsizei height, GLenum format, GLenum type, GLvoid* pixels); // Morph changes the factory used to create surfaces. void Morph(UniquePtr newFactory); protected: // Returns false on error or inability to resize. bool Swap(const gfx::IntSize& size); public: bool PublishFrame(const gfx::IntSize& size); bool Resize(const gfx::IntSize& size); protected: bool Attach(SharedSurface* surf, const gfx::IntSize& size); UniquePtr CreateRead(SharedSurface* surf); public: /* `fb` in these functions is the framebuffer the GLContext is hoping to * bind. When this is 0, we intercept the call and bind our own * framebuffers. As a client of these functions, just bind 0 when you want * to draw to the default framebuffer/'screen'. */ void BindFB(GLuint fb); void BindDrawFB(GLuint fb); void BindReadFB(GLuint fb); GLuint GetFB() const; GLuint GetDrawFB() const; GLuint GetReadFB() const; // Here `fb` is the actual framebuffer you want bound. Binding 0 will // bind the (generally useless) default framebuffer. void BindFB_Internal(GLuint fb); void BindDrawFB_Internal(GLuint fb); void BindReadFB_Internal(GLuint fb); bool IsDrawFramebufferDefault() const; bool IsReadFramebufferDefault() const; }; } // namespace gl } // namespace mozilla #endif // SCREEN_BUFFER_H_