no bug - Bumping Firefox l10n changesets r=release a=l10n-bump DONTBUILD CLOSED TREE
[gecko.git] / dom / canvas / DrawTargetWebglInternal.h
blob69d89ed72e5fe361e34ccc42b153bfe24fa34feb
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/. */
7 #ifndef _MOZILLA_GFX_DRAWTARGETWEBGL_INTERNAL_H
8 #define _MOZILLA_GFX_DRAWTARGETWEBGL_INTERNAL_H
10 #include "DrawTargetWebgl.h"
12 #include "mozilla/HashFunctions.h"
13 #include "mozilla/gfx/PathSkia.h"
14 #include "mozilla/gfx/WPFGpuRaster.h"
16 namespace mozilla::gfx {
18 // TexturePacker implements a bin-packing algorithm for 2D rectangles. It uses
19 // a binary tree that partitions the space of a node at a given split. This
20 // produces two children, one on either side of the split. This subdivision
21 // proceeds recursively as necessary.
22 class TexturePacker {
23 public:
24 explicit TexturePacker(const IntRect& aBounds, bool aAvailable = true)
25 : mBounds(aBounds),
26 mAvailable(aAvailable ? std::min(aBounds.width, aBounds.height) : 0) {}
28 Maybe<IntPoint> Insert(const IntSize& aSize);
30 bool Remove(const IntRect& aBounds);
32 const IntRect& GetBounds() const { return mBounds; }
34 private:
35 bool IsLeaf() const { return !mChildren; }
36 bool IsFullyAvailable() const { return IsLeaf() && mAvailable > 0; }
38 void DiscardChildren() { mChildren.reset(); }
40 // If applicable, the two children produced by picking a single axis split
41 // within the node's bounds and subdividing the bounds there.
42 UniquePtr<TexturePacker[]> mChildren;
43 // The bounds enclosing this node and any children within it.
44 IntRect mBounds;
45 // For a leaf node, specifies the size of the smallest dimension available to
46 // allocate. For a branch node, specifies largest potential available size of
47 // all children. This can be used during the allocation process to rapidly
48 // reject certain sub-trees without having to search all the way to a leaf
49 // node if we know that largest available size within the sub-tree wouldn't
50 // fit the requested size.
51 int mAvailable = 0;
54 // CacheEnty is a generic interface for various items that need to be cached to
55 // a texture.
56 class CacheEntry : public RefCounted<CacheEntry> {
57 public:
58 MOZ_DECLARE_REFCOUNTED_VIRTUAL_TYPENAME(CacheEntry)
60 CacheEntry(const Matrix& aTransform, const IntRect& aBounds, HashNumber aHash)
61 : mTransform(aTransform), mBounds(aBounds), mHash(aHash) {}
62 virtual ~CacheEntry() = default;
64 void Link(const RefPtr<TextureHandle>& aHandle);
65 void Unlink();
67 const RefPtr<TextureHandle>& GetHandle() const { return mHandle; }
69 const Matrix& GetTransform() const { return mTransform; }
70 const IntRect& GetBounds() const { return mBounds; }
71 HashNumber GetHash() const { return mHash; }
73 virtual bool IsValid() const { return true; }
75 protected:
76 virtual void RemoveFromList() = 0;
78 // The handle of the rendered cache item.
79 RefPtr<TextureHandle> mHandle;
80 // The transform that was used to render the entry. This is necessary as
81 // the geometry might only be correctly rendered in device space after
82 // the transform is applied, so in general we can't cache untransformed
83 // geometry.
84 Matrix mTransform;
85 // The device space bounds of the rendered geometry.
86 IntRect mBounds;
87 // A hash of the geometry that may be used for quickly rejecting entries.
88 HashNumber mHash;
91 // CacheEntryImpl provides type-dependent boilerplate code for implementations
92 // of CacheEntry.
93 template <typename T>
94 class CacheEntryImpl : public CacheEntry, public LinkedListElement<RefPtr<T>> {
95 typedef LinkedListElement<RefPtr<T>> ListType;
97 public:
98 CacheEntryImpl(const Matrix& aTransform, const IntRect& aBounds,
99 HashNumber aHash)
100 : CacheEntry(aTransform, aBounds, aHash) {}
102 void RemoveFromList() override {
103 if (ListType::isInList()) {
104 ListType::remove();
109 // CacheImpl manages a list of CacheEntry.
110 template <typename T, bool BIG>
111 class CacheImpl {
112 protected:
113 typedef LinkedList<RefPtr<T>> ListType;
115 // Whether the cache should be small and space-efficient or prioritize speed.
116 static constexpr size_t kNumChains = BIG ? 499 : 17;
118 public:
119 ~CacheImpl() {
120 for (auto& chain : mChains) {
121 while (RefPtr<T> entry = chain.popLast()) {
122 entry->Unlink();
127 protected:
128 ListType& GetChain(HashNumber aHash) { return mChains[aHash % kNumChains]; }
130 void Insert(T* aEntry) { GetChain(aEntry->GetHash()).insertFront(aEntry); }
132 ListType mChains[kNumChains];
135 // BackingTexture provides information about the shared or standalone texture
136 // that is backing a texture handle.
137 class BackingTexture {
138 public:
139 BackingTexture(const IntSize& aSize, SurfaceFormat aFormat,
140 const RefPtr<WebGLTextureJS>& aTexture);
142 SurfaceFormat GetFormat() const { return mFormat; }
143 IntSize GetSize() const { return mSize; }
145 static inline size_t UsedBytes(SurfaceFormat aFormat, const IntSize& aSize) {
146 return size_t(BytesPerPixel(aFormat)) * size_t(aSize.width) *
147 size_t(aSize.height);
150 size_t UsedBytes() const { return UsedBytes(GetFormat(), GetSize()); }
152 const RefPtr<WebGLTextureJS>& GetWebGLTexture() const { return mTexture; }
154 bool IsInitialized() const { return mFlags & INITIALIZED; }
155 void MarkInitialized() { mFlags |= INITIALIZED; }
157 bool IsRenderable() const { return mFlags & RENDERABLE; }
158 void MarkRenderable() { mFlags |= RENDERABLE; }
160 protected:
161 IntSize mSize;
162 SurfaceFormat mFormat;
163 RefPtr<WebGLTextureJS> mTexture;
165 private:
166 enum Flags : uint8_t {
167 INITIALIZED = 1 << 0,
168 RENDERABLE = 1 << 1,
171 uint8_t mFlags = 0;
174 // TextureHandle is an abstract base class for supplying textures to drawing
175 // commands that may be backed by different resource types (such as a shared
176 // or standalone texture). It may be further linked to use-specific metadata
177 // such as for shadow drawing or for cached entries in the glyph cache.
178 class TextureHandle : public RefCounted<TextureHandle>,
179 public LinkedListElement<RefPtr<TextureHandle>> {
180 public:
181 MOZ_DECLARE_REFCOUNTED_VIRTUAL_TYPENAME(TextureHandle)
183 enum Type { SHARED, STANDALONE };
185 virtual Type GetType() const = 0;
186 virtual IntRect GetBounds() const = 0;
187 IntSize GetSize() const { return GetBounds().Size(); }
188 virtual SurfaceFormat GetFormat() const = 0;
190 virtual BackingTexture* GetBackingTexture() = 0;
192 size_t UsedBytes() const {
193 return BackingTexture::UsedBytes(GetFormat(), GetSize());
196 virtual void UpdateSize(const IntSize& aSize) {}
198 virtual void Cleanup(DrawTargetWebgl::SharedContext& aContext) {}
200 virtual ~TextureHandle() {}
202 bool IsValid() const { return mValid; }
203 void Invalidate() { mValid = false; }
205 void SetSurface(SourceSurface* aSurface) { mSurface = aSurface; }
206 SourceSurface* GetSurface() const { return mSurface; }
208 float GetSigma() const { return mSigma; }
209 void SetSigma(float aSigma) { mSigma = aSigma; }
210 bool IsShadow() const { return mSigma >= 0.0f; }
212 void SetSamplingOffset(const IntPoint& aSamplingOffset) {
213 mSamplingOffset = aSamplingOffset;
215 const IntPoint& GetSamplingOffset() const { return mSamplingOffset; }
216 IntRect GetSamplingRect() const {
217 return IntRect(GetSamplingOffset(), GetSize());
220 const RefPtr<CacheEntry>& GetCacheEntry() const { return mCacheEntry; }
221 void SetCacheEntry(const RefPtr<CacheEntry>& aEntry) { mCacheEntry = aEntry; }
223 // Note as used if there is corresponding surface or cache entry.
224 bool IsUsed() const {
225 return mSurface || (mCacheEntry && mCacheEntry->IsValid());
228 private:
229 bool mValid = true;
230 // If applicable, weak pointer to the SourceSurface that is linked to this
231 // TextureHandle.
232 SourceSurface* mSurface = nullptr;
233 // If this TextureHandle stores a cached shadow, then we need to remember the
234 // blur sigma used to produce the shadow.
235 float mSigma = -1.0f;
236 // If the originating surface requested a sampling rect, then we need to know
237 // the offset of the subrect within the surface for texture coordinates.
238 IntPoint mSamplingOffset;
239 // If applicable, the CacheEntry that is linked to this TextureHandle.
240 RefPtr<CacheEntry> mCacheEntry;
243 class SharedTextureHandle;
245 // SharedTexture is a large slab texture that is subdivided (by using a
246 // TexturePacker) to hold many small SharedTextureHandles. This avoids needing
247 // to allocate many WebGL textures for every single small Canvas 2D texture.
248 class SharedTexture : public RefCounted<SharedTexture>, public BackingTexture {
249 public:
250 MOZ_DECLARE_REFCOUNTED_TYPENAME(SharedTexture)
252 SharedTexture(const IntSize& aSize, SurfaceFormat aFormat,
253 const RefPtr<WebGLTextureJS>& aTexture);
255 already_AddRefed<SharedTextureHandle> Allocate(const IntSize& aSize);
256 bool Free(const SharedTextureHandle& aHandle);
258 bool HasAllocatedHandles() const { return mAllocatedHandles > 0; }
260 private:
261 TexturePacker mPacker;
262 size_t mAllocatedHandles = 0;
265 // SharedTextureHandle is an allocated region within a large SharedTexture page
266 // that owns it.
267 class SharedTextureHandle : public TextureHandle {
268 friend class SharedTexture;
270 public:
271 MOZ_DECLARE_REFCOUNTED_VIRTUAL_TYPENAME(SharedTextureHandle, override)
273 SharedTextureHandle(const IntRect& aBounds, SharedTexture* aTexture);
275 Type GetType() const override { return Type::SHARED; }
277 IntRect GetBounds() const override { return mBounds; }
279 SurfaceFormat GetFormat() const override { return mTexture->GetFormat(); }
281 BackingTexture* GetBackingTexture() override { return mTexture.get(); }
283 void Cleanup(DrawTargetWebgl::SharedContext& aContext) override;
285 const RefPtr<SharedTexture>& GetOwner() const { return mTexture; }
287 private:
288 IntRect mBounds;
289 RefPtr<SharedTexture> mTexture;
292 // StandaloneTexture is a texture that can not be effectively shared within
293 // a SharedTexture page, such that it is better to assign it its own WebGL
294 // texture.
295 class StandaloneTexture : public TextureHandle, public BackingTexture {
296 public:
297 MOZ_DECLARE_REFCOUNTED_VIRTUAL_TYPENAME(StandaloneTexture, override)
299 StandaloneTexture(const IntSize& aSize, SurfaceFormat aFormat,
300 const RefPtr<WebGLTextureJS>& aTexture);
302 Type GetType() const override { return Type::STANDALONE; }
304 IntRect GetBounds() const override {
305 return IntRect(IntPoint(0, 0), BackingTexture::GetSize());
308 SurfaceFormat GetFormat() const override {
309 return BackingTexture::GetFormat();
312 using BackingTexture::UsedBytes;
314 BackingTexture* GetBackingTexture() override { return this; }
316 void UpdateSize(const IntSize& aSize) override { mSize = aSize; }
318 void Cleanup(DrawTargetWebgl::SharedContext& aContext) override;
321 // GlyphCacheEntry stores rendering metadata for a rendered text run, as well
322 // the handle to the texture it was rendered into, so that it can be located
323 // for reuse under similar rendering circumstances.
324 class GlyphCacheEntry : public CacheEntryImpl<GlyphCacheEntry> {
325 public:
326 MOZ_DECLARE_REFCOUNTED_VIRTUAL_TYPENAME(GlyphCacheEntry, override)
328 GlyphCacheEntry(const GlyphBuffer& aBuffer, const DeviceColor& aColor,
329 const Matrix& aTransform, const IntPoint& aQuantizeScale,
330 const IntRect& aBounds, const IntRect& aFullBounds,
331 HashNumber aHash,
332 StoredStrokeOptions* aStrokeOptions = nullptr);
333 ~GlyphCacheEntry();
335 const GlyphBuffer& GetGlyphBuffer() const { return mBuffer; }
337 bool MatchesGlyphs(const GlyphBuffer& aBuffer, const DeviceColor& aColor,
338 const Matrix& aTransform, const IntPoint& aQuantizeOffset,
339 const IntPoint& aBoundsOffset, const IntRect& aClipRect,
340 HashNumber aHash, const StrokeOptions* aStrokeOptions);
342 static HashNumber HashGlyphs(const GlyphBuffer& aBuffer,
343 const Matrix& aTransform,
344 const IntPoint& aQuantizeScale);
346 private:
347 // The glyph keys used to render the text run.
348 GlyphBuffer mBuffer = {nullptr, 0};
349 // The color of the text run.
350 DeviceColor mColor;
351 // The full bounds of the text run without any clipping applied.
352 IntRect mFullBounds;
353 // Stroke options for the text run.
354 UniquePtr<StoredStrokeOptions> mStrokeOptions;
357 // GlyphCache maintains a list of GlyphCacheEntry's representing previously
358 // rendered text runs. The cache is searched to see if a given incoming text
359 // run has already been rendered to a texture, and if so, just reuses it.
360 // Otherwise, the text run will be rendered to a new texture handle and
361 // inserted into a new GlyphCacheEntry to represent it.
362 class GlyphCache : public LinkedListElement<GlyphCache>,
363 public CacheImpl<GlyphCacheEntry, false> {
364 public:
365 explicit GlyphCache(ScaledFont* aFont);
367 ScaledFont* GetFont() const { return mFont; }
369 already_AddRefed<GlyphCacheEntry> FindEntry(const GlyphBuffer& aBuffer,
370 const DeviceColor& aColor,
371 const Matrix& aTransform,
372 const IntPoint& aQuantizeScale,
373 const IntRect& aClipRect,
374 HashNumber aHash,
375 const StrokeOptions* aOptions);
377 already_AddRefed<GlyphCacheEntry> InsertEntry(
378 const GlyphBuffer& aBuffer, const DeviceColor& aColor,
379 const Matrix& aTransform, const IntPoint& aQuantizeScale,
380 const IntRect& aBounds, const IntRect& aFullBounds, HashNumber aHash,
381 const StrokeOptions* aOptions);
383 private:
384 // Weak pointer to the owning font
385 ScaledFont* mFont;
388 struct QuantizedPath {
389 explicit QuantizedPath(const WGR::Path& aPath);
390 // Ensure the path can only be moved, but not copied.
391 QuantizedPath(QuantizedPath&&) noexcept;
392 QuantizedPath(const QuantizedPath&) = delete;
393 ~QuantizedPath();
395 bool operator==(const QuantizedPath&) const;
397 WGR::Path mPath;
400 struct PathVertexRange {
401 uint32_t mOffset;
402 uint32_t mLength;
404 PathVertexRange() : mOffset(0), mLength(0) {}
405 PathVertexRange(uint32_t aOffset, uint32_t aLength)
406 : mOffset(aOffset), mLength(aLength) {}
408 bool IsValid() const { return mLength > 0; }
411 // PathCacheEntry stores a rasterized version of a supplied path with a given
412 // pattern.
413 class PathCacheEntry : public CacheEntryImpl<PathCacheEntry> {
414 public:
415 MOZ_DECLARE_REFCOUNTED_VIRTUAL_TYPENAME(PathCacheEntry, override)
417 PathCacheEntry(QuantizedPath&& aPath, Pattern* aPattern,
418 StoredStrokeOptions* aStrokeOptions, const Matrix& aTransform,
419 const IntRect& aBounds, const Point& aOrigin, HashNumber aHash,
420 float aSigma = -1.0f);
422 bool MatchesPath(const QuantizedPath& aPath, const Pattern* aPattern,
423 const StrokeOptions* aStrokeOptions,
424 const Matrix& aTransform, const IntRect& aBounds,
425 const Point& aOrigin, HashNumber aHash, float aSigma);
427 static HashNumber HashPath(const QuantizedPath& aPath,
428 const Pattern* aPattern, const Matrix& aTransform,
429 const IntRect& aBounds, const Point& aOrigin);
431 const QuantizedPath& GetPath() const { return mPath; }
433 const Point& GetOrigin() const { return mOrigin; }
435 // Valid if either a mask (no pattern) or there is valid pattern.
436 bool IsValid() const override { return !mPattern || mPattern->IsValid(); }
438 const PathVertexRange& GetVertexRange() const { return mVertexRange; }
439 void SetVertexRange(const PathVertexRange& aRange) { mVertexRange = aRange; }
441 private:
442 // The actual path geometry supplied
443 QuantizedPath mPath;
444 // The transformed origin of the path
445 Point mOrigin;
446 // The pattern used to rasterize the path, if not a mask
447 UniquePtr<Pattern> mPattern;
448 // The StrokeOptions used for stroked paths, if applicable
449 UniquePtr<StoredStrokeOptions> mStrokeOptions;
450 // The shadow blur sigma
451 float mSigma;
452 // If the path has cached geometry in the vertex buffer.
453 PathVertexRange mVertexRange;
456 class PathCache : public CacheImpl<PathCacheEntry, true> {
457 public:
458 PathCache() = default;
460 already_AddRefed<PathCacheEntry> FindOrInsertEntry(
461 QuantizedPath aPath, const Pattern* aPattern,
462 const StrokeOptions* aStrokeOptions, const Matrix& aTransform,
463 const IntRect& aBounds, const Point& aOrigin, float aSigma = -1.0f);
465 void ClearVertexRanges();
468 } // namespace mozilla::gfx
470 #endif // _MOZILLA_GFX_DRAWTARGETWEBGL_INTERNAL_H