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:
parent
bc654f8007
commit
c40da067cd
5 changed files with 43 additions and 129 deletions
|
|
@ -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);
|
||||
|
|
|
|||
|
|
@ -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())
|
||||
{
|
||||
|
|
|
|||
|
|
@ -120,7 +120,6 @@
|
|||
|
||||
//==============================================================================
|
||||
#include "fonts/juce_FunctionPointerDestructor.h"
|
||||
#include "fonts/juce_LruCache.h"
|
||||
|
||||
#include "colour/juce_Colour.cpp"
|
||||
#include "colour/juce_ColourGradient.cpp"
|
||||
|
|
|
|||
|
|
@ -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"
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue