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: /* GLScreenBuffer is the abstraction for the "default framebuffer" used michael@0: * by an offscreen GLContext. Since it's only for offscreen GLContext's, michael@0: * it's only useful for things like WebGL, and is NOT used by the michael@0: * compositor's GLContext. Remember that GLContext provides an abstraction michael@0: * so that even if you want to draw to the 'screen', even if that's not michael@0: * actually the screen, just draw to 0. This GLScreenBuffer class takes the michael@0: * logic handling out of GLContext. michael@0: */ michael@0: michael@0: #ifndef SCREEN_BUFFER_H_ michael@0: #define SCREEN_BUFFER_H_ michael@0: michael@0: #include "SurfaceTypes.h" michael@0: #include "SurfaceStream.h" michael@0: #include "GLContextTypes.h" michael@0: #include "GLDefs.h" michael@0: #include "mozilla/gfx/2D.h" michael@0: #include "mozilla/gfx/Point.h" michael@0: michael@0: // Forwards: michael@0: class gfxImageSurface; michael@0: michael@0: namespace mozilla { michael@0: namespace gfx { michael@0: class SurfaceStream; michael@0: class SharedSurface; michael@0: } michael@0: namespace gl { michael@0: class GLContext; michael@0: class SharedSurface_GL; michael@0: class SurfaceFactory_GL; michael@0: } michael@0: } michael@0: michael@0: namespace mozilla { michael@0: namespace gl { michael@0: michael@0: class DrawBuffer michael@0: { michael@0: protected: michael@0: typedef struct gfx::SurfaceCaps SurfaceCaps; michael@0: michael@0: public: michael@0: // Infallible, may return null if unneeded. michael@0: static 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: protected: michael@0: GLContext* const mGL; michael@0: const gfx::IntSize mSize; michael@0: const GLuint mFB; michael@0: const GLuint mColorMSRB; michael@0: const GLuint mDepthRB; michael@0: const GLuint mStencilRB; michael@0: michael@0: DrawBuffer(GLContext* gl, michael@0: const gfx::IntSize& size, michael@0: GLuint fb, michael@0: GLuint colorMSRB, michael@0: GLuint depthRB, michael@0: GLuint stencilRB) michael@0: : mGL(gl) michael@0: , mSize(size) michael@0: , mFB(fb) michael@0: , mColorMSRB(colorMSRB) michael@0: , mDepthRB(depthRB) michael@0: , mStencilRB(stencilRB) michael@0: {} michael@0: michael@0: public: michael@0: virtual ~DrawBuffer(); michael@0: michael@0: const gfx::IntSize& Size() const { michael@0: return mSize; michael@0: } michael@0: michael@0: GLuint FB() const { michael@0: return mFB; michael@0: } michael@0: }; michael@0: michael@0: class ReadBuffer michael@0: { michael@0: protected: michael@0: typedef struct gfx::SurfaceCaps SurfaceCaps; michael@0: michael@0: public: michael@0: // Infallible, always non-null. michael@0: static ReadBuffer* Create(GLContext* gl, michael@0: const SurfaceCaps& caps, michael@0: const GLFormats& formats, michael@0: SharedSurface_GL* surf); michael@0: michael@0: protected: michael@0: GLContext* const mGL; michael@0: michael@0: const GLuint mFB; michael@0: // mFB has the following attachments: michael@0: const GLuint mDepthRB; michael@0: const GLuint mStencilRB; michael@0: // note no mColorRB here: this is provided by mSurf. michael@0: SharedSurface_GL* mSurf; // Owned by GLScreenBuffer's SurfaceStream. michael@0: michael@0: ReadBuffer(GLContext* gl, michael@0: GLuint fb, michael@0: GLuint depthRB, michael@0: GLuint stencilRB, michael@0: SharedSurface_GL* surf) michael@0: : mGL(gl) michael@0: , mFB(fb) michael@0: , mDepthRB(depthRB) michael@0: , mStencilRB(stencilRB) michael@0: , mSurf(surf) michael@0: {} michael@0: michael@0: public: michael@0: virtual ~ReadBuffer(); michael@0: michael@0: // Cannot attach a surf of a different AttachType or Size than before. michael@0: void Attach(SharedSurface_GL* surf); michael@0: michael@0: const gfx::IntSize& Size() const; michael@0: michael@0: GLuint FB() const { michael@0: return mFB; michael@0: } michael@0: michael@0: SharedSurface_GL* SharedSurf() const { michael@0: return mSurf; michael@0: } michael@0: }; michael@0: michael@0: michael@0: class GLScreenBuffer michael@0: { michael@0: protected: michael@0: typedef class gfx::SurfaceStream SurfaceStream; michael@0: typedef class gfx::SharedSurface SharedSurface; michael@0: typedef gfx::SurfaceStreamType SurfaceStreamType; michael@0: typedef gfx::SharedSurfaceType SharedSurfaceType; michael@0: typedef struct gfx::SurfaceCaps SurfaceCaps; michael@0: michael@0: public: michael@0: // Infallible. michael@0: static GLScreenBuffer* Create(GLContext* gl, michael@0: const gfx::IntSize& size, michael@0: const SurfaceCaps& caps); michael@0: michael@0: protected: michael@0: GLContext* const mGL; // Owns us. michael@0: SurfaceCaps mCaps; michael@0: SurfaceFactory_GL* mFactory; // Owned by us. michael@0: RefPtr mStream; michael@0: michael@0: DrawBuffer* mDraw; // Owned by us. michael@0: ReadBuffer* mRead; // Owned by us. michael@0: michael@0: bool mNeedsBlit; michael@0: michael@0: // Below are the parts that help us pretend to be framebuffer 0: michael@0: GLuint mUserDrawFB; michael@0: GLuint mUserReadFB; michael@0: GLuint mInternalDrawFB; michael@0: GLuint mInternalReadFB; michael@0: michael@0: #ifdef DEBUG michael@0: bool mInInternalMode_DrawFB; michael@0: bool mInInternalMode_ReadFB; michael@0: #endif michael@0: michael@0: GLScreenBuffer(GLContext* gl, michael@0: const SurfaceCaps& caps, michael@0: SurfaceFactory_GL* factory, michael@0: SurfaceStream* stream) michael@0: : mGL(gl) michael@0: , mCaps(caps) michael@0: , mFactory(factory) michael@0: , mStream(stream) michael@0: , mDraw(nullptr) michael@0: , mRead(nullptr) michael@0: , mNeedsBlit(true) michael@0: , mUserDrawFB(0) michael@0: , mUserReadFB(0) michael@0: , mInternalDrawFB(0) michael@0: , mInternalReadFB(0) michael@0: #ifdef DEBUG michael@0: , mInInternalMode_DrawFB(true) michael@0: , mInInternalMode_ReadFB(true) michael@0: #endif michael@0: {} michael@0: michael@0: public: michael@0: virtual ~GLScreenBuffer(); michael@0: michael@0: SurfaceStream* Stream() const { michael@0: return mStream; michael@0: } michael@0: michael@0: SurfaceFactory_GL* Factory() const { michael@0: return mFactory; michael@0: } michael@0: michael@0: SharedSurface_GL* SharedSurf() const { michael@0: MOZ_ASSERT(mRead); michael@0: return mRead->SharedSurf(); michael@0: } michael@0: michael@0: bool PreserveBuffer() const { michael@0: return mCaps.preserve; michael@0: } michael@0: michael@0: const SurfaceCaps& Caps() const { michael@0: return mCaps; michael@0: } michael@0: michael@0: GLuint DrawFB() const { michael@0: if (!mDraw) michael@0: return ReadFB(); michael@0: michael@0: return mDraw->FB(); michael@0: } michael@0: michael@0: GLuint ReadFB() const { michael@0: return mRead->FB(); michael@0: } michael@0: michael@0: void DeletingFB(GLuint fb); michael@0: michael@0: const gfx::IntSize& Size() const { michael@0: MOZ_ASSERT(mRead); michael@0: MOZ_ASSERT(!mDraw || mDraw->Size() == mRead->Size()); michael@0: return mRead->Size(); michael@0: } michael@0: michael@0: void BindAsFramebuffer(GLContext* const gl, GLenum target) const; michael@0: michael@0: void RequireBlit(); michael@0: void AssureBlitted(); michael@0: void AfterDrawCall(); michael@0: void BeforeReadCall(); michael@0: michael@0: /** michael@0: * Attempts to read pixels from the current bound framebuffer, if michael@0: * it is backed by a SharedSurface_GL. michael@0: * michael@0: * Returns true if the pixel data has been read back, false michael@0: * otherwise. michael@0: */ michael@0: bool ReadPixels(GLint x, GLint y, GLsizei width, GLsizei height, michael@0: GLenum format, GLenum type, GLvoid *pixels); michael@0: michael@0: /* Morph swaps out our SurfaceStream mechanism and replaces it with michael@0: * one best suited to our platform and compositor configuration. michael@0: * michael@0: * Must be called on the producing thread. michael@0: * We haven't made any guarantee that rendering is actually michael@0: * done when Morph is run, just that it can't run concurrently michael@0: * with rendering. This means that we can't just drop the contents michael@0: * of the buffer, since we may only be partially done rendering. michael@0: * michael@0: * Once you pass newFactory into Morph, newFactory will be owned by michael@0: * GLScreenBuffer, so `forget` any references to it that still exist. michael@0: */ michael@0: void Morph(SurfaceFactory_GL* newFactory, SurfaceStreamType streamType); michael@0: michael@0: protected: michael@0: // Returns false on error or inability to resize. michael@0: bool Swap(const gfx::IntSize& size); michael@0: michael@0: public: michael@0: bool PublishFrame(const gfx::IntSize& size); michael@0: michael@0: bool Resize(const gfx::IntSize& size); michael@0: michael@0: void Readback(SharedSurface_GL* src, gfx::DataSourceSurface* dest); michael@0: void DeprecatedReadback(SharedSurface_GL* src, gfxImageSurface* dest); michael@0: michael@0: protected: michael@0: void Attach(SharedSurface* surface, const gfx::IntSize& size); michael@0: michael@0: DrawBuffer* CreateDraw(const gfx::IntSize& size); michael@0: ReadBuffer* CreateRead(SharedSurface_GL* surf); michael@0: michael@0: public: michael@0: /* `fb` in these functions is the framebuffer the GLContext is hoping to michael@0: * bind. When this is 0, we intercept the call and bind our own michael@0: * framebuffers. As a client of these functions, just bind 0 when you want michael@0: * to draw to the default framebuffer/'screen'. michael@0: */ michael@0: void BindFB(GLuint fb); michael@0: void BindDrawFB(GLuint fb); michael@0: void BindReadFB(GLuint fb); michael@0: GLuint GetFB() const; michael@0: GLuint GetDrawFB() const; michael@0: GLuint GetReadFB() const; michael@0: michael@0: // Here `fb` is the actual framebuffer you want bound. Binding 0 will michael@0: // bind the (generally useless) default framebuffer. michael@0: void BindDrawFB_Internal(GLuint fb); michael@0: void BindReadFB_Internal(GLuint fb); michael@0: }; michael@0: michael@0: } // namespace gl michael@0: } // namespace mozilla michael@0: michael@0: #endif // SCREEN_BUFFER_H_