Skip to content

Commit

Permalink
TFT spped improvements
Browse files Browse the repository at this point in the history
  • Loading branch information
robertfisk authored and caveman99 committed Nov 2, 2024
1 parent 93bc61c commit 83a9ab5
Show file tree
Hide file tree
Showing 2 changed files with 87 additions and 13 deletions.
98 changes: 85 additions & 13 deletions src/graphics/TFTDisplay.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -681,29 +681,92 @@ void TFTDisplay::display(bool fromBlank)
// tft->clear();
concurrency::LockGuard g(spiLock);

uint16_t x, y;
uint32_t x, y;
uint32_t y_byteIndex;
uint8_t y_byteMask;
uint32_t x_FirstPixelUpdate;
uint32_t x_LastPixelUpdate;
bool isset, dblbuf_isset;
uint16_t colorTftMesh, colorTftBlack;
bool somethingChanged = false;

// Store colors byte-reversed so that TFT_eSPI doesn't have to swap bytes in a separate step
colorTftMesh = (TFT_MESH >> 8) | ((TFT_MESH & 0xFF) << 8);
colorTftBlack = (TFT_BLACK >> 8) | ((TFT_BLACK & 0xFF) << 8);

for (y = 0; y < displayHeight; y++) {
for (x = 0; x < displayWidth; x++) {
auto isset = buffer[x + (y / 8) * displayWidth] & (1 << (y & 7));
y_byteIndex = (y / 8) * displayWidth;
y_byteMask = (1 << (y & 7));

// Step 1: Do a quick scan of 8 rows together. This allows fast-forwarding over unchanged screen areas.
if (y_byteMask == 1) {
if (!fromBlank) {
// get src pixel in the page based ordering the OLED lib uses FIXME, super inefficent
auto dblbuf_isset = buffer_back[x + (y / 8) * displayWidth] & (1 << (y & 7));
for (x = 0; x < displayWidth; x++) {
if (buffer[x + y_byteIndex] != buffer_back[x + y_byteIndex])
break;
}
} else {
for (x = 0; x < displayWidth; x++) {
if (buffer[x + y_byteIndex] != 0)
break;
}
}
if (x >= displayWidth) {
// No changed pixels found in these 8 rows, fast-forward to the next 8
y = y + 7;
continue;
}
}

// Step 2: Scan each of the 8 rows individually. Find the first pixel in each row that needs updating
for (x_FirstPixelUpdate = 0; x_FirstPixelUpdate < displayWidth; x_FirstPixelUpdate++) {
isset = buffer[x_FirstPixelUpdate + y_byteIndex] & y_byteMask;

if (!fromBlank) {
// get src pixel in the page based ordering the OLED lib uses
dblbuf_isset = buffer_back[x_FirstPixelUpdate + y_byteIndex] & y_byteMask;
if (isset != dblbuf_isset) {
tft->drawPixel(x, y, isset ? TFT_MESH : TFT_BLACK);
break;
}
} else if (isset) {
tft->drawPixel(x, y, TFT_MESH);
break;
}
}
}
// Copy the Buffer to the Back Buffer
for (y = 0; y < (displayHeight / 8); y++) {
for (x = 0; x < displayWidth; x++) {
uint16_t pos = x + y * displayWidth;
buffer_back[pos] = buffer[pos];

// Did we find a pixel that needs updating on this row?
if (x_FirstPixelUpdate < displayWidth) {

// Quickly write out the first changed pixel (saves another array lookup)
linePixelBuffer[x_FirstPixelUpdate] = isset ? colorTftMesh : colorTftBlack;
x_LastPixelUpdate = x_FirstPixelUpdate;

// Step 3: copy all remaining pixels in this row into the pixel line buffer,
// while also recording the last pixel in the row that needs updating
for (x = x_FirstPixelUpdate + 1; x < displayWidth; x++) {
isset = buffer[x + y_byteIndex] & y_byteMask;
linePixelBuffer[x] = isset ? colorTftMesh : colorTftBlack;

if (!fromBlank) {
dblbuf_isset = buffer_back[x + y_byteIndex] & y_byteMask;
if (isset != dblbuf_isset) {
x_LastPixelUpdate = x;
}
} else if (isset) {
x_LastPixelUpdate = x;
}
}

// Step 4: Send the changed pixels on this line to the screen as a single block transfer.
// This function accepts pixel data MSB first so it can dump the memory straight out the SPI port.
tft->pushRect(x_FirstPixelUpdate, y, (x_LastPixelUpdate - x_FirstPixelUpdate + 1), 1,
&linePixelBuffer[x_FirstPixelUpdate]);

somethingChanged = true;
}
}
// Copy the Buffer to the Back Buffer
if (somethingChanged)
memcpy(buffer_back, buffer, displayBufferSize);
}

// Send a command to the display (low level function)
Expand Down Expand Up @@ -857,6 +920,15 @@ bool TFTDisplay::connect()
#endif
tft->fillScreen(TFT_BLACK);

if (this->linePixelBuffer == NULL) {
this->linePixelBuffer = (uint16_t *)malloc(sizeof(uint16_t) * displayWidth);

if (!this->linePixelBuffer) {
LOG_INFO("Not enough memory to create TFT line buffer\n");
return false;
}
}

return true;
}

Expand Down
2 changes: 2 additions & 0 deletions src/graphics/TFTDisplay.h
Original file line number Diff line number Diff line change
Expand Up @@ -48,6 +48,8 @@ class TFTDisplay : public OLEDDisplay
*/
static GpioPin *backlightEnable;

uint16_t *linePixelBuffer;

protected:
// the header size of the buffer used, e.g. for the SPI command header
virtual int getBufferOffset(void) override { return 0; }
Expand Down

0 comments on commit 83a9ab5

Please sign in to comment.