184 lines
4.8 KiB
Plaintext

/* DO NOT EDIT THIS FILE */
/* This file is autogenerated by the text-database code generator */
#include <fonts/CompressedFontCache.hpp>
#include <touchgfx/hal/HAL.hpp>
#include <touchgfx/hal/Paint.hpp>
namespace touchgfx
{
LOCATION_PRAGMA_32("TouchGFX_CompressedFontCache")
uint32_t CompressedFontCache::bitmapFontCache[cacheWords] LOCATION_ATTRIBUTE_32("TouchGFX_CompressedFontCache");
uint8_t* CompressedFontCache::pixelsTop = (uint8_t*)CompressedFontCache::bitmapFontCache;
int CompressedFontCache::glyphsAllocated = 0;
int CompressedFontCache::cacheClearCounter = 0;
namespace
{
/* Read nibbles from a compressed data array */
struct NibReader
{
NibReader(const uint8_t* buffer)
: buffer(buffer), byteIndex(0), low(true)
{}
const uint8_t* buffer;
int byteIndex;
bool low;
uint8_t getNext()
{
if (low)
{
const uint8_t val = buffer[byteIndex] & 0xF;
low = false;
return val;
}
const uint8_t val = buffer[byteIndex] >> 4;
low = true;
byteIndex++;
return val;
}
};
struct NibWriter
{
NibWriter(uint8_t* buffer, int size)
: buffer(buffer), bufferEnd(buffer + size), low(true) {}
uint8_t* buffer;
uint8_t* bufferEnd;
int low;
void put(uint8_t v)
{
if (low)
{
*buffer = v;
low = false;
return;
}
*buffer |= (v << 4);
buffer++;
low = true;
}
bool eof() { return buffer >= bufferEnd; }
};
} // anonymous namespace
uint8_t* CompressedFontCache::decompressGlyph(uint8_t* pixelsTop, const GlyphNode* glyphNode, const uint8_t* compressedData)
{
const int byteSize = (glyphNode->width() + 1) / 2 * glyphNode->height();
NibWriter writer(pixelsTop, byteSize);
NibReader reader(compressedData);
uint8_t* const pixelsEnd = pixelsTop + byteSize;
const int algorithm = glyphNode->dataOffset >> 30;
if (algorithm == 1)
{
// RLE1
while (!writer.eof())
{
const uint8_t value = reader.getNext();
if (value == 0)
{
int zeroCount = reader.getNext();
while (zeroCount)
{
writer.put(0);
zeroCount--;
}
}
writer.put(value);
}
}
else if (algorithm == 2)
{
// RLE2
while (!writer.eof())
{
const uint8_t value = reader.getNext();
if (value == 0 || value == 0xF)
{
int count = reader.getNext();
while (count)
{
writer.put(value);
count--;
}
}
writer.put(value);
}
}
else
{
// Uncompressed
while (pixelsTop < pixelsEnd)
{
*pixelsTop++ = *compressedData++;
}
}
return pixelsEnd;
}
void CompressedFontCache::clearCache()
{
// Wait for DMA2D/GPU2D to finish drawing
HAL::getInstance()->lockUnlockFrameBuffer();
glyphsAllocated = 0;
cacheClearCounter++;
pixelsTop = (uint8_t*)bitmapFontCache;
}
void CompressedFontCache::unableToCache(const GlyphNode* glyphNode, int byteSize)
{
while(1);
}
const uint8_t* CompressedFontCache::hasCachedGlyph(const GlyphNode* glyphNode)
{
const BitmapFontCacheKey* end = (const BitmapFontCacheKey*)&bitmapFontCache[cacheWords];
const BitmapFontCacheKey* first = end - glyphsAllocated;
while (first < end)
{
if (first->glyphNode == glyphNode)
{
return first->pixels;
}
first++;
}
return 0;
}
const uint8_t* CompressedFontCache::cacheGlyph(const GlyphNode* glyph, const uint8_t* compressedData)
{
const int byteSize = (glyph->width() + 1) / 2 * glyph->height();
if (byteSize + 8 > cacheSizeBytes)
{
unableToCache(glyph, byteSize);
return 0;
}
const BitmapFontCacheKey* end = (const BitmapFontCacheKey*)&bitmapFontCache[cacheWords];
if (pixelsTop + byteSize + 8 > (const uint8_t*)&end[-glyphsAllocated])
{
// Unable to fit glyph in data, clear cache
clearCache();
}
const uint8_t* glyphData = pixelsTop;
pixelsTop = decompressGlyph(pixelsTop, glyph, compressedData);
// Flush the cache lines, must be 32byte aligned
uint8_t* rowStart = reinterpret_cast<uint8_t*>(reinterpret_cast<uintptr_t>(glyphData) & ~0x1F);
int alignmentOffset = glyphData - rowStart;
paint::flushLine((uint32_t*)rowStart, byteSize + alignmentOffset);
paint::invalidateTextureCache();
glyphsAllocated++;
BitmapFontCacheKey* key = const_cast<BitmapFontCacheKey*>(end - glyphsAllocated);
key->glyphNode = glyph;
key->pixels = glyphData;
return glyphData;
}
} // namespace touchgfx