1
0
Fork 0

[QP] Add support for OLED, variable framebuffer bpp (#19997)

Co-authored-by: Pablo Martínez <58857054+elpekenin@users.noreply.github.com>
Co-authored-by: Dasky <32983009+daskygit@users.noreply.github.com>
Fixup delta frame coordinates after #20296.
This commit is contained in:
Nick Brassel 2023-10-22 13:27:31 +11:00 committed by GitHub
parent 48d9140cfc
commit 8e614250b4
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
51 changed files with 1610 additions and 497 deletions

View file

@ -10,7 +10,7 @@
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
// QFF API
bool qff_read_font_descriptor(qp_stream_t *stream, uint8_t *line_height, bool *has_ascii_table, uint16_t *num_unicode_glyphs, uint8_t *bpp, bool *has_palette, painter_compression_t *compression_scheme, uint32_t *total_bytes) {
bool qff_read_font_descriptor(qp_stream_t *stream, uint8_t *line_height, bool *has_ascii_table, uint16_t *num_unicode_glyphs, uint8_t *bpp, bool *has_palette, bool *is_panel_native, painter_compression_t *compression_scheme, uint32_t *total_bytes) {
// Seek to the start
qp_stream_setpos(stream, 0);
@ -49,7 +49,7 @@ bool qff_read_font_descriptor(qp_stream_t *stream, uint8_t *line_height, bool *h
*num_unicode_glyphs = font_descriptor.num_unicode_glyphs;
}
if (bpp || has_palette) {
if (!qgf_parse_format(font_descriptor.format, bpp, has_palette)) {
if (!qgf_parse_format(font_descriptor.format, bpp, has_palette, is_panel_native)) {
return false;
}
}
@ -102,7 +102,7 @@ bool qff_validate_stream(qp_stream_t *stream) {
bool has_ascii_table;
uint16_t num_unicode_glyphs;
if (!qff_read_font_descriptor(stream, NULL, &has_ascii_table, &num_unicode_glyphs, NULL, NULL, NULL, NULL)) {
if (!qff_read_font_descriptor(stream, NULL, &has_ascii_table, &num_unicode_glyphs, NULL, NULL, NULL, NULL, NULL)) {
return false;
}
@ -127,7 +127,7 @@ uint32_t qff_get_total_size(qp_stream_t *stream) {
// Read the font descriptor, grabbing the size
uint32_t total_size;
if (!qff_read_font_descriptor(stream, NULL, NULL, NULL, NULL, NULL, NULL, &total_size)) {
if (!qff_read_font_descriptor(stream, NULL, NULL, NULL, NULL, NULL, NULL, NULL, &total_size)) {
return false;
}

View file

@ -85,4 +85,4 @@ typedef struct QP_PACKED qff_unicode_glyph_table_v1_t {
bool qff_validate_stream(qp_stream_t *stream);
uint32_t qff_get_total_size(qp_stream_t *stream);
bool qff_read_font_descriptor(qp_stream_t *stream, uint8_t *line_height, bool *has_ascii_table, uint16_t *num_unicode_glyphs, uint8_t *bpp, bool *has_palette, painter_compression_t *compression_scheme, uint32_t *total_bytes);
bool qff_read_font_descriptor(qp_stream_t *stream, uint8_t *line_height, bool *has_ascii_table, uint16_t *num_unicode_glyphs, uint8_t *bpp, bool *has_palette, bool *is_panel_native, painter_compression_t *compression_scheme, uint32_t *total_bytes);

View file

@ -24,22 +24,23 @@ bool qgf_validate_block_header(qgf_block_header_v1_t *desc, uint8_t expected_typ
return true;
}
bool qgf_parse_format(qp_image_format_t format, uint8_t *bpp, bool *has_palette) {
bool qgf_parse_format(qp_image_format_t format, uint8_t *bpp, bool *has_palette, bool *is_panel_native) {
// clang-format off
static const struct QP_PACKED {
static const struct QP_PACKED {
uint8_t bpp;
bool has_palette;
bool is_panel_native;
} formats[] = {
[GRAYSCALE_1BPP] = {.bpp = 1, .has_palette = false},
[GRAYSCALE_2BPP] = {.bpp = 2, .has_palette = false},
[GRAYSCALE_4BPP] = {.bpp = 4, .has_palette = false},
[GRAYSCALE_8BPP] = {.bpp = 8, .has_palette = false},
[PALETTE_1BPP] = {.bpp = 1, .has_palette = true},
[PALETTE_2BPP] = {.bpp = 2, .has_palette = true},
[PALETTE_4BPP] = {.bpp = 4, .has_palette = true},
[PALETTE_8BPP] = {.bpp = 8, .has_palette = true},
[RGB565_16BPP] = {.bpp = 16, .has_palette = false},
[RGB888_24BPP] = {.bpp = 24, .has_palette = false},
[GRAYSCALE_1BPP] = {.bpp = 1, .has_palette = false, .is_panel_native = false},
[GRAYSCALE_2BPP] = {.bpp = 2, .has_palette = false, .is_panel_native = false},
[GRAYSCALE_4BPP] = {.bpp = 4, .has_palette = false, .is_panel_native = false},
[GRAYSCALE_8BPP] = {.bpp = 8, .has_palette = false, .is_panel_native = false},
[PALETTE_1BPP] = {.bpp = 1, .has_palette = true, .is_panel_native = false},
[PALETTE_2BPP] = {.bpp = 2, .has_palette = true, .is_panel_native = false},
[PALETTE_4BPP] = {.bpp = 4, .has_palette = true, .is_panel_native = false},
[PALETTE_8BPP] = {.bpp = 8, .has_palette = true, .is_panel_native = false},
[RGB565_16BPP] = {.bpp = 16, .has_palette = false, .is_panel_native = true},
[RGB888_24BPP] = {.bpp = 24, .has_palette = false, .is_panel_native = true},
};
// clang-format on
@ -56,13 +57,16 @@ bool qgf_parse_format(qp_image_format_t format, uint8_t *bpp, bool *has_palette)
if (has_palette) {
*has_palette = formats[format].has_palette;
}
if (is_panel_native) {
*is_panel_native = formats[format].is_panel_native;
}
return true;
}
bool qgf_parse_frame_descriptor(qgf_frame_v1_t *frame_descriptor, uint8_t *bpp, bool *has_palette, bool *is_delta, painter_compression_t *compression_scheme, uint16_t *delay) {
bool qgf_parse_frame_descriptor(qgf_frame_v1_t *frame_descriptor, uint8_t *bpp, bool *has_palette, bool *is_panel_native, bool *is_delta, painter_compression_t *compression_scheme, uint16_t *delay) {
// Decode the format
qgf_parse_format(frame_descriptor->format, bpp, has_palette);
qgf_parse_format(frame_descriptor->format, bpp, has_palette, is_panel_native);
// Copy out the required info
if (is_delta) {
@ -173,7 +177,7 @@ void qgf_seek_to_frame_descriptor(qp_stream_t *stream, uint16_t frame_number) {
qp_stream_setpos(stream, offset);
}
bool qgf_validate_frame_descriptor(qp_stream_t *stream, uint16_t frame_number, uint8_t *bpp, bool *has_palette, bool *is_delta) {
bool qgf_validate_frame_descriptor(qp_stream_t *stream, uint16_t frame_number, uint8_t *bpp, bool *has_palette, bool *is_panel_native, bool *is_delta) {
// Seek to the correct location
qgf_seek_to_frame_descriptor(stream, frame_number);
@ -189,7 +193,7 @@ bool qgf_validate_frame_descriptor(qp_stream_t *stream, uint16_t frame_number, u
return false;
}
return qgf_parse_frame_descriptor(&frame_descriptor, bpp, has_palette, is_delta, NULL, NULL);
return qgf_parse_frame_descriptor(&frame_descriptor, bpp, has_palette, is_panel_native, is_delta, NULL, NULL);
}
bool qgf_validate_palette_descriptor(qp_stream_t *stream, uint16_t frame_number, uint8_t bpp) {
@ -253,8 +257,9 @@ bool qgf_validate_stream(qp_stream_t *stream) {
// Validate the frame descriptor block
uint8_t bpp;
bool has_palette;
bool is_panel_native;
bool has_delta;
if (!qgf_validate_frame_descriptor(stream, i, &bpp, &has_palette, &has_delta)) {
if (!qgf_validate_frame_descriptor(stream, i, &bpp, &has_palette, &is_panel_native, &has_delta)) {
return false;
}

View file

@ -65,7 +65,7 @@ _Static_assert(sizeof(qgf_frame_offsets_v1_t) == sizeof(qgf_block_header_v1_t),
typedef struct QP_PACKED qgf_frame_v1_t {
qgf_block_header_v1_t header; // = { .type_id = 0x02, .neg_type_id = (~0x02), .length = 6 }
qp_image_format_t format : 8; // Frame format, see qp.h.
qp_image_format_t format : 8; // Frame format, see qp_internal_formats.h.
uint8_t flags; // Frame flags, see below.
painter_compression_t compression_scheme : 8; // Compression scheme, see qp.h.
uint8_t transparency_index; // palette index used for transparent pixels (not yet implemented)
@ -131,6 +131,6 @@ uint32_t qgf_get_total_size(qp_stream_t *stream);
bool qgf_validate_stream(qp_stream_t *stream);
bool qgf_validate_block_header(qgf_block_header_v1_t *desc, uint8_t expected_typeid, int32_t expected_length);
bool qgf_read_graphics_descriptor(qp_stream_t *stream, uint16_t *image_width, uint16_t *image_height, uint16_t *frame_count, uint32_t *total_bytes);
bool qgf_parse_format(qp_image_format_t format, uint8_t *bpp, bool *has_palette);
bool qgf_parse_format(qp_image_format_t format, uint8_t *bpp, bool *has_palette, bool *is_panel_native);
void qgf_seek_to_frame_descriptor(qp_stream_t *stream, uint16_t frame_number);
bool qgf_parse_frame_descriptor(qgf_frame_v1_t *frame_descriptor, uint8_t *bpp, bool *has_palette, bool *is_delta, painter_compression_t *compression_scheme, uint16_t *delay);
bool qgf_parse_frame_descriptor(qgf_frame_v1_t *frame_descriptor, uint8_t *bpp, bool *has_palette, bool *is_panel_native, bool *is_delta, painter_compression_t *compression_scheme, uint16_t *delay);

View file

@ -12,11 +12,11 @@
// Internal driver validation
static bool validate_driver_vtable(painter_driver_t *driver) {
return (driver->driver_vtable && driver->driver_vtable->init && driver->driver_vtable->power && driver->driver_vtable->clear && driver->driver_vtable->viewport && driver->driver_vtable->pixdata && driver->driver_vtable->palette_convert && driver->driver_vtable->append_pixels && driver->driver_vtable->append_pixdata) ? true : false;
return (driver && driver->driver_vtable && driver->driver_vtable->init && driver->driver_vtable->power && driver->driver_vtable->clear && driver->driver_vtable->viewport && driver->driver_vtable->pixdata && driver->driver_vtable->palette_convert && driver->driver_vtable->append_pixels && driver->driver_vtable->append_pixdata) ? true : false;
}
static bool validate_comms_vtable(painter_driver_t *driver) {
return (driver->comms_vtable && driver->comms_vtable->comms_init && driver->comms_vtable->comms_start && driver->comms_vtable->comms_stop && driver->comms_vtable->comms_send) ? true : false;
return (driver && driver->comms_vtable && driver->comms_vtable->comms_init && driver->comms_vtable->comms_start && driver->comms_vtable->comms_stop && driver->comms_vtable->comms_send) ? true : false;
}
static bool validate_driver_integrity(painter_driver_t *driver) {

View file

@ -539,6 +539,12 @@ int16_t qp_drawtext_recolor(painter_device_t device, uint16_t x, uint16_t y, pai
# define SSD1351_NUM_DEVICES 0
#endif // QUANTUM_PAINTER_SSD1351_ENABLE
#ifdef QUANTUM_PAINTER_SH1106_ENABLE
# include "qp_sh1106.h"
#else // QUANTUM_PAINTER_SH1106_ENABLE
# define SH1106_NUM_DEVICES 0
#endif // QUANTUM_PAINTER_SH1106_ENABLE
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
// Quantum Painter Extras

View file

@ -115,6 +115,7 @@ typedef struct qgf_frame_info_t {
painter_compression_t compression_scheme;
uint8_t bpp;
bool has_palette;
bool is_panel_native;
bool is_delta;
uint16_t left;
uint16_t top;
@ -143,7 +144,7 @@ static bool qp_drawimage_prepare_frame_for_stream_read(painter_device_t device,
}
// Parse out the frame info
if (!qgf_parse_frame_descriptor(&frame_descriptor, &info->bpp, &info->has_palette, &info->is_delta, &info->compression_scheme, &info->delay)) {
if (!qgf_parse_frame_descriptor(&frame_descriptor, &info->bpp, &info->has_palette, &info->is_panel_native, &info->is_delta, &info->compression_scheme, &info->delay)) {
return false;
}
@ -236,8 +237,8 @@ static bool qp_drawimage_recolor_impl(painter_device_t device, uint16_t x, uint1
if (frame_info->is_delta) {
l = x + frame_info->left;
t = y + frame_info->top;
r = x + frame_info->right - 1;
b = y + frame_info->bottom - 1;
r = x + frame_info->right;
b = y + frame_info->bottom;
} else {
l = x;
t = y;
@ -263,7 +264,7 @@ static bool qp_drawimage_recolor_impl(painter_device_t device, uint16_t x, uint1
}
bool ret = false;
if (frame_info->bpp <= 8) {
if (!frame_info->is_panel_native) {
// Set up the output state
qp_internal_pixel_output_state_t output_state = {.device = device, .pixel_write_pos = 0, .max_pixels = qp_internal_num_pixels_in_buffer(device)};

View file

@ -19,6 +19,7 @@ typedef struct qff_font_handle_t {
uint16_t num_unicode_glyphs;
uint8_t bpp;
bool has_palette;
bool is_panel_native;
painter_compression_t compression_scheme;
union {
qp_stream_t stream;
@ -97,7 +98,7 @@ static painter_font_handle_t qp_load_font_internal(bool (*stream_factory)(qff_fo
#endif // QUANTUM_PAINTER_LOAD_FONTS_TO_RAM
// Read the info (parsing already successful above, no need to check return value)
qff_read_font_descriptor(&font->stream, &font->base.line_height, &font->has_ascii_table, &font->num_unicode_glyphs, &font->bpp, &font->has_palette, &font->compression_scheme, NULL);
qff_read_font_descriptor(&font->stream, &font->base.line_height, &font->has_ascii_table, &font->num_unicode_glyphs, &font->bpp, &font->has_palette, &font->is_panel_native, &font->compression_scheme, NULL);
if (!qp_internal_bpp_capable(font->bpp)) {
qp_dprintf("qp_load_font: fail (image bpp too high (%d), check QUANTUM_PAINTER_SUPPORTS_256_PALETTE or QUANTUM_PAINTER_SUPPORTS_NATIVE_COLORS)\n", (int)font->bpp);

View file

@ -16,6 +16,7 @@ enum {
+ (ST7735_NUM_DEVICES) // ST7735
+ (GC9A01_NUM_DEVICES) // GC9A01
+ (SSD1351_NUM_DEVICES) // SSD1351
+ (SH1106_NUM_DEVICES) // SH1106
};
static painter_device_t qp_devices[QP_NUM_DEVICES] = {NULL};

View file

@ -44,8 +44,8 @@ typedef enum qp_image_format_t {
PALETTE_2BPP = 0x05,
PALETTE_4BPP = 0x06,
PALETTE_8BPP = 0x07,
RGB565_16BPP = 0x08,
RGB888_24BPP = 0x09,
RGB565_16BPP = 0x08, // Natively streamed to the panel, no interpolation or palette handling
RGB888_24BPP = 0x09, // Natively streamed to the panel, no interpolation or palette handling
} qp_image_format_t;
typedef enum painter_compression_t { IMAGE_UNCOMPRESSED, IMAGE_COMPRESSED_RLE } painter_compression_t;

View file

@ -6,14 +6,16 @@ QUANTUM_PAINTER_LVGL_INTEGRATION ?= no
# The list of permissible drivers that can be listed in QUANTUM_PAINTER_DRIVERS
VALID_QUANTUM_PAINTER_DRIVERS := \
rgb565_surface \
ili9163_spi \
ili9341_spi \
ili9488_spi \
st7735_spi \
st7789_spi \
gc9a01_spi \
ssd1351_spi
surface \
ili9163_spi \
ili9341_spi \
ili9488_spi \
st7735_spi \
st7789_spi \
gc9a01_spi \
ssd1351_spi \
sh1106_i2c \
sh1106_spi
#-------------------------------------------------------------------------------
@ -42,7 +44,9 @@ ifeq ($(strip $(QUANTUM_PAINTER_ANIMATIONS_ENABLE)), yes)
endif
# Comms flags
QUANTUM_PAINTER_NEEDS_COMMS_DUMMY ?= no
QUANTUM_PAINTER_NEEDS_COMMS_SPI ?= no
QUANTUM_PAINTER_NEEDS_COMMS_I2C ?= no
# Handler for each driver
define handle_quantum_painter_driver
@ -51,12 +55,8 @@ define handle_quantum_painter_driver
ifeq ($$(filter $$(strip $$(CURRENT_PAINTER_DRIVER)),$$(VALID_QUANTUM_PAINTER_DRIVERS)),)
$$(error "$$(CURRENT_PAINTER_DRIVER)" is not a valid Quantum Painter driver)
else ifeq ($$(strip $$(CURRENT_PAINTER_DRIVER)),rgb565_surface)
OPT_DEFS += -DQUANTUM_PAINTER_RGB565_SURFACE_ENABLE
COMMON_VPATH += \
$(DRIVER_PATH)/painter/generic
SRC += \
$(DRIVER_PATH)/painter/generic/qp_rgb565_surface.c \
else ifeq ($$(strip $$(CURRENT_PAINTER_DRIVER)),surface)
QUANTUM_PAINTER_NEEDS_SURFACE := yes
else ifeq ($$(strip $$(CURRENT_PAINTER_DRIVER)),ili9163_spi)
QUANTUM_PAINTER_NEEDS_COMMS_SPI := yes
@ -135,16 +135,60 @@ define handle_quantum_painter_driver
$(DRIVER_PATH)/painter/tft_panel/qp_tft_panel.c \
$(DRIVER_PATH)/painter/ssd1351/qp_ssd1351.c
else ifeq ($$(strip $$(CURRENT_PAINTER_DRIVER)),sh1106_spi)
QUANTUM_PAINTER_NEEDS_SURFACE := yes
QUANTUM_PAINTER_NEEDS_COMMS_SPI := yes
QUANTUM_PAINTER_NEEDS_COMMS_SPI_DC_RESET := yes
OPT_DEFS += -DQUANTUM_PAINTER_SH1106_ENABLE -DQUANTUM_PAINTER_SH1106_SPI_ENABLE
COMMON_VPATH += \
$(DRIVER_PATH)/painter/oled_panel \
$(DRIVER_PATH)/painter/sh1106
SRC += \
$(DRIVER_PATH)/painter/oled_panel/qp_oled_panel.c \
$(DRIVER_PATH)/painter/sh1106/qp_sh1106.c
else ifeq ($$(strip $$(CURRENT_PAINTER_DRIVER)),sh1106_i2c)
QUANTUM_PAINTER_NEEDS_SURFACE := yes
QUANTUM_PAINTER_NEEDS_COMMS_I2C := yes
OPT_DEFS += -DQUANTUM_PAINTER_SH1106_ENABLE -DQUANTUM_PAINTER_SH1106_I2C_ENABLE
COMMON_VPATH += \
$(DRIVER_PATH)/painter/oled_panel \
$(DRIVER_PATH)/painter/sh1106
SRC += \
$(DRIVER_PATH)/painter/oled_panel/qp_oled_panel.c \
$(DRIVER_PATH)/painter/sh1106/qp_sh1106.c
endif
endef
# Iterate through the listed drivers for the build, including what's necessary
$(foreach qp_driver,$(QUANTUM_PAINTER_DRIVERS),$(eval $(call handle_quantum_painter_driver,$(qp_driver))))
# If a surface is needed, set up the required files
ifeq ($(strip $(QUANTUM_PAINTER_NEEDS_SURFACE)), yes)
QUANTUM_PAINTER_NEEDS_COMMS_DUMMY := yes
OPT_DEFS += -DQUANTUM_PAINTER_SURFACE_ENABLE
COMMON_VPATH += \
$(DRIVER_PATH)/painter/generic
SRC += \
$(DRIVER_PATH)/painter/generic/qp_surface_common.c \
$(DRIVER_PATH)/painter/generic/qp_surface_mono1bpp.c \
$(DRIVER_PATH)/painter/generic/qp_surface_rgb565.c
endif
# If dummy comms is needed, set up the required files
ifeq ($(strip $(QUANTUM_PAINTER_NEEDS_COMMS_DUMMY)), yes)
OPT_DEFS += -DQUANTUM_PAINTER_DUMMY_COMMS_ENABLE
VPATH += $(DRIVER_PATH)/painter/comms
SRC += \
$(QUANTUM_DIR)/painter/qp_comms.c \
$(DRIVER_PATH)/painter/comms/qp_comms_dummy.c
endif
# If SPI comms is needed, set up the required files
ifeq ($(strip $(QUANTUM_PAINTER_NEEDS_COMMS_SPI)), yes)
OPT_DEFS += -DQUANTUM_PAINTER_SPI_ENABLE
QUANTUM_LIB_SRC += spi_master.c
SPI_DRIVER_REQUIRED = yes
VPATH += $(DRIVER_PATH)/painter/comms
SRC += \
$(QUANTUM_DIR)/painter/qp_comms.c \
@ -155,7 +199,17 @@ ifeq ($(strip $(QUANTUM_PAINTER_NEEDS_COMMS_SPI)), yes)
endif
endif
# If I2C comms is needed, set up the required files
ifeq ($(strip $(QUANTUM_PAINTER_NEEDS_COMMS_I2C)), yes)
OPT_DEFS += -DQUANTUM_PAINTER_I2C_ENABLE
I2C_DRIVER_REQUIRED = yes
VPATH += $(DRIVER_PATH)/painter/comms
SRC += \
$(QUANTUM_DIR)/painter/qp_comms.c \
$(DRIVER_PATH)/painter/comms/qp_comms_i2c.c
endif
# Check if LVGL needs to be enabled
ifeq ($(strip $(QUANTUM_PAINTER_LVGL_INTEGRATION)), yes)
include $(QUANTUM_DIR)/painter/lvgl/rules.mk
include $(QUANTUM_DIR)/painter/lvgl/rules.mk
endif