Grayscale quantization and fixing some defaults to support rgb565
This commit is contained in:
@@ -1,8 +1,11 @@
|
||||
#include "lv_setup.hpp"
|
||||
|
||||
#include "esp_heap_caps.h"
|
||||
#include "esp_log.h"
|
||||
#include "esp_timer.h"
|
||||
#include "freertos/task.h"
|
||||
#include "lodepng_alloc.hpp"
|
||||
|
||||
#include "types.hpp"
|
||||
|
||||
internal const char *kTagLvgl = "LVGL";
|
||||
@@ -13,94 +16,117 @@ uint8_t *g_LvglDrawBuffer = nullptr;
|
||||
|
||||
internal void lvgl_tick_task(void *arg)
|
||||
{
|
||||
while (true)
|
||||
{
|
||||
vTaskDelay(pdMS_TO_TICKS(10));
|
||||
while (true)
|
||||
{
|
||||
vTaskDelay(pdMS_TO_TICKS(10));
|
||||
|
||||
if (xSemaphoreTake(g_LvglMutex, portMAX_DELAY) == pdTRUE)
|
||||
{
|
||||
lv_timer_handler();
|
||||
xSemaphoreGive(g_LvglMutex);
|
||||
}
|
||||
if (xSemaphoreTake(g_LvglMutex, portMAX_DELAY) == pdTRUE)
|
||||
{
|
||||
lv_timer_handler();
|
||||
xSemaphoreGive(g_LvglMutex);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
internal uint32_t my_tick_get_cb()
|
||||
{
|
||||
return (uint32_t)(esp_timer_get_time() / 1000);
|
||||
return (uint32_t)(esp_timer_get_time() / 1000);
|
||||
}
|
||||
|
||||
internal void lv_dummy_flush_cb(lv_display_t *disp, const lv_area_t *area, uint8_t *px_map)
|
||||
internal void lv_dummy_flush_cb(lv_display_t *disp, const lv_area_t *area,
|
||||
uint8_t *px_map)
|
||||
{
|
||||
// Headless display, so we don't actually flush to SPI/I2C.
|
||||
// We just tell LVGL that the "flush" is completed so it unblocks wait_for_flushing.
|
||||
lv_display_flush_ready(disp);
|
||||
// Headless display, so we don't actually flush to SPI/I2C.
|
||||
// We just tell LVGL that the "flush" is completed so it unblocks
|
||||
// wait_for_flushing.
|
||||
lv_display_flush_ready(disp);
|
||||
}
|
||||
|
||||
internal void lv_draw_sample_ui()
|
||||
{
|
||||
lv_obj_t *scr = lv_screen_active();
|
||||
// Default background to white for the grayscale PNG
|
||||
lv_obj_set_style_bg_color(scr, lv_color_white(), 0);
|
||||
lv_obj_t *scr = lv_screen_active();
|
||||
// Default background to white for the grayscale PNG
|
||||
lv_obj_set_style_bg_color(scr, lv_color_white(), 0);
|
||||
|
||||
lv_obj_t *label = lv_label_create(scr);
|
||||
lv_label_set_text(label, "Calendink Provider\nLVGL Headless Renderer");
|
||||
lv_obj_align(label, LV_ALIGN_CENTER, 0, 0);
|
||||
lv_obj_t *label = lv_label_create(scr);
|
||||
lv_label_set_text(label, "Calendink Provider\nLVGL Headless Renderer");
|
||||
lv_obj_align(label, LV_ALIGN_CENTER, 0, 0);
|
||||
|
||||
static lv_style_t style;
|
||||
lv_style_init(&style);
|
||||
|
||||
lv_style_set_line_color(&style, lv_palette_main(LV_PALETTE_GREY));
|
||||
lv_style_set_line_width(&style, 6);
|
||||
lv_style_set_line_rounded(&style, true);
|
||||
|
||||
/*Create an object with the new style*/
|
||||
lv_obj_t *obj = lv_line_create(scr);
|
||||
lv_obj_add_style(obj, &style, 0);
|
||||
|
||||
static lv_point_precise_t p[] = {{10, 30}, {30, 50}, {100, 0}};
|
||||
lv_line_set_points(obj, p, 3);
|
||||
|
||||
lv_obj_center(obj);
|
||||
}
|
||||
|
||||
void setup_lvgl()
|
||||
{
|
||||
ESP_LOGI(kTagLvgl, "Initializing LVGL");
|
||||
ESP_LOGI(kTagLvgl, "Initializing LVGL");
|
||||
|
||||
g_LvglMutex = xSemaphoreCreateMutex();
|
||||
g_LvglMutex = xSemaphoreCreateMutex();
|
||||
|
||||
lv_init();
|
||||
lv_tick_set_cb(my_tick_get_cb);
|
||||
lv_init();
|
||||
lv_tick_set_cb(my_tick_get_cb);
|
||||
|
||||
uint32_t width = CONFIG_CALENDINK_DISPLAY_WIDTH;
|
||||
uint32_t height = CONFIG_CALENDINK_DISPLAY_HEIGHT;
|
||||
uint32_t width = CONFIG_CALENDINK_DISPLAY_WIDTH;
|
||||
uint32_t height = CONFIG_CALENDINK_DISPLAY_HEIGHT;
|
||||
|
||||
// Create a virtual display
|
||||
g_LvglDisplay = lv_display_create(width, height);
|
||||
lv_display_set_flush_cb(g_LvglDisplay, lv_dummy_flush_cb);
|
||||
// Create a virtual display
|
||||
g_LvglDisplay = lv_display_create(width, height);
|
||||
lv_display_set_flush_cb(g_LvglDisplay, lv_dummy_flush_cb);
|
||||
|
||||
// Initialize LodePNG custom bump allocator
|
||||
lodepng_allocator_init();
|
||||
// Initialize LodePNG custom bump allocator
|
||||
lodepng_allocator_init();
|
||||
|
||||
// Allocate draw buffers in PSRAM
|
||||
// Using LV_COLOR_FORMAT_L8 (1 byte per pixel)
|
||||
size_t buf_size = LV_DRAW_BUF_SIZE(width, height, LV_COLOR_FORMAT_L8);
|
||||
|
||||
// Fallback to MALLOC_CAP_DEFAULT if we can't get SPIRAM (for debugging without it)
|
||||
void *buf1 = heap_caps_malloc(buf_size, MALLOC_CAP_SPIRAM);
|
||||
if (!buf1)
|
||||
{
|
||||
ESP_LOGW(kTagLvgl, "Failed to allocate LVGL draw buffer in PSRAM, falling back to internal RAM");
|
||||
buf1 = heap_caps_malloc(buf_size, MALLOC_CAP_DEFAULT);
|
||||
}
|
||||
|
||||
if (!buf1)
|
||||
{
|
||||
ESP_LOGE(kTagLvgl, "Failed to allocate LVGL draw buffer entirely.");
|
||||
return;
|
||||
}
|
||||
// Allocate draw buffers in PSRAM
|
||||
// Using LV_COLOR_FORMAT_RGB565 (2 bytes per pixel)
|
||||
size_t buf_size = LV_DRAW_BUF_SIZE(width, height, LV_COLOR_FORMAT_RGB565);
|
||||
|
||||
g_LvglDrawBuffer = (uint8_t *)buf1;
|
||||
// Fallback to MALLOC_CAP_DEFAULT if we can't get SPIRAM (for debugging
|
||||
// without it)
|
||||
void *buf1 = heap_caps_malloc(buf_size, MALLOC_CAP_SPIRAM);
|
||||
if (!buf1)
|
||||
{
|
||||
ESP_LOGW(kTagLvgl, "Failed to allocate LVGL draw buffer in PSRAM, falling "
|
||||
"back to internal RAM");
|
||||
buf1 = heap_caps_malloc(buf_size, MALLOC_CAP_DEFAULT);
|
||||
}
|
||||
|
||||
lv_display_set_buffers(g_LvglDisplay, buf1, nullptr, buf_size, LV_DISPLAY_RENDER_MODE_FULL);
|
||||
|
||||
// Explicitly set the color format of the display if it's set in sdkconfig/driver
|
||||
lv_display_set_color_format(g_LvglDisplay, LV_COLOR_FORMAT_L8);
|
||||
if (!buf1)
|
||||
{
|
||||
ESP_LOGE(kTagLvgl, "Failed to allocate LVGL draw buffer entirely.");
|
||||
return;
|
||||
}
|
||||
|
||||
// Create the background task for the LVGL timer
|
||||
xTaskCreate(lvgl_tick_task, "LVGL Tick", 4096, nullptr, 5, nullptr);
|
||||
g_LvglDrawBuffer = (uint8_t *)buf1;
|
||||
|
||||
// Draw the sample UI
|
||||
if (xSemaphoreTake(g_LvglMutex, portMAX_DELAY) == pdTRUE)
|
||||
{
|
||||
lv_draw_sample_ui();
|
||||
xSemaphoreGive(g_LvglMutex);
|
||||
}
|
||||
// Explicitly set the color format of the display FIRST
|
||||
// so that stride and byte-per-pixel calculations align with our buffer.
|
||||
lv_display_set_color_format(g_LvglDisplay, LV_COLOR_FORMAT_RGB565);
|
||||
|
||||
ESP_LOGI(kTagLvgl, "LVGL fully initialized. Display %lux%lu created.", width, height);
|
||||
lv_display_set_buffers(g_LvglDisplay, buf1, nullptr, buf_size,
|
||||
LV_DISPLAY_RENDER_MODE_FULL);
|
||||
|
||||
// Create the background task for the LVGL timer
|
||||
xTaskCreate(lvgl_tick_task, "LVGL Tick", 4096, nullptr, 5, nullptr);
|
||||
|
||||
// Draw the sample UI
|
||||
if (xSemaphoreTake(g_LvglMutex, portMAX_DELAY) == pdTRUE)
|
||||
{
|
||||
lv_draw_sample_ui();
|
||||
xSemaphoreGive(g_LvglMutex);
|
||||
}
|
||||
|
||||
ESP_LOGI(kTagLvgl, "LVGL fully initialized. Display %lux%lu created.", width,
|
||||
height);
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user