mirror of
https://github.com/meshtastic/firmware.git
synced 2025-09-02 17:53:46 +00:00
TFT spped improvements
This commit is contained in:
parent
893efe4f11
commit
c479951bb2
@ -681,29 +681,92 @@ void TFTDisplay::display(bool fromBlank)
|
|||||||
// tft->clear();
|
// tft->clear();
|
||||||
concurrency::LockGuard g(spiLock);
|
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 (y = 0; y < displayHeight; y++) {
|
||||||
for (x = 0; x < displayWidth; x++) {
|
y_byteIndex = (y / 8) * displayWidth;
|
||||||
auto isset = buffer[x + (y / 8) * displayWidth] & (1 << (y & 7));
|
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) {
|
if (!fromBlank) {
|
||||||
// get src pixel in the page based ordering the OLED lib uses FIXME, super inefficent
|
for (x = 0; x < displayWidth; x++) {
|
||||||
auto dblbuf_isset = buffer_back[x + (y / 8) * displayWidth] & (1 << (y & 7));
|
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) {
|
if (isset != dblbuf_isset) {
|
||||||
tft->drawPixel(x, y, isset ? TFT_MESH : TFT_BLACK);
|
break;
|
||||||
}
|
}
|
||||||
} else if (isset) {
|
} else if (isset) {
|
||||||
tft->drawPixel(x, y, TFT_MESH);
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// 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
|
// Copy the Buffer to the Back Buffer
|
||||||
for (y = 0; y < (displayHeight / 8); y++) {
|
if (somethingChanged)
|
||||||
for (x = 0; x < displayWidth; x++) {
|
memcpy(buffer_back, buffer, displayBufferSize);
|
||||||
uint16_t pos = x + y * displayWidth;
|
|
||||||
buffer_back[pos] = buffer[pos];
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Send a command to the display (low level function)
|
// Send a command to the display (low level function)
|
||||||
@ -857,6 +920,15 @@ bool TFTDisplay::connect()
|
|||||||
#endif
|
#endif
|
||||||
tft->fillScreen(TFT_BLACK);
|
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;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -48,6 +48,8 @@ class TFTDisplay : public OLEDDisplay
|
|||||||
*/
|
*/
|
||||||
static GpioPin *backlightEnable;
|
static GpioPin *backlightEnable;
|
||||||
|
|
||||||
|
uint16_t *linePixelBuffer;
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
// the header size of the buffer used, e.g. for the SPI command header
|
// the header size of the buffer used, e.g. for the SPI command header
|
||||||
virtual int getBufferOffset(void) override { return 0; }
|
virtual int getBufferOffset(void) override { return 0; }
|
||||||
|
Loading…
Reference in New Issue
Block a user