264 lines
7.4 KiB
Plaintext
264 lines
7.4 KiB
Plaintext
/* DO NOT EDIT THIS FILE */
|
|
/* This file is autogenerated by the text-database code generator */
|
|
|
|
#include <fonts/CompressedUnmappedFontCache.hpp>
|
|
#include <touchgfx/hal/HAL.hpp>
|
|
#include <touchgfx/hal/Paint.hpp>
|
|
|
|
namespace touchgfx
|
|
{
|
|
LOCATION_PRAGMA_32("TouchGFX_CompressedUnmappedFontCache")
|
|
uint32_t CompressedUnmappedFontCache::bitmapFontCache[cacheWords] LOCATION_ATTRIBUTE_32("TouchGFX_CompressedUnmappedFontCache");
|
|
uint8_t* CompressedUnmappedFontCache::pixelsTop = (uint8_t*)CompressedUnmappedFontCache::bitmapFontCache;
|
|
int CompressedUnmappedFontCache::glyphsAllocated = 0;
|
|
int CompressedUnmappedFontCache::cacheClearCounter = 0;
|
|
|
|
namespace
|
|
{
|
|
/* Read nibbles from compressed data in unmapped flash. Must read through reader object */
|
|
struct NibUnmapReader
|
|
{
|
|
NibUnmapReader(const uint8_t* srcAddress, touchgfx::FlashDataReader* reader)
|
|
: address(srcAddress), reader(reader), byteIndex(0), low(true)
|
|
{
|
|
address += bufferSize;
|
|
reader->copyData(srcAddress, buffer, sizeof(buffer));
|
|
}
|
|
|
|
const uint8_t* address; //next reading address
|
|
touchgfx::FlashDataReader* reader;
|
|
static const int bufferSize = 16;
|
|
uint8_t buffer[bufferSize];
|
|
uint8_t value;
|
|
int byteIndex;
|
|
bool low;
|
|
uint8_t getNext()
|
|
{
|
|
if (low)
|
|
{
|
|
value = buffer[byteIndex];
|
|
const uint8_t val = value & 0xF;
|
|
low = false;
|
|
return val;
|
|
}
|
|
const uint8_t val = value >> 4;
|
|
low = true;
|
|
if (byteIndex == bufferSize - 1)
|
|
{
|
|
reader->copyData(address, buffer, bufferSize);
|
|
address += bufferSize;
|
|
byteIndex = 0;
|
|
}
|
|
else
|
|
{
|
|
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* CompressedUnmappedFontCache::decompressGlyph(uint8_t* pixelsTop, const GlyphNode* glyphNode, const uint8_t* compressedData, touchgfx::FlashDataReader* flashReader)
|
|
{
|
|
const int byteSize = (glyphNode->width() + 1) / 2 * glyphNode->height();
|
|
NibWriter writer(pixelsTop, byteSize);
|
|
NibUnmapReader reader(compressedData, flashReader);
|
|
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
|
|
flashReader->copyData(compressedData, pixelsTop, byteSize);
|
|
}
|
|
|
|
return pixelsEnd;
|
|
}
|
|
|
|
void CompressedUnmappedFontCache::clearCache()
|
|
{
|
|
// Wait for DMA2D/GPU2D to finish drawing
|
|
HAL::getInstance()->lockUnlockFrameBuffer();
|
|
glyphsAllocated = 0;
|
|
cacheClearCounter++;
|
|
pixelsTop = (uint8_t*)bitmapFontCache;
|
|
}
|
|
|
|
void CompressedUnmappedFontCache::unableToCache(const GlyphNode* glyphNode, int byteSize)
|
|
{
|
|
while(1);
|
|
}
|
|
|
|
const GlyphNode* CompressedUnmappedFontCache::hasCachedGlyphNode(const GlyphNode* glyphNode)
|
|
{
|
|
const BitmapFontCacheKey* end = (const BitmapFontCacheKey*)&bitmapFontCache[cacheWords];
|
|
const BitmapFontCacheKey* first = end - glyphsAllocated;
|
|
while (first < end)
|
|
{
|
|
if (first->glyphNodeSrc == glyphNode)
|
|
{
|
|
return &first->glyphNodeCopy;
|
|
}
|
|
first++;
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
const GlyphNode* CompressedUnmappedFontCache::hasCachedGlyphData(const GlyphNode* glyphNode, const uint8_t*& pixelData)
|
|
{
|
|
const BitmapFontCacheKey* end = (const BitmapFontCacheKey*)&bitmapFontCache[cacheWords];
|
|
const BitmapFontCacheKey* first = end - glyphsAllocated;
|
|
while (first < end)
|
|
{
|
|
if (first->glyphNodeSrc == glyphNode)
|
|
{
|
|
//Pixel data can be zero!
|
|
pixelData = first->pixels;
|
|
return &first->glyphNodeCopy;
|
|
}
|
|
first++;
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
GlyphNode* CompressedUnmappedFontCache::cacheGlyphNode(const GlyphNode* glyph)
|
|
{
|
|
const BitmapFontCacheKey* end = (const BitmapFontCacheKey*)&bitmapFontCache[cacheWords];
|
|
if (pixelsTop + sizeof(BitmapFontCacheKey) > (const uint8_t*)&end[-glyphsAllocated])
|
|
{
|
|
// Unable to fit GlyphNode in data, clear cache
|
|
clearCache();
|
|
}
|
|
|
|
glyphsAllocated++;
|
|
BitmapFontCacheKey* key = const_cast<BitmapFontCacheKey*>(end - glyphsAllocated);
|
|
key->glyphNodeSrc = glyph;
|
|
key->pixels = 0;
|
|
|
|
return &key->glyphNodeCopy;
|
|
}
|
|
|
|
const uint8_t* CompressedUnmappedFontCache::cacheGlyphData(const GlyphNode* glyph, const uint8_t* compressedData, touchgfx::FlashDataReader* reader)
|
|
{
|
|
// Search keys for glyph
|
|
BitmapFontCacheKey* end = (BitmapFontCacheKey*)&bitmapFontCache[cacheWords];
|
|
BitmapFontCacheKey* it = end - glyphsAllocated;
|
|
while (it < end)
|
|
{
|
|
if (it->glyphNodeSrc == glyph)
|
|
{
|
|
break;
|
|
}
|
|
it++;
|
|
}
|
|
|
|
if (it == end)
|
|
{
|
|
// broken invariant!
|
|
return 0;
|
|
}
|
|
|
|
const int byteSize = (it->glyphNodeCopy.width() + 1) / 2 * it->glyphNodeCopy.height();
|
|
// Check if pixels can fit in cache
|
|
if (pixelsTop + byteSize > (const uint8_t*)&end[-glyphsAllocated])
|
|
{
|
|
// Can it fit in a clean cache?
|
|
if (byteSize + sizeof(BitmapFontCacheKey) > cacheSizeBytes)
|
|
{
|
|
unableToCache(glyph, byteSize);
|
|
return 0;
|
|
}
|
|
|
|
// Unable to fit pixel in data, must clear cache
|
|
|
|
// Save address of GlyphNode in cache
|
|
const GlyphNode* cachedGn = &it->glyphNodeCopy;
|
|
|
|
// Now clear (reset pointer)
|
|
clearCache();
|
|
|
|
// Insert glyph node again
|
|
glyphsAllocated++;
|
|
it = const_cast<BitmapFontCacheKey*>(end - 1);
|
|
it->glyphNodeSrc = glyph;
|
|
it->pixels = 0;
|
|
// Copy GlyphNode content from previous position in cache
|
|
it->glyphNodeCopy = *cachedGn;
|
|
}
|
|
|
|
//Now decompress data
|
|
const uint8_t* glyphData = pixelsTop;
|
|
pixelsTop = decompressGlyph(pixelsTop, &it->glyphNodeCopy, compressedData, reader);
|
|
|
|
// 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();
|
|
|
|
it->pixels = glyphData;
|
|
|
|
return glyphData;
|
|
}
|
|
|
|
} // namespace touchgfx
|