summary refs log tree commit diff
diff options
context:
space:
mode:
-rw-r--r--docs/quantum_painter.md22
-rw-r--r--drivers/painter/gc9a01/qp_gc9a01.c7
-rw-r--r--drivers/painter/ili9xxx/qp_ili9163.c8
-rw-r--r--drivers/painter/ili9xxx/qp_ili9341.c8
-rw-r--r--drivers/painter/ili9xxx/qp_ili9488.c8
-rw-r--r--drivers/painter/ssd1351/qp_ssd1351.c8
-rw-r--r--drivers/painter/st77xx/qp_st7735.c8
-rw-r--r--drivers/painter/st77xx/qp_st7789.c8
-rw-r--r--quantum/painter/qp.h36
-rw-r--r--quantum/painter/qp_draw_image.c14
-rw-r--r--quantum/painter/qp_internal.c96
-rw-r--r--quantum/painter/qp_internal_driver.h7
-rw-r--r--quantum/painter/rules.mk1
13 files changed, 199 insertions, 32 deletions
diff --git a/docs/quantum_painter.md b/docs/quantum_painter.md
index ac37053c79..acb9d1d384 100644
--- a/docs/quantum_painter.md
+++ b/docs/quantum_painter.md
@@ -32,16 +32,18 @@ Supported devices:
 
 ## Quantum Painter Configuration :id=quantum-painter-config
 
-| Option                                   | Default | Purpose                                                                                                                                     |
-|------------------------------------------|---------|---------------------------------------------------------------------------------------------------------------------------------------------|
-| `QUANTUM_PAINTER_NUM_IMAGES`             | `8`     | The maximum number of images/animations that can be loaded at any one time.                                                                 |
-| `QUANTUM_PAINTER_NUM_FONTS`              | `4`     | The maximum number of fonts that can be loaded at any one time.                                                                             |
-| `QUANTUM_PAINTER_CONCURRENT_ANIMATIONS`  | `4`     | The maximum number of animations that can be executed at the same time.                                                                     |
-| `QUANTUM_PAINTER_LOAD_FONTS_TO_RAM`      | `FALSE` | Whether or not fonts should be loaded to RAM. Relevant for fonts stored in off-chip persistent storage, such as external flash.             |
-| `QUANTUM_PAINTER_PIXDATA_BUFFER_SIZE`    | `32`    | The limit of the amount of pixel data that can be transmitted in one transaction to the display. Higher values require more RAM on the MCU. |
-| `QUANTUM_PAINTER_SUPPORTS_256_PALETTE`   | `FALSE` | If 256-color palettes are supported. Requires significantly more RAM on the MCU.                                                            |
-| `QUANTUM_PAINTER_SUPPORTS_NATIVE_COLORS` | `FALSE` | If native color range is supported. Requires significantly more RAM on the MCU.                                                             |
-| `QUANTUM_PAINTER_DEBUG`                  | _unset_ | Prints out significant amounts of debugging information to CONSOLE output. Significant performance degradation, use only for debugging.     |
+| Option                                   | Default | Purpose                                                                                                                                                                                      |
+|------------------------------------------|---------|----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|
+| `QUANTUM_PAINTER_DISPLAY_TIMEOUT`        | `30000` | This controls the amount of time (in milliseconds) that all displays will remain on after the last user input. If set to `0`, the display will remain on indefinitely.                       |
+| `QUANTUM_PAINTER_TASK_THROTTLE`          | `1`     | This controls the amount of time (in milliseconds) that the Quantum Painter internal task will wait between each execution. Affects animations, display timeout, and LVGL timing if enabled. |
+| `QUANTUM_PAINTER_NUM_IMAGES`             | `8`     | The maximum number of images/animations that can be loaded at any one time.                                                                                                                  |
+| `QUANTUM_PAINTER_NUM_FONTS`              | `4`     | The maximum number of fonts that can be loaded at any one time.                                                                                                                              |
+| `QUANTUM_PAINTER_CONCURRENT_ANIMATIONS`  | `4`     | The maximum number of animations that can be executed at the same time.                                                                                                                      |
+| `QUANTUM_PAINTER_LOAD_FONTS_TO_RAM`      | `FALSE` | Whether or not fonts should be loaded to RAM. Relevant for fonts stored in off-chip persistent storage, such as external flash.                                                              |
+| `QUANTUM_PAINTER_PIXDATA_BUFFER_SIZE`    | `32`    | The limit of the amount of pixel data that can be transmitted in one transaction to the display. Higher values require more RAM on the MCU.                                                  |
+| `QUANTUM_PAINTER_SUPPORTS_256_PALETTE`   | `FALSE` | If 256-color palettes are supported. Requires significantly more RAM on the MCU.                                                                                                             |
+| `QUANTUM_PAINTER_SUPPORTS_NATIVE_COLORS` | `FALSE` | If native color range is supported. Requires significantly more RAM on the MCU.                                                                                                              |
+| `QUANTUM_PAINTER_DEBUG`                  | _unset_ | Prints out significant amounts of debugging information to CONSOLE output. Significant performance degradation, use only for debugging.                                                      |
 
 Drivers have their own set of configurable options, and are described in their respective sections.
 
diff --git a/drivers/painter/gc9a01/qp_gc9a01.c b/drivers/painter/gc9a01/qp_gc9a01.c
index 5d079435c6..56140fa50e 100644
--- a/drivers/painter/gc9a01/qp_gc9a01.c
+++ b/drivers/painter/gc9a01/qp_gc9a01.c
@@ -1,4 +1,5 @@
 // Copyright 2021 Paul Cotter (@gr1mr3aver)
+// Copyright 2023 Nick Brassel (@tzarc)
 // SPDX-License-Identifier: GPL-2.0-or-later
 
 #include <wait.h>
@@ -141,6 +142,12 @@ painter_device_t qp_gc9a01_make_spi_device(uint16_t panel_width, uint16_t panel_
             driver->spi_dc_reset_config.spi_config.mode            = spi_mode;
             driver->spi_dc_reset_config.dc_pin                     = dc_pin;
             driver->spi_dc_reset_config.reset_pin                  = reset_pin;
+
+            if (!qp_internal_register_device((painter_device_t)driver)) {
+                memset(driver, 0, sizeof(tft_panel_dc_reset_painter_device_t));
+                return NULL;
+            }
+
             return (painter_device_t)driver;
         }
     }
diff --git a/drivers/painter/ili9xxx/qp_ili9163.c b/drivers/painter/ili9xxx/qp_ili9163.c
index af37686631..917650953d 100644
--- a/drivers/painter/ili9xxx/qp_ili9163.c
+++ b/drivers/painter/ili9xxx/qp_ili9163.c
@@ -1,4 +1,4 @@
-// Copyright 2021 Nick Brassel (@tzarc)
+// Copyright 2021-2023 Nick Brassel (@tzarc)
 // SPDX-License-Identifier: GPL-2.0-or-later
 
 #include "qp_internal.h"
@@ -110,6 +110,12 @@ painter_device_t qp_ili9163_make_spi_device(uint16_t panel_width, uint16_t panel
             driver->spi_dc_reset_config.spi_config.mode            = spi_mode;
             driver->spi_dc_reset_config.dc_pin                     = dc_pin;
             driver->spi_dc_reset_config.reset_pin                  = reset_pin;
+
+            if (!qp_internal_register_device((painter_device_t)driver)) {
+                memset(driver, 0, sizeof(tft_panel_dc_reset_painter_device_t));
+                return NULL;
+            }
+
             return (painter_device_t)driver;
         }
     }
diff --git a/drivers/painter/ili9xxx/qp_ili9341.c b/drivers/painter/ili9xxx/qp_ili9341.c
index aca3809912..ed6766666c 100644
--- a/drivers/painter/ili9xxx/qp_ili9341.c
+++ b/drivers/painter/ili9xxx/qp_ili9341.c
@@ -1,4 +1,4 @@
-// Copyright 2021 Nick Brassel (@tzarc)
+// Copyright 2021-2023 Nick Brassel (@tzarc)
 // SPDX-License-Identifier: GPL-2.0-or-later
 
 #include "qp_internal.h"
@@ -117,6 +117,12 @@ painter_device_t qp_ili9341_make_spi_device(uint16_t panel_width, uint16_t panel
             driver->spi_dc_reset_config.spi_config.mode            = spi_mode;
             driver->spi_dc_reset_config.dc_pin                     = dc_pin;
             driver->spi_dc_reset_config.reset_pin                  = reset_pin;
+
+            if (!qp_internal_register_device((painter_device_t)driver)) {
+                memset(driver, 0, sizeof(tft_panel_dc_reset_painter_device_t));
+                return NULL;
+            }
+
             return (painter_device_t)driver;
         }
     }
diff --git a/drivers/painter/ili9xxx/qp_ili9488.c b/drivers/painter/ili9xxx/qp_ili9488.c
index e51f0e1d51..3740666583 100644
--- a/drivers/painter/ili9xxx/qp_ili9488.c
+++ b/drivers/painter/ili9xxx/qp_ili9488.c
@@ -1,4 +1,4 @@
-// Copyright 2021 Nick Brassel (@tzarc)
+// Copyright 2021-2023 Nick Brassel (@tzarc)
 // SPDX-License-Identifier: GPL-2.0-or-later
 
 #include "qp_internal.h"
@@ -110,6 +110,12 @@ painter_device_t qp_ili9488_make_spi_device(uint16_t panel_width, uint16_t panel
             driver->spi_dc_reset_config.spi_config.mode            = spi_mode;
             driver->spi_dc_reset_config.dc_pin                     = dc_pin;
             driver->spi_dc_reset_config.reset_pin                  = reset_pin;
+
+            if (!qp_internal_register_device((painter_device_t)driver)) {
+                memset(driver, 0, sizeof(tft_panel_dc_reset_painter_device_t));
+                return NULL;
+            }
+
             return (painter_device_t)driver;
         }
     }
diff --git a/drivers/painter/ssd1351/qp_ssd1351.c b/drivers/painter/ssd1351/qp_ssd1351.c
index 548785a1bd..7ee249752b 100644
--- a/drivers/painter/ssd1351/qp_ssd1351.c
+++ b/drivers/painter/ssd1351/qp_ssd1351.c
@@ -1,4 +1,4 @@
-// Copyright 2021 Nick Brassel (@tzarc)
+// Copyright 2021-2023 Nick Brassel (@tzarc)
 // SPDX-License-Identifier: GPL-2.0-or-later
 
 #include "qp_internal.h"
@@ -114,6 +114,12 @@ painter_device_t qp_ssd1351_make_spi_device(uint16_t panel_width, uint16_t panel
             driver->spi_dc_reset_config.spi_config.mode            = spi_mode;
             driver->spi_dc_reset_config.dc_pin                     = dc_pin;
             driver->spi_dc_reset_config.reset_pin                  = reset_pin;
+
+            if (!qp_internal_register_device((painter_device_t)driver)) {
+                memset(driver, 0, sizeof(tft_panel_dc_reset_painter_device_t));
+                return NULL;
+            }
+
             return (painter_device_t)driver;
         }
     }
diff --git a/drivers/painter/st77xx/qp_st7735.c b/drivers/painter/st77xx/qp_st7735.c
index 7ee5a6b562..1fd8f42186 100644
--- a/drivers/painter/st77xx/qp_st7735.c
+++ b/drivers/painter/st77xx/qp_st7735.c
@@ -1,5 +1,5 @@
 // Copyright 2021 Paul Cotter (@gr1mr3aver)
-// Copyright 2021 Nick Brassel (@tzarc)
+// Copyright 2021-2023 Nick Brassel (@tzarc)
 // Copyright 2022 David Hoelscher (@customMK)
 // SPDX-License-Identifier: GPL-2.0-or-later
 
@@ -134,6 +134,12 @@ painter_device_t qp_st7735_make_spi_device(uint16_t panel_width, uint16_t panel_
             driver->spi_dc_reset_config.spi_config.mode            = spi_mode;
             driver->spi_dc_reset_config.dc_pin                     = dc_pin;
             driver->spi_dc_reset_config.reset_pin                  = reset_pin;
+
+            if (!qp_internal_register_device((painter_device_t)driver)) {
+                memset(driver, 0, sizeof(tft_panel_dc_reset_painter_device_t));
+                return NULL;
+            }
+
             return (painter_device_t)driver;
         }
     }
diff --git a/drivers/painter/st77xx/qp_st7789.c b/drivers/painter/st77xx/qp_st7789.c
index 9f474369d6..df43437733 100644
--- a/drivers/painter/st77xx/qp_st7789.c
+++ b/drivers/painter/st77xx/qp_st7789.c
@@ -1,5 +1,5 @@
 // Copyright 2021 Paul Cotter (@gr1mr3aver)
-// Copyright 2021 Nick Brassel (@tzarc)
+// Copyright 2021-2023 Nick Brassel (@tzarc)
 // SPDX-License-Identifier: GPL-2.0-or-later
 
 #include "qp_internal.h"
@@ -133,6 +133,12 @@ painter_device_t qp_st7789_make_spi_device(uint16_t panel_width, uint16_t panel_
             driver->spi_dc_reset_config.spi_config.mode            = spi_mode;
             driver->spi_dc_reset_config.dc_pin                     = dc_pin;
             driver->spi_dc_reset_config.reset_pin                  = reset_pin;
+
+            if (!qp_internal_register_device((painter_device_t)driver)) {
+                memset(driver, 0, sizeof(tft_panel_dc_reset_painter_device_t));
+                return NULL;
+            }
+
             return (painter_device_t)driver;
         }
     }
diff --git a/quantum/painter/qp.h b/quantum/painter/qp.h
index 00f5d7931a..7222d3b413 100644
--- a/quantum/painter/qp.h
+++ b/quantum/painter/qp.h
@@ -1,4 +1,4 @@
-// Copyright 2021 Nick Brassel (@tzarc)
+// Copyright 2021-2023 Nick Brassel (@tzarc)
 // SPDX-License-Identifier: GPL-2.0-or-later
 
 #pragma once
@@ -11,6 +11,22 @@
 ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
 // Quantum Painter global configurables (add to your keyboard's config.h)
 
+#ifndef QUANTUM_PAINTER_DISPLAY_TIMEOUT
+/**
+ * @def This controls the amount of time (in milliseconds) that all displays will remain on after the last user input.
+ *      If set to 0, the display will remain on indefinitely.
+ */
+#    define QUANTUM_PAINTER_DISPLAY_TIMEOUT 30000
+#endif // QUANTUM_PAINTER_DISPLAY_TIMEOUT
+
+#ifndef QUANTUM_PAINTER_TASK_THROTTLE
+/**
+ * @def This controls the amount of time (in milliseconds) that the Quantum Painter internal task will wait between
+ *      each execution.
+ */
+#    define QUANTUM_PAINTER_TASK_THROTTLE 1
+#endif // QUANTUM_PAINTER_TASK_THROTTLE
+
 #ifndef QUANTUM_PAINTER_NUM_IMAGES
 /**
  * @def This controls the maximum number of images that Quantum Painter can load at any one time. Images can be loaded
@@ -53,7 +69,7 @@
  * @def This controls the maximum size of the pixel data buffer used for single blocks of transmission. Larger buffers
  *      means more data is processed at one time, with less frequent transmissions, at the cost of RAM.
  */
-#    define QUANTUM_PAINTER_PIXDATA_BUFFER_SIZE 32
+#    define QUANTUM_PAINTER_PIXDATA_BUFFER_SIZE 1024
 #endif
 
 #ifndef QUANTUM_PAINTER_SUPPORTS_256_PALETTE
@@ -442,34 +458,50 @@ int16_t qp_drawtext_recolor(painter_device_t device, uint16_t x, uint16_t y, pai
 
 #ifdef QUANTUM_PAINTER_RGB565_SURFACE_ENABLE
 #    include "qp_rgb565_surface.h"
+#else // QUANTUM_PAINTER_RGB565_SURFACE_ENABLE
+#    define RGB565_SURFACE_NUM_DEVICES 0
 #endif // QUANTUM_PAINTER_RGB565_SURFACE_ENABLE
 
 #ifdef QUANTUM_PAINTER_ILI9163_ENABLE
 #    include "qp_ili9163.h"
+#else // QUANTUM_PAINTER_ILI9163_ENABLE
+#    define ILI9163_NUM_DEVICES 0
 #endif // QUANTUM_PAINTER_ILI9163_ENABLE
 
 #ifdef QUANTUM_PAINTER_ILI9341_ENABLE
 #    include "qp_ili9341.h"
+#else // QUANTUM_PAINTER_ILI9341_ENABLE
+#    define ILI9341_NUM_DEVICES 0
 #endif // QUANTUM_PAINTER_ILI9341_ENABLE
 
 #ifdef QUANTUM_PAINTER_ILI9488_ENABLE
 #    include "qp_ili9488.h"
+#else // QUANTUM_PAINTER_ILI9488_ENABLE
+#    define ILI9488_NUM_DEVICES 0
 #endif // QUANTUM_PAINTER_ILI9488_ENABLE
 
 #ifdef QUANTUM_PAINTER_ST7789_ENABLE
 #    include "qp_st7789.h"
+#else // QUANTUM_PAINTER_ST7789_ENABLE
+#    define ST7789_NUM_DEVICES 0
 #endif // QUANTUM_PAINTER_ST7789_ENABLE
 
 #ifdef QUANTUM_PAINTER_ST7735_ENABLE
 #    include "qp_st7735.h"
+#else // QUANTUM_PAINTER_ST7735_ENABLE
+#    define ST7735_NUM_DEVICES 0
 #endif // QUANTUM_PAINTER_ST7735_ENABLE
 
 #ifdef QUANTUM_PAINTER_GC9A01_ENABLE
 #    include "qp_gc9a01.h"
+#else // QUANTUM_PAINTER_GC9A01_ENABLE
+#    define GC9A01_NUM_DEVICES 0
 #endif // QUANTUM_PAINTER_GC9A01_ENABLE
 
 #ifdef QUANTUM_PAINTER_SSD1351_ENABLE
 #    include "qp_ssd1351.h"
+#else // QUANTUM_PAINTER_SSD1351_ENABLE
+#    define SSD1351_NUM_DEVICES 0
 #endif // QUANTUM_PAINTER_SSD1351_ENABLE
 
 ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
diff --git a/quantum/painter/qp_draw_image.c b/quantum/painter/qp_draw_image.c
index fa80617242..e722f3cf02 100644
--- a/quantum/painter/qp_draw_image.c
+++ b/quantum/painter/qp_draw_image.c
@@ -1,4 +1,4 @@
-// Copyright 2021 Nick Brassel (@tzarc)
+// Copyright 2021-2023 Nick Brassel (@tzarc)
 // SPDX-License-Identifier: GPL-2.0-or-later
 
 #include "qp_internal.h"
@@ -414,15 +414,3 @@ void qp_internal_animation_tick(void) {
     static uint32_t last_anim_exec = 0;
     deferred_exec_advanced_task(animation_executors, QUANTUM_PAINTER_CONCURRENT_ANIMATIONS, &last_anim_exec);
 }
-
-////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
-// Quantum Painter Core API: qp_internal_task
-
-void qp_internal_task(void) {
-    qp_internal_animation_tick();
-#ifdef QUANTUM_PAINTER_LVGL_INTEGRATION_ENABLE
-    // Run LVGL ticks
-    void qp_lvgl_internal_tick(void);
-    qp_lvgl_internal_tick();
-#endif
-}
diff --git a/quantum/painter/qp_internal.c b/quantum/painter/qp_internal.c
new file mode 100644
index 0000000000..ea23aef7c3
--- /dev/null
+++ b/quantum/painter/qp_internal.c
@@ -0,0 +1,96 @@
+// Copyright 2023 Nick Brassel (@tzarc)
+// SPDX-License-Identifier: GPL-2.0-or-later
+
+#include "qp_internal.h"
+
+////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
+// Quantum Painter Core API: device registration
+
+enum {
+    // Work out how many devices we're actually going to be instantiating
+    // NOTE: We intentionally do not include surfaces here, despite them conforming to the same API.
+    QP_NUM_DEVICES = (ILI9163_NUM_DEVICES)   // ILI9163
+                     + (ILI9341_NUM_DEVICES) // ILI9341
+                     + (ILI9488_NUM_DEVICES) // ILI9488
+                     + (ST7789_NUM_DEVICES)  // ST7789
+                     + (ST7735_NUM_DEVICES)  // ST7735
+                     + (GC9A01_NUM_DEVICES)  // GC9A01
+                     + (SSD1351_NUM_DEVICES) // SSD1351
+};
+
+static painter_device_t qp_devices[QP_NUM_DEVICES] = {NULL};
+
+bool qp_internal_register_device(painter_device_t driver) {
+    for (uint8_t i = 0; i < QP_NUM_DEVICES; i++) {
+        if (qp_devices[i] == NULL) {
+            qp_devices[i] = driver;
+            return true;
+        }
+    }
+
+    // We should never get here -- someone has screwed up their device counts during config
+    qp_dprintf("qp_internal_register_device: no more space for devices!\n");
+    return false;
+}
+
+#if (QUANTUM_PAINTER_DISPLAY_TIMEOUT) > 0
+static void qp_internal_display_timeout_task(void) {
+    // Handle power on/off state
+    static bool display_on                  = true;
+    bool        should_change_display_state = false;
+    bool        target_display_state        = false;
+    if (last_input_activity_elapsed() < (QUANTUM_PAINTER_DISPLAY_TIMEOUT)) {
+        should_change_display_state = display_on == false;
+        target_display_state        = true;
+    } else {
+        should_change_display_state = display_on == true;
+        target_display_state        = false;
+    }
+
+    if (should_change_display_state) {
+        for (uint8_t i = 0; i < QP_NUM_DEVICES; i++) {
+            if (qp_devices[i] != NULL) {
+                qp_power(qp_devices[i], target_display_state);
+            }
+        }
+
+        display_on = target_display_state;
+    }
+}
+#endif // (QUANTUM_PAINTER_DISPLAY_TIMEOUT) > 0
+
+////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
+// Quantum Painter Core API: qp_internal_task
+
+_Static_assert((QUANTUM_PAINTER_TASK_THROTTLE) > 0 && (QUANTUM_PAINTER_TASK_THROTTLE) < 1000, "QUANTUM_PAINTER_TASK_THROTTLE must be between 1 and 999");
+
+void qp_internal_task(void) {
+    // Perform throttling of the internal processing of Quantum Painter
+    static uint32_t last_tick = 0;
+    uint32_t        now       = timer_read32();
+    if (TIMER_DIFF_32(now, last_tick) < (QUANTUM_PAINTER_TASK_THROTTLE)) {
+        return;
+    }
+    last_tick = now;
+
+#if (QUANTUM_PAINTER_DISPLAY_TIMEOUT) > 0
+    qp_internal_display_timeout_task();
+#endif // (QUANTUM_PAINTER_DISPLAY_TIMEOUT) > 0
+
+    // Handle animations
+    void qp_internal_animation_tick(void);
+    qp_internal_animation_tick();
+
+#ifdef QUANTUM_PAINTER_LVGL_INTEGRATION_ENABLE
+    // Run LVGL ticks
+    void qp_lvgl_internal_tick(void);
+    qp_lvgl_internal_tick();
+#endif
+
+    // Flush (render) dirty regions to corresponding displays
+    for (uint8_t i = 0; i < QP_NUM_DEVICES; i++) {
+        if (qp_devices[i] != NULL) {
+            qp_flush(qp_devices[i]);
+        }
+    }
+}
diff --git a/quantum/painter/qp_internal_driver.h b/quantum/painter/qp_internal_driver.h
index 82a0178a73..c976ff9db7 100644
--- a/quantum/painter/qp_internal_driver.h
+++ b/quantum/painter/qp_internal_driver.h
@@ -1,4 +1,4 @@
-// Copyright 2021 Nick Brassel (@tzarc)
+// Copyright 2021-2023 Nick Brassel (@tzarc)
 // SPDX-License-Identifier: GPL-2.0-or-later
 
 #pragma once
@@ -82,3 +82,8 @@ struct painter_driver_t {
     // Comms config pointer -- needs to point to an appropriate comms config if the comms driver requires it.
     void *comms_config;
 };
+
+////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
+// Device internals
+
+bool qp_internal_register_device(painter_device_t driver);
diff --git a/quantum/painter/rules.mk b/quantum/painter/rules.mk
index 199e406dd6..7752936cbd 100644
--- a/quantum/painter/rules.mk
+++ b/quantum/painter/rules.mk
@@ -24,6 +24,7 @@ SRC += \
     $(QUANTUM_DIR)/unicode/utf8.c \
     $(QUANTUM_DIR)/color.c \
     $(QUANTUM_DIR)/painter/qp.c \
+    $(QUANTUM_DIR)/painter/qp_internal.c \
     $(QUANTUM_DIR)/painter/qp_stream.c \
     $(QUANTUM_DIR)/painter/qgf.c \
     $(QUANTUM_DIR)/painter/qff.c \