michael@0: /* -*- Mode: C++; tab-width: 20; indent-tabs-mode: nil; c-basic-offset: 2 -*- 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: #ifndef MOZILLA_GFX_COMPOSITOR_H michael@0: #define MOZILLA_GFX_COMPOSITOR_H michael@0: michael@0: #include "Units.h" // for ScreenPoint michael@0: #include "mozilla/Assertions.h" // for MOZ_ASSERT, etc michael@0: #include "mozilla/RefPtr.h" // for TemporaryRef, RefCounted michael@0: #include "mozilla/gfx/Point.h" // for IntSize, Point michael@0: #include "mozilla/gfx/Rect.h" // for Rect, IntRect michael@0: #include "mozilla/gfx/Types.h" // for Float michael@0: #include "mozilla/layers/CompositorTypes.h" // for DiagnosticTypes, etc michael@0: #include "mozilla/layers/LayersTypes.h" // for LayersBackend michael@0: #include "nsISupportsImpl.h" // for MOZ_COUNT_CTOR, etc michael@0: #include "nsRegion.h" michael@0: #include michael@0: #include "mozilla/WidgetUtils.h" michael@0: michael@0: /** michael@0: * Different elements of a web pages are rendered into separate "layers" before michael@0: * they are flattened into the final image that is brought to the screen. michael@0: * See Layers.h for more informations about layers and why we use retained michael@0: * structures. michael@0: * Most of the documentation for layers is directly in the source code in the michael@0: * form of doc comments. An overview can also be found in the the wiki: michael@0: * https://wiki.mozilla.org/Gecko:Overview#Graphics michael@0: * michael@0: * michael@0: * # Main interfaces and abstractions michael@0: * michael@0: * - Layer, ShadowableLayer and LayerComposite michael@0: * (see Layers.h and ipc/ShadowLayers.h) michael@0: * - CompositableClient and CompositableHost michael@0: * (client/CompositableClient.h composite/CompositableHost.h) michael@0: * - TextureClient and TextureHost michael@0: * (client/TextureClient.h composite/TextureHost.h) michael@0: * - TextureSource michael@0: * (composite/TextureHost.h) michael@0: * - Forwarders michael@0: * (ipc/CompositableForwarder.h ipc/ShadowLayers.h) michael@0: * - Compositor michael@0: * (this file) michael@0: * - IPDL protocols michael@0: * (.ipdl files under the gfx/layers/ipc directory) michael@0: * michael@0: * The *Client and Shadowable* classes are always used on the content thread. michael@0: * Forwarders are always used on the content thread. michael@0: * The *Host and Shadow* classes are always used on the compositor thread. michael@0: * Compositors, TextureSource, and Effects are always used on the compositor michael@0: * thread. michael@0: * Most enums and constants are declared in LayersTypes.h and CompositorTypes.h. michael@0: * michael@0: * michael@0: * # Texture transfer michael@0: * michael@0: * Most layer classes own a Compositable plus some extra information like michael@0: * transforms and clip rects. They are platform independent. michael@0: * Compositable classes manipulate Texture objects and are reponsible for michael@0: * things like tiling, buffer rotation or double buffering. Compositables michael@0: * are also platform-independent. Examples of compositable classes are: michael@0: * - ImageClient michael@0: * - CanvasClient michael@0: * - ContentHost michael@0: * - etc. michael@0: * Texture classes (TextureClient and TextureHost) are thin abstractions over michael@0: * platform-dependent texture memory. They are maniplulated by compositables michael@0: * and don't know about buffer rotations and such. The purposes of TextureClient michael@0: * and TextureHost are to synchronize, serialize and deserialize texture data. michael@0: * TextureHosts provide access to TextureSources that are views on the michael@0: * Texture data providing the necessary api for Compositor backend to composite michael@0: * them. michael@0: * michael@0: * Compositable and Texture clients and hosts are created using factory methods. michael@0: * They should only be created by using their constructor in exceptional michael@0: * circumstances. The factory methods are located: michael@0: * TextureClient - CompositableClient::CreateTextureClient michael@0: * TextureHost - TextureHost::CreateTextureHost, which calls a michael@0: * platform-specific function, e.g., CreateTextureHostOGL michael@0: * CompositableClient - in the appropriate subclass, e.g., michael@0: * CanvasClient::CreateCanvasClient michael@0: * CompositableHost - CompositableHost::Create michael@0: * michael@0: * michael@0: * # IPDL michael@0: * michael@0: * If off-main-thread compositing (OMTC) is enabled, compositing is performed michael@0: * in a dedicated thread. In some setups compositing happens in a dedicated michael@0: * process. Documentation may refer to either the compositor thread or the michael@0: * compositor process. michael@0: * See explanations in ShadowLayers.h. michael@0: * michael@0: * michael@0: * # Backend implementations michael@0: * michael@0: * Compositor backends like OpenGL or flavours of D3D live in their own directory michael@0: * under gfx/layers/. To add a new backend, implement at least the following michael@0: * interfaces: michael@0: * - Compositor (ex. CompositorOGL) michael@0: * - TextureHost (ex. SharedTextureHostOGL) michael@0: * Depending on the type of data that needs to be serialized, you may need to michael@0: * add specific TextureClient implementations. michael@0: */ michael@0: michael@0: class nsIWidget; michael@0: struct nsIntSize; michael@0: class nsIntRegion; michael@0: michael@0: namespace mozilla { michael@0: namespace gfx { michael@0: class Matrix; michael@0: class Matrix4x4; michael@0: class DrawTarget; michael@0: } michael@0: michael@0: namespace layers { michael@0: michael@0: struct Effect; michael@0: struct EffectChain; michael@0: class Image; michael@0: class ISurfaceAllocator; michael@0: class Layer; michael@0: class NewTextureSource; michael@0: class DataTextureSource; michael@0: class CompositingRenderTarget; michael@0: class PCompositorParent; michael@0: class LayerManagerComposite; michael@0: michael@0: enum SurfaceInitMode michael@0: { michael@0: INIT_MODE_NONE, michael@0: INIT_MODE_CLEAR michael@0: }; michael@0: michael@0: /** michael@0: * A base class for a platform-dependent helper for use by TextureHost. michael@0: */ michael@0: class CompositorBackendSpecificData michael@0: { michael@0: NS_INLINE_DECL_REFCOUNTING(CompositorBackendSpecificData) michael@0: michael@0: protected: michael@0: virtual ~CompositorBackendSpecificData() {} michael@0: }; michael@0: michael@0: /** michael@0: * Common interface for compositor backends. michael@0: * michael@0: * Compositor provides a cross-platform interface to a set of operations for michael@0: * compositing quads. Compositor knows nothing about the layer tree. It must be michael@0: * told everything about each composited quad - contents, location, transform, michael@0: * opacity, etc. michael@0: * michael@0: * In theory it should be possible for different widgets to use the same michael@0: * compositor. In practice, we use one compositor per window. michael@0: * michael@0: * # Usage michael@0: * michael@0: * For an example of a user of Compositor, see LayerManagerComposite. michael@0: * michael@0: * Initialization: create a Compositor object, call Initialize(). michael@0: * michael@0: * Destruction: destroy any resources associated with the compositor, call michael@0: * Destroy(), delete the Compositor object. michael@0: * michael@0: * Composition: michael@0: * call BeginFrame, michael@0: * for each quad to be composited: michael@0: * call MakeCurrent if necessary (not necessary if no other context has been michael@0: * made current), michael@0: * take care of any texture upload required to composite the quad, this step michael@0: * is backend-dependent, michael@0: * construct an EffectChain for the quad, michael@0: * call DrawQuad, michael@0: * call EndFrame. michael@0: * If the user has to stop compositing at any point before EndFrame, call michael@0: * AbortFrame. michael@0: * If the compositor is usually used for compositing but compositing is michael@0: * temporarily done without the compositor, call EndFrameForExternalComposition michael@0: * after compositing each frame so the compositor can remain internally michael@0: * consistent. michael@0: * michael@0: * By default, the compositor will render to the screen, to render to a target, michael@0: * call SetTargetContext or SetRenderTarget, the latter with a target created michael@0: * by CreateRenderTarget or CreateRenderTargetFromSource. michael@0: * michael@0: * The target and viewport methods can be called before any DrawQuad call and michael@0: * affect any subsequent DrawQuad calls. michael@0: */ michael@0: class Compositor michael@0: { michael@0: protected: michael@0: virtual ~Compositor() {} michael@0: michael@0: public: michael@0: NS_INLINE_DECL_REFCOUNTING(Compositor) michael@0: michael@0: Compositor(PCompositorParent* aParent = nullptr) michael@0: : mCompositorID(0) michael@0: , mDiagnosticTypes(DIAGNOSTIC_NONE) michael@0: , mParent(aParent) michael@0: , mScreenRotation(ROTATION_0) michael@0: { michael@0: } michael@0: michael@0: virtual TemporaryRef CreateDataTextureSource(TextureFlags aFlags = 0) = 0; michael@0: virtual bool Initialize() = 0; michael@0: virtual void Destroy() = 0; michael@0: michael@0: /** michael@0: * Return true if the effect type is supported. michael@0: * michael@0: * By default Compositor implementations should support all effects but in michael@0: * some rare cases it is not possible to support an effect efficiently. michael@0: * This is the case for BasicCompositor with EffectYCbCr. michael@0: */ michael@0: virtual bool SupportsEffect(EffectTypes aEffect) { return true; } michael@0: michael@0: /** michael@0: * Request a texture host identifier that may be used for creating textures michael@0: * across process or thread boundaries that are compatible with this michael@0: * compositor. michael@0: */ michael@0: virtual TextureFactoryIdentifier GetTextureFactoryIdentifier() = 0; michael@0: michael@0: /** michael@0: * Properties of the compositor. michael@0: */ michael@0: virtual bool CanUseCanvasLayerForSize(const gfx::IntSize& aSize) = 0; michael@0: virtual int32_t GetMaxTextureSize() const = 0; michael@0: michael@0: /** michael@0: * Set the target for rendering. Results will have been written to aTarget by michael@0: * the time that EndFrame returns. michael@0: * michael@0: * If this method is not used, or we pass in nullptr, we target the compositor's michael@0: * usual swap chain and render to the screen. michael@0: */ michael@0: virtual void SetTargetContext(gfx::DrawTarget* aTarget) = 0; michael@0: michael@0: typedef uint32_t MakeCurrentFlags; michael@0: static const MakeCurrentFlags ForceMakeCurrent = 0x1; michael@0: /** michael@0: * Make this compositor's rendering context the current context for the michael@0: * underlying graphics API. This may be a global operation, depending on the michael@0: * API. Our context will remain the current one until someone else changes it. michael@0: * michael@0: * Clients of the compositor should call this at the start of the compositing michael@0: * process, it might be required by texture uploads etc. michael@0: * michael@0: * If aFlags == ForceMakeCurrent then we will (re-)set our context on the michael@0: * underlying API even if it is already the current context. michael@0: */ michael@0: virtual void MakeCurrent(MakeCurrentFlags aFlags = 0) = 0; michael@0: michael@0: /** michael@0: * Creates a Surface that can be used as a rendering target by this michael@0: * compositor. michael@0: */ michael@0: virtual TemporaryRef michael@0: CreateRenderTarget(const gfx::IntRect& aRect, SurfaceInitMode aInit) = 0; michael@0: michael@0: /** michael@0: * Creates a Surface that can be used as a rendering target by this michael@0: * compositor, and initializes the surface by copying from aSource. michael@0: * If aSource is null, then the current screen buffer is used as source. michael@0: * michael@0: * aSourcePoint specifies the point in aSource to copy data from. michael@0: */ michael@0: virtual TemporaryRef michael@0: CreateRenderTargetFromSource(const gfx::IntRect& aRect, michael@0: const CompositingRenderTarget* aSource, michael@0: const gfx::IntPoint& aSourcePoint) = 0; michael@0: michael@0: /** michael@0: * Sets the given surface as the target for subsequent calls to DrawQuad. michael@0: * Passing null as aSurface sets the screen as the target. michael@0: */ michael@0: virtual void SetRenderTarget(CompositingRenderTarget* aSurface) = 0; michael@0: michael@0: /** michael@0: * Returns the current target for rendering. Will return null if we are michael@0: * rendering to the screen. michael@0: */ michael@0: virtual CompositingRenderTarget* GetCurrentRenderTarget() const = 0; michael@0: michael@0: /** michael@0: * Mostly the compositor will pull the size from a widget and this method will michael@0: * be ignored, but compositor implementations are free to use it if they like. michael@0: */ michael@0: virtual void SetDestinationSurfaceSize(const gfx::IntSize& aSize) = 0; michael@0: michael@0: /** michael@0: * Declare an offset to use when rendering layers. This will be ignored when michael@0: * rendering to a target instead of the screen. michael@0: */ michael@0: virtual void SetScreenRenderOffset(const ScreenPoint& aOffset) = 0; michael@0: michael@0: /** michael@0: * Tell the compositor to draw a quad. What to do draw and how it is michael@0: * drawn is specified by aEffectChain. aRect is the quad to draw, in user space. michael@0: * aTransform transforms from user space to screen space. If texture coords are michael@0: * required, these will be in the primary effect in the effect chain. michael@0: */ michael@0: virtual void DrawQuad(const gfx::Rect& aRect, const gfx::Rect& aClipRect, michael@0: const EffectChain& aEffectChain, michael@0: gfx::Float aOpacity, const gfx::Matrix4x4 &aTransform) = 0; michael@0: michael@0: /** michael@0: * Tell the compositor to draw lines connecting the points. Behaves like michael@0: * DrawQuad. michael@0: */ michael@0: virtual void DrawLines(const std::vector& aLines, const gfx::Rect& aClipRect, michael@0: const gfx::Color& aColor, michael@0: gfx::Float aOpacity, const gfx::Matrix4x4 &aTransform) michael@0: { /* Should turn into pure virtual once implemented in D3D */ } michael@0: michael@0: /* michael@0: * Clear aRect on current render target. michael@0: */ michael@0: virtual void ClearRect(const gfx::Rect& aRect) { } michael@0: michael@0: /** michael@0: * Start a new frame. michael@0: * michael@0: * aInvalidRect is the invalid region of the screen; it can be ignored for michael@0: * compositors where the performance for compositing the entire window is michael@0: * sufficient. michael@0: * michael@0: * aClipRectIn is the clip rect for the window in window space (optional). michael@0: * aTransform is the transform from user space to window space. michael@0: * aRenderBounds bounding rect for rendering, in user space. michael@0: * michael@0: * If aClipRectIn is null, this method sets *aClipRectOut to the clip rect michael@0: * actually used for rendering (if aClipRectIn is non-null, we will use that michael@0: * for the clip rect). michael@0: * michael@0: * If aRenderBoundsOut is non-null, it will be set to the render bounds michael@0: * actually used by the compositor in window space. If aRenderBoundsOut michael@0: * is returned empty, composition should be aborted. michael@0: */ michael@0: virtual void BeginFrame(const nsIntRegion& aInvalidRegion, michael@0: const gfx::Rect* aClipRectIn, michael@0: const gfx::Matrix& aTransform, michael@0: const gfx::Rect& aRenderBounds, michael@0: gfx::Rect* aClipRectOut = nullptr, michael@0: gfx::Rect* aRenderBoundsOut = nullptr) = 0; michael@0: michael@0: /** michael@0: * Flush the current frame to the screen and tidy up. michael@0: */ michael@0: virtual void EndFrame() = 0; michael@0: michael@0: virtual void SetFBAcquireFence(Layer* aLayer) {} michael@0: michael@0: /** michael@0: * Post-rendering stuff if the rendering is done outside of this Compositor michael@0: * e.g., by Composer2D. michael@0: * aTransform is the transform from user space to window space. michael@0: */ michael@0: virtual void EndFrameForExternalComposition(const gfx::Matrix& aTransform) = 0; michael@0: michael@0: /** michael@0: * Tidy up if BeginFrame has been called, but EndFrame won't be. michael@0: */ michael@0: virtual void AbortFrame() = 0; michael@0: michael@0: /** michael@0: * Setup the viewport and projection matrix for rendering to a target of the michael@0: * given dimensions. The size and transform here will override those set in michael@0: * BeginFrame. BeginFrame sets a size and transform for the default render michael@0: * target, usually the screen. Calling this method prepares the compositor to michael@0: * render using a different viewport (that is, size and transform), usually michael@0: * associated with a new render target. michael@0: * aWorldTransform is the transform from user space to the new viewport's michael@0: * coordinate space. michael@0: */ michael@0: virtual void PrepareViewport(const gfx::IntSize& aSize, michael@0: const gfx::Matrix& aWorldTransform) = 0; michael@0: michael@0: /** michael@0: * Whether textures created by this compositor can receive partial updates. michael@0: */ michael@0: virtual bool SupportsPartialTextureUpdate() = 0; michael@0: michael@0: void SetDiagnosticTypes(DiagnosticTypes aDiagnostics) michael@0: { michael@0: mDiagnosticTypes = aDiagnostics; michael@0: } michael@0: michael@0: DiagnosticTypes GetDiagnosticTypes() const michael@0: { michael@0: return mDiagnosticTypes; michael@0: } michael@0: michael@0: void DrawDiagnostics(DiagnosticFlags aFlags, michael@0: const gfx::Rect& visibleRect, michael@0: const gfx::Rect& aClipRect, michael@0: const gfx::Matrix4x4& transform, michael@0: uint32_t aFlashCounter = DIAGNOSTIC_FLASH_COUNTER_MAX); michael@0: michael@0: void DrawDiagnostics(DiagnosticFlags aFlags, michael@0: const nsIntRegion& visibleRegion, michael@0: const gfx::Rect& aClipRect, michael@0: const gfx::Matrix4x4& transform, michael@0: uint32_t aFlashCounter = DIAGNOSTIC_FLASH_COUNTER_MAX); michael@0: michael@0: #ifdef MOZ_DUMP_PAINTING michael@0: virtual const char* Name() const = 0; michael@0: #endif // MOZ_DUMP_PAINTING michael@0: michael@0: virtual LayersBackend GetBackendType() const = 0; michael@0: michael@0: /** michael@0: * Each Compositor has a unique ID. michael@0: * This ID is used to keep references to each Compositor in a map accessed michael@0: * from the compositor thread only, so that async compositables can find michael@0: * the right compositor parent and schedule compositing even if the compositor michael@0: * changed. michael@0: */ michael@0: uint32_t GetCompositorID() const michael@0: { michael@0: return mCompositorID; michael@0: } michael@0: void SetCompositorID(uint32_t aID) michael@0: { michael@0: MOZ_ASSERT(mCompositorID == 0, "The compositor ID must be set only once."); michael@0: mCompositorID = aID; michael@0: } michael@0: michael@0: /** michael@0: * Notify the compositor that composition is being paused. This allows the michael@0: * compositor to temporarily release any resources. michael@0: * Between calling Pause and Resume, compositing may fail. michael@0: */ michael@0: virtual void Pause() {} michael@0: /** michael@0: * Notify the compositor that composition is being resumed. The compositor michael@0: * regain any resources it requires for compositing. michael@0: * Returns true if succeeded. michael@0: */ michael@0: virtual bool Resume() { return true; } michael@0: michael@0: /** michael@0: * Call before rendering begins to ensure the compositor is ready to michael@0: * composite. Returns false if rendering should be aborted. michael@0: */ michael@0: virtual bool Ready() { return true; } michael@0: michael@0: // XXX I expect we will want to move mWidget into this class and implement michael@0: // these methods properly. michael@0: virtual nsIWidget* GetWidget() const { return nullptr; } michael@0: michael@0: /** michael@0: * Debug-build assertion that can be called to ensure code is running on the michael@0: * compositor thread. michael@0: */ michael@0: static void AssertOnCompositorThread(); michael@0: michael@0: /** michael@0: * We enforce that there can only be one Compositor backend type off the main michael@0: * thread at the same time. The backend type in use can be checked with this michael@0: * static method. We need this for creating texture clients/hosts etc. when we michael@0: * don't have a reference to a Compositor. michael@0: * michael@0: * This can only be used from the compositor thread! michael@0: */ michael@0: static LayersBackend GetBackend(); michael@0: michael@0: size_t GetFillRatio() { michael@0: float fillRatio = 0; michael@0: if (mPixelsFilled > 0 && mPixelsPerFrame > 0) { michael@0: fillRatio = 100.0f * float(mPixelsFilled) / float(mPixelsPerFrame); michael@0: if (fillRatio > 999.0f) { michael@0: fillRatio = 999.0f; michael@0: } michael@0: } michael@0: return fillRatio; michael@0: } michael@0: michael@0: virtual CompositorBackendSpecificData* GetCompositorBackendSpecificData() { michael@0: return nullptr; michael@0: } michael@0: michael@0: ScreenRotation GetScreenRotation() const { michael@0: return mScreenRotation; michael@0: } michael@0: michael@0: void SetScreenRotation(ScreenRotation aRotation) { michael@0: mScreenRotation = aRotation; michael@0: } michael@0: michael@0: // On b2g the clip rect is in the coordinate space of the physical screen michael@0: // independently of its rotation, while the coordinate space of the layers, michael@0: // on the other hand, depends on the screen orientation. michael@0: // This only applies to b2g as with other platforms, orientation is handled michael@0: // at the OS level rather than in Gecko. michael@0: // In addition, the clip rect needs to be offset by the rendering origin. michael@0: // This becomes important if intermediate surfaces are used. michael@0: gfx::Rect ClipRectInLayersCoordinates(gfx::Rect aClip) const; michael@0: michael@0: protected: michael@0: void DrawDiagnosticsInternal(DiagnosticFlags aFlags, michael@0: const gfx::Rect& aVisibleRect, michael@0: const gfx::Rect& aClipRect, michael@0: const gfx::Matrix4x4& transform, michael@0: uint32_t aFlashCounter); michael@0: michael@0: bool ShouldDrawDiagnostics(DiagnosticFlags); michael@0: michael@0: /** michael@0: * Set the global Compositor backend, checking that one isn't already set. michael@0: */ michael@0: static void SetBackend(LayersBackend backend); michael@0: michael@0: uint32_t mCompositorID; michael@0: DiagnosticTypes mDiagnosticTypes; michael@0: PCompositorParent* mParent; michael@0: michael@0: /** michael@0: * We keep track of the total number of pixels filled as we composite the michael@0: * current frame. This value is an approximation and is not accurate, michael@0: * especially in the presence of transforms. michael@0: */ michael@0: size_t mPixelsPerFrame; michael@0: size_t mPixelsFilled; michael@0: michael@0: ScreenRotation mScreenRotation; michael@0: michael@0: virtual gfx::IntSize GetWidgetSize() const = 0; michael@0: michael@0: private: michael@0: static LayersBackend sBackend; michael@0: michael@0: }; michael@0: michael@0: } // namespace layers michael@0: } // namespace mozilla michael@0: michael@0: #endif /* MOZILLA_GFX_COMPOSITOR_H */