1 /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
2 /* vim: set ts=8 sts=2 et sw=2 tw=80: */
3 /* This Source Code Form is subject to the terms of the Mozilla Public
4  * License, v. 2.0. If a copy of the MPL was not distributed with this
5  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
6 
7 #ifndef MOZILLA_GFX_COMPOSITOROGL_H
8 #define MOZILLA_GFX_COMPOSITOROGL_H
9 
10 #include <map>
11 #include <unordered_map>
12 #include <unordered_set>
13 
14 #include "gfx2DGlue.h"
15 #include "GLContextTypes.h"             // for GLContext, etc
16 #include "GLDefs.h"                     // for GLuint, LOCAL_GL_TEXTURE_2D, etc
17 #include "OGLShaderConfig.h"            // for ShaderConfigOGL
18 #include "Units.h"                      // for ScreenPoint
19 #include "mozilla/Assertions.h"         // for MOZ_ASSERT, etc
20 #include "mozilla/Attributes.h"         // for override, final
21 #include "mozilla/RefPtr.h"             // for already_AddRefed, RefPtr
22 #include "mozilla/gfx/2D.h"             // for DrawTarget
23 #include "mozilla/gfx/BaseSize.h"       // for BaseSize
24 #include "mozilla/gfx/MatrixFwd.h"      // for Matrix4x4
25 #include "mozilla/gfx/Point.h"          // for IntSize, Point
26 #include "mozilla/gfx/Rect.h"           // for Rect, IntRect
27 #include "mozilla/gfx/Triangle.h"       // for Triangle
28 #include "mozilla/gfx/Types.h"          // for Float, SurfaceFormat, etc
29 #include "mozilla/layers/Compositor.h"  // for SurfaceInitMode, Compositor, etc
30 #include "mozilla/layers/CompositorTypes.h"  // for MaskType::MaskType::NumMaskTypes, etc
31 #include "mozilla/layers/LayersTypes.h"
32 #include "nsCOMPtr.h"         // for already_AddRefed
33 #include "nsDebug.h"          // for NS_ASSERTION, NS_WARNING
34 #include "nsISupportsImpl.h"  // for MOZ_COUNT_CTOR, etc
35 #include "nsTArray.h"         // for AutoTArray, nsTArray, etc
36 #include "nsThreadUtils.h"    // for nsRunnable
37 #include "nsXULAppAPI.h"      // for XRE_GetProcessType
38 #include "nscore.h"           // for NS_IMETHOD
39 
40 class nsIWidget;
41 
42 namespace mozilla {
43 
44 namespace layers {
45 
46 class CompositingRenderTarget;
47 class CompositingRenderTargetOGL;
48 class DataTextureSource;
49 class ShaderProgramOGL;
50 class TextureSource;
51 class TextureSourceOGL;
52 class BufferTextureHost;
53 struct Effect;
54 struct EffectChain;
55 class GLBlitTextureImageHelper;
56 
57 /**
58  * Interface for pools of temporary gl textures for the compositor.
59  * The textures are fully owned by the pool, so the latter is responsible
60  * calling fDeleteTextures accordingly.
61  * Users of GetTexture receive a texture that is only valid for the duration
62  * of the current frame.
63  * This is primarily intended for direct texturing APIs that need to attach
64  * shared objects (such as an EGLImage) to a gl texture.
65  */
66 class CompositorTexturePoolOGL {
67  protected:
68   virtual ~CompositorTexturePoolOGL() = default;
69 
70  public:
71   NS_INLINE_DECL_REFCOUNTING(CompositorTexturePoolOGL)
72 
73   virtual void Clear() = 0;
74 
75   virtual GLuint GetTexture(GLenum aTarget, GLenum aEnum) = 0;
76 
77   virtual void EndFrame() = 0;
78 };
79 
80 /**
81  * Agressively reuses textures. One gl texture per texture unit in total.
82  * So far this hasn't shown the best results on b2g.
83  */
84 class PerUnitTexturePoolOGL : public CompositorTexturePoolOGL {
85  public:
86   explicit PerUnitTexturePoolOGL(gl::GLContext* aGL);
87   virtual ~PerUnitTexturePoolOGL();
88 
Clear()89   void Clear() override { DestroyTextures(); }
90 
91   GLuint GetTexture(GLenum aTarget, GLenum aUnit) override;
92 
EndFrame()93   void EndFrame() override {}
94 
95  protected:
96   void DestroyTextures();
97 
98   GLenum mTextureTarget;
99   nsTArray<GLuint> mTextures;
100   RefPtr<gl::GLContext> mGL;
101 };
102 
103 // If you want to make this class not final, first remove calls to virtual
104 // methods (Destroy) that are made in the destructor.
105 class CompositorOGL final : public Compositor {
106   typedef mozilla::gl::GLContext GLContext;
107 
108   friend class CompositingRenderTargetOGL;
109 
110   std::map<ShaderConfigOGL, ShaderProgramOGL*> mPrograms;
111 
112  public:
113   CompositorOGL(CompositorBridgeParent* aParent,
114                 widget::CompositorWidget* aWidget, int aSurfaceWidth = -1,
115                 int aSurfaceHeight = -1, bool aUseExternalSurfaceSize = false);
116 
117  protected:
118   virtual ~CompositorOGL();
119 
120  public:
AsCompositorOGL()121   CompositorOGL* AsCompositorOGL() override { return this; }
122 
123   already_AddRefed<DataTextureSource> CreateDataTextureSource(
124       TextureFlags aFlags = TextureFlags::NO_FLAGS) override;
125 
126   already_AddRefed<DataTextureSource> CreateDataTextureSourceAroundYCbCr(
127       TextureHost* aTexture) override;
128 
129   already_AddRefed<DataTextureSource> CreateDataTextureSourceAround(
130       gfx::DataSourceSurface* aSurface) override;
131 
132   bool Initialize(nsCString* const out_failureReason) override;
133 
134   void Destroy() override;
135 
GetTextureFactoryIdentifier()136   TextureFactoryIdentifier GetTextureFactoryIdentifier() override {
137     TextureFactoryIdentifier result = TextureFactoryIdentifier(
138         LayersBackend::LAYERS_OPENGL, XRE_GetProcessType(), GetMaxTextureSize(),
139         SupportsTextureDirectMapping(), false,
140         mFBOTextureTarget == LOCAL_GL_TEXTURE_2D,
141         SupportsPartialTextureUpdate());
142     return result;
143   }
144 
145   // Returns a render target for the native layer.
146   // aInvalidRegion is in window coordinates, i.e. in the same space as
147   // aNativeLayer->GetPosition().
148   already_AddRefed<CompositingRenderTargetOGL> RenderTargetForNativeLayer(
149       NativeLayer* aNativeLayer, const gfx::IntRegion& aInvalidRegion);
150 
151   already_AddRefed<CompositingRenderTarget> CreateRenderTarget(
152       const gfx::IntRect& aRect, SurfaceInitMode aInit) override;
153 
154   already_AddRefed<CompositingRenderTarget> CreateRenderTargetFromSource(
155       const gfx::IntRect& aRect, const CompositingRenderTarget* aSource,
156       const gfx::IntPoint& aSourcePoint) override;
157 
158   void SetRenderTarget(CompositingRenderTarget* aSurface) override;
159   already_AddRefed<CompositingRenderTarget> GetCurrentRenderTarget()
160       const override;
161   already_AddRefed<CompositingRenderTarget> GetWindowRenderTarget()
162       const override;
163 
164   bool ReadbackRenderTarget(CompositingRenderTarget* aSource,
165                             AsyncReadbackBuffer* aDest) override;
166 
167   already_AddRefed<AsyncReadbackBuffer> CreateAsyncReadbackBuffer(
168       const gfx::IntSize& aSize) override;
169 
170   bool BlitRenderTarget(CompositingRenderTarget* aSource,
171                         const gfx::IntSize& aSourceSize,
172                         const gfx::IntSize& aDestSize) override;
173 
174   void DrawQuad(const gfx::Rect& aRect, const gfx::IntRect& aClipRect,
175                 const EffectChain& aEffectChain, gfx::Float aOpacity,
176                 const gfx::Matrix4x4& aTransform,
177                 const gfx::Rect& aVisibleRect) override;
178 
179   void DrawTriangles(const nsTArray<gfx::TexturedTriangle>& aTriangles,
180                      const gfx::Rect& aRect, const gfx::IntRect& aClipRect,
181                      const EffectChain& aEffectChain, gfx::Float aOpacity,
182                      const gfx::Matrix4x4& aTransform,
183                      const gfx::Rect& aVisibleRect) override;
184 
185   bool SupportsLayerGeometry() const override;
186 
187   void NormalDrawingDone() override;
188 
189   void EndFrame() override;
190 
191   void WaitForGPU() override;
192 
193   RefPtr<SurfacePoolHandle> GetSurfacePoolHandle() override;
194 
195   bool SupportsPartialTextureUpdate() override;
196 
CanUseCanvasLayerForSize(const gfx::IntSize & aSize)197   bool CanUseCanvasLayerForSize(const gfx::IntSize& aSize) override {
198     if (!mGLContext) return false;
199     int32_t maxSize = GetMaxTextureSize();
200     return aSize <= gfx::IntSize(maxSize, maxSize);
201   }
202 
203   int32_t GetMaxTextureSize() const override;
204 
205   /**
206    * Set the size of the EGL surface we're rendering to, if we're rendering to
207    * an EGL surface.
208    */
209   void SetDestinationSurfaceSize(const gfx::IntSize& aSize) override;
210 
211   void MakeCurrent(MakeCurrentFlags aFlags = 0) override;
212 
213 #ifdef MOZ_DUMP_PAINTING
Name()214   const char* Name() const override { return "OGL"; }
215 #endif  // MOZ_DUMP_PAINTING
216 
GetBackendType()217   LayersBackend GetBackendType() const override {
218     return LayersBackend::LAYERS_OPENGL;
219   }
220 
221   void Pause() override;
222   bool Resume() override;
223 
gl()224   GLContext* gl() const { return mGLContext; }
GetGLContext()225   GLContext* GetGLContext() const override { return mGLContext; }
226 
227 #ifdef XP_DARWIN
228   void MaybeUnlockBeforeNextComposition(TextureHost* aTextureHost) override;
229   void TryUnlockTextures() override;
230 #endif
231 
232   /**
233    * Clear the program state. This must be called
234    * before operating on the GLContext directly. */
235   void ResetProgram();
236 
GetFBOFormat()237   gfx::SurfaceFormat GetFBOFormat() const {
238     return gfx::SurfaceFormat::R8G8B8A8;
239   }
240 
241   GLBlitTextureImageHelper* BlitTextureImageHelper();
242 
243   /**
244    * The compositor provides with temporary textures for use with direct
245    * textruing.
246    */
247   GLuint GetTemporaryTexture(GLenum aTarget, GLenum aUnit);
248 
GetDestinationSurfaceSize()249   const gfx::IntSize GetDestinationSurfaceSize() const {
250     return gfx::IntSize(mSurfaceSize.width, mSurfaceSize.height);
251   }
252 
253   /**
254    * Allow the origin of the surface to be offset so that content does not
255    * start at (0, 0) on the surface.
256    */
SetSurfaceOrigin(const ScreenIntPoint & aOrigin)257   void SetSurfaceOrigin(const ScreenIntPoint& aOrigin) {
258     mSurfaceOrigin = aOrigin;
259   }
260 
261   // Register TextureSource which own device data that have to be deleted before
262   // destroying this CompositorOGL.
263   void RegisterTextureSource(TextureSource* aTextureSource);
264   void UnregisterTextureSource(TextureSource* aTextureSource);
265 
266  private:
267   template <typename Geometry>
268   void DrawGeometry(const Geometry& aGeometry, const gfx::Rect& aRect,
269                     const gfx::IntRect& aClipRect,
270                     const EffectChain& aEffectChain, gfx::Float aOpacity,
271                     const gfx::Matrix4x4& aTransform,
272                     const gfx::Rect& aVisibleRect);
273 
274   void PrepareViewport(CompositingRenderTargetOGL* aRenderTarget);
275 
276   bool SupportsTextureDirectMapping();
277 
278   void InsertFrameDoneSync();
279 
280   bool NeedToRecreateFullWindowRenderTarget() const;
281 
282   /** Widget associated with this compositor */
283   LayoutDeviceIntSize mWidgetSize;
284   RefPtr<GLContext> mGLContext;
285   RefPtr<SurfacePoolHandle> mSurfacePoolHandle;
286   UniquePtr<GLBlitTextureImageHelper> mBlitTextureImageHelper;
287   gfx::Matrix4x4 mProjMatrix;
288   bool mCanRenderToDefaultFramebuffer = true;
289 
290 #ifdef XP_DARWIN
291   nsTArray<RefPtr<BufferTextureHost>> mMaybeUnlockBeforeNextComposition;
292 #endif
293 
294   /** The size of the surface we are rendering to */
295   gfx::IntSize mSurfaceSize;
296 
297   /** The origin of the content on the surface */
298   ScreenIntPoint mSurfaceOrigin;
299 
300   already_AddRefed<mozilla::gl::GLContext> CreateContext();
301 
302   /** Texture target to use for FBOs */
303   GLenum mFBOTextureTarget;
304 
305   /** Currently bound render target */
306   RefPtr<CompositingRenderTargetOGL> mCurrentRenderTarget;
307 
308   // The 1x1 dummy render target that's the "current" render target between
309   // BeginFrameForNativeLayers and EndFrame but outside pairs of
310   // Begin/EndRenderingToNativeLayer. Created on demand.
311   RefPtr<CompositingRenderTarget> mNativeLayersReferenceRT;
312 
313   // The render target that profiler screenshots / frame recording read from.
314   // This will be the actual window framebuffer when rendering to a window, and
315   // it will be mFullWindowRenderTarget when rendering to native layers.
316   RefPtr<CompositingRenderTargetOGL> mWindowRenderTarget;
317 
318   // Non-null when using native layers and frame recording is requested.
319   // EndNormalDrawing() maintains a copy of the entire window contents in this
320   // render target, by copying from the native layer render targets.
321   RefPtr<CompositingRenderTargetOGL> mFullWindowRenderTarget;
322 
323   /**
324    * VBO that has some basics in it for a textured quad, including vertex
325    * coords and texcoords.
326    */
327   GLuint mQuadVBO;
328 
329   /**
330    * VBO that stores dynamic triangle geometry.
331    */
332   GLuint mTriangleVBO;
333 
334   // Used to apply back-pressure in WaitForPreviousFrameDoneSync().
335   GLsync mPreviousFrameDoneSync;
336   GLsync mThisFrameDoneSync;
337 
338   bool mHasBGRA;
339 
340   /**
341    * When rendering to some EGL surfaces (e.g. on Android), we rely on being
342    * told about size changes (via SetSurfaceSize) rather than pulling this
343    * information from the widget.
344    */
345   bool mUseExternalSurfaceSize;
346 
347   /**
348    * Have we had DrawQuad calls since the last frame was rendered?
349    */
350   bool mFrameInProgress;
351 
352   // Only true between BeginFromeForNativeLayers and EndFrame, and only if the
353   // full window render target needed to be recreated in the current frame.
354   bool mShouldInvalidateWindow = false;
355 
356   /*
357    * Clear aRect on current render target.
358    */
359   void ClearRect(const gfx::Rect& aRect) override;
360 
361   /* Start a new frame.
362    */
363   Maybe<gfx::IntRect> BeginFrameForWindow(
364       const nsIntRegion& aInvalidRegion, const Maybe<gfx::IntRect>& aClipRect,
365       const gfx::IntRect& aRenderBounds,
366       const nsIntRegion& aOpaqueRegion) override;
367 
368   Maybe<gfx::IntRect> BeginFrameForTarget(
369       const nsIntRegion& aInvalidRegion, const Maybe<gfx::IntRect>& aClipRect,
370       const gfx::IntRect& aRenderBounds, const nsIntRegion& aOpaqueRegion,
371       gfx::DrawTarget* aTarget, const gfx::IntRect& aTargetBounds) override;
372 
373   void BeginFrameForNativeLayers() override;
374 
375   Maybe<gfx::IntRect> BeginRenderingToNativeLayer(
376       const nsIntRegion& aInvalidRegion, const Maybe<gfx::IntRect>& aClipRect,
377       const nsIntRegion& aOpaqueRegion, NativeLayer* aNativeLayer) override;
378 
379   void EndRenderingToNativeLayer() override;
380 
381   Maybe<gfx::IntRect> BeginFrame(const nsIntRegion& aInvalidRegion,
382                                  const Maybe<gfx::IntRect>& aClipRect,
383                                  const gfx::IntRect& aRenderBounds,
384                                  const nsIntRegion& aOpaqueRegion);
385 
386   ShaderConfigOGL GetShaderConfigFor(
387       Effect* aEffect, TextureSourceOGL* aSourceMask = nullptr,
388       gfx::CompositionOp aOp = gfx::CompositionOp::OP_OVER,
389       bool aColorMatrix = false, bool aDEAAEnabled = false) const;
390 
391   ShaderProgramOGL* GetShaderProgramFor(const ShaderConfigOGL& aConfig);
392 
ApplyPrimitiveConfig(ShaderConfigOGL & aConfig,const gfx::Rect &)393   void ApplyPrimitiveConfig(ShaderConfigOGL& aConfig, const gfx::Rect&) {
394     aConfig.SetDynamicGeometry(false);
395   }
396 
ApplyPrimitiveConfig(ShaderConfigOGL & aConfig,const nsTArray<gfx::TexturedTriangle> &)397   void ApplyPrimitiveConfig(ShaderConfigOGL& aConfig,
398                             const nsTArray<gfx::TexturedTriangle>&) {
399     aConfig.SetDynamicGeometry(true);
400   }
401 
402   /**
403    * Create a FBO backed by a texture.
404    * Note that the texture target type will be
405    * of the type returned by FBOTextureTarget; different
406    * shaders are required to sample from the different
407    * texture types.
408    */
409   void CreateFBOWithTexture(const gfx::IntRect& aRect, bool aCopyFromSource,
410                             GLuint aSourceFrameBuffer, GLuint* aFBO,
411                             GLuint* aTexture,
412                             gfx::IntSize* aAllocSize = nullptr);
413 
414   GLuint CreateTexture(const gfx::IntRect& aRect, bool aCopyFromSource,
415                        GLuint aSourceFrameBuffer,
416                        gfx::IntSize* aAllocSize = nullptr);
417 
418   gfx::Point3D GetLineCoefficients(const gfx::Point& aPoint1,
419                                    const gfx::Point& aPoint2);
420 
421   void ActivateProgram(ShaderProgramOGL* aProg);
422 
423   void CleanupResources();
424 
425   void BindAndDrawQuads(ShaderProgramOGL* aProg, int aQuads,
426                         const gfx::Rect* aLayerRect,
427                         const gfx::Rect* aTextureRect);
428 
429   void BindAndDrawQuad(ShaderProgramOGL* aProg, const gfx::Rect& aLayerRect,
430                        const gfx::Rect& aTextureRect = gfx::Rect(0.0f, 0.0f,
431                                                                  1.0f, 1.0f)) {
432     gfx::Rect layerRects[4];
433     gfx::Rect textureRects[4];
434     layerRects[0] = aLayerRect;
435     textureRects[0] = aTextureRect;
436     BindAndDrawQuads(aProg, 1, layerRects, textureRects);
437   }
438 
439   void BindAndDrawGeometry(ShaderProgramOGL* aProgram, const gfx::Rect& aRect);
440 
441   void BindAndDrawGeometry(ShaderProgramOGL* aProgram,
442                            const nsTArray<gfx::TexturedTriangle>& aTriangles);
443 
444   void BindAndDrawGeometryWithTextureRect(ShaderProgramOGL* aProg,
445                                           const gfx::Rect& aRect,
446                                           const gfx::Rect& aTexCoordRect,
447                                           TextureSource* aTexture);
448 
449   void BindAndDrawGeometryWithTextureRect(
450       ShaderProgramOGL* aProg,
451       const nsTArray<gfx::TexturedTriangle>& aTriangles,
452       const gfx::Rect& aTexCoordRect, TextureSource* aTexture);
453 
454   void InitializeVAO(const GLuint aAttribIndex, const GLint aComponents,
455                      const GLsizei aStride, const size_t aOffset);
456 
457   gfx::Rect GetTextureCoordinates(gfx::Rect textureRect,
458                                   TextureSource* aTexture);
459 
460   /**
461    * Bind the texture behind the current render target as the backdrop for a
462    * mix-blend shader.
463    */
464   void BindBackdrop(ShaderProgramOGL* aProgram, GLuint aBackdrop,
465                     GLenum aTexUnit);
466 
467   /**
468    * Copies the content of the current render target to the set transaction
469    * target.
470    */
471   void CopyToTarget(gfx::DrawTarget* aTarget, const nsIntPoint& aTopLeft,
472                     const gfx::Matrix& aWorldMatrix);
473 
474   /**
475    * Implements the flipping of the y-axis to convert from layers/compositor
476    * coordinates to OpenGL coordinates.
477    *
478    * Indeed, the only coordinate system that OpenGL knows has the y-axis
479    * pointing upwards, but the layers/compositor coordinate system has the
480    * y-axis pointing downwards, for good reason as Web pages are typically
481    * scrolled downwards. So, some flipping has to take place; FlippedY does it.
482    */
FlipY(GLint y)483   GLint FlipY(GLint y) const { return mViewportSize.height - y; }
484 
485   // The DrawTarget from BeginFrameForTarget, which EndFrame needs to copy the
486   // window contents into.
487   // Only non-null between BeginFrameForTarget and EndFrame.
488   RefPtr<gfx::DrawTarget> mTarget;
489   gfx::IntRect mTargetBounds;
490 
491   RefPtr<CompositorTexturePoolOGL> mTexturePool;
492 
493   // The native layer that we're currently rendering to, if any.
494   // Non-null only between BeginFrame and EndFrame if BeginFrame has been called
495   // with a non-null aNativeLayer.
496   RefPtr<NativeLayer> mCurrentNativeLayer;
497 
498 #ifdef MOZ_WIDGET_GTK
499   // Hold TextureSources which own device data that have to be deleted before
500   // destroying this CompositorOGL.
501   std::unordered_set<TextureSource*> mRegisteredTextureSources;
502 #endif
503 
504   bool mDestroyed;
505 
506   /**
507    * Size of the OpenGL context's primary framebuffer in pixels. Used by
508    * FlipY for the y-flipping calculation and by the DEAA shader.
509    */
510   gfx::IntSize mViewportSize;
511 
512   gfx::IntRegion mCurrentFrameInvalidRegion;
513 
514   ShaderProgramOGL* mCurrentProgram;
515 };
516 
517 }  // namespace layers
518 }  // namespace mozilla
519 
520 #endif /* MOZILLA_GFX_COMPOSITOROGL_H */
521