gfx/webrender_bindings/WebRenderAPI.h
author Lee Salzman <lsalzman@mozilla.com>
Mon, 06 Nov 2017 20:19:46 -0500
changeset 390416 e0ad40dad503e8d176512140c32d05513a57e4a9
parent 389461 dbd7c51e79f2c5e6d7765150e55d4b4ce292b67b
child 390639 857a0e87e490abaab3595ed0cbb5a5d969860772
permissions -rw-r--r--
Bug 1403198 - send font descriptors to WR instead of raw fonts where possible. r=jrmuizel MozReview-Commit-ID: DYcaO3fE1fc

/* -*- 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_LAYERS_WEBRENDERAPI_H
#define MOZILLA_LAYERS_WEBRENDERAPI_H

#include <vector>
#include <unordered_map>
#include <unordered_set>

#include "mozilla/AlreadyAddRefed.h"
#include "mozilla/layers/SyncObject.h"
#include "mozilla/Range.h"
#include "mozilla/webrender/webrender_ffi.h"
#include "mozilla/webrender/WebRenderTypes.h"
#include "FrameMetrics.h"
#include "GLTypes.h"
#include "Units.h"

namespace mozilla {

struct DisplayItemClipChain;

namespace widget {
class CompositorWidget;
}

namespace layers {
class CompositorBridgeParentBase;
class WebRenderBridgeParent;
}

namespace wr {

class DisplayListBuilder;
class RendererOGL;
class RendererEvent;

// This isn't part of WR's API, but we define it here to simplify layout's
// logic and data plumbing.
struct Line {
  wr::LayoutRect bounds;
  float wavyLineThickness;
  wr::LineOrientation orientation;
  wr::ColorF color;
  wr::LineStyle style;
};

/// Updates to retained resources such as images and fonts, applied within the
/// same transaction.
class ResourceUpdateQueue {
public:
  ResourceUpdateQueue();
  ~ResourceUpdateQueue();
  ResourceUpdateQueue(ResourceUpdateQueue&&);
  ResourceUpdateQueue(const ResourceUpdateQueue&) = delete;
  ResourceUpdateQueue& operator=(ResourceUpdateQueue&&);
  ResourceUpdateQueue& operator=(const ResourceUpdateQueue&) = delete;

  void AddImage(wr::ImageKey aKey,
                const ImageDescriptor& aDescriptor,
                wr::Vec_u8& aBytes);

  void AddBlobImage(wr::ImageKey aKey,
                    const ImageDescriptor& aDescriptor,
                    wr::Vec_u8& aBytes);

  void AddExternalImageBuffer(ImageKey key,
                              const ImageDescriptor& aDescriptor,
                              ExternalImageId aHandle);

  void AddExternalImage(ImageKey key,
                        const ImageDescriptor& aDescriptor,
                        ExternalImageId aExtID,
                        WrExternalImageBufferType aBufferType,
                        uint8_t aChannelIndex = 0);

  void UpdateImageBuffer(wr::ImageKey aKey,
                         const ImageDescriptor& aDescriptor,
                         wr::Vec_u8& aBytes);

  void UpdateBlobImage(wr::ImageKey aKey,
                       const ImageDescriptor& aDescriptor,
                       wr::Vec_u8& aBytes,
                       const wr::DeviceUintRect& aDirtyRect);

  void UpdateExternalImage(ImageKey aKey,
                           const ImageDescriptor& aDescriptor,
                           ExternalImageId aExtID,
                           wr::WrExternalImageBufferType aBufferType,
                           uint8_t aChannelIndex = 0);

  void DeleteImage(wr::ImageKey aKey);

  void AddRawFont(wr::FontKey aKey, wr::Vec_u8& aBytes, uint32_t aIndex);

  void AddFontDescriptor(wr::FontKey aKey, wr::Vec_u8& aBytes, uint32_t aIndex);

  void DeleteFont(wr::FontKey aKey);

  void AddFontInstance(wr::FontInstanceKey aKey,
                       wr::FontKey aFontKey,
                       float aGlyphSize,
                       const wr::FontInstanceOptions* aOptions,
                       const wr::FontInstancePlatformOptions* aPlatformOptions,
                       wr::Vec_u8& aVariations);

  void DeleteFontInstance(wr::FontInstanceKey aKey);

  void Clear();

  // Try to avoid using this when possible.
  wr::ResourceUpdates* Raw() { return mUpdates; }

protected:
  explicit ResourceUpdateQueue(wr::ResourceUpdates* aUpdates)
  : mUpdates(aUpdates) {}

  wr::ResourceUpdates* mUpdates;
};

class WebRenderAPI
{
  NS_INLINE_DECL_REFCOUNTING(WebRenderAPI);

public:
  /// This can be called on the compositor thread only.
  static already_AddRefed<WebRenderAPI> Create(layers::CompositorBridgeParentBase* aBridge,
                                               RefPtr<widget::CompositorWidget>&& aWidget,
                                               LayoutDeviceIntSize aSize);

  already_AddRefed<WebRenderAPI> Clone();

  wr::WindowId GetId() const { return mId; }

  void UpdateScrollPosition(const wr::WrPipelineId& aPipelineId,
                            const layers::FrameMetrics::ViewID& aScrollId,
                            const wr::LayoutPoint& aScrollPosition);

  void GenerateFrame();
  void GenerateFrame(const nsTArray<wr::WrOpacityProperty>& aOpacityArray,
                     const nsTArray<wr::WrTransformProperty>& aTransformArray);

  void SetWindowParameters(LayoutDeviceIntSize size);

  void SetDisplayList(gfx::Color aBgColor,
                      Epoch aEpoch,
                      mozilla::LayerSize aViewportSize,
                      wr::WrPipelineId pipeline_id,
                      const wr::LayoutSize& content_size,
                      wr::BuiltDisplayListDescriptor dl_descriptor,
                      uint8_t *dl_data,
                      size_t dl_size,
                      ResourceUpdateQueue& aResources);

  void ClearDisplayList(Epoch aEpoch, wr::WrPipelineId pipeline_id);

  void SetRootPipeline(wr::PipelineId aPipeline);

  void UpdateResources(ResourceUpdateQueue& aUpdates);

  void UpdatePipelineResources(ResourceUpdateQueue& aUpdates, PipelineId aPipeline, Epoch aEpoch);

  void SetFrameStartTime(const TimeStamp& aTime);

  void RunOnRenderThread(UniquePtr<RendererEvent> aEvent);

  void Readback(gfx::IntSize aSize, uint8_t *aBuffer, uint32_t aBufferSize);

  void Pause();
  bool Resume();

  wr::WrIdNamespace GetNamespace();
  uint32_t GetMaxTextureSize() const { return mMaxTextureSize; }
  bool GetUseANGLE() const { return mUseANGLE; }
  layers::SyncHandle GetSyncHandle() const { return mSyncHandle; }

protected:
  WebRenderAPI(wr::DocumentHandle* aHandle, wr::WindowId aId, uint32_t aMaxTextureSize, bool aUseANGLE, layers::SyncHandle aSyncHandle)
    : mDocHandle(aHandle)
    , mId(aId)
    , mMaxTextureSize(aMaxTextureSize)
    , mUseANGLE(aUseANGLE)
    , mSyncHandle(aSyncHandle)
  {}

  ~WebRenderAPI();
  // Should be used only for shutdown handling
  void WaitFlushed();

  wr::DocumentHandle* mDocHandle;
  wr::WindowId mId;
  uint32_t mMaxTextureSize;
  bool mUseANGLE;
  layers::SyncHandle mSyncHandle;
  RefPtr<wr::WebRenderAPI> mRootApi;

  friend class DisplayListBuilder;
  friend class layers::WebRenderBridgeParent;
};

/// This is a simple C++ wrapper around WrState defined in the rust bindings.
/// We may want to turn this into a direct wrapper on top of WebRenderFrameBuilder
/// instead, so the interface may change a bit.
class DisplayListBuilder {
public:
  explicit DisplayListBuilder(wr::PipelineId aId,
                              const wr::LayoutSize& aContentSize,
                              size_t aCapacity = 0);
  DisplayListBuilder(DisplayListBuilder&&) = default;

  ~DisplayListBuilder();

  void Save();
  void Restore();
  void ClearSave();

  void Finalize(wr::LayoutSize& aOutContentSize,
                wr::BuiltDisplayList& aOutDisplayList);

  void PushStackingContext(const wr::LayoutRect& aBounds, // TODO: We should work with strongly typed rects
                           const uint64_t& aAnimationId,
                           const float* aOpacity,
                           const gfx::Matrix4x4* aTransform,
                           wr::TransformStyle aTransformStyle,
                           const gfx::Matrix4x4* aPerspective,
                           const wr::MixBlendMode& aMixBlendMode,
                           const nsTArray<wr::WrFilterOp>& aFilters,
                           bool aIsBackfaceVisible);
  void PopStackingContext();

  wr::WrClipId DefineClip(const Maybe<layers::FrameMetrics::ViewID>& aAncestorScrollId,
                          const Maybe<wr::WrClipId>& aAncestorClipId,
                          const wr::LayoutRect& aClipRect,
                          const nsTArray<wr::ComplexClipRegion>* aComplex = nullptr,
                          const wr::WrImageMask* aMask = nullptr);
  void PushClip(const wr::WrClipId& aClipId, const DisplayItemClipChain* aParent = nullptr);
  void PopClip(const DisplayItemClipChain* aParent = nullptr);
  Maybe<wr::WrClipId> GetCacheOverride(const DisplayItemClipChain* aParent);

  wr::WrStickyId DefineStickyFrame(const wr::LayoutRect& aContentRect,
                                   const float* aTopMargin,
                                   const float* aRightMargin,
                                   const float* aBottomMargin,
                                   const float* aLeftMargin,
                                   const StickyOffsetBounds& aVerticalBounds,
                                   const StickyOffsetBounds& aHorizontalBounds);
  void PushStickyFrame(const wr::WrStickyId& aStickyId,
                       const DisplayItemClipChain* aParent);
  void PopStickyFrame(const DisplayItemClipChain* aParent);

  bool IsScrollLayerDefined(layers::FrameMetrics::ViewID aScrollId) const;
  void DefineScrollLayer(const layers::FrameMetrics::ViewID& aScrollId,
                         const Maybe<layers::FrameMetrics::ViewID>& aAncestorScrollId,
                         const Maybe<wr::WrClipId>& aAncestorClipId,
                         const wr::LayoutRect& aContentRect, // TODO: We should work with strongly typed rects
                         const wr::LayoutRect& aClipRect);
  void PushScrollLayer(const layers::FrameMetrics::ViewID& aScrollId);
  void PopScrollLayer();

  void PushClipAndScrollInfo(const layers::FrameMetrics::ViewID& aScrollId,
                             const wr::WrClipId* aClipId);
  void PopClipAndScrollInfo();

  void PushRect(const wr::LayoutRect& aBounds,
                const wr::LayoutRect& aClip,
                bool aIsBackfaceVisible,
                const wr::ColorF& aColor);

  void PushClearRect(const wr::LayoutRect& aBounds);

  void PushLinearGradient(const wr::LayoutRect& aBounds,
                          const wr::LayoutRect& aClip,
                          bool aIsBackfaceVisible,
                          const wr::LayoutPoint& aStartPoint,
                          const wr::LayoutPoint& aEndPoint,
                          const nsTArray<wr::GradientStop>& aStops,
                          wr::ExtendMode aExtendMode,
                          const wr::LayoutSize aTileSize,
                          const wr::LayoutSize aTileSpacing);

  void PushRadialGradient(const wr::LayoutRect& aBounds,
                          const wr::LayoutRect& aClip,
                          bool aIsBackfaceVisible,
                          const wr::LayoutPoint& aCenter,
                          const wr::LayoutSize& aRadius,
                          const nsTArray<wr::GradientStop>& aStops,
                          wr::ExtendMode aExtendMode,
                          const wr::LayoutSize aTileSize,
                          const wr::LayoutSize aTileSpacing);

  void PushImage(const wr::LayoutRect& aBounds,
                 const wr::LayoutRect& aClip,
                 bool aIsBackfaceVisible,
                 wr::ImageRendering aFilter,
                 wr::ImageKey aImage);

  void PushImage(const wr::LayoutRect& aBounds,
                 const wr::LayoutRect& aClip,
                 bool aIsBackfaceVisible,
                 const wr::LayoutSize& aStretchSize,
                 const wr::LayoutSize& aTileSpacing,
                 wr::ImageRendering aFilter,
                 wr::ImageKey aImage);

  void PushYCbCrPlanarImage(const wr::LayoutRect& aBounds,
                            const wr::LayoutRect& aClip,
                            bool aIsBackfaceVisible,
                            wr::ImageKey aImageChannel0,
                            wr::ImageKey aImageChannel1,
                            wr::ImageKey aImageChannel2,
                            wr::WrYuvColorSpace aColorSpace,
                            wr::ImageRendering aFilter);

  void PushNV12Image(const wr::LayoutRect& aBounds,
                     const wr::LayoutRect& aClip,
                     bool aIsBackfaceVisible,
                     wr::ImageKey aImageChannel0,
                     wr::ImageKey aImageChannel1,
                     wr::WrYuvColorSpace aColorSpace,
                     wr::ImageRendering aFilter);

  void PushYCbCrInterleavedImage(const wr::LayoutRect& aBounds,
                                 const wr::LayoutRect& aClip,
                                 bool aIsBackfaceVisible,
                                 wr::ImageKey aImageChannel0,
                                 wr::WrYuvColorSpace aColorSpace,
                                 wr::ImageRendering aFilter);

  void PushIFrame(const wr::LayoutRect& aBounds,
                  bool aIsBackfaceVisible,
                  wr::PipelineId aPipeline);

  // XXX WrBorderSides are passed with Range.
  // It is just to bypass compiler bug. See Bug 1357734.
  void PushBorder(const wr::LayoutRect& aBounds,
                  const wr::LayoutRect& aClip,
                  bool aIsBackfaceVisible,
                  const wr::BorderWidths& aWidths,
                  const Range<const wr::BorderSide>& aSides,
                  const wr::BorderRadius& aRadius);

  void PushBorderImage(const wr::LayoutRect& aBounds,
                       const wr::LayoutRect& aClip,
                       bool aIsBackfaceVisible,
                       const wr::BorderWidths& aWidths,
                       wr::ImageKey aImage,
                       const wr::NinePatchDescriptor& aPatch,
                       const wr::SideOffsets2D_f32& aOutset,
                       const wr::RepeatMode& aRepeatHorizontal,
                       const wr::RepeatMode& aRepeatVertical);

  void PushBorderGradient(const wr::LayoutRect& aBounds,
                          const wr::LayoutRect& aClip,
                          bool aIsBackfaceVisible,
                          const wr::BorderWidths& aWidths,
                          const wr::LayoutPoint& aStartPoint,
                          const wr::LayoutPoint& aEndPoint,
                          const nsTArray<wr::GradientStop>& aStops,
                          wr::ExtendMode aExtendMode,
                          const wr::SideOffsets2D_f32& aOutset);

  void PushBorderRadialGradient(const wr::LayoutRect& aBounds,
                                const wr::LayoutRect& aClip,
                                bool aIsBackfaceVisible,
                                const wr::BorderWidths& aWidths,
                                const wr::LayoutPoint& aCenter,
                                const wr::LayoutSize& aRadius,
                                const nsTArray<wr::GradientStop>& aStops,
                                wr::ExtendMode aExtendMode,
                                const wr::SideOffsets2D_f32& aOutset);

  void PushText(const wr::LayoutRect& aBounds,
                const wr::LayoutRect& aClip,
                bool aIsBackfaceVisible,
                const wr::ColorF& aColor,
                wr::FontInstanceKey aFontKey,
                Range<const wr::GlyphInstance> aGlyphBuffer,
                const wr::GlyphOptions* aGlyphOptions = nullptr);

  void PushLine(const wr::LayoutRect& aClip,
                bool aIsBackfaceVisible,
                const wr::Line& aLine);

  void PushShadow(const wr::LayoutRect& aBounds,
                      const wr::LayoutRect& aClip,
                      bool aIsBackfaceVisible,
                      const wr::Shadow& aShadow);

  void PopAllShadows();



  void PushBoxShadow(const wr::LayoutRect& aRect,
                     const wr::LayoutRect& aClip,
                     bool aIsBackfaceVisible,
                     const wr::LayoutRect& aBoxBounds,
                     const wr::LayoutVector2D& aOffset,
                     const wr::ColorF& aColor,
                     const float& aBlurRadius,
                     const float& aSpreadRadius,
                     const wr::BorderRadius& aBorderRadius,
                     const wr::BoxShadowClipMode& aClipMode);

  // Returns the clip id that was most recently pushed with PushClip and that
  // has not yet been popped with PopClip. Return Nothing() if the clip stack
  // is empty.
  Maybe<wr::WrClipId> TopmostClipId();
  // Same as TopmostClipId() but for scroll layers.
  layers::FrameMetrics::ViewID TopmostScrollId();
  // If the topmost item on the stack is a clip or a scroll layer
  bool TopmostIsClip();

  // Try to avoid using this when possible.
  wr::WrState* Raw() { return mWrState; }

  // Return true if the current clip stack has any extra clip.
  bool HasExtraClip() { return !mCacheOverride.empty(); }

protected:
  void PushCacheOverride(const DisplayItemClipChain* aParent,
                         const wr::WrClipId& aClipId);
  void PopCacheOverride(const DisplayItemClipChain* aParent);

  wr::WrState* mWrState;

  // Track the stack of clip ids and scroll layer ids that have been pushed
  // (by PushClip and PushScrollLayer/PushClipAndScrollInfo, respectively) and
  // haven't yet been popped.
  std::vector<wr::ScrollOrClipId> mClipStack;

  // Track each scroll id that we encountered. We use this structure to
  // ensure that we don't define a particular scroll layer multiple times,
  // as that results in undefined behaviour in WR.
  std::unordered_set<layers::FrameMetrics::ViewID> mScrollIdsDefined;

  // A map that holds the cache overrides creates by "out of band" clips, i.e.
  // clips that are generated by display items but that ScrollingLayersHelper
  // doesn't know about. These are called "cache overrides" because while we're
  // inside one of these clips, the WR clip stack is different from what
  // ScrollingLayersHelper thinks it actually is (because of the out-of-band
  // clip that was pushed onto the stack) and so ScrollingLayersHelper cannot
  // use its clip cache as-is. Instead, any time ScrollingLayersHelper wants
  // to define a new clip as a child of clip X, it should first check the
  // cache overrides to see if there is an out-of-band clip Y that is already a
  // child of X, and then define its clip as a child of Y instead. This map
  // stores X -> ClipId of Y, which allows ScrollingLayersHelper to do the
  // necessary lookup. Note that there theoretically might be multiple
  // different "Y" clips which is why we need a vector.
  std::unordered_map<const DisplayItemClipChain*, std::vector<wr::WrClipId>> mCacheOverride;

  friend class WebRenderAPI;
};

Maybe<wr::ImageFormat>
SurfaceFormatToImageFormat(gfx::SurfaceFormat aFormat);

} // namespace wr
} // namespace mozilla

#endif