1
0
Fork 0
mirror of https://github.com/juce-framework/JUCE.git synced 2026-01-24 01:54:22 +00:00

RenderingHelpers: Implement GlyphCache in terms of LruCache

This commit is contained in:
reuk 2024-02-28 13:44:35 +00:00
parent bc654f8007
commit c40da067cd
No known key found for this signature in database
GPG key ID: FCB43929F012EE5C
5 changed files with 43 additions and 129 deletions

View file

@ -35,11 +35,6 @@
namespace juce
{
struct GraphicsFontHelpers
{
static auto compareFont (const Font& a, const Font& b) { return Font::compare (a, b); }
};
static auto operator< (const Font& a, const Font& b)
{
return GraphicsFontHelpers::compareFont (a, b);

View file

@ -40,7 +40,7 @@ class LruCache
{
public:
template <typename Fn>
Value get (Key key, Fn&& fn)
const Value& get (Key key, Fn&& fn)
{
if (const auto iter = map.find (key); iter != map.end())
{

View file

@ -120,7 +120,6 @@
//==============================================================================
#include "fonts/juce_FunctionPointerDestructor.h"
#include "fonts/juce_LruCache.h"
#include "colour/juce_Colour.cpp"
#include "colour/juce_ColourGradient.cpp"

View file

@ -150,6 +150,7 @@ namespace juce
#include "images/juce_Image.h"
#include "images/juce_ScaledImage.h"
#include "colour/juce_FillType.h"
#include "fonts/juce_LruCache.h"
#include "native/juce_RenderingHelpers.h"
#include "contexts/juce_LowLevelGraphicsSoftwareRenderer.h"
#include "contexts/juce_LowLevelGraphicsPostScriptRenderer.h"

View file

@ -32,6 +32,14 @@
==============================================================================
*/
namespace juce
{
struct GraphicsFontHelpers
{
static auto compareFont (const Font& a, const Font& b) { return Font::compare (a, b); }
};
}
namespace juce::RenderingHelpers
{
@ -142,43 +150,6 @@ public:
bool isOnlyTranslated = true, isRotated = false;
};
//==============================================================================
/** Caches a glyph as an edge-table.
@tags{Graphics}
*/
class CachedGlyphEdgeTable : public ReferenceCountedObject
{
public:
CachedGlyphEdgeTable() = default;
template <class RendererType>
void draw (RendererType& state, Point<float> pos) const
{
if (edgeTable != nullptr)
state.fillEdgeTable (*edgeTable, pos.x, roundToInt (pos.y));
}
void generate (const Font& newFont, int glyphNumber)
{
font = newFont;
glyph = glyphNumber;
auto fontHeight = font.getHeight();
auto typeface = newFont.getTypefacePtr();
edgeTable.reset (typeface->getEdgeTableForGlyph (glyphNumber,
AffineTransform::scale (fontHeight * font.getHorizontalScale(),
fontHeight),
fontHeight));
}
Font font;
std::unique_ptr<EdgeTable> edgeTable;
int glyph = 0, lastAccessCount = 0;
JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (CachedGlyphEdgeTable)
};
//==============================================================================
/** Holds a cache of recently-used glyph objects of some type.
@ -187,10 +158,7 @@ public:
class GlyphCache : private DeletedAtShutdown
{
public:
GlyphCache()
{
reset();
}
GlyphCache() = default;
~GlyphCache() override
{
@ -210,98 +178,49 @@ public:
//==============================================================================
void reset()
{
const ScopedLock sl (lock);
glyphs.clear();
addNewGlyphSlots (120);
hits = 0;
misses = 0;
const ScopedLock sl { lock };
cache = {};
}
template <class RenderTargetType>
void drawGlyph (RenderTargetType& target, const Font& font, const int glyphNumber, Point<float> pos)
{
if (auto glyph = findOrCreateGlyph (font, glyphNumber))
const ScopedLock sl { lock };
const auto& table = cache.get (Key { font, glyphNumber }, [] (const auto& key)
{
glyph->lastAccessCount = ++accessCounter;
glyph->draw (target, pos);
}
auto fontHeight = key.font.getHeight();
auto typeface = key.font.getTypefacePtr();
return rawToUniquePtr (typeface->getEdgeTableForGlyph (key.glyph,
AffineTransform::scale (fontHeight * key.font.getHorizontalScale(),
fontHeight),
fontHeight));
});
if (table != nullptr)
target.fillEdgeTable (*table, pos.x, roundToInt (pos.y));
}
private:
ReferenceCountedArray<CachedGlyphEdgeTable> glyphs;
Atomic<int> accessCounter, hits, misses;
struct Key
{
Font font;
int glyph;
bool operator< (const Key& other) const
{
if (glyph < other.glyph)
return true;
if (other.glyph < glyph)
return false;
return GraphicsFontHelpers::compareFont (font, other.font);
}
};
LruCache<Key, std::unique_ptr<EdgeTable>> cache;
CriticalSection lock;
ReferenceCountedObjectPtr<CachedGlyphEdgeTable> findOrCreateGlyph (const Font& font, int glyphNumber)
{
const ScopedLock sl (lock);
if (auto g = findExistingGlyph (font, glyphNumber))
{
++hits;
return g;
}
++misses;
auto g = getGlyphForReuse();
jassert (g != nullptr);
g->generate (font, glyphNumber);
return g;
}
ReferenceCountedObjectPtr<CachedGlyphEdgeTable> findExistingGlyph (const Font& font, int glyphNumber) const noexcept
{
for (auto g : glyphs)
if (g->glyph == glyphNumber && g->font == font)
return *g;
return {};
}
ReferenceCountedObjectPtr<CachedGlyphEdgeTable> getGlyphForReuse()
{
if (hits.get() + misses.get() > glyphs.size() * 16)
{
if (misses.get() * 2 > hits.get())
addNewGlyphSlots (32);
hits = 0;
misses = 0;
}
if (auto g = findLeastRecentlyUsedGlyph())
return *g;
addNewGlyphSlots (32);
return glyphs.getLast();
}
void addNewGlyphSlots (int num)
{
glyphs.ensureStorageAllocated (glyphs.size() + num);
while (--num >= 0)
glyphs.add (new CachedGlyphEdgeTable());
}
CachedGlyphEdgeTable* findLeastRecentlyUsedGlyph() const noexcept
{
CachedGlyphEdgeTable* oldest = nullptr;
auto oldestCounter = std::numeric_limits<int>::max();
for (auto* g : glyphs)
{
if (g->lastAccessCount <= oldestCounter
&& g->getReferenceCount() == 1)
{
oldestCounter = g->lastAccessCount;
oldest = g;
}
}
return oldest;
}
static GlyphCache*& getSingletonPointer() noexcept
{
static GlyphCache* g = nullptr;