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/Etagere.h"
14 #include "mozilla/gfx/PathSkia.h"
15 #include "mozilla/gfx/WPFGpuRaster.h"
17 namespace mozilla::gfx
{
19 // CacheEnty is a generic interface for various items that need to be cached to
21 class CacheEntry
: public RefCounted
<CacheEntry
> {
23 MOZ_DECLARE_REFCOUNTED_VIRTUAL_TYPENAME(CacheEntry
)
25 CacheEntry(const Matrix
& aTransform
, const IntRect
& aBounds
, HashNumber aHash
)
26 : mTransform(aTransform
), mBounds(aBounds
), mHash(aHash
) {}
27 virtual ~CacheEntry() = default;
29 void Link(const RefPtr
<TextureHandle
>& aHandle
);
32 const RefPtr
<TextureHandle
>& GetHandle() const { return mHandle
; }
34 const Matrix
& GetTransform() const { return mTransform
; }
35 const IntRect
& GetBounds() const { return mBounds
; }
36 HashNumber
GetHash() const { return mHash
; }
38 virtual bool IsValid() const { return true; }
41 virtual void RemoveFromList() = 0;
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
50 // The device space bounds of the rendered geometry.
52 // A hash of the geometry that may be used for quickly rejecting entries.
56 // CacheEntryImpl provides type-dependent boilerplate code for implementations
59 class CacheEntryImpl
: public CacheEntry
, public LinkedListElement
<RefPtr
<T
>> {
60 typedef LinkedListElement
<RefPtr
<T
>> ListType
;
63 CacheEntryImpl(const Matrix
& aTransform
, const IntRect
& aBounds
,
65 : CacheEntry(aTransform
, aBounds
, aHash
) {}
67 void RemoveFromList() override
{
68 if (ListType::isInList()) {
74 // CacheImpl manages a list of CacheEntry.
75 template <typename T
, bool BIG
>
78 typedef LinkedList
<RefPtr
<T
>> ListType
;
80 // Whether the cache should be small and space-efficient or prioritize speed.
81 static constexpr size_t kNumChains
= BIG
? 499 : 71;
85 for (auto& chain
: mChains
) {
86 while (RefPtr
<T
> entry
= chain
.popLast()) {
93 ListType
& GetChain(HashNumber aHash
) { return mChains
[aHash
% kNumChains
]; }
95 void Insert(T
* aEntry
) { GetChain(aEntry
->GetHash()).insertFront(aEntry
); }
97 ListType mChains
[kNumChains
];
100 // BackingTexture provides information about the shared or standalone texture
101 // that is backing a texture handle.
102 class BackingTexture
{
104 BackingTexture(const IntSize
& aSize
, SurfaceFormat aFormat
,
105 const RefPtr
<WebGLTexture
>& aTexture
);
107 SurfaceFormat
GetFormat() const { return mFormat
; }
108 IntSize
GetSize() const { return mSize
; }
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
);
115 size_t UsedBytes() const { return UsedBytes(GetFormat(), GetSize()); }
117 const RefPtr
<WebGLTexture
>& GetWebGLTexture() const { return mTexture
; }
119 bool IsInitialized() const { return mFlags
& INITIALIZED
; }
120 void MarkInitialized() { mFlags
|= INITIALIZED
; }
122 bool IsRenderable() const { return mFlags
& RENDERABLE
; }
123 void MarkRenderable() { mFlags
|= RENDERABLE
; }
127 SurfaceFormat mFormat
;
128 RefPtr
<WebGLTexture
> mTexture
;
131 enum Flags
: uint8_t {
132 INITIALIZED
= 1 << 0,
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 LinkedListElement
<RefPtr
<TextureHandle
>> {
146 MOZ_DECLARE_REFCOUNTED_VIRTUAL_TYPENAME(TextureHandle
)
148 enum Type
{ SHARED
, STANDALONE
};
150 virtual Type
GetType() const = 0;
151 virtual IntRect
GetBounds() const = 0;
152 IntSize
GetSize() const { return GetBounds().Size(); }
153 virtual SurfaceFormat
GetFormat() const = 0;
155 virtual BackingTexture
* GetBackingTexture() = 0;
157 size_t UsedBytes() const {
158 return BackingTexture::UsedBytes(GetFormat(), GetSize());
161 virtual void UpdateSize(const IntSize
& aSize
) {}
163 virtual void Cleanup(SharedContextWebgl
& aContext
) {}
165 virtual ~TextureHandle() {}
167 bool IsValid() const { return mValid
; }
168 void Invalidate() { mValid
= false; }
170 void ClearSurface() { mSurface
= nullptr; }
171 void SetSurface(const RefPtr
<SourceSurface
>& aSurface
) {
174 already_AddRefed
<SourceSurface
> GetSurface() const {
175 RefPtr
<SourceSurface
> surface(mSurface
);
176 return surface
.forget();
179 float GetSigma() const { return mSigma
; }
180 void SetSigma(float aSigma
) { mSigma
= aSigma
; }
181 bool IsShadow() const { return mSigma
>= 0.0f
; }
183 void SetSamplingOffset(const IntPoint
& aSamplingOffset
) {
184 mSamplingOffset
= aSamplingOffset
;
186 const IntPoint
& GetSamplingOffset() const { return mSamplingOffset
; }
187 IntRect
GetSamplingRect() const {
188 return IntRect(GetSamplingOffset(), GetSize());
191 const RefPtr
<CacheEntry
>& GetCacheEntry() const { return mCacheEntry
; }
192 void SetCacheEntry(const RefPtr
<CacheEntry
>& aEntry
) { mCacheEntry
= aEntry
; }
194 // Note as used if there is corresponding surface or cache entry.
195 bool IsUsed() const {
196 return !mSurface
.IsDead() || (mCacheEntry
&& mCacheEntry
->IsValid());
201 // If applicable, weak pointer to the SourceSurface that is linked to this
203 ThreadSafeWeakPtr
<SourceSurface
> mSurface
;
204 // If this TextureHandle stores a cached shadow, then we need to remember the
205 // blur sigma used to produce the shadow.
206 float mSigma
= -1.0f
;
207 // If the originating surface requested a sampling rect, then we need to know
208 // the offset of the subrect within the surface for texture coordinates.
209 IntPoint mSamplingOffset
;
210 // If applicable, the CacheEntry that is linked to this TextureHandle.
211 RefPtr
<CacheEntry
> mCacheEntry
;
214 class SharedTextureHandle
;
216 // SharedTexture is a large slab texture that is subdivided (by using a
217 // TexturePacker) to hold many small SharedTextureHandles. This avoids needing
218 // to allocate many WebGL textures for every single small Canvas 2D texture.
219 class SharedTexture
: public RefCounted
<SharedTexture
>, public BackingTexture
{
221 MOZ_DECLARE_REFCOUNTED_TYPENAME(SharedTexture
)
223 SharedTexture(const IntSize
& aSize
, SurfaceFormat aFormat
,
224 const RefPtr
<WebGLTexture
>& aTexture
);
227 already_AddRefed
<SharedTextureHandle
> Allocate(const IntSize
& aSize
);
228 bool Free(SharedTextureHandle
& aHandle
);
230 bool HasAllocatedHandles() const {
231 return mAtlasAllocator
&& Etagere::etagere_atlas_allocator_allocated_space(
232 mAtlasAllocator
) > 0;
236 Etagere::AtlasAllocator
* mAtlasAllocator
= nullptr;
239 // SharedTextureHandle is an allocated region within a large SharedTexture page
241 class SharedTextureHandle
: public TextureHandle
{
242 friend class SharedTexture
;
245 MOZ_DECLARE_REFCOUNTED_VIRTUAL_TYPENAME(SharedTextureHandle
, override
)
247 SharedTextureHandle(Etagere::AllocationId aId
, const IntRect
& aBounds
,
248 SharedTexture
* aTexture
);
250 Type
GetType() const override
{ return Type::SHARED
; }
252 IntRect
GetBounds() const override
{ return mBounds
; }
254 SurfaceFormat
GetFormat() const override
{ return mTexture
->GetFormat(); }
256 BackingTexture
* GetBackingTexture() override
{ return mTexture
.get(); }
258 void Cleanup(SharedContextWebgl
& aContext
) override
;
260 const RefPtr
<SharedTexture
>& GetOwner() const { return mTexture
; }
263 Etagere::AllocationId mAllocationId
= Etagere::INVALID_ALLOCATION_ID
;
265 RefPtr
<SharedTexture
> mTexture
;
268 // StandaloneTexture is a texture that can not be effectively shared within
269 // a SharedTexture page, such that it is better to assign it its own WebGL
271 class StandaloneTexture
: public TextureHandle
, public BackingTexture
{
273 MOZ_DECLARE_REFCOUNTED_VIRTUAL_TYPENAME(StandaloneTexture
, override
)
275 StandaloneTexture(const IntSize
& aSize
, SurfaceFormat aFormat
,
276 const RefPtr
<WebGLTexture
>& aTexture
);
278 Type
GetType() const override
{ return Type::STANDALONE
; }
280 IntRect
GetBounds() const override
{
281 return IntRect(IntPoint(0, 0), BackingTexture::GetSize());
284 SurfaceFormat
GetFormat() const override
{
285 return BackingTexture::GetFormat();
288 using BackingTexture::UsedBytes
;
290 BackingTexture
* GetBackingTexture() override
{ return this; }
292 void UpdateSize(const IntSize
& aSize
) override
{ mSize
= aSize
; }
294 void Cleanup(SharedContextWebgl
& aContext
) override
;
297 // GlyphCacheEntry stores rendering metadata for a rendered text run, as well
298 // the handle to the texture it was rendered into, so that it can be located
299 // for reuse under similar rendering circumstances.
300 class GlyphCacheEntry
: public CacheEntryImpl
<GlyphCacheEntry
> {
302 MOZ_DECLARE_REFCOUNTED_VIRTUAL_TYPENAME(GlyphCacheEntry
, override
)
304 GlyphCacheEntry(const GlyphBuffer
& aBuffer
, const DeviceColor
& aColor
,
305 const Matrix
& aTransform
, const IntPoint
& aQuantizeScale
,
306 const IntRect
& aBounds
, const IntRect
& aFullBounds
,
308 StoredStrokeOptions
* aStrokeOptions
= nullptr);
311 const GlyphBuffer
& GetGlyphBuffer() const { return mBuffer
; }
313 bool MatchesGlyphs(const GlyphBuffer
& aBuffer
, const DeviceColor
& aColor
,
314 const Matrix
& aTransform
, const IntPoint
& aQuantizeOffset
,
315 const IntPoint
& aBoundsOffset
, const IntRect
& aClipRect
,
316 HashNumber aHash
, const StrokeOptions
* aStrokeOptions
);
318 static HashNumber
HashGlyphs(const GlyphBuffer
& aBuffer
,
319 const Matrix
& aTransform
,
320 const IntPoint
& aQuantizeScale
);
323 // The glyph keys used to render the text run.
324 GlyphBuffer mBuffer
= {nullptr, 0};
325 // The color of the text run.
327 // The full bounds of the text run without any clipping applied.
329 // Stroke options for the text run.
330 UniquePtr
<StoredStrokeOptions
> mStrokeOptions
;
333 // GlyphCache maintains a list of GlyphCacheEntry's representing previously
334 // rendered text runs. The cache is searched to see if a given incoming text
335 // run has already been rendered to a texture, and if so, just reuses it.
336 // Otherwise, the text run will be rendered to a new texture handle and
337 // inserted into a new GlyphCacheEntry to represent it.
338 class GlyphCache
: public LinkedListElement
<GlyphCache
>,
339 public CacheImpl
<GlyphCacheEntry
, false> {
341 explicit GlyphCache(ScaledFont
* aFont
);
343 ScaledFont
* GetFont() const { return mFont
; }
345 already_AddRefed
<GlyphCacheEntry
> FindEntry(const GlyphBuffer
& aBuffer
,
346 const DeviceColor
& aColor
,
347 const Matrix
& aTransform
,
348 const IntPoint
& aQuantizeScale
,
349 const IntRect
& aClipRect
,
351 const StrokeOptions
* aOptions
);
353 already_AddRefed
<GlyphCacheEntry
> InsertEntry(
354 const GlyphBuffer
& aBuffer
, const DeviceColor
& aColor
,
355 const Matrix
& aTransform
, const IntPoint
& aQuantizeScale
,
356 const IntRect
& aBounds
, const IntRect
& aFullBounds
, HashNumber aHash
,
357 const StrokeOptions
* aOptions
);
359 bool IsWhitespace(const GlyphBuffer
& aBuffer
) const;
360 void SetLastWhitespace(const GlyphBuffer
& aBuffer
);
363 // Weak pointer to the owning font
365 // The last whitespace queried from this cache
366 Maybe
<uint32_t> mLastWhitespace
;
369 struct QuantizedPath
{
370 explicit QuantizedPath(const WGR::Path
& aPath
);
371 // Ensure the path can only be moved, but not copied.
372 QuantizedPath(QuantizedPath
&&) noexcept
;
373 QuantizedPath(const QuantizedPath
&) = delete;
376 bool operator==(const QuantizedPath
&) const;
381 struct PathVertexRange
{
385 PathVertexRange() : mOffset(0), mLength(0) {}
386 PathVertexRange(uint32_t aOffset
, uint32_t aLength
)
387 : mOffset(aOffset
), mLength(aLength
) {}
389 bool IsValid() const { return mLength
> 0; }
392 enum class AAStrokeMode
{
398 // PathCacheEntry stores a rasterized version of a supplied path with a given
400 class PathCacheEntry
: public CacheEntryImpl
<PathCacheEntry
> {
402 MOZ_DECLARE_REFCOUNTED_VIRTUAL_TYPENAME(PathCacheEntry
, override
)
404 PathCacheEntry(QuantizedPath
&& aPath
, Pattern
* aPattern
,
405 StoredStrokeOptions
* aStrokeOptions
, AAStrokeMode aStrokeMode
,
406 const Matrix
& aTransform
, const IntRect
& aBounds
,
407 const Point
& aOrigin
, HashNumber aHash
, float aSigma
= -1.0f
);
409 bool MatchesPath(const QuantizedPath
& aPath
, const Pattern
* aPattern
,
410 const StrokeOptions
* aStrokeOptions
,
411 AAStrokeMode aStrokeMode
, const Matrix
& aTransform
,
412 const IntRect
& aBounds
, const Point
& aOrigin
,
413 HashNumber aHash
, float aSigma
);
415 static HashNumber
HashPath(const QuantizedPath
& aPath
,
416 const Pattern
* aPattern
, const Matrix
& aTransform
,
417 const IntRect
& aBounds
, const Point
& aOrigin
);
419 const QuantizedPath
& GetPath() const { return mPath
; }
421 const Point
& GetOrigin() const { return mOrigin
; }
423 // Valid if either a mask (no pattern) or there is valid pattern.
424 bool IsValid() const override
{ return !mPattern
|| mPattern
->IsValid(); }
426 const PathVertexRange
& GetVertexRange() const { return mVertexRange
; }
427 void SetVertexRange(const PathVertexRange
& aRange
) { mVertexRange
= aRange
; }
430 // The actual path geometry supplied
432 // The transformed origin of the path
434 // The pattern used to rasterize the path, if not a mask
435 UniquePtr
<Pattern
> mPattern
;
436 // The StrokeOptions used for stroked paths, if applicable
437 UniquePtr
<StoredStrokeOptions
> mStrokeOptions
;
438 // The AAStroke mode used for rendering a stroked path.
439 AAStrokeMode mAAStrokeMode
= AAStrokeMode::Unsupported
;
440 // The shadow blur sigma
442 // If the path has cached geometry in the vertex buffer.
443 PathVertexRange mVertexRange
;
446 class PathCache
: public CacheImpl
<PathCacheEntry
, true> {
448 PathCache() = default;
450 already_AddRefed
<PathCacheEntry
> FindOrInsertEntry(
451 QuantizedPath aPath
, const Pattern
* aPattern
,
452 const StrokeOptions
* aStrokeOptions
, AAStrokeMode aStrokeMode
,
453 const Matrix
& aTransform
, const IntRect
& aBounds
, const Point
& aOrigin
,
454 float aSigma
= -1.0f
);
456 void ClearVertexRanges();
459 } // namespace mozilla::gfx
461 #endif // _MOZILLA_GFX_DRAWTARGETWEBGL_INTERNAL_H