diff options
Diffstat (limited to 'gfx/gl/GLScreenBuffer.h')
-rw-r--r-- | gfx/gl/GLScreenBuffer.h | 301 |
1 files changed, 301 insertions, 0 deletions
diff --git a/gfx/gl/GLScreenBuffer.h b/gfx/gl/GLScreenBuffer.h new file mode 100644 index 000000000..6cacf221d --- /dev/null +++ b/gfx/gl/GLScreenBuffer.h @@ -0,0 +1,301 @@ +/* -*- Mode: c++; c-basic-offset: 4; indent-tabs-mode: nil; tab-width: 40; -*- */ +/* 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 DrawBuffer +{ +public: + // Fallible! + // But it may return true with *out_buffer==nullptr if unneeded. + static bool Create(GLContext* const gl, + const SurfaceCaps& caps, + const GLFormats& formats, + const gfx::IntSize& size, + UniquePtr<DrawBuffer>* out_buffer); + +protected: + GLContext* const mGL; +public: + const gfx::IntSize mSize; + const GLsizei mSamples; + const GLuint mFB; +protected: + const GLuint mColorMSRB; + const GLuint mDepthRB; + const GLuint mStencilRB; + + DrawBuffer(GLContext* gl, + const gfx::IntSize& size, + GLsizei samples, + GLuint fb, + GLuint colorMSRB, + GLuint depthRB, + GLuint stencilRB) + : mGL(gl) + , mSize(size) + , mSamples(samples) + , mFB(fb) + , mColorMSRB(colorMSRB) + , mDepthRB(depthRB) + , mStencilRB(stencilRB) + {} + +public: + virtual ~DrawBuffer(); +}; + +class ReadBuffer +{ +public: + // Infallible, always non-null. + static UniquePtr<ReadBuffer> 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<GLScreenBuffer> Create(GLContext* gl, + const gfx::IntSize& size, + const SurfaceCaps& caps); + + static UniquePtr<SurfaceFactory> + CreateFactory(GLContext* gl, + const SurfaceCaps& caps, + layers::KnowsCompositor* compositorConnection, + const layers::TextureFlags& flags); + static UniquePtr<SurfaceFactory> + CreateFactory(GLContext* gl, + const SurfaceCaps& caps, + layers::LayersIPCChannel* ipcChannel, + const mozilla::layers::LayersBackend backend, + const layers::TextureFlags& flags); + +protected: + GLContext* const mGL; // Owns us. +public: + const SurfaceCaps mCaps; +protected: + UniquePtr<SurfaceFactory> mFactory; + + RefPtr<layers::SharedSurfaceTextureClient> mBack; + RefPtr<layers::SharedSurfaceTextureClient> mFront; + + UniquePtr<DrawBuffer> mDraw; + UniquePtr<ReadBuffer> 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<SurfaceFactory> factory); + +public: + virtual ~GLScreenBuffer(); + + SurfaceFactory* Factory() const { + return mFactory.get(); + } + + const RefPtr<layers::SharedSurfaceTextureClient>& Front() const { + return mFront; + } + + SharedSurface* SharedSurf() const { + MOZ_ASSERT(mRead); + return mRead->SharedSurf(); + } + + bool ShouldPreserveBuffer() const { + return mCaps.preserve; + } + + GLuint DrawFB() const { + if (!mDraw) + return ReadFB(); + + return mDraw->mFB; + } + + GLuint ReadFB() const { + return mRead->mFB; + } + + GLsizei Samples() const { + if (!mDraw) + return 0; + + return mDraw->mSamples; + } + + uint32_t DepthBits() const; + + void DeletingFB(GLuint fb); + + const gfx::IntSize& Size() const { + MOZ_ASSERT(mRead); + MOZ_ASSERT(!mDraw || mDraw->mSize == mRead->Size()); + return mRead->Size(); + } + + 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<SurfaceFactory> 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); + + bool CreateDraw(const gfx::IntSize& size, UniquePtr<DrawBuffer>* out_buffer); + UniquePtr<ReadBuffer> 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_ |