cache

package
v0.0.9 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Dec 6, 2024 License: MIT Imports: 7 Imported by: 2

Documentation

Overview

The cache subpackage defines the GlyphCacheHandler interface used within etxt and provides a default cache implementation.

Since glyph rasterization is an expensive CPU process, caches are a vital part of any real-time text rendering pipeline.

As far as practical advice goes, "how to determine the size of my cache" would be the main topic of discussion. Sadly, there's no good rule of thumb to say "set your cache size to half its peak memory usage" or similar. Cache sizes really depend on your use-case: sometimes you have only a couple fonts at a few fixed sizes and you want your cache to fit everything. Sometimes you determine your font sizes based on the current screen size and can absolutely not pretend to cache all the masks that the renderers may generate. The DefaultCache.PeakSize() function is a good tool to assist you, but you will have to figure out your requirements by yourself. Of course, you can also just use Renderer.Utils().SetCache8MiB() and see how far does that get you.

To give a more concrete size reference, though, let's assume a normal or small reading font size, where each glyph mask is around 11x11 on average (many glyphs don't have ascenders or descenders). That's about 676 bytes per mask on Ebitengine. Then say we will have around 64 different glyphs (there may only be 26 letters in english, but we also need to account for uppercase, numbers, punctuation, variants with diacritic marks, etc.). We would already be around 42KiB of data. If you account for a couple different fonts being used in an app, bigger sizes and maybe variants with italics or bold, you get closer to be working with MiBs of data, not KiBs. If you also disable full quantization, each glyph mask will need to be rendered for different subpixel positions. This can range from anywhere between x2 to x64 memory usage in most common scenarios.

The summary would be that anything below 64KiB of cache is almost sure to fall short in many scenarios, with a few MiBs of capacity probably being a much better ballpark estimate for what many games and applications will end up using on their UI screens.

Index

Constants

This section is empty.

Variables

This section is empty.

Functions

func GlyphMaskByteSize

func GlyphMaskByteSize(mask GlyphMask) uint32

Returns an approximation of a GlyphMask size in bytes.

With Ebitengine, the exact amount of mipmaps and helper fields is not known, so the values may not be completely accurate, and should be treated as a lower bound. With gtxt, the returned values are exact.

Types

type DefaultCache

type DefaultCache struct {
	// contains filtered or unexported fields
}

The default etxt cache. It is concurrent-safe (though not optimized or expected to be used under heavily concurrent scenarios), it has memory bounds and uses random sampling for evicting entries.

func NewDefaultCache

func NewDefaultCache(capacityInBytes int) *DefaultCache

Creates a new cache bounded by the given capacity. Negative values will panic.

Values below 32*1024 (32KiB) are not recommended; allowing the cache to grow up to a few MiBs in size is generally preferable. For more concrete size estimations, the package overview includes a more detailed explanation.

func (*DefaultCache) Capacity

func (self *DefaultCache) Capacity() int

Returns the capacity of the cache, in bytes.

func (*DefaultCache) CurrentSize

func (self *DefaultCache) CurrentSize() int

Returns an approximation of the number of bytes taken by the glyph masks currently stored in the cache.

func (*DefaultCache) GetMask

func (self *DefaultCache) GetMask(key [3]uint64) (GlyphMask, bool)

Gets the mask associated to the given key.

func (*DefaultCache) NewHandler

func (self *DefaultCache) NewHandler() *DefaultCacheHandler

Returns a new cache handler for the current cache. While DefaultCache is concurrent-safe, handlers can only be used non-concurrently. One can create multiple handlers for the same cache to be used with different renderers.

func (*DefaultCache) NumEntries

func (self *DefaultCache) NumEntries() int

Returns the number of cached masks currently in the cache.

func (*DefaultCache) PassMask

func (self *DefaultCache) PassMask(key [3]uint64, mask GlyphMask)

Stores the given mask with the given key.

func (*DefaultCache) PeakSize

func (self *DefaultCache) PeakSize() int

Returns an approximation of the maximum amount of bytes that the cache has been filled with throughout its life.

This method can be useful to determine the actual usage of a cache within your application and set its capacity to a reasonable value.

type DefaultCacheHandler

type DefaultCacheHandler struct {
	// contains filtered or unexported fields
}

A default implementation of GlyphCacheHandler.

func (*DefaultCacheHandler) Cache

func (self *DefaultCacheHandler) Cache() *DefaultCache

Provides access to the underlying DefaultCache.

func (*DefaultCacheHandler) GetMask

func (self *DefaultCacheHandler) GetMask(index sfnt.GlyphIndex) (GlyphMask, bool)

Implements GlyphCacheHandler.GetMask(...)

func (*DefaultCacheHandler) NotifyFontChange

func (self *DefaultCacheHandler) NotifyFontChange(font *sfnt.Font)

Implements GlyphCacheHandler.NotifyFontChange(...)

func (*DefaultCacheHandler) NotifyFractChange

func (self *DefaultCacheHandler) NotifyFractChange(fract fract.Point)

Implements GlyphCacheHandler.NotifyFractChange(...)

func (*DefaultCacheHandler) NotifyRasterizerChange

func (self *DefaultCacheHandler) NotifyRasterizerChange(rasterizer mask.Rasterizer)

Implements GlyphCacheHandler.NotifyRasterizerChange(...)

func (*DefaultCacheHandler) NotifySizeChange

func (self *DefaultCacheHandler) NotifySizeChange(size fract.Unit)

Implements GlyphCacheHandler.NotifySizeChange(...)

func (*DefaultCacheHandler) PassMask

func (self *DefaultCacheHandler) PassMask(index sfnt.GlyphIndex, mask GlyphMask)

Implements GlyphCacheHandler.PassMask(...)

type GlyphCacheHandler

type GlyphCacheHandler interface {

	// Notifies that the font in use has changed.
	NotifyFontChange(*sfnt.Font)

	// Notifies that the text size (in pixels) has changed.
	NotifySizeChange(fract.Unit)

	// Notifies that the rasterizer has changed. Typically, the
	// rasterizer's CacheSignature() will be used to tell them apart.
	NotifyRasterizerChange(mask.Rasterizer) // called on config changes too

	// Notifies that the fractional drawing position has changed.
	// Only the 6 bits corresponding to the non-integer part of each
	// coordinate are considered.
	NotifyFractChange(fract.Point)

	// Gets the mask image for the given glyph index and current configuration.
	// The bool indicates whether the mask has been found (as it may be nil).
	GetMask(sfnt.GlyphIndex) (GlyphMask, bool)

	// Passes a mask image for the given glyph index and current
	// configuration to the underlying cache. PassMask should only
	// be called after GetMask() fails.
	//
	// Given a specific configuration, the contents of the mask image
	// must always be consistent. This implies that passed masks may be
	// ignored if a mask is already cached under that configuration, as
	// it will be considered superfluous. In other words: passing different
	// masks for the same configuration may cause inconsistent results.
	PassMask(sfnt.GlyphIndex, GlyphMask)
}

A GlyphCacheHandler acts as an intermediator between a glyph cache and another object, typically a Renderer, to give the later a clear target interface to conform to while abstracting the details of an underlying cache, which might be finickier to deal with directly in a performant way.

Glyph cache handlers can't be used concurrently unless the concrete implementation explicitly says otherwise.

type GlyphMask

type GlyphMask = *ebiten.Image

Same as etxt.GlyphMask, redefined locally for improved clarity and consistency with the etxt parent package when defining caches and the GlyphCacheHandler interface.

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL