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