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