diff options
Diffstat (limited to '')
-rw-r--r-- | gfx/layers/Compositor.h | 416 |
1 files changed, 416 insertions, 0 deletions
diff --git a/gfx/layers/Compositor.h b/gfx/layers/Compositor.h new file mode 100644 index 0000000000..b4e05674a8 --- /dev/null +++ b/gfx/layers/Compositor.h @@ -0,0 +1,416 @@ +/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* vim: set ts=8 sts=2 et sw=2 tw=80: */ +/* 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/. */ + +#ifndef MOZILLA_GFX_COMPOSITOR_H +#define MOZILLA_GFX_COMPOSITOR_H + +#include "Units.h" // for ScreenPoint +#include "mozilla/Assertions.h" // for MOZ_ASSERT, etc +#include "mozilla/RefPtr.h" // for already_AddRefed, RefCounted +#include "mozilla/gfx/2D.h" // for DrawTarget +#include "mozilla/gfx/MatrixFwd.h" // for Matrix, Matrix4x4 +#include "mozilla/gfx/Point.h" // for IntSize, Point +#include "mozilla/gfx/Polygon.h" // for Polygon +#include "mozilla/gfx/Rect.h" // for Rect, IntRect +#include "mozilla/gfx/Types.h" // for Float +#include "mozilla/gfx/Triangle.h" // for Triangle, TexturedTriangle +#include "mozilla/layers/CompositorTypes.h" // for DiagnosticTypes, etc +#include "mozilla/layers/LayersTypes.h" // for LayersBackend +#include "mozilla/layers/SurfacePool.h" // for SurfacePoolHandle +#include "mozilla/layers/TextureSourceProvider.h" +#include "mozilla/widget/CompositorWidget.h" +#include "nsISupportsImpl.h" // for MOZ_COUNT_CTOR, etc +#include "nsRegion.h" +#include <vector> +#include "mozilla/WidgetUtils.h" + +/** + * Different elements of a web pages are rendered into separate "layers" before + * they are flattened into the final image that is brought to the screen. + * See Layers.h for more informations about layers and why we use retained + * structures. + * Most of the documentation for layers is directly in the source code in the + * form of doc comments. An overview can also be found in the the wiki: + * https://wiki.mozilla.org/Gecko:Overview#Graphics + * + * + * # Main interfaces and abstractions + * + * - CompositableClient and CompositableHost + * (client/CompositableClient.h composite/CompositableHost.h) + * - TextureClient and TextureHost + * (client/TextureClient.h composite/TextureHost.h) + * - TextureSource + * (composite/TextureHost.h) + * - Forwarders + * (ipc/CompositableForwarder.h ipc/ShadowLayers.h) + * - Compositor + * (this file) + * - IPDL protocols + * (.ipdl files under the gfx/layers/ipc directory) + * + * The *Client and Shadowable* classes are always used on the content thread. + * Forwarders are always used on the content thread. + * The *Host and Shadow* classes are always used on the compositor thread. + * Compositors, TextureSource, and Effects are always used on the compositor + * thread. + * Most enums and constants are declared in LayersTypes.h and CompositorTypes.h. + * + * + * # Texture transfer + * + * Most layer classes own a Compositable plus some extra information like + * transforms and clip rects. They are platform independent. + * Compositable classes manipulate Texture objects and are reponsible for + * things like tiling, buffer rotation or double buffering. Compositables + * are also platform-independent. Examples of compositable classes are: + * - ImageClient + * - CanvasClient + * - etc. + * Texture classes (TextureClient and TextureHost) are thin abstractions over + * platform-dependent texture memory. They are maniplulated by compositables + * and don't know about buffer rotations and such. The purposes of TextureClient + * and TextureHost are to synchronize, serialize and deserialize texture data. + * TextureHosts provide access to TextureSources that are views on the + * Texture data providing the necessary api for Compositor backend to composite + * them. + * + * Compositable and Texture clients and hosts are created using factory methods. + * They should only be created by using their constructor in exceptional + * circumstances. The factory methods are located: + * TextureClient - CompositableClient::CreateTextureClient + * TextureHost - TextureHost::CreateTextureHost, which calls a + * platform-specific function, e.g., + * CreateTextureHostOGL CompositableClient - in the appropriate subclass, e.g., + * CanvasClient::CreateCanvasClient + * CompositableHost - CompositableHost::Create + * + * + * # IPDL + * + * If off-main-thread compositing (OMTC) is enabled, compositing is performed + * in a dedicated thread. In some setups compositing happens in a dedicated + * process. Documentation may refer to either the compositor thread or the + * compositor process. + * See explanations in ShadowLayers.h. + * + * + * # Backend implementations + * + * Compositor backends like OpenGL or flavours of D3D live in their own + * directory under gfx/layers/. To add a new backend, implement at least the + * following interfaces: + * - Compositor (ex. CompositorOGL) + * - TextureHost (ex. SurfaceTextureHost) + * Depending on the type of data that needs to be serialized, you may need to + * add specific TextureClient implementations. + */ + +class nsIWidget; + +namespace mozilla { +namespace gfx { +class DrawTarget; +class DataSourceSurface; +} // namespace gfx + +namespace layers { + +struct Effect; +struct EffectChain; +class Image; +class Layer; +class TextureSource; +class DataTextureSource; +class CompositingRenderTarget; +class CompositorBridgeParent; +class NativeLayer; +class CompositorOGL; +class CompositorD3D11; +class TextureReadLock; +struct GPUStats; +class AsyncReadbackBuffer; +class RecordedFrame; + +enum SurfaceInitMode { INIT_MODE_NONE, INIT_MODE_CLEAR }; + +/** + * Common interface for compositor backends. + * + * Compositor provides a cross-platform interface to a set of operations for + * compositing quads. Compositor knows nothing about the layer tree. It must be + * told everything about each composited quad - contents, location, transform, + * opacity, etc. + * + * In theory it should be possible for different widgets to use the same + * compositor. In practice, we use one compositor per window. + * + * # Usage + * + * For an example of a user of Compositor, see LayerManagerComposite. + * + * Initialization: create a Compositor object, call Initialize(). + * + * Destruction: destroy any resources associated with the compositor, call + * Destroy(), delete the Compositor object. + * + * Composition: + * call BeginFrame, + * for each quad to be composited: + * call MakeCurrent if necessary (not necessary if no other context has been + * made current), + * take care of any texture upload required to composite the quad, this step + * is backend-dependent, + * construct an EffectChain for the quad, + * call DrawQuad, + * call EndFrame. + * + * By default, the compositor will render to the screen if BeginFrameForWindow + * is called. To render to a target, call BeginFrameForTarget or + * or SetRenderTarget, the latter with a target created + * by CreateRenderTarget or CreateRenderTargetFromSource. + * + * The target and viewport methods can be called before any DrawQuad call and + * affect any subsequent DrawQuad calls. + */ +class Compositor : public TextureSourceProvider { + protected: + virtual ~Compositor(); + + public: + explicit Compositor(widget::CompositorWidget* aWidget); + + bool IsValid() const override { return true; } + + virtual bool Initialize(nsCString* const out_failureReason) = 0; + void Destroy() override; + bool IsDestroyed() const { return mIsDestroyed; } + + /** + * Creates a Surface that can be used as a rendering target by this + * compositor. + */ + virtual already_AddRefed<CompositingRenderTarget> CreateRenderTarget( + const gfx::IntRect& aRect, SurfaceInitMode aInit) = 0; + + /** + * Grab a snapshot of aSource and store it in aDest, so that the pixels can + * be read on the CPU by mapping aDest at some point in the future. + * aSource and aDest must have the same size. + * If this is a GPU compositor, this call must not block on the GPU. + * Returns whether the operation was successful. + */ + virtual bool ReadbackRenderTarget(CompositingRenderTarget* aSource, + AsyncReadbackBuffer* aDest) = 0; + + /** + * Create an AsyncReadbackBuffer of the specified size. Can return null. + */ + virtual already_AddRefed<AsyncReadbackBuffer> CreateAsyncReadbackBuffer( + const gfx::IntSize& aSize) = 0; + + /** + * Draw a part of aSource into the current render target. + * Scaling is done with linear filtering. + * Returns whether the operation was successful. + */ + virtual bool BlitRenderTarget(CompositingRenderTarget* aSource, + const gfx::IntSize& aSourceSize, + const gfx::IntSize& aDestSize) = 0; + + /** + * Sets the given surface as the target for subsequent calls to DrawQuad. + * Passing null as aSurface sets the screen as the target. + */ + virtual void SetRenderTarget(CompositingRenderTarget* aSurface) = 0; + + /** + * Returns the current target for rendering. Will return null if we are + * rendering to the screen. + */ + virtual already_AddRefed<CompositingRenderTarget> GetCurrentRenderTarget() + const = 0; + + /** + * Returns a render target which contains the entire window's drawing. + * On platforms where no such render target is used during compositing (e.g. + * with buffered BasicCompositor, where only the invalid area is drawn to a + * render target), this will return null. + */ + virtual already_AddRefed<CompositingRenderTarget> GetWindowRenderTarget() + const = 0; + + /** + * Mostly the compositor will pull the size from a widget and this method will + * be ignored, but compositor implementations are free to use it if they like. + */ + virtual void SetDestinationSurfaceSize(const gfx::IntSize& aSize) = 0; + + /** + * Tell the compositor to draw a quad. What to do draw and how it is + * drawn is specified by aEffectChain. aRect is the quad to draw, in user + * space. aTransform transforms from user space to screen space. If texture + * coords are required, these will be in the primary effect in the effect + * chain. aVisibleRect is used to determine which edges should be antialiased, + * without applying the effect to the inner edges of a tiled layer. + */ + virtual void DrawQuad(const gfx::Rect& aRect, const gfx::IntRect& aClipRect, + const EffectChain& aEffectChain, gfx::Float aOpacity, + const gfx::Matrix4x4& aTransform, + const gfx::Rect& aVisibleRect) = 0; + + void SetClearColor(const gfx::DeviceColor& aColor) { mClearColor = aColor; } + + /** + * Start a new frame for rendering to the window. + * Needs to be paired with a call to EndFrame() if the return value is not + * Nothing(). + * + * aInvalidRegion is the invalid region of the window. + * aClipRect is the clip rect for all drawing (optional). + * aRenderBounds is the bounding rect for rendering. + * aOpaqueRegion is the area that contains opaque content. + * All coordinates are in window space. + * + * Returns the non-empty render bounds actually used by the compositor in + * window space, or Nothing() if composition should be aborted. + */ + virtual Maybe<gfx::IntRect> BeginFrameForWindow( + const nsIntRegion& aInvalidRegion, const Maybe<gfx::IntRect>& aClipRect, + const gfx::IntRect& aRenderBounds, const nsIntRegion& aOpaqueRegion) = 0; + + /** + * Flush the current frame to the screen and tidy up. + * + * Derived class overriding this should call Compositor::EndFrame. + */ + virtual void EndFrame(); + + virtual void CancelFrame(bool aNeedFlush = true) {} + +#ifdef MOZ_DUMP_PAINTING + virtual const char* Name() const = 0; +#endif // MOZ_DUMP_PAINTING + + virtual CompositorD3D11* AsCompositorD3D11() { return nullptr; } + + Compositor* AsCompositor() override { return this; } + + TimeStamp GetLastCompositionEndTime() const override { + return mLastCompositionEndTime; + } + + /** + * Notify the compositor that composition is being paused. This allows the + * compositor to temporarily release any resources. + * Between calling Pause and Resume, compositing may fail. + */ + virtual void Pause() {} + /** + * Notify the compositor that composition is being resumed. The compositor + * regain any resources it requires for compositing. + * Returns true if succeeded. + */ + virtual bool Resume() { return true; } + + widget::CompositorWidget* GetWidget() const { return mWidget; } + + /** + * Request the compositor to allow recording its frames. + * + * This is a noop on |CompositorOGL|. + */ + virtual void RequestAllowFrameRecording(bool aWillRecord) { + mRecordFrames = aWillRecord; + } + + protected: + /** + * Whether or not the compositor should be prepared to record frames. While + * this returns true, compositors are expected to maintain a full window + * render target that they return from GetWindowRenderTarget() between + * NormalDrawingDone() and EndFrame(). + * + * This will be true when either we are recording a profile with screenshots + * enabled or the |LayerManagerComposite| has requested us to record frames + * for the |CompositionRecorder|. + */ + bool ShouldRecordFrames() const; + + /** + * Last Composition end time. + */ + TimeStamp mLastCompositionEndTime; + + widget::CompositorWidget* mWidget; + + bool mIsDestroyed; + + gfx::DeviceColor mClearColor; + + bool mRecordFrames = false; + + private: + static LayersBackend sBackend; +}; + +// Returns the number of rects. (Up to 4) +typedef gfx::Rect decomposedRectArrayT[4]; +size_t DecomposeIntoNoRepeatRects(const gfx::Rect& aRect, + const gfx::Rect& aTexCoordRect, + decomposedRectArrayT* aLayerRects, + decomposedRectArrayT* aTextureRects); + +static inline bool BlendOpIsMixBlendMode(gfx::CompositionOp aOp) { + switch (aOp) { + case gfx::CompositionOp::OP_MULTIPLY: + case gfx::CompositionOp::OP_SCREEN: + case gfx::CompositionOp::OP_OVERLAY: + case gfx::CompositionOp::OP_DARKEN: + case gfx::CompositionOp::OP_LIGHTEN: + case gfx::CompositionOp::OP_COLOR_DODGE: + case gfx::CompositionOp::OP_COLOR_BURN: + case gfx::CompositionOp::OP_HARD_LIGHT: + case gfx::CompositionOp::OP_SOFT_LIGHT: + case gfx::CompositionOp::OP_DIFFERENCE: + case gfx::CompositionOp::OP_EXCLUSION: + case gfx::CompositionOp::OP_HUE: + case gfx::CompositionOp::OP_SATURATION: + case gfx::CompositionOp::OP_COLOR: + case gfx::CompositionOp::OP_LUMINOSITY: + return true; + default: + return false; + } +} + +class AsyncReadbackBuffer { + public: + NS_INLINE_DECL_REFCOUNTING(AsyncReadbackBuffer) + + gfx::IntSize GetSize() const { return mSize; } + virtual bool MapAndCopyInto(gfx::DataSourceSurface* aSurface, + const gfx::IntSize& aReadSize) const = 0; + + protected: + explicit AsyncReadbackBuffer(const gfx::IntSize& aSize) : mSize(aSize) {} + virtual ~AsyncReadbackBuffer() = default; + + gfx::IntSize mSize; +}; + +struct TexturedVertex { + float position[2]; + float texCoords[2]; +}; + +nsTArray<TexturedVertex> TexturedTrianglesToVertexArray( + const nsTArray<gfx::TexturedTriangle>& aTriangles); + +} // namespace layers +} // namespace mozilla + +#endif /* MOZILLA_GFX_COMPOSITOR_H */ |