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