tor-browser

The Tor Browser
git clone https://git.dasho.dev/tor-browser.git
Log | Files | Refs | README | LICENSE

DrawTargetWebglInternal.h (16788B)


      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_DRAWTARGETWEBGL_INTERNAL_H
      8 #define _MOZILLA_GFX_DRAWTARGETWEBGL_INTERNAL_H
      9 
     10 #include "DrawTargetWebgl.h"
     11 #include "mozilla/HashFunctions.h"
     12 #include "mozilla/WeakPtr.h"
     13 #include "mozilla/gfx/Etagere.h"
     14 #include "mozilla/gfx/PathSkia.h"
     15 #include "mozilla/gfx/WPFGpuRaster.h"
     16 
     17 namespace mozilla::gfx {
     18 
     19 // CacheEnty is a generic interface for various items that need to be cached to
     20 // a texture.
     21 class CacheEntry : public RefCounted<CacheEntry> {
     22 public:
     23  MOZ_DECLARE_REFCOUNTED_VIRTUAL_TYPENAME(CacheEntry)
     24 
     25  CacheEntry(const Matrix& aTransform, const IntRect& aBounds, HashNumber aHash)
     26      : mTransform(aTransform), mBounds(aBounds), mHash(aHash) {}
     27  virtual ~CacheEntry() = default;
     28 
     29  void Link(const RefPtr<TextureHandle>& aHandle);
     30  void Unlink();
     31 
     32  const RefPtr<TextureHandle>& GetHandle() const { return mHandle; }
     33 
     34  const Matrix& GetTransform() const { return mTransform; }
     35  const IntRect& GetBounds() const { return mBounds; }
     36  HashNumber GetHash() const { return mHash; }
     37 
     38  virtual bool IsValid() const { return true; }
     39 
     40 protected:
     41  virtual void RemoveFromList() = 0;
     42 
     43  // The handle of the rendered cache item.
     44  RefPtr<TextureHandle> mHandle;
     45  // The transform that was used to render the entry. This is necessary as
     46  // the geometry might only be correctly rendered in device space after
     47  // the transform is applied, so in general we can't cache untransformed
     48  // geometry.
     49  Matrix mTransform;
     50  // The device space bounds of the rendered geometry.
     51  IntRect mBounds;
     52  // A hash of the geometry that may be used for quickly rejecting entries.
     53  HashNumber mHash;
     54 };
     55 
     56 // CacheEntryImpl provides type-dependent boilerplate code for implementations
     57 // of CacheEntry.
     58 template <typename T>
     59 class CacheEntryImpl : public CacheEntry, public LinkedListElement<RefPtr<T>> {
     60  typedef LinkedListElement<RefPtr<T>> ListType;
     61 
     62 public:
     63  CacheEntryImpl(const Matrix& aTransform, const IntRect& aBounds,
     64                 HashNumber aHash)
     65      : CacheEntry(aTransform, aBounds, aHash) {}
     66 
     67  void RemoveFromList() override {
     68    if (ListType::isInList()) {
     69      ListType::remove();
     70    }
     71  }
     72 };
     73 
     74 // CacheImpl manages a list of CacheEntry.
     75 template <typename T, bool BIG>
     76 class CacheImpl {
     77 protected:
     78  typedef LinkedList<RefPtr<T>> ListType;
     79 
     80  // Whether the cache should be small and space-efficient or prioritize speed.
     81  static constexpr size_t kNumChains = BIG ? 499 : 71;
     82 
     83 public:
     84  ~CacheImpl() {
     85    for (auto& chain : mChains) {
     86      while (RefPtr<T> entry = chain.popLast()) {
     87        entry->Unlink();
     88      }
     89    }
     90  }
     91 
     92 protected:
     93  ListType& GetChain(HashNumber aHash) { return mChains[aHash % kNumChains]; }
     94 
     95  void Insert(T* aEntry) { GetChain(aEntry->GetHash()).insertFront(aEntry); }
     96 
     97  ListType mChains[kNumChains];
     98 };
     99 
    100 // BackingTexture provides information about the shared or standalone texture
    101 // that is backing a texture handle.
    102 class BackingTexture {
    103 public:
    104  BackingTexture(const IntSize& aSize, SurfaceFormat aFormat,
    105                 const RefPtr<WebGLTexture>& aTexture);
    106 
    107  SurfaceFormat GetFormat() const { return mFormat; }
    108  IntSize GetSize() const { return mSize; }
    109 
    110  static inline size_t UsedBytes(SurfaceFormat aFormat, const IntSize& aSize) {
    111    return size_t(BytesPerPixel(aFormat)) * size_t(aSize.width) *
    112           size_t(aSize.height);
    113  }
    114 
    115  size_t UsedBytes() const { return UsedBytes(GetFormat(), GetSize()); }
    116 
    117  const RefPtr<WebGLTexture>& GetWebGLTexture() const { return mTexture; }
    118 
    119  bool IsInitialized() const { return mFlags & INITIALIZED; }
    120  void MarkInitialized() { mFlags |= INITIALIZED; }
    121 
    122  bool IsRenderable() const { return mFlags & RENDERABLE; }
    123  void MarkRenderable() { mFlags |= RENDERABLE; }
    124 
    125 protected:
    126  IntSize mSize;
    127  SurfaceFormat mFormat;
    128  RefPtr<WebGLTexture> mTexture;
    129 
    130 private:
    131  enum Flags : uint8_t {
    132    INITIALIZED = 1 << 0,
    133    RENDERABLE = 1 << 1,
    134  };
    135 
    136  uint8_t mFlags = 0;
    137 };
    138 
    139 // TextureHandle is an abstract base class for supplying textures to drawing
    140 // commands that may be backed by different resource types (such as a shared
    141 // or standalone texture). It may be further linked to use-specific metadata
    142 // such as for shadow drawing or for cached entries in the glyph cache.
    143 class TextureHandle : public RefCounted<TextureHandle>,
    144                      public SupportsWeakPtr,
    145                      public LinkedListElement<RefPtr<TextureHandle>> {
    146 public:
    147  MOZ_DECLARE_REFCOUNTED_VIRTUAL_TYPENAME(TextureHandle)
    148 
    149  enum Type { SHARED, STANDALONE };
    150 
    151  virtual Type GetType() const = 0;
    152  virtual IntRect GetBounds() const = 0;
    153  IntSize GetSize() const { return GetBounds().Size(); }
    154  virtual SurfaceFormat GetFormat() const = 0;
    155 
    156  virtual BackingTexture* GetBackingTexture() = 0;
    157 
    158  size_t UsedBytes() const {
    159    return BackingTexture::UsedBytes(GetFormat(), GetSize());
    160  }
    161 
    162  virtual void UpdateSize(const IntSize& aSize) {}
    163 
    164  virtual void Cleanup(SharedContextWebgl& aContext) {}
    165 
    166  virtual ~TextureHandle() {}
    167 
    168  bool IsValid() const { return mValid; }
    169  void Invalidate() { mValid = false; }
    170 
    171  void ClearSurface() { mSurface = nullptr; }
    172  void SetSurface(const RefPtr<SourceSurface>& aSurface) {
    173    mSurface = aSurface;
    174  }
    175  already_AddRefed<SourceSurface> GetSurface() const {
    176    RefPtr<SourceSurface> surface(mSurface);
    177    return surface.forget();
    178  }
    179 
    180  float GetSigma() const { return mSigma; }
    181  void SetSigma(float aSigma) { mSigma = aSigma; }
    182  bool IsShadow() const { return mSigma >= 0.0f; }
    183 
    184  void SetSamplingOffset(const IntPoint& aSamplingOffset) {
    185    mSamplingOffset = aSamplingOffset;
    186  }
    187  const IntPoint& GetSamplingOffset() const { return mSamplingOffset; }
    188  IntRect GetSamplingRect() const {
    189    return IntRect(GetSamplingOffset(), GetSize());
    190  }
    191 
    192  const RefPtr<CacheEntry>& GetCacheEntry() const { return mCacheEntry; }
    193  void SetCacheEntry(const RefPtr<CacheEntry>& aEntry) { mCacheEntry = aEntry; }
    194 
    195  // Note as used if there is corresponding surface or cache entry.
    196  bool IsUsed() const {
    197    return !mSurface.IsDead() || (mCacheEntry && mCacheEntry->IsValid());
    198  }
    199 
    200 private:
    201  bool mValid = true;
    202  // If applicable, weak pointer to the SourceSurface that is linked to this
    203  // TextureHandle.
    204  ThreadSafeWeakPtr<SourceSurface> mSurface;
    205  // If this TextureHandle stores a cached shadow, then we need to remember the
    206  // blur sigma used to produce the shadow.
    207  float mSigma = -1.0f;
    208  // If the originating surface requested a sampling rect, then we need to know
    209  // the offset of the subrect within the surface for texture coordinates.
    210  IntPoint mSamplingOffset;
    211  // If applicable, the CacheEntry that is linked to this TextureHandle.
    212  RefPtr<CacheEntry> mCacheEntry;
    213 };
    214 
    215 class SharedTextureHandle;
    216 
    217 // SharedTexture is a large slab texture that is subdivided (by using a
    218 // TexturePacker) to hold many small SharedTextureHandles. This avoids needing
    219 // to allocate many WebGL textures for every single small Canvas 2D texture.
    220 class SharedTexture : public RefCounted<SharedTexture>, public BackingTexture {
    221 public:
    222  MOZ_DECLARE_REFCOUNTED_TYPENAME(SharedTexture)
    223 
    224  SharedTexture(const IntSize& aSize, SurfaceFormat aFormat,
    225                const RefPtr<WebGLTexture>& aTexture);
    226  ~SharedTexture();
    227 
    228  already_AddRefed<SharedTextureHandle> Allocate(const IntSize& aSize);
    229  bool Free(SharedTextureHandle& aHandle);
    230 
    231  bool HasAllocatedHandles() const {
    232    return mAtlasAllocator && Etagere::etagere_atlas_allocator_allocated_space(
    233                                  mAtlasAllocator) > 0;
    234  }
    235 
    236 private:
    237  Etagere::AtlasAllocator* mAtlasAllocator = nullptr;
    238 };
    239 
    240 // SharedTextureHandle is an allocated region within a large SharedTexture page
    241 // that owns it.
    242 class SharedTextureHandle : public TextureHandle {
    243  friend class SharedTexture;
    244 
    245 public:
    246  MOZ_DECLARE_REFCOUNTED_VIRTUAL_TYPENAME(SharedTextureHandle, override)
    247 
    248  SharedTextureHandle(Etagere::AllocationId aId, const IntRect& aBounds,
    249                      SharedTexture* aTexture);
    250 
    251  Type GetType() const override { return Type::SHARED; }
    252 
    253  IntRect GetBounds() const override { return mBounds; }
    254 
    255  SurfaceFormat GetFormat() const override { return mTexture->GetFormat(); }
    256 
    257  BackingTexture* GetBackingTexture() override { return mTexture.get(); }
    258 
    259  void Cleanup(SharedContextWebgl& aContext) override;
    260 
    261  const RefPtr<SharedTexture>& GetOwner() const { return mTexture; }
    262 
    263 private:
    264  Etagere::AllocationId mAllocationId = Etagere::INVALID_ALLOCATION_ID;
    265  IntRect mBounds;
    266  RefPtr<SharedTexture> mTexture;
    267 };
    268 
    269 // StandaloneTexture is a texture that can not be effectively shared within
    270 // a SharedTexture page, such that it is better to assign it its own WebGL
    271 // texture.
    272 class StandaloneTexture : public TextureHandle, public BackingTexture {
    273 public:
    274  MOZ_DECLARE_REFCOUNTED_VIRTUAL_TYPENAME(StandaloneTexture, override)
    275 
    276  StandaloneTexture(const IntSize& aSize, SurfaceFormat aFormat,
    277                    const RefPtr<WebGLTexture>& aTexture);
    278 
    279  Type GetType() const override { return Type::STANDALONE; }
    280 
    281  IntRect GetBounds() const override {
    282    return IntRect(IntPoint(0, 0), BackingTexture::GetSize());
    283  }
    284 
    285  SurfaceFormat GetFormat() const override {
    286    return BackingTexture::GetFormat();
    287  }
    288 
    289  using BackingTexture::UsedBytes;
    290 
    291  BackingTexture* GetBackingTexture() override { return this; }
    292 
    293  void UpdateSize(const IntSize& aSize) override { mSize = aSize; }
    294 
    295  void Cleanup(SharedContextWebgl& aContext) override;
    296 };
    297 
    298 // GlyphCacheEntry stores rendering metadata for a rendered text run, as well
    299 // the handle to the texture it was rendered into, so that it can be located
    300 // for reuse under similar rendering circumstances.
    301 class GlyphCacheEntry : public CacheEntryImpl<GlyphCacheEntry> {
    302 public:
    303  MOZ_DECLARE_REFCOUNTED_VIRTUAL_TYPENAME(GlyphCacheEntry, override)
    304 
    305  GlyphCacheEntry(const GlyphBuffer& aBuffer, const DeviceColor& aColor,
    306                  const Matrix& aTransform, const IntPoint& aQuantizeScale,
    307                  const IntRect& aBounds, const IntRect& aFullBounds,
    308                  HashNumber aHash,
    309                  StoredStrokeOptions* aStrokeOptions = nullptr);
    310  ~GlyphCacheEntry();
    311 
    312  const GlyphBuffer& GetGlyphBuffer() const { return mBuffer; }
    313 
    314  bool MatchesGlyphs(const GlyphBuffer& aBuffer, const DeviceColor& aColor,
    315                     const Matrix& aTransform, const IntPoint& aQuantizeOffset,
    316                     const IntPoint& aBoundsOffset, const IntRect& aClipRect,
    317                     HashNumber aHash, const StrokeOptions* aStrokeOptions);
    318 
    319  static HashNumber HashGlyphs(const GlyphBuffer& aBuffer,
    320                               const Matrix& aTransform,
    321                               const IntPoint& aQuantizeScale);
    322 
    323 private:
    324  // The glyph keys used to render the text run.
    325  GlyphBuffer mBuffer = {nullptr, 0};
    326  // The color of the text run.
    327  DeviceColor mColor;
    328  // The full bounds of the text run without any clipping applied.
    329  IntRect mFullBounds;
    330  // Stroke options for the text run.
    331  UniquePtr<StoredStrokeOptions> mStrokeOptions;
    332 };
    333 
    334 // GlyphCache maintains a list of GlyphCacheEntry's representing previously
    335 // rendered text runs. The cache is searched to see if a given incoming text
    336 // run has already been rendered to a texture, and if so, just reuses it.
    337 // Otherwise, the text run will be rendered to a new texture handle and
    338 // inserted into a new GlyphCacheEntry to represent it.
    339 class GlyphCache : public LinkedListElement<GlyphCache>,
    340                   public CacheImpl<GlyphCacheEntry, false> {
    341 public:
    342  explicit GlyphCache(ScaledFont* aFont);
    343 
    344  ScaledFont* GetFont() const { return mFont; }
    345 
    346  already_AddRefed<GlyphCacheEntry> FindEntry(const GlyphBuffer& aBuffer,
    347                                              const DeviceColor& aColor,
    348                                              const Matrix& aTransform,
    349                                              const IntPoint& aQuantizeScale,
    350                                              const IntRect& aClipRect,
    351                                              HashNumber aHash,
    352                                              const StrokeOptions* aOptions);
    353 
    354  already_AddRefed<GlyphCacheEntry> InsertEntry(
    355      const GlyphBuffer& aBuffer, const DeviceColor& aColor,
    356      const Matrix& aTransform, const IntPoint& aQuantizeScale,
    357      const IntRect& aBounds, const IntRect& aFullBounds, HashNumber aHash,
    358      const StrokeOptions* aOptions);
    359 
    360  bool IsWhitespace(const GlyphBuffer& aBuffer) const;
    361  void SetLastWhitespace(const GlyphBuffer& aBuffer);
    362 
    363 private:
    364  // Weak pointer to the owning font
    365  ScaledFont* mFont;
    366  // The last whitespace queried from this cache
    367  Maybe<uint32_t> mLastWhitespace;
    368 };
    369 
    370 struct QuantizedPath {
    371  explicit QuantizedPath(const WGR::Path& aPath);
    372  // Ensure the path can only be moved, but not copied.
    373  QuantizedPath(QuantizedPath&&) noexcept;
    374  QuantizedPath(const QuantizedPath&) = delete;
    375  ~QuantizedPath();
    376 
    377  bool operator==(const QuantizedPath&) const;
    378 
    379  WGR::Path mPath;
    380 };
    381 
    382 struct PathVertexRange {
    383  uint32_t mOffset;
    384  uint32_t mLength;
    385 
    386  PathVertexRange() : mOffset(0), mLength(0) {}
    387  PathVertexRange(uint32_t aOffset, uint32_t aLength)
    388      : mOffset(aOffset), mLength(aLength) {}
    389 
    390  bool IsValid() const { return mLength > 0; }
    391 };
    392 
    393 enum class AAStrokeMode {
    394  Unsupported,
    395  Geometry,
    396  Mask,
    397 };
    398 
    399 // PathCacheEntry stores a rasterized version of a supplied path with a given
    400 // pattern.
    401 class PathCacheEntry : public CacheEntryImpl<PathCacheEntry> {
    402 public:
    403  MOZ_DECLARE_REFCOUNTED_VIRTUAL_TYPENAME(PathCacheEntry, override)
    404 
    405  PathCacheEntry(QuantizedPath&& aPath, Pattern* aPattern,
    406                 StoredStrokeOptions* aStrokeOptions, AAStrokeMode aStrokeMode,
    407                 const Matrix& aTransform, const IntRect& aBounds,
    408                 const Point& aOrigin, HashNumber aHash, float aSigma = -1.0f);
    409 
    410  bool MatchesPath(const QuantizedPath& aPath, const Pattern* aPattern,
    411                   const StrokeOptions* aStrokeOptions,
    412                   AAStrokeMode aStrokeMode, const Matrix& aTransform,
    413                   const IntRect& aBounds, const Point& aOrigin,
    414                   HashNumber aHash, float aSigma);
    415 
    416  static HashNumber HashPath(const QuantizedPath& aPath,
    417                             const Pattern* aPattern, const Matrix& aTransform,
    418                             const IntRect& aBounds, const Point& aOrigin);
    419 
    420  const QuantizedPath& GetPath() const { return mPath; }
    421 
    422  const Point& GetOrigin() const { return mOrigin; }
    423 
    424  // Valid if either a mask (no pattern) or there is valid pattern.
    425  bool IsValid() const override { return !mPattern || mPattern->IsValid(); }
    426 
    427  const PathVertexRange& GetVertexRange() const { return mVertexRange; }
    428  void SetVertexRange(const PathVertexRange& aRange) { mVertexRange = aRange; }
    429 
    430  const WeakPtr<TextureHandle>& GetSecondaryHandle() const {
    431    return mSecondaryHandle;
    432  }
    433  void SetSecondaryHandle(WeakPtr<TextureHandle> aHandle) {
    434    mSecondaryHandle = std::move(aHandle);
    435  }
    436 
    437 private:
    438  // The actual path geometry supplied
    439  QuantizedPath mPath;
    440  // The transformed origin of the path
    441  Point mOrigin;
    442  // The pattern used to rasterize the path, if not a mask
    443  UniquePtr<Pattern> mPattern;
    444  // The StrokeOptions used for stroked paths, if applicable
    445  UniquePtr<StoredStrokeOptions> mStrokeOptions;
    446  // The AAStroke mode used for rendering a stroked path.
    447  AAStrokeMode mAAStrokeMode = AAStrokeMode::Unsupported;
    448  // The shadow blur sigma
    449  float mSigma;
    450  // If the path has cached geometry in the vertex buffer.
    451  PathVertexRange mVertexRange;
    452  // Secondary texture handle that is not linked and only weakly referenced.
    453  WeakPtr<TextureHandle> mSecondaryHandle;
    454 };
    455 
    456 class PathCache : public CacheImpl<PathCacheEntry, true> {
    457 public:
    458  PathCache() = default;
    459 
    460  already_AddRefed<PathCacheEntry> FindOrInsertEntry(
    461      QuantizedPath aPath, const Pattern* aPattern,
    462      const StrokeOptions* aStrokeOptions, AAStrokeMode aStrokeMode,
    463      const Matrix& aTransform, const IntRect& aBounds, const Point& aOrigin,
    464      float aSigma = -1.0f);
    465 
    466  already_AddRefed<PathCacheEntry> FindEntry(
    467      const QuantizedPath& aPath, const Pattern* aPattern,
    468      const StrokeOptions* aStrokeOptions, AAStrokeMode aStrokeMode,
    469      const Matrix& aTransform, const IntRect& aBounds, const Point& aOrigin,
    470      float aSigma = -1.0f, bool aHasSecondaryHandle = false);
    471 
    472  void ClearVertexRanges();
    473 };
    474 
    475 }  // namespace mozilla::gfx
    476 
    477 #endif  // _MOZILLA_GFX_DRAWTARGETWEBGL_INTERNAL_H