/* DO NOT EDIT THIS FILE */ /* This file is autogenerated by the text-database code generator */ #include #include #include 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(reinterpret_cast(glyphData) & ~0x1F); int alignmentOffset = glyphData - rowStart; paint::flushLine((uint32_t*)rowStart, byteSize + alignmentOffset); paint::invalidateTextureCache(); glyphsAllocated++; BitmapFontCacheKey* key = const_cast(end - glyphsAllocated); key->glyphNode = glyph; key->pixels = glyphData; return glyphData; } } // namespace touchgfx