Faster TFTColor processing (#10814)
This commit is contained in:
co-authored by
GitHub
parent
fd8ba4fa4e
commit
21dbe21745
@@ -792,6 +792,20 @@ void clearTFTColorRegions()
|
||||
colorRegionCount = 0;
|
||||
}
|
||||
|
||||
// Per-row culling fast path (see TFTColorRegions.h / resolveTFTColorPixelRow()).
|
||||
uint8_t tftColorRowRegions[MAX_TFT_COLOR_REGIONS];
|
||||
uint8_t tftColorRowCount = 0;
|
||||
|
||||
void beginTFTColorRow(int16_t y)
|
||||
{
|
||||
tftColorRowCount = 0;
|
||||
for (uint8_t i = 0; i < colorRegionCount; i++) {
|
||||
const TFTColorRegion &r = colorRegions[i];
|
||||
if (y >= r.y && y < r.y + r.height)
|
||||
tftColorRowRegions[tftColorRowCount++] = i;
|
||||
}
|
||||
}
|
||||
|
||||
uint16_t resolveTFTColorPixel(int16_t x, int16_t y, bool isset, uint16_t defaultOnColor, uint16_t defaultOffColor)
|
||||
{
|
||||
for (int i = static_cast<int>(colorRegionCount) - 1; i >= 0; i--) {
|
||||
|
||||
@@ -67,6 +67,29 @@ uint16_t resolveTFTColorPixel(int16_t x, int16_t y, bool isset, uint16_t default
|
||||
// Resolve effective region-mapped OFF color at a coordinate in native-endian RGB565.
|
||||
uint16_t resolveTFTOffColorAt(int16_t x, int16_t y, uint16_t defaultOffColor);
|
||||
|
||||
// -- Per-row fast path for the hot pixel loops in TFTDisplay::display() --------
|
||||
// resolveTFTColorPixel() is O(regions) per pixel; for a full 800x480 repaint that
|
||||
// dominates redraw time. Regions are vertically localized, so cull to the regions
|
||||
// overlapping the current row once per row, then resolve each pixel against only
|
||||
// those (inlined here, so no per-pixel cross-TU call).
|
||||
extern uint8_t tftColorRowRegions[MAX_TFT_COLOR_REGIONS]; // indices into colorRegions[], ascending
|
||||
extern uint8_t tftColorRowCount;
|
||||
|
||||
// Build tftColorRowRegions for row y. Call once per row before resolveTFTColorPixelRow().
|
||||
void beginTFTColorRow(int16_t y);
|
||||
|
||||
// Resolve one pixel against the current row's active regions (set by beginTFTColorRow()).
|
||||
// Highest-index region wins, matching resolveTFTColorPixel()'s precedence.
|
||||
inline uint16_t resolveTFTColorPixelRow(int16_t x, bool isset, uint16_t defaultOnColor, uint16_t defaultOffColor)
|
||||
{
|
||||
for (int j = static_cast<int>(tftColorRowCount) - 1; j >= 0; j--) {
|
||||
const TFTColorRegion &r = colorRegions[tftColorRowRegions[j]];
|
||||
if (x >= r.x && x < r.x + r.width)
|
||||
return isset ? r.onColorBe : r.offColorBe;
|
||||
}
|
||||
return isset ? defaultOnColor : defaultOffColor;
|
||||
}
|
||||
|
||||
// -- Theme engine ------------------------------------------------------
|
||||
// Each theme has four fields that work together:
|
||||
//
|
||||
|
||||
@@ -1270,13 +1270,30 @@ void TFTDisplay::display(bool fromBlank)
|
||||
y_byteMask = (1 << (y & 7));
|
||||
|
||||
uint16_t *chunkRow = repaintChunkBuffer + (row * displayWidth);
|
||||
|
||||
// Step 1: fill the whole row with the default colors. No per-pixel
|
||||
// region scan, so background pixels (the bulk of the screen) are O(1).
|
||||
for (x = 0; x < displayWidth; x++) {
|
||||
isset = (buffer[x + y_byteIndex] & y_byteMask) != 0;
|
||||
if (hasColorRegions) {
|
||||
chunkRow[x] = graphics::resolveTFTColorPixel(static_cast<int16_t>(x), static_cast<int16_t>(y), isset,
|
||||
colorTftWhite, colorTftBlack);
|
||||
} else {
|
||||
chunkRow[x] = isset ? colorTftWhite : colorTftBlack;
|
||||
chunkRow[x] = isset ? colorTftWhite : colorTftBlack;
|
||||
}
|
||||
|
||||
// Step 2: overprint each region overlapping this row, applied in
|
||||
// ascending index order so the highest-index region wins (matches
|
||||
// resolveTFTColorPixel precedence). Only region-covered pixels are
|
||||
// re-touched, so total cost is ~screen + sum of region spans.
|
||||
if (hasColorRegions) {
|
||||
graphics::beginTFTColorRow(static_cast<int16_t>(y));
|
||||
for (uint8_t k = 0; k < graphics::tftColorRowCount; k++) {
|
||||
const graphics::TFTColorRegion &r = graphics::colorRegions[graphics::tftColorRowRegions[k]];
|
||||
int32_t xs = r.x > 0 ? r.x : 0;
|
||||
int32_t xe = r.x + r.width;
|
||||
if (xe > (int32_t)displayWidth)
|
||||
xe = (int32_t)displayWidth;
|
||||
for (int32_t xx = xs; xx < xe; xx++) {
|
||||
isset = (buffer[xx + y_byteIndex] & y_byteMask) != 0;
|
||||
chunkRow[xx] = isset ? r.onColorBe : r.offColorBe;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1363,12 +1380,16 @@ void TFTDisplay::display(bool fromBlank)
|
||||
}
|
||||
|
||||
// Step 3: Copy only the changed span into the pixel line buffer.
|
||||
#if GRAPHICS_TFT_COLORING_ENABLED
|
||||
if (hasColorRegions)
|
||||
graphics::beginTFTColorRow(static_cast<int16_t>(y));
|
||||
#endif
|
||||
for (x = x_FirstPixelUpdate; x <= x_LastPixelUpdate; x++) {
|
||||
isset = buffer[x + y_byteIndex] & y_byteMask;
|
||||
#if GRAPHICS_TFT_COLORING_ENABLED
|
||||
if (hasColorRegions) {
|
||||
linePixelBuffer[x] = graphics::resolveTFTColorPixel(static_cast<int16_t>(x), static_cast<int16_t>(y), isset,
|
||||
colorTftWhite, colorTftBlack);
|
||||
linePixelBuffer[x] =
|
||||
graphics::resolveTFTColorPixelRow(static_cast<int16_t>(x), isset, colorTftWhite, colorTftBlack);
|
||||
} else {
|
||||
linePixelBuffer[x] = isset ? colorTftWhite : colorTftBlack;
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user