1.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 1.2 +++ b/gfx/gl/GLScreenBuffer.h Wed Dec 31 06:09:35 2014 +0100 1.3 @@ -0,0 +1,313 @@ 1.4 +/* -*- Mode: c++; c-basic-offset: 4; indent-tabs-mode: nil; tab-width: 40; -*- */ 1.5 +/* This Source Code Form is subject to the terms of the Mozilla Public 1.6 + * License, v. 2.0. If a copy of the MPL was not distributed with this 1.7 + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ 1.8 + 1.9 +/* GLScreenBuffer is the abstraction for the "default framebuffer" used 1.10 + * by an offscreen GLContext. Since it's only for offscreen GLContext's, 1.11 + * it's only useful for things like WebGL, and is NOT used by the 1.12 + * compositor's GLContext. Remember that GLContext provides an abstraction 1.13 + * so that even if you want to draw to the 'screen', even if that's not 1.14 + * actually the screen, just draw to 0. This GLScreenBuffer class takes the 1.15 + * logic handling out of GLContext. 1.16 +*/ 1.17 + 1.18 +#ifndef SCREEN_BUFFER_H_ 1.19 +#define SCREEN_BUFFER_H_ 1.20 + 1.21 +#include "SurfaceTypes.h" 1.22 +#include "SurfaceStream.h" 1.23 +#include "GLContextTypes.h" 1.24 +#include "GLDefs.h" 1.25 +#include "mozilla/gfx/2D.h" 1.26 +#include "mozilla/gfx/Point.h" 1.27 + 1.28 +// Forwards: 1.29 +class gfxImageSurface; 1.30 + 1.31 +namespace mozilla { 1.32 + namespace gfx { 1.33 + class SurfaceStream; 1.34 + class SharedSurface; 1.35 + } 1.36 + namespace gl { 1.37 + class GLContext; 1.38 + class SharedSurface_GL; 1.39 + class SurfaceFactory_GL; 1.40 + } 1.41 +} 1.42 + 1.43 +namespace mozilla { 1.44 +namespace gl { 1.45 + 1.46 +class DrawBuffer 1.47 +{ 1.48 +protected: 1.49 + typedef struct gfx::SurfaceCaps SurfaceCaps; 1.50 + 1.51 +public: 1.52 + // Infallible, may return null if unneeded. 1.53 + static DrawBuffer* Create(GLContext* const gl, 1.54 + const SurfaceCaps& caps, 1.55 + const GLFormats& formats, 1.56 + const gfx::IntSize& size); 1.57 + 1.58 +protected: 1.59 + GLContext* const mGL; 1.60 + const gfx::IntSize mSize; 1.61 + const GLuint mFB; 1.62 + const GLuint mColorMSRB; 1.63 + const GLuint mDepthRB; 1.64 + const GLuint mStencilRB; 1.65 + 1.66 + DrawBuffer(GLContext* gl, 1.67 + const gfx::IntSize& size, 1.68 + GLuint fb, 1.69 + GLuint colorMSRB, 1.70 + GLuint depthRB, 1.71 + GLuint stencilRB) 1.72 + : mGL(gl) 1.73 + , mSize(size) 1.74 + , mFB(fb) 1.75 + , mColorMSRB(colorMSRB) 1.76 + , mDepthRB(depthRB) 1.77 + , mStencilRB(stencilRB) 1.78 + {} 1.79 + 1.80 +public: 1.81 + virtual ~DrawBuffer(); 1.82 + 1.83 + const gfx::IntSize& Size() const { 1.84 + return mSize; 1.85 + } 1.86 + 1.87 + GLuint FB() const { 1.88 + return mFB; 1.89 + } 1.90 +}; 1.91 + 1.92 +class ReadBuffer 1.93 +{ 1.94 +protected: 1.95 + typedef struct gfx::SurfaceCaps SurfaceCaps; 1.96 + 1.97 +public: 1.98 + // Infallible, always non-null. 1.99 + static ReadBuffer* Create(GLContext* gl, 1.100 + const SurfaceCaps& caps, 1.101 + const GLFormats& formats, 1.102 + SharedSurface_GL* surf); 1.103 + 1.104 +protected: 1.105 + GLContext* const mGL; 1.106 + 1.107 + const GLuint mFB; 1.108 + // mFB has the following attachments: 1.109 + const GLuint mDepthRB; 1.110 + const GLuint mStencilRB; 1.111 + // note no mColorRB here: this is provided by mSurf. 1.112 + SharedSurface_GL* mSurf; // Owned by GLScreenBuffer's SurfaceStream. 1.113 + 1.114 + ReadBuffer(GLContext* gl, 1.115 + GLuint fb, 1.116 + GLuint depthRB, 1.117 + GLuint stencilRB, 1.118 + SharedSurface_GL* surf) 1.119 + : mGL(gl) 1.120 + , mFB(fb) 1.121 + , mDepthRB(depthRB) 1.122 + , mStencilRB(stencilRB) 1.123 + , mSurf(surf) 1.124 + {} 1.125 + 1.126 +public: 1.127 + virtual ~ReadBuffer(); 1.128 + 1.129 + // Cannot attach a surf of a different AttachType or Size than before. 1.130 + void Attach(SharedSurface_GL* surf); 1.131 + 1.132 + const gfx::IntSize& Size() const; 1.133 + 1.134 + GLuint FB() const { 1.135 + return mFB; 1.136 + } 1.137 + 1.138 + SharedSurface_GL* SharedSurf() const { 1.139 + return mSurf; 1.140 + } 1.141 +}; 1.142 + 1.143 + 1.144 +class GLScreenBuffer 1.145 +{ 1.146 +protected: 1.147 + typedef class gfx::SurfaceStream SurfaceStream; 1.148 + typedef class gfx::SharedSurface SharedSurface; 1.149 + typedef gfx::SurfaceStreamType SurfaceStreamType; 1.150 + typedef gfx::SharedSurfaceType SharedSurfaceType; 1.151 + typedef struct gfx::SurfaceCaps SurfaceCaps; 1.152 + 1.153 +public: 1.154 + // Infallible. 1.155 + static GLScreenBuffer* Create(GLContext* gl, 1.156 + const gfx::IntSize& size, 1.157 + const SurfaceCaps& caps); 1.158 + 1.159 +protected: 1.160 + GLContext* const mGL; // Owns us. 1.161 + SurfaceCaps mCaps; 1.162 + SurfaceFactory_GL* mFactory; // Owned by us. 1.163 + RefPtr<SurfaceStream> mStream; 1.164 + 1.165 + DrawBuffer* mDraw; // Owned by us. 1.166 + ReadBuffer* mRead; // Owned by us. 1.167 + 1.168 + bool mNeedsBlit; 1.169 + 1.170 + // Below are the parts that help us pretend to be framebuffer 0: 1.171 + GLuint mUserDrawFB; 1.172 + GLuint mUserReadFB; 1.173 + GLuint mInternalDrawFB; 1.174 + GLuint mInternalReadFB; 1.175 + 1.176 +#ifdef DEBUG 1.177 + bool mInInternalMode_DrawFB; 1.178 + bool mInInternalMode_ReadFB; 1.179 +#endif 1.180 + 1.181 + GLScreenBuffer(GLContext* gl, 1.182 + const SurfaceCaps& caps, 1.183 + SurfaceFactory_GL* factory, 1.184 + SurfaceStream* stream) 1.185 + : mGL(gl) 1.186 + , mCaps(caps) 1.187 + , mFactory(factory) 1.188 + , mStream(stream) 1.189 + , mDraw(nullptr) 1.190 + , mRead(nullptr) 1.191 + , mNeedsBlit(true) 1.192 + , mUserDrawFB(0) 1.193 + , mUserReadFB(0) 1.194 + , mInternalDrawFB(0) 1.195 + , mInternalReadFB(0) 1.196 +#ifdef DEBUG 1.197 + , mInInternalMode_DrawFB(true) 1.198 + , mInInternalMode_ReadFB(true) 1.199 +#endif 1.200 + {} 1.201 + 1.202 +public: 1.203 + virtual ~GLScreenBuffer(); 1.204 + 1.205 + SurfaceStream* Stream() const { 1.206 + return mStream; 1.207 + } 1.208 + 1.209 + SurfaceFactory_GL* Factory() const { 1.210 + return mFactory; 1.211 + } 1.212 + 1.213 + SharedSurface_GL* SharedSurf() const { 1.214 + MOZ_ASSERT(mRead); 1.215 + return mRead->SharedSurf(); 1.216 + } 1.217 + 1.218 + bool PreserveBuffer() const { 1.219 + return mCaps.preserve; 1.220 + } 1.221 + 1.222 + const SurfaceCaps& Caps() const { 1.223 + return mCaps; 1.224 + } 1.225 + 1.226 + GLuint DrawFB() const { 1.227 + if (!mDraw) 1.228 + return ReadFB(); 1.229 + 1.230 + return mDraw->FB(); 1.231 + } 1.232 + 1.233 + GLuint ReadFB() const { 1.234 + return mRead->FB(); 1.235 + } 1.236 + 1.237 + void DeletingFB(GLuint fb); 1.238 + 1.239 + const gfx::IntSize& Size() const { 1.240 + MOZ_ASSERT(mRead); 1.241 + MOZ_ASSERT(!mDraw || mDraw->Size() == mRead->Size()); 1.242 + return mRead->Size(); 1.243 + } 1.244 + 1.245 + void BindAsFramebuffer(GLContext* const gl, GLenum target) const; 1.246 + 1.247 + void RequireBlit(); 1.248 + void AssureBlitted(); 1.249 + void AfterDrawCall(); 1.250 + void BeforeReadCall(); 1.251 + 1.252 + /** 1.253 + * Attempts to read pixels from the current bound framebuffer, if 1.254 + * it is backed by a SharedSurface_GL. 1.255 + * 1.256 + * Returns true if the pixel data has been read back, false 1.257 + * otherwise. 1.258 + */ 1.259 + bool ReadPixels(GLint x, GLint y, GLsizei width, GLsizei height, 1.260 + GLenum format, GLenum type, GLvoid *pixels); 1.261 + 1.262 + /* Morph swaps out our SurfaceStream mechanism and replaces it with 1.263 + * one best suited to our platform and compositor configuration. 1.264 + * 1.265 + * Must be called on the producing thread. 1.266 + * We haven't made any guarantee that rendering is actually 1.267 + * done when Morph is run, just that it can't run concurrently 1.268 + * with rendering. This means that we can't just drop the contents 1.269 + * of the buffer, since we may only be partially done rendering. 1.270 + * 1.271 + * Once you pass newFactory into Morph, newFactory will be owned by 1.272 + * GLScreenBuffer, so `forget` any references to it that still exist. 1.273 + */ 1.274 + void Morph(SurfaceFactory_GL* newFactory, SurfaceStreamType streamType); 1.275 + 1.276 +protected: 1.277 + // Returns false on error or inability to resize. 1.278 + bool Swap(const gfx::IntSize& size); 1.279 + 1.280 +public: 1.281 + bool PublishFrame(const gfx::IntSize& size); 1.282 + 1.283 + bool Resize(const gfx::IntSize& size); 1.284 + 1.285 + void Readback(SharedSurface_GL* src, gfx::DataSourceSurface* dest); 1.286 + void DeprecatedReadback(SharedSurface_GL* src, gfxImageSurface* dest); 1.287 + 1.288 +protected: 1.289 + void Attach(SharedSurface* surface, const gfx::IntSize& size); 1.290 + 1.291 + DrawBuffer* CreateDraw(const gfx::IntSize& size); 1.292 + ReadBuffer* CreateRead(SharedSurface_GL* surf); 1.293 + 1.294 +public: 1.295 + /* `fb` in these functions is the framebuffer the GLContext is hoping to 1.296 + * bind. When this is 0, we intercept the call and bind our own 1.297 + * framebuffers. As a client of these functions, just bind 0 when you want 1.298 + * to draw to the default framebuffer/'screen'. 1.299 + */ 1.300 + void BindFB(GLuint fb); 1.301 + void BindDrawFB(GLuint fb); 1.302 + void BindReadFB(GLuint fb); 1.303 + GLuint GetFB() const; 1.304 + GLuint GetDrawFB() const; 1.305 + GLuint GetReadFB() const; 1.306 + 1.307 + // Here `fb` is the actual framebuffer you want bound. Binding 0 will 1.308 + // bind the (generally useless) default framebuffer. 1.309 + void BindDrawFB_Internal(GLuint fb); 1.310 + void BindReadFB_Internal(GLuint fb); 1.311 +}; 1.312 + 1.313 +} // namespace gl 1.314 +} // namespace mozilla 1.315 + 1.316 +#endif // SCREEN_BUFFER_H_