gfx/layers/wr/WebRenderUserData.h
author Byron Campen <docfaraday@gmail.com>
Mon, 20 Sep 2021 16:45:53 +0000
changeset 592504 20b482455364fc14118bd32de96ae52cc81c7f3a
parent 592428 78f012e85b57c9df93e078f4376124dc457b20ab
permissions -rw-r--r--
Bug 1651268: Make sure the pre-run code for FindExpirationTime waits for timers to fire on all threads. r=xpcom-reviewers,nika Differential Revision: https://phabricator.services.mozilla.com/D125603

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

#include <vector>
#include "mozilla/webrender/WebRenderAPI.h"
#include "mozilla/layers/AnimationInfo.h"
#include "mozilla/dom/RemoteBrowser.h"
#include "mozilla/UniquePtr.h"
#include "nsIFrame.h"
#include "nsRefPtrHashtable.h"
#include "nsTHashSet.h"
#include "ImageTypes.h"
#include "DisplayItemClip.h"

namespace mozilla {

class nsDisplayItemGeometry;

namespace webgpu {
class WebGPUChild;
}

namespace wr {
class IpcResourceUpdateQueue;
}

namespace gfx {
class SourceSurface;
}

namespace layers {

class BasicLayerManager;
class ImageClient;
class ImageContainer;
class WebRenderBridgeChild;
class WebRenderCanvasData;
class WebRenderCanvasRenderer;
class WebRenderCanvasRendererAsync;
class WebRenderImageData;
class WebRenderFallbackData;
class WebRenderLocalCanvasData;
class RenderRootStateManager;
class WebRenderGroupData;

class WebRenderBackgroundData {
 public:
  WebRenderBackgroundData(wr::LayoutRect aBounds, wr::ColorF aColor)
      : mBounds(aBounds), mColor(aColor) {}
  void AddWebRenderCommands(wr::DisplayListBuilder& aBuilder);

 protected:
  wr::LayoutRect mBounds;
  wr::ColorF mColor;
};

/// Parent class for arbitrary WebRender-specific data that can be associated
/// to an nsFrame.
class WebRenderUserData {
 public:
  typedef nsTHashSet<RefPtr<WebRenderUserData>> WebRenderUserDataRefTable;

  static bool SupportsAsyncUpdate(nsIFrame* aFrame);

  static bool ProcessInvalidateForImage(nsIFrame* aFrame, DisplayItemType aType,
                                        ContainerProducerID aProducerId);

  NS_INLINE_DECL_REFCOUNTING(WebRenderUserData)

  WebRenderUserData(RenderRootStateManager* aManager, nsDisplayItem* aItem);
  WebRenderUserData(RenderRootStateManager* aManager, uint32_t mDisplayItemKey,
                    nsIFrame* aFrame);

  virtual WebRenderImageData* AsImageData() { return nullptr; }
  virtual WebRenderFallbackData* AsFallbackData() { return nullptr; }
  virtual WebRenderCanvasData* AsCanvasData() { return nullptr; }
  virtual WebRenderLocalCanvasData* AsLocalCanvasData() { return nullptr; }
  virtual WebRenderGroupData* AsGroupData() { return nullptr; }

  enum class UserDataType {
    eImage,
    eFallback,
    eAPZAnimation,
    eAnimation,
    eCanvas,
    eLocalCanvas,
    eRemote,
    eGroup,
    eMask,
    eBlobImage,  // SVG image
  };

  virtual UserDataType GetType() = 0;
  bool IsUsed() { return mUsed; }
  void SetUsed(bool aUsed) { mUsed = aUsed; }
  nsIFrame* GetFrame() { return mFrame; }
  uint32_t GetDisplayItemKey() { return mDisplayItemKey; }
  void RemoveFromTable();
  virtual nsDisplayItemGeometry* GetGeometry() { return nullptr; }

 protected:
  virtual ~WebRenderUserData();

  WebRenderBridgeChild* WrBridge() const;

  RefPtr<RenderRootStateManager> mManager;
  nsIFrame* mFrame;
  uint32_t mDisplayItemKey;
  WebRenderUserDataRefTable* mTable;
  bool mUsed;
};

struct WebRenderUserDataKey {
  WebRenderUserDataKey(uint32_t aFrameKey,
                       WebRenderUserData::UserDataType aType)
      : mFrameKey(aFrameKey), mType(aType) {}

  bool operator==(const WebRenderUserDataKey& other) const {
    return mFrameKey == other.mFrameKey && mType == other.mType;
  }
  PLDHashNumber Hash() const {
    return HashGeneric(
        mFrameKey,
        static_cast<std::underlying_type<decltype(mType)>::type>(mType));
  }

  uint32_t mFrameKey;
  WebRenderUserData::UserDataType mType;
};

typedef nsRefPtrHashtable<
    nsGenericHashKey<mozilla::layers::WebRenderUserDataKey>, WebRenderUserData>
    WebRenderUserDataTable;

/// Holds some data used to share TextureClient/ImageClient with the parent
/// process.
class WebRenderImageData : public WebRenderUserData {
 public:
  WebRenderImageData(RenderRootStateManager* aManager, nsDisplayItem* aItem);
  WebRenderImageData(RenderRootStateManager* aManager, uint32_t aDisplayItemKey,
                     nsIFrame* aFrame);
  virtual ~WebRenderImageData();

  WebRenderImageData* AsImageData() override { return this; }
  UserDataType GetType() override { return UserDataType::eImage; }
  static UserDataType Type() { return UserDataType::eImage; }
  Maybe<wr::ImageKey> GetImageKey() { return mKey; }
  void SetImageKey(const wr::ImageKey& aKey);
  already_AddRefed<ImageClient> GetImageClient();

  Maybe<wr::ImageKey> UpdateImageKey(ImageContainer* aContainer,
                                     wr::IpcResourceUpdateQueue& aResources,
                                     bool aFallback = false);

  void CreateAsyncImageWebRenderCommands(
      mozilla::wr::DisplayListBuilder& aBuilder, ImageContainer* aContainer,
      const StackingContextHelper& aSc, const LayoutDeviceRect& aBounds,
      const LayoutDeviceRect& aSCBounds, VideoInfo::Rotation aRotation,
      const wr::ImageRendering& aFilter, const wr::MixBlendMode& aMixBlendMode,
      bool aIsBackfaceVisible);

  void CreateImageClientIfNeeded();

  bool IsAsync() { return mPipelineId.isSome(); }

  bool UsingSharedSurface(ContainerProducerID aProducerId) const;

  void ClearImageKey();

 protected:
  Maybe<wr::ImageKey> mKey;
  RefPtr<TextureClient> mTextureOfImage;
  RefPtr<ImageClient> mImageClient;
  Maybe<wr::PipelineId> mPipelineId;
  RefPtr<ImageContainer> mContainer;
  // The key can be owned by a shared surface that is used by several elements.
  // when this is the case the shared surface is responsible for managing the
  // destruction of the key.
  // TODO: we surely can come up with a simpler/safer way to model this.
  bool mOwnsKey;
};

/// Holds some data used to share blob recordings from VectorImages with the
/// parent process.
class WebRenderBlobImageData : public WebRenderUserData {
 public:
  WebRenderBlobImageData(RenderRootStateManager* aManager,
                         nsDisplayItem* aItem);
  WebRenderBlobImageData(RenderRootStateManager* aManager,
                         uint32_t aDisplayItemKey, nsIFrame* aFrame);
  virtual ~WebRenderBlobImageData() {}

  UserDataType GetType() override { return UserDataType::eBlobImage; }
  static UserDataType Type() { return UserDataType::eBlobImage; }
  Maybe<wr::BlobImageKey> GetImageKey() { return mKey; }

  Maybe<wr::BlobImageKey> UpdateImageKey(
      ImageContainer* aContainer, wr::IpcResourceUpdateQueue& aResources);

 protected:
  Maybe<wr::BlobImageKey> mKey;
  RefPtr<ImageContainer> mContainer;
};

/// Used for fallback rendering.
///
/// In most cases this uses blob images but it can also render on the content
/// side directly into a texture.
class WebRenderFallbackData : public WebRenderUserData {
 public:
  WebRenderFallbackData(RenderRootStateManager* aManager, nsDisplayItem* aItem);
  virtual ~WebRenderFallbackData();

  WebRenderFallbackData* AsFallbackData() override { return this; }
  UserDataType GetType() override { return UserDataType::eFallback; }
  static UserDataType Type() { return UserDataType::eFallback; }
  nsDisplayItemGeometry* GetGeometry() override { return mGeometry.get(); }

  void SetInvalid(bool aInvalid) { mInvalid = aInvalid; }
  bool IsInvalid() { return mInvalid; }
  void SetFonts(const std::vector<RefPtr<gfx::ScaledFont>>& aFonts) {
    mFonts = aFonts;
  }
  Maybe<wr::BlobImageKey> GetBlobImageKey() { return mBlobKey; }
  void SetBlobImageKey(const wr::BlobImageKey& aKey);
  Maybe<wr::ImageKey> GetImageKey();

  /// Create a WebRenderImageData to manage the image we are about to render
  /// into.
  WebRenderImageData* PaintIntoImage();

  std::vector<RefPtr<gfx::SourceSurface>> mExternalSurfaces;
  UniquePtr<nsDisplayItemGeometry> mGeometry;
  DisplayItemClip mClip;
  nsRect mBounds;
  nsRect mBuildingRect;
  gfx::Size mScale;

 protected:
  void ClearImageKey();

  std::vector<RefPtr<gfx::ScaledFont>> mFonts;
  Maybe<wr::BlobImageKey> mBlobKey;
  // When rendering into a blob image, mImageData is null. It is non-null only
  // when we render directly into a texture on the content side.
  RefPtr<WebRenderImageData> mImageData;
  bool mInvalid;
};

class WebRenderAPZAnimationData : public WebRenderUserData {
 public:
  WebRenderAPZAnimationData(RenderRootStateManager* aManager,
                            nsDisplayItem* aItem);
  virtual ~WebRenderAPZAnimationData() = default;

  UserDataType GetType() override { return UserDataType::eAPZAnimation; }
  static UserDataType Type() { return UserDataType::eAPZAnimation; }
  uint64_t GetAnimationId() { return mAnimationId; }

 private:
  uint64_t mAnimationId;
};

class WebRenderAnimationData : public WebRenderUserData {
 public:
  WebRenderAnimationData(RenderRootStateManager* aManager,
                         nsDisplayItem* aItem);
  virtual ~WebRenderAnimationData();

  UserDataType GetType() override { return UserDataType::eAnimation; }
  static UserDataType Type() { return UserDataType::eAnimation; }
  AnimationInfo& GetAnimationInfo() { return mAnimationInfo; }

 protected:
  AnimationInfo mAnimationInfo;
};

class WebRenderCanvasData : public WebRenderUserData {
 public:
  WebRenderCanvasData(RenderRootStateManager* aManager, nsDisplayItem* aItem);
  virtual ~WebRenderCanvasData();

  WebRenderCanvasData* AsCanvasData() override { return this; }
  UserDataType GetType() override { return UserDataType::eCanvas; }
  static UserDataType Type() { return UserDataType::eCanvas; }

  void ClearCanvasRenderer();
  WebRenderCanvasRendererAsync* GetCanvasRenderer();
  WebRenderCanvasRendererAsync* CreateCanvasRenderer();

  void SetImageContainer(ImageContainer* aImageContainer);
  ImageContainer* GetImageContainer();
  void ClearImageContainer();

 protected:
  RefPtr<WebRenderCanvasRendererAsync> mCanvasRenderer;
  RefPtr<ImageContainer> mContainer;
};

// WebRender data assocatiated with canvases that don't need to
// synchronize across content-GPU process barrier.
class WebRenderLocalCanvasData : public WebRenderUserData {
 public:
  WebRenderLocalCanvasData(RenderRootStateManager* aManager,
                           nsDisplayItem* aItem);
  virtual ~WebRenderLocalCanvasData();

  WebRenderLocalCanvasData* AsLocalCanvasData() override { return this; }
  UserDataType GetType() override { return UserDataType::eLocalCanvas; }
  static UserDataType Type() { return UserDataType::eLocalCanvas; }

  void RequestFrameReadback();
  void RefreshExternalImage();

  // TODO: introduce a CanvasRenderer derivative to store here?

  WeakPtr<webgpu::WebGPUChild> mGpuBridge;
  uint64_t mGpuTextureId = 0;
  wr::ExternalImageId mExternalImageId = {0};
  wr::ImageKey mImageKey = {};
  wr::ImageDescriptor mDescriptor;
  gfx::SurfaceFormat mFormat = gfx::SurfaceFormat::UNKNOWN;
  bool mDirty = false;
};

class WebRenderRemoteData : public WebRenderUserData {
 public:
  WebRenderRemoteData(RenderRootStateManager* aManager, nsDisplayItem* aItem);
  virtual ~WebRenderRemoteData();

  UserDataType GetType() override { return UserDataType::eRemote; }
  static UserDataType Type() { return UserDataType::eRemote; }

  void SetRemoteBrowser(dom::RemoteBrowser* aBrowser) {
    mRemoteBrowser = aBrowser;
  }

 protected:
  RefPtr<dom::RemoteBrowser> mRemoteBrowser;
};

extern void DestroyWebRenderUserDataTable(WebRenderUserDataTable* aTable);

struct WebRenderUserDataProperty {
  NS_DECLARE_FRAME_PROPERTY_WITH_DTOR(Key, WebRenderUserDataTable,
                                      DestroyWebRenderUserDataTable)
};

template <class T>
already_AddRefed<T> GetWebRenderUserData(const nsIFrame* aFrame,
                                         uint32_t aPerFrameKey) {
  MOZ_ASSERT(aFrame);
  WebRenderUserDataTable* userDataTable =
      aFrame->GetProperty(WebRenderUserDataProperty::Key());
  if (!userDataTable) {
    return nullptr;
  }

  WebRenderUserData* data =
      userDataTable->GetWeak(WebRenderUserDataKey(aPerFrameKey, T::Type()));
  if (data) {
    RefPtr<T> result = static_cast<T*>(data);
    return result.forget();
  }

  return nullptr;
}

}  // namespace layers
}  // namespace mozilla

#endif /* GFX_WEBRENDERUSERDATA_H */