Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Quantum Painter QoL enhancements -- auto-poweroff, auto-flush, buffer sizing #20013

Merged
merged 1 commit into from
Mar 20, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
22 changes: 12 additions & 10 deletions docs/quantum_painter.md
Original file line number Diff line number Diff line change
Expand Up @@ -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.

Expand Down
7 changes: 7 additions & 0 deletions drivers/painter/gc9a01/qp_gc9a01.c
Original file line number Diff line number Diff line change
@@ -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>
Expand Down Expand Up @@ -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;
}
tzarc marked this conversation as resolved.
Show resolved Hide resolved

return (painter_device_t)driver;
}
}
Expand Down
8 changes: 7 additions & 1 deletion drivers/painter/ili9xxx/qp_ili9163.c
Original file line number Diff line number Diff line change
@@ -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"
Expand Down Expand Up @@ -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;
}
}
Expand Down
8 changes: 7 additions & 1 deletion drivers/painter/ili9xxx/qp_ili9341.c
Original file line number Diff line number Diff line change
@@ -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"
Expand Down Expand Up @@ -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;
}
}
Expand Down
8 changes: 7 additions & 1 deletion drivers/painter/ili9xxx/qp_ili9488.c
Original file line number Diff line number Diff line change
@@ -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"
Expand Down Expand Up @@ -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;
}
}
Expand Down
8 changes: 7 additions & 1 deletion drivers/painter/ssd1351/qp_ssd1351.c
Original file line number Diff line number Diff line change
@@ -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"
Expand Down Expand Up @@ -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;
}
}
Expand Down
8 changes: 7 additions & 1 deletion drivers/painter/st77xx/qp_st7735.c
Original file line number Diff line number Diff line change
@@ -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

Expand Down Expand Up @@ -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;
}
}
Expand Down
8 changes: 7 additions & 1 deletion drivers/painter/st77xx/qp_st7789.c
Original file line number Diff line number Diff line change
@@ -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"
Expand Down Expand Up @@ -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;
}
}
Expand Down
36 changes: 34 additions & 2 deletions quantum/painter/qp.h
Original file line number Diff line number Diff line change
@@ -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
Expand All @@ -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
Expand Down Expand Up @@ -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
Expand Down Expand Up @@ -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

////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
Expand Down
14 changes: 1 addition & 13 deletions quantum/painter/qp_draw_image.c
Original file line number Diff line number Diff line change
@@ -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"
Expand Down Expand Up @@ -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
}
96 changes: 96 additions & 0 deletions quantum/painter/qp_internal.c
Original file line number Diff line number Diff line change
@@ -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]);
}
}
}
7 changes: 6 additions & 1 deletion quantum/painter/qp_internal_driver.h
Original file line number Diff line number Diff line change
@@ -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
Expand Down Expand Up @@ -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);
1 change: 1 addition & 0 deletions quantum/painter/rules.mk
Original file line number Diff line number Diff line change
Expand Up @@ -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 \
Expand Down