Browse Source

⚡️ Compact RGB565 TFT boot images (#26011)

Co-authored-by: Scott Lahteine <thinkyhead@users.noreply.github.com>
ellensp 1 year ago
parent
commit
5bcaae62f2

+ 2 - 0
Marlin/Configuration.h

@@ -3313,6 +3313,8 @@
   #define TFT_THEME BLACK_MARLIN
 
   //#define TFT_SHARED_IO   // I/O is shared between TFT display and other devices. Disable async data transfer.
+
+  #define COMPACT_MARLIN_BOOT_LOGO  // Use compressed data to save Flash space
 #endif
 
 #if ENABLED(TFT_LVGL_UI)

+ 3 - 3
Marlin/src/HAL/LPC1768/tft/tft_spi.h

@@ -49,7 +49,7 @@
 #define DATASIZE_8BIT     SSP_DATABIT_8
 #define DATASIZE_16BIT    SSP_DATABIT_16
 #define TFT_IO_DRIVER     TFT_SPI
-#define DMA_MAX_SIZE      0xFFF
+#define DMA_MAX_WORDS     0xFFF
 
 #define DMA_MINC_ENABLE   1
 #define DMA_MINC_DISABLE  0
@@ -82,8 +82,8 @@ public:
   static void writeSequence(uint16_t *data, uint16_t count) { transmit(DMA_MINC_ENABLE, data, count); }
   static void writeMultiple(uint16_t color, uint32_t count) {
     while (count > 0) {
-      transmit(DMA_MINC_DISABLE, &color, count > DMA_MAX_SIZE ? DMA_MAX_SIZE : count);
-      count = count > DMA_MAX_SIZE ? count - DMA_MAX_SIZE : 0;
+      transmit(DMA_MINC_DISABLE, &color, count > DMA_MAX_WORDS ? DMA_MAX_WORDS : count);
+      count = count > DMA_MAX_WORDS ? count - DMA_MAX_WORDS : 0;
     }
   }
 };

+ 1 - 1
Marlin/src/HAL/NATIVE_SIM/tft/tft_spi.h

@@ -33,7 +33,7 @@
 #define DATASIZE_8BIT    8
 #define DATASIZE_16BIT  16
 #define TFT_IO_DRIVER   TFT_SPI
-#define DMA_MAX_SIZE    0xFFFF
+#define DMA_MAX_WORDS   0xFFFF
 
 #define DMA_MINC_ENABLE  1
 #define DMA_MINC_DISABLE 0

+ 3 - 3
Marlin/src/HAL/STM32/tft/tft_fsmc.h

@@ -45,7 +45,7 @@
 #define DATASIZE_8BIT  SPI_DATASIZE_8BIT
 #define DATASIZE_16BIT SPI_DATASIZE_16BIT
 #define TFT_IO_DRIVER  TFT_FSMC
-#define DMA_MAX_SIZE   0xFFFF
+#define DMA_MAX_WORDS  0xFFFF
 
 #define TFT_DATASIZE TERN(TFT_INTERFACE_FSMC_8BIT, DATASIZE_8BIT, DATASIZE_16BIT)
 typedef TERN(TFT_INTERFACE_FSMC_8BIT, uint8_t, uint16_t) tft_data_t;
@@ -85,8 +85,8 @@ class TFT_FSMC {
     static void writeSequence(uint16_t *data, uint16_t count) { transmit(DMA_PINC_ENABLE, data, count); }
     static void writeMultiple(uint16_t color, uint32_t count) {
       while (count > 0) {
-        transmit(DMA_MINC_DISABLE, &color, count > DMA_MAX_SIZE ? DMA_MAX_SIZE : count);
-        count = count > DMA_MAX_SIZE ? count - DMA_MAX_SIZE : 0;
+        transmit(DMA_MINC_DISABLE, &color, count > DMA_MAX_WORDS ? DMA_MAX_WORDS : count);
+        count = count > DMA_MAX_WORDS ? count - DMA_MAX_WORDS : 0;
       }
     }
 };

+ 3 - 3
Marlin/src/HAL/STM32/tft/tft_ltdc.h

@@ -32,7 +32,7 @@
 #define DATASIZE_8BIT  SPI_DATASIZE_8BIT
 #define DATASIZE_16BIT SPI_DATASIZE_16BIT
 #define TFT_IO_DRIVER  TFT_LTDC
-#define DMA_MAX_SIZE   0xFFFF
+#define DMA_MAX_WORDS  0xFFFF
 
 #define TFT_DATASIZE DATASIZE_16BIT
 typedef uint16_t tft_data_t;
@@ -71,8 +71,8 @@ class TFT_LTDC {
     static void writeSequence(uint16_t *data, uint16_t count) { transmit(DMA_PINC_ENABLE, data, count); }
     static void writeMultiple(uint16_t color, uint32_t count) {
       while (count > 0) {
-        transmit(DMA_PINC_DISABLE, &color, count > DMA_MAX_SIZE ? DMA_MAX_SIZE : count);
-        count = count > DMA_MAX_SIZE ? count - DMA_MAX_SIZE : 0;
+        transmit(DMA_PINC_DISABLE, &color, count > DMA_MAX_WORDS ? DMA_MAX_WORDS : count);
+        count = count > DMA_MAX_WORDS ? count - DMA_MAX_WORDS : 0;
       }
     }
 };

+ 3 - 3
Marlin/src/HAL/STM32/tft/tft_spi.h

@@ -42,7 +42,7 @@
 #define DATASIZE_16BIT SPI_DATASIZE_16BIT
 #define DATASIZE_32BIT SPI_DATASIZE_32BIT
 #define TFT_IO_DRIVER  TFT_SPI
-#define DMA_MAX_SIZE   0xFFFF
+#define DMA_MAX_WORDS  0xFFFF
 
 class TFT_SPI {
 private:
@@ -81,8 +81,8 @@ public:
   static void writeSequence(uint16_t *data, uint16_t count) { transmit(DMA_MINC_ENABLE, data, count); }
   static void writeMultiple(uint16_t color, uint32_t count) {
     while (count > 0) {
-      transmit(DMA_MINC_DISABLE, &color, count > DMA_MAX_SIZE ? DMA_MAX_SIZE : count);
-      count = count > DMA_MAX_SIZE ? count - DMA_MAX_SIZE : 0;
+      transmit(DMA_MINC_DISABLE, &color, count > DMA_MAX_WORDS ? DMA_MAX_WORDS : count);
+      count = count > DMA_MAX_WORDS ? count - DMA_MAX_WORDS : 0;
     }
   }
 };

+ 3 - 3
Marlin/src/HAL/STM32F1/tft/tft_fsmc.h

@@ -40,7 +40,7 @@
 #define DATASIZE_8BIT  DMA_SIZE_8BITS
 #define DATASIZE_16BIT DMA_SIZE_16BITS
 #define TFT_IO_DRIVER  TFT_FSMC
-#define DMA_MAX_SIZE   0xFFFF
+#define DMA_MAX_WORDS  0xFFFF
 
 #define DMA_PINC_ENABLE   DMA_PINC_MODE
 #define DMA_PINC_DISABLE  0
@@ -77,8 +77,8 @@ class TFT_FSMC {
     static void writeSequence(uint16_t *data, uint16_t count) { transmit(DMA_PINC_ENABLE, data, count); }
     static void writeMultiple(uint16_t color, uint32_t count) {
       while (count > 0) {
-        transmit(DMA_PINC_DISABLE, &color, count > DMA_MAX_SIZE ? DMA_MAX_SIZE : count);
-        count = count > DMA_MAX_SIZE ? count - DMA_MAX_SIZE : 0;
+        transmit(DMA_PINC_DISABLE, &color, count > DMA_MAX_WORDS ? DMA_MAX_WORDS : count);
+        count = count > DMA_MAX_WORDS ? count - DMA_MAX_WORDS : 0;
       }
     }
 };

+ 3 - 3
Marlin/src/HAL/STM32F1/tft/tft_spi.h

@@ -56,7 +56,7 @@
 #define DATASIZE_8BIT  DATA_SIZE_8BIT
 #define DATASIZE_16BIT DATA_SIZE_16BIT
 #define TFT_IO_DRIVER  TFT_SPI
-#define DMA_MAX_SIZE   0xFFFF
+#define DMA_MAX_WORDS  0xFFFF
 
 #define DMA_MINC_ENABLE   DMA_MINC_MODE
 #define DMA_MINC_DISABLE  0
@@ -89,8 +89,8 @@ public:
   static void writeSequence(uint16_t *data, uint16_t count) { transmit(DMA_MINC_ENABLE, data, count); }
   static void writeMultiple(uint16_t color, uint32_t count) {
     while (count > 0) {
-      transmit(DMA_MINC_DISABLE, &color, count > DMA_MAX_SIZE ? DMA_MAX_SIZE : count);
-      count = count > DMA_MAX_SIZE ? count - DMA_MAX_SIZE : 0;
+      transmit(DMA_MINC_DISABLE, &color, count > DMA_MAX_WORDS ? DMA_MAX_WORDS : count);
+      count = count > DMA_MAX_WORDS ? count - DMA_MAX_WORDS : 0;
     }
   }
 };

+ 83 - 25
Marlin/src/lcd/tft/canvas.cpp

@@ -37,12 +37,14 @@ void Canvas::instantiate(uint16_t x, uint16_t y, uint16_t width, uint16_t height
   startLine = 0;
   endLine = 0;
 
+  // The TFT handles DMA within the given canvas rectangle
+  // so whatever is drawn will be offset on the screen by x,y.
   tft.set_window(x, y, x + width - 1, y + height - 1);
 }
 
 void Canvas::next() {
   startLine = endLine;
-  endLine = TFT_BUFFER_SIZE < width * (height - startLine) ? startLine + TFT_BUFFER_SIZE / width : height;
+  endLine = (TFT_BUFFER_WORDS) < width * (height - startLine) ? startLine + (TFT_BUFFER_WORDS) / width : height;
 }
 
 bool Canvas::toScreen() {
@@ -99,28 +101,84 @@ void Canvas::addImage(int16_t x, int16_t y, MarlinImage image, uint16_t *colors)
   uint16_t *data = (uint16_t *)images[image].data;
   if (!data) return;
 
-  uint16_t image_width = images[image].width,
-           image_height = images[image].height;
+  const uint16_t image_width = images[image].width,
+                image_height = images[image].height;
   colorMode_t color_mode = images[image].colorMode;
 
-  if (color_mode != HIGHCOLOR)
-    return addImage(x, y, image_width, image_height, color_mode, (uint8_t *)data, colors);
-
-  // HIGHCOLOR - 16 bits per pixel
-
-  for (int16_t i = 0; i < image_height; i++) {
-    int16_t line = y + i;
-    if (line >= startLine && line < endLine) {
-      uint16_t *pixel = buffer + x + (line - startLine) * width;
-      for (int16_t j = 0; j < image_width; j++) {
-        if ((x + j >= 0) && (x + j < width)) *pixel = ENDIAN_COLOR(*data);
-        pixel++;
-        data++;
+  if (color_mode == HIGHCOLOR) {
+    // HIGHCOLOR - 16 bits per pixel
+    int16_t line = y;
+    for (int16_t i = 0; i < image_height; i++, line++) {
+      if (WITHIN(line, startLine, endLine - 1)) {
+        uint16_t *pixel = buffer + x + (line - startLine) * width;
+        uint16_t cx = x;
+        for (int16_t j = 0; j < image_width; j++, cx++) {
+          if (WITHIN(cx, 0, width - 1)) {
+            uint16_t color = ENDIAN_COLOR(*data);
+            if (color == 0x0001) color = COLOR_BACKGROUND;
+            *pixel = color;
+          }
+          pixel++;
+          data++;
+        }
       }
+      else
+        data += image_width;
     }
-    else
-      data += image_width;
+    return;
   }
+
+  #if ENABLED(COMPACT_MARLIN_BOOT_LOGO)
+    // RLE16 HIGHCOLOR - 16 bits per pixel
+    if (color_mode == RLE16) {
+      uint8_t *bytedata = (uint8_t *)images[image].data;
+      if (!bytedata) return;
+
+      // Loop through the image data advancing the row and column as needed
+      int16_t srcy = 0, srcx = 0,                   // Image data line / column index
+              dsty = y, dstx = x;                   // Destination line / column index
+
+      uint16_t color = 0;                           // Persist the last fetched color value
+      bool done = false;
+      while (!done) {
+        uint8_t count = *bytedata++;                // Get the count byte
+        const bool uniq = bool(count & 0x80);       // >= 128 is a distinct run; < 128 is a repeat run
+        count = (count & 0x7F) + 1;                 // Actual count is 7-bit plus 1
+
+        bool getcol = true;                         // Get at least one color word
+        while (count--) {                           // Emit 'count' pixels
+
+          if (getcol) {
+            getcol = uniq;                          // Keep getting colors if not RLE
+            const uint16_t msb = *bytedata++,       // Color most-significant bits
+                           lsb = *bytedata++;       // Color least-significant bits
+            color = ENDIAN_COLOR((msb << 8) | lsb); // Color with proper endianness
+            if (color == 0x0001) color = COLOR_BACKGROUND; // 0x0001 is "transparent"
+          }
+
+          if (WITHIN(dsty, startLine, endLine - 1)) { // Dest pixel Y within the segment?
+            if (WITHIN(dstx, 0, width - 1)) {       // Dest pixel X within the canvas?
+              uint16_t * const pixel = buffer + dstx + (dsty - startLine) * width;
+              *pixel = color;                       // Store the color in the pixel
+            }
+          }
+
+          ++srcx; ++dstx;                           // Advance the pixel column
+          if (srcx >= image_width) {                // Past the right edge of the source image?
+            ++srcy; ++dsty;                         // Advance to the next line
+            srcx = 0; dstx = x;                     // May be shifted within the canvas, but usually not
+            if (dsty >= endLine || srcy >= image_height) { // Done with the segment or the image?
+              done = true;                          // Set a flag to end the loop...
+              break;                                // ...and break out of while(count--)
+            }
+          }
+        }
+      }
+      return;
+    }
+  #endif // COMPACT_MARLIN_BOOT_LOGO
+
+  addImage(x, y, image_width, image_height, color_mode, (uint8_t *)data, colors);
 }
 
 void Canvas::addImage(int16_t x, int16_t y, uint8_t image_width, uint8_t image_height, colorMode_t color_mode, uint8_t *data, uint16_t *colors) {
@@ -138,8 +196,8 @@ void Canvas::addImage(int16_t x, int16_t y, uint8_t image_width, uint8_t image_h
   colors--;
 
   for (int16_t i = 0; i < image_height; i++) {
-    int16_t line = y + i;
-    if (line >= startLine && line < endLine) {
+    const int16_t line = y + i;
+    if (WITHIN(line, startLine, endLine - 1)) {
       uint16_t *pixel = buffer + x + (line - startLine) * width;
       uint8_t offset = 8 - bitsPerPixel;
       for (int16_t j = 0; j < image_width; j++) {
@@ -147,7 +205,7 @@ void Canvas::addImage(int16_t x, int16_t y, uint8_t image_width, uint8_t image_h
           data++;
           offset = 8 - bitsPerPixel;
         }
-        if ((x + j >= 0) && (x + j < width)) {
+        if (WITHIN(x + j, 0, width - 1)) {
           const uint8_t color = ((*data) >> offset) & mask;
           if (color) *pixel = *(colors + color);
         }
@@ -165,8 +223,8 @@ void Canvas::addRect(uint16_t x, uint16_t y, uint16_t rectangleWidth, uint16_t r
   if (endLine < y || startLine > y + rectangleHeight) return;
 
   for (uint16_t i = 0; i < rectangleHeight; i++) {
-    uint16_t line = y + i;
-    if (line >= startLine && line < endLine) {
+    const uint16_t line = y + i;
+    if (WITHIN(line, startLine, endLine - 1)) {
       uint16_t *pixel = buffer + x + (line - startLine) * width;
       if (i == 0 || i == rectangleHeight - 1) {
         for (uint16_t j = 0; j < rectangleWidth; j++) *pixel++ = color;
@@ -184,8 +242,8 @@ void Canvas::addBar(uint16_t x, uint16_t y, uint16_t barWidth, uint16_t barHeigh
   if (endLine < y || startLine > y + barHeight) return;
 
   for (uint16_t i = 0; i < barHeight; i++) {
-    uint16_t line = y + i;
-    if (line >= startLine && line < endLine) {
+    const uint16_t line = y + i;
+    if (WITHIN(line, startLine, endLine - 1)) {
       uint16_t *pixel = buffer + x + (line - startLine) * width;
       for (uint16_t j = 0; j < barWidth; j++) *pixel++ = color;
     }

+ 3 - 3
Marlin/src/lcd/tft/images/back_32x32x4.cpp

@@ -21,12 +21,10 @@
  */
 
 #include "../../../inc/MarlinConfigPre.h"
-#include "../tft_image.h"
 
 #if HAS_GRAPHICAL_TFT
 
-extern const uint8_t back_32x32x4[];
-const tImage Back_32x32x4 = { (void *)back_32x32x4, 32, 32, GREYSCALE4 };
+#include "../tft_image.h"
 
 const uint8_t back_32x32x4[512] = {
   0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88,
@@ -63,4 +61,6 @@ const uint8_t back_32x32x4[512] = {
   0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88,
 };
 
+const tImage Back_32x32x4 = { (void *)back_32x32x4, 32, 32, GREYSCALE4 };
+
 #endif // HAS_GRAPHICAL_TFT

Some files were not shown because too many files changed in this diff