Refactor draw buffer handling
This commit is contained in:
@@ -26,10 +26,6 @@ LVGLHandler::~LVGLHandler() {
|
||||
lv_draw_buf_destroy(lvgl_draw_buf_);
|
||||
lvgl_draw_buf_ = nullptr;
|
||||
}
|
||||
if (framebuffer_ != nullptr) {
|
||||
heap_caps_free(framebuffer_);
|
||||
framebuffer_ = nullptr;
|
||||
}
|
||||
}
|
||||
|
||||
esp_err_t LVGLHandler::initLVGL(EventGroupHandle_t system_event_group) {
|
||||
@@ -94,8 +90,8 @@ void LVGLHandler::flush_cb_(lv_display_t* disp, const lv_area_t* area, uint8_t*
|
||||
return;
|
||||
}
|
||||
LVGLHandler* handler = static_cast<LVGLHandler*>(lv_display_get_user_data(disp));
|
||||
if (handler == nullptr || handler->display_handler_ == nullptr || handler->framebuffer_ == nullptr) {
|
||||
ESP_LOGE(TAG, "Invalid handler or framebuffer in flush callback");
|
||||
if (handler == nullptr || handler->display_handler_ == nullptr) {
|
||||
ESP_LOGE(TAG, "Invalid handler in flush callback");
|
||||
lv_display_flush_ready(disp);
|
||||
return;
|
||||
}
|
||||
@@ -107,81 +103,46 @@ void LVGLHandler::flush_cb_(lv_display_t* disp, const lv_area_t* area, uint8_t*
|
||||
int32_t area_w = lv_area_get_width(area);
|
||||
int32_t area_h = lv_area_get_height(area);
|
||||
if (area->x1 == 0 && area->y1 == 0 && area_w == DISPLAY_WIDTH && area_h == DISPLAY_HEIGHT) {
|
||||
// Check if content actually changed before triggering expensive e-ink refresh
|
||||
if (memcmp(handler->framebuffer_, pixel_data, DISPLAY_BUFFER_SIZE) == 0) {
|
||||
ESP_LOGD(TAG, "Full screen flush with no changes - skipping e-ink refresh");
|
||||
lv_display_flush_ready(disp);
|
||||
return;
|
||||
}
|
||||
ESP_LOGI(TAG, "Full screen update");
|
||||
memcpy(handler->framebuffer_, pixel_data, DISPLAY_BUFFER_SIZE);
|
||||
// invert the framebuffer for e-ink display
|
||||
for (size_t i = 0; i < DISPLAY_BUFFER_SIZE; ++i) {
|
||||
handler->framebuffer_[i] = ~handler->framebuffer_[i];
|
||||
}
|
||||
// request full refresh
|
||||
esp_err_t err = handler->display_handler_->full_write(handler->framebuffer_, true);
|
||||
esp_err_t err = handler->display_handler_->full_write(
|
||||
pixel_data,
|
||||
true // white basemap
|
||||
);
|
||||
if (err != ESP_OK) {
|
||||
ESP_LOGE(TAG, "Full refresh request failed: %s", esp_err_to_name(err));
|
||||
}
|
||||
} else {
|
||||
// partial update
|
||||
ESP_LOGI(TAG, "Partial update: x1=%d, y1=%d, w=%d, h=%d", area->x1, area->y1, area_w, area_h);
|
||||
// update the framebuffer with the partial data
|
||||
for (int32_t row = 0; row < area_h; ++row) {
|
||||
int32_t fb_y = area->y1 + row;
|
||||
int32_t fb_x_byte_start = area->x1 / 8;
|
||||
int32_t fb_x_byte_end = area->x2 / 8;
|
||||
uint8_t* fb_ptr = &handler->framebuffer_[fb_y * (DISPLAY_WIDTH / 8) + fb_x_byte_start];
|
||||
const uint8_t* src_ptr = &pixel_data[row * (area_w / 8)];
|
||||
// invert the partial framebuffer data for e-ink display
|
||||
for (int32_t i = 0; i < (fb_x_byte_end - fb_x_byte_start + 1); ++i) {
|
||||
fb_ptr[i] = ~src_ptr[i];
|
||||
|
||||
// Prepare partial buffer
|
||||
const uint32_t area_width_bytes = (area->x2 - area->x1 + 1) / 8;
|
||||
const uint32_t area_height = area->y2 - area->y1 + 1;
|
||||
const size_t partial_buffer_size = area_width_bytes * area_height;
|
||||
uint8_t* partial_buffer = new uint8_t[partial_buffer_size];
|
||||
if (partial_buffer == nullptr) {
|
||||
ESP_LOGE(TAG, "Failed to allocate partial buffer for flush callback");
|
||||
lv_display_flush_ready(disp);
|
||||
return;
|
||||
}
|
||||
// Copy pixel data to partial buffer and invert for e-ink
|
||||
for (int32_t row = 0; row < area_height; ++row) {
|
||||
for (int32_t col = 0; col < area_width_bytes; ++col) {
|
||||
size_t src_index = row * area_width_bytes + col;
|
||||
partial_buffer[src_index] = ~pixel_data[src_index];
|
||||
}
|
||||
}
|
||||
// update the refresh area
|
||||
handler->refresh_area_.expand_to_include(area->x1, area->y1, area->x2, area->y2);
|
||||
//
|
||||
|
||||
if (lv_display_flush_is_last(disp) && !handler->refresh_area_.is_empty()) {
|
||||
ESP_LOGI(TAG, "Last flush in batch - performing partial refresh");
|
||||
ESP_LOGI(TAG, "Refresh area: x1=%d, y1=%d, x2=%d, y2=%d",
|
||||
handler->refresh_area_.x1, handler->refresh_area_.y1,
|
||||
handler->refresh_area_.x2, handler->refresh_area_.y2);
|
||||
// copy the area to refresh
|
||||
uint8_t* partial_buffer = new uint8_t[handler->refresh_area_.area() / 8];
|
||||
if (partial_buffer == nullptr) {
|
||||
ESP_LOGE(TAG, "Failed to allocate partial buffer for refresh");
|
||||
lv_display_flush_ready(disp);
|
||||
return;
|
||||
}
|
||||
// loop the refresh area and copy data
|
||||
uint32_t x1 = handler->refresh_area_.x1;
|
||||
uint32_t x2 = handler->refresh_area_.x2;
|
||||
uint32_t y1 = handler->refresh_area_.y1;
|
||||
uint32_t y2 = handler->refresh_area_.y2;
|
||||
uint32_t height = y2 - y1 + 1;
|
||||
uint32_t width = x2 - x1 + 1;
|
||||
esp_err_t err = handler->display_handler_->partial_refresh(partial_buffer,
|
||||
RefreshArea {
|
||||
area->x1,
|
||||
area->y1,
|
||||
area->x2,
|
||||
area->y2
|
||||
}, lv_display_flush_is_last(disp));
|
||||
delete[] partial_buffer;
|
||||
|
||||
for (uint32_t row = 0; row < height; ++row) {
|
||||
uint32_t fb_y = y1 + row;
|
||||
uint32_t fb_x_byte_start = x1 / 8;
|
||||
uint32_t fb_x_byte_end = x2 / 8;
|
||||
uint8_t* fb_ptr = &handler->framebuffer_[fb_y * (DISPLAY_WIDTH / 8) + fb_x_byte_start];
|
||||
uint8_t* dest_ptr = &partial_buffer[row * (width / 8)];
|
||||
for (uint32_t i = 0; i < (fb_x_byte_end - fb_x_byte_start + 1); ++i) {
|
||||
dest_ptr[i] = ~fb_ptr[i];
|
||||
}
|
||||
}
|
||||
|
||||
esp_err_t err = handler->display_handler_->partial_refresh(partial_buffer,
|
||||
handler->refresh_area_);
|
||||
delete[] partial_buffer;
|
||||
|
||||
if (err != ESP_OK) {
|
||||
ESP_LOGE(TAG, "Partial refresh request failed: %s", esp_err_to_name(err));
|
||||
}
|
||||
handler->refresh_area_.reset();
|
||||
if (err != ESP_OK) {
|
||||
ESP_LOGE(TAG, "Partial refresh request failed: %s", esp_err_to_name(err));
|
||||
}
|
||||
}
|
||||
//
|
||||
@@ -252,31 +213,10 @@ esp_err_t LVGLHandler::initLVGLDisplay_() {
|
||||
return ESP_FAIL;
|
||||
}
|
||||
|
||||
// set framebuffer
|
||||
framebuffer_ = (uint8_t*)heap_caps_malloc(LVGL_BUFFER_SIZE, MALLOC_CAP_SPIRAM);
|
||||
if (framebuffer_ != nullptr) {
|
||||
framebuffer_in_psram_ = true;
|
||||
ESP_LOGI(TAG, "Framebuffer allocated in PSRAM (%zu bytes)", LVGL_BUFFER_SIZE);
|
||||
} else {
|
||||
ESP_LOGW(TAG, "PSRAM not available, allocating framebuffer in internal RAM");
|
||||
framebuffer_ = (uint8_t*)heap_caps_malloc(LVGL_BUFFER_SIZE, MALLOC_CAP_INTERNAL);
|
||||
framebuffer_in_psram_ = false;
|
||||
if (framebuffer_ == nullptr) {
|
||||
ESP_LOGE(TAG, "Failed to allocate framebuffer");
|
||||
lv_display_delete(lvgl_display_);
|
||||
lvgl_display_ = nullptr;
|
||||
lvgl_port_unlock();
|
||||
return ESP_FAIL;
|
||||
}
|
||||
ESP_LOGI(TAG, "Framebuffer allocated in internal RAM (%zu bytes)", LVGL_BUFFER_SIZE);
|
||||
}
|
||||
memset(framebuffer_, 0xFF, LVGL_BUFFER_SIZE); // Initialize to white
|
||||
// Create a draw buffer covering the entire display
|
||||
lvgl_draw_buf_ = lv_draw_buf_create(DISPLAY_WIDTH, DISPLAY_HEIGHT, LV_COLOR_FORMAT_I1, LV_STRIDE_AUTO);
|
||||
if (lvgl_draw_buf_ == nullptr) {
|
||||
ESP_LOGE(TAG, "Failed to create LVGL draw buffer");
|
||||
heap_caps_free(framebuffer_);
|
||||
framebuffer_ = nullptr;
|
||||
lv_display_delete(lvgl_display_);
|
||||
lvgl_display_ = nullptr;
|
||||
lvgl_port_unlock();
|
||||
|
||||
Reference in New Issue
Block a user