mirror of
https://github.com/esphome/esphome.git
synced 2026-10-15 10:42:52 +00:00
Fold the update flag into the flush, inline the rotation, write a buffered block straight out when not updating
This commit is contained in:
@@ -183,7 +183,6 @@ void MipiDsi::update() {
|
||||
if (this->auto_clear_enabled_) {
|
||||
this->clear();
|
||||
}
|
||||
// Blocks drawn by the writer stay in the buffer until the one flush below
|
||||
this->updating_ = true;
|
||||
if (this->show_test_card_) {
|
||||
this->test_card();
|
||||
@@ -198,14 +197,9 @@ void MipiDsi::update() {
|
||||
this->flush_dirty_();
|
||||
}
|
||||
|
||||
// Outside update() nothing else would flush, inside it the end of update() does.
|
||||
void MipiDsi::flush_now_() {
|
||||
if (!this->updating_)
|
||||
this->flush_dirty_();
|
||||
}
|
||||
|
||||
void MipiDsi::flush_dirty_() {
|
||||
if (this->buffer_ == nullptr || this->x_low_ > this->x_high_ || this->y_low_ > this->y_high_)
|
||||
// Inside update() the one flush at its end sends everything
|
||||
if (this->updating_ || this->buffer_ == nullptr || this->x_low_ > this->x_high_ || this->y_low_ > this->y_high_)
|
||||
return;
|
||||
ESP_LOGV(TAG, "x_low %d, y_low %d, x_high %d, y_high %d", this->x_low_, this->y_low_, this->x_high_, this->y_high_);
|
||||
int w = this->x_high_ - this->x_low_ + 1;
|
||||
@@ -223,9 +217,7 @@ void MipiDsi::draw_pixels_at(int x_start, int y_start, int w, int h, const uint8
|
||||
display::ColorBitness bitness, bool big_endian, int x_offset, int y_offset, int x_pad) {
|
||||
if (w <= 0 || h <= 0)
|
||||
return;
|
||||
// Copy as is only when the bytes are laid out the way draw_pixel_at() writes them; an RGB
|
||||
// ordered little endian 888 block is b,g,r in memory. Anything else, or a block drawn under a clipping
|
||||
// region, goes per pixel.
|
||||
// An RGB ordered little endian 888 block is b,g,r in memory, as the BGR colour mode writes it
|
||||
const bool same_layout = bitness == display::COLOR_BITNESS_565
|
||||
? big_endian == this->big_endian_
|
||||
: big_endian == (this->color_mode_ == display::COLOR_ORDER_RGB);
|
||||
@@ -234,12 +226,11 @@ void MipiDsi::draw_pixels_at(int x_start, int y_start, int w, int h, const uint8
|
||||
display::Display::draw_pixels_at(x_start, y_start, w, h, ptr, order, bitness, big_endian, x_offset, y_offset,
|
||||
x_pad);
|
||||
this->mark_dirty_(x_start, y_start, w, h);
|
||||
this->flush_now_();
|
||||
this->flush_dirty_();
|
||||
return;
|
||||
}
|
||||
if (this->buffer_ != nullptr) {
|
||||
// With a buffer the block goes through it, or a flush of the old contents would paint over it
|
||||
// Only the part on the panel
|
||||
const int first_col = std::max(0, -x_start), end_col = std::min(w, static_cast<int>(this->width_) - x_start);
|
||||
const int first_row = std::max(0, -y_start), end_row = std::min(h, static_cast<int>(this->height_) - y_start);
|
||||
if (first_col >= end_col || first_row >= end_row)
|
||||
@@ -251,8 +242,12 @@ void MipiDsi::draw_pixels_at(int x_start, int y_start, int w, int h, const uint8
|
||||
ptr + ((y_offset + y) * stride + x_offset + first_col) * bytes_per_pixel,
|
||||
(end_col - first_col) * bytes_per_pixel);
|
||||
}
|
||||
this->mark_dirty_(x_start + first_col, y_start + first_row, end_col - first_col, end_row - first_row);
|
||||
this->flush_now_();
|
||||
if (this->updating_) {
|
||||
this->mark_dirty_(x_start + first_col, y_start + first_row, end_col - first_col, end_row - first_row);
|
||||
} else {
|
||||
this->write_to_display_(x_start + first_col, y_start + first_row, end_col - first_col, end_row - first_row, ptr,
|
||||
x_offset + first_col, y_offset + first_row, x_pad + w - end_col);
|
||||
}
|
||||
return;
|
||||
}
|
||||
this->write_to_display_(x_start, y_start, w, h, ptr, x_offset, y_offset, x_pad);
|
||||
@@ -300,26 +295,6 @@ bool MipiDsi::check_buffer_() {
|
||||
return true;
|
||||
}
|
||||
|
||||
// Maps drawn coordinates to the buffer the way draw_pixel_at() stores them.
|
||||
void MipiDsi::rotate_(int &x, int &y) const {
|
||||
switch (this->rotation_) {
|
||||
case display::DISPLAY_ROTATION_0_DEGREES:
|
||||
break;
|
||||
case display::DISPLAY_ROTATION_90_DEGREES:
|
||||
std::swap(x, y);
|
||||
x = this->width_ - x - 1;
|
||||
break;
|
||||
case display::DISPLAY_ROTATION_180_DEGREES:
|
||||
x = this->width_ - x - 1;
|
||||
y = this->height_ - y - 1;
|
||||
break;
|
||||
case display::DISPLAY_ROTATION_270_DEGREES:
|
||||
std::swap(x, y);
|
||||
y = this->height_ - y - 1;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
// Widen the dirty box to the drawn rectangle, even where the buffer already held the same values.
|
||||
void MipiDsi::mark_dirty_(int x_start, int y_start, int w, int h) {
|
||||
int x1 = x_start, y1 = y_start;
|
||||
|
||||
@@ -7,6 +7,8 @@
|
||||
#ifdef USE_ESP32_VARIANT_ESP32P4
|
||||
#include "esphome/core/component.h"
|
||||
#include "esphome/core/helpers.h"
|
||||
|
||||
#include <utility>
|
||||
#include "esphome/core/application.h"
|
||||
#include "esphome/core/log.h"
|
||||
#include "esphome/core/gpio.h"
|
||||
@@ -88,8 +90,25 @@ class MipiDsi final : public display::Display {
|
||||
bool check_buffer_();
|
||||
/// Send the region touched since the last flush to the panel.
|
||||
void flush_dirty_();
|
||||
void flush_now_();
|
||||
void rotate_(int &x, int &y) const;
|
||||
// Maps drawn coordinates to the buffer the way draw_pixel_at() stores them
|
||||
void rotate_(int &x, int &y) const {
|
||||
switch (this->rotation_) {
|
||||
case display::DISPLAY_ROTATION_0_DEGREES:
|
||||
break;
|
||||
case display::DISPLAY_ROTATION_90_DEGREES:
|
||||
std::swap(x, y);
|
||||
x = this->width_ - x - 1;
|
||||
break;
|
||||
case display::DISPLAY_ROTATION_180_DEGREES:
|
||||
x = this->width_ - x - 1;
|
||||
y = this->height_ - y - 1;
|
||||
break;
|
||||
case display::DISPLAY_ROTATION_270_DEGREES:
|
||||
std::swap(x, y);
|
||||
y = this->height_ - y - 1;
|
||||
break;
|
||||
}
|
||||
}
|
||||
void mark_dirty_(int x_start, int y_start, int w, int h);
|
||||
/// Pack a colour as the 565 value the panel's byte order expects in memory.
|
||||
uint16_t to_panel_565_(Color color) const {
|
||||
@@ -118,6 +137,7 @@ class MipiDsi final : public display::Display {
|
||||
display::ColorOrder color_mode_{display::COLOR_ORDER_BGR};
|
||||
display::ColorBitness color_depth_;
|
||||
bool big_endian_{false};
|
||||
bool updating_{false};
|
||||
uint8_t pixel_mode_{};
|
||||
|
||||
esp_lcd_panel_handle_t handle_{};
|
||||
@@ -125,7 +145,6 @@ class MipiDsi final : public display::Display {
|
||||
esp_lcd_panel_io_handle_t io_handle_{};
|
||||
SemaphoreHandle_t io_lock_{};
|
||||
uint8_t *buffer_{nullptr};
|
||||
bool updating_{false};
|
||||
uint16_t x_low_{1};
|
||||
uint16_t y_low_{1};
|
||||
uint16_t x_high_{0};
|
||||
|
||||
@@ -188,7 +188,6 @@ void MipiRgb::update() {
|
||||
if (this->auto_clear_enabled_) {
|
||||
this->clear();
|
||||
}
|
||||
// Blocks drawn by the writer stay in the buffer until the one flush below
|
||||
this->updating_ = true;
|
||||
if (this->show_test_card_) {
|
||||
this->test_card();
|
||||
@@ -203,14 +202,9 @@ void MipiRgb::update() {
|
||||
this->flush_dirty_();
|
||||
}
|
||||
|
||||
// Outside update() nothing else would flush, inside it the end of update() does.
|
||||
void MipiRgb::flush_now_() {
|
||||
if (!this->updating_)
|
||||
this->flush_dirty_();
|
||||
}
|
||||
|
||||
void MipiRgb::flush_dirty_() {
|
||||
if (this->buffer_ == nullptr || this->x_low_ > this->x_high_ || this->y_low_ > this->y_high_)
|
||||
// Inside update() the one flush at its end sends everything
|
||||
if (this->updating_ || this->buffer_ == nullptr || this->x_low_ > this->x_high_ || this->y_low_ > this->y_high_)
|
||||
return;
|
||||
ESP_LOGV(TAG, "x_low %d, y_low %d, x_high %d, y_high %d", this->x_low_, this->y_low_, this->x_high_, this->y_high_);
|
||||
int w = this->x_high_ - this->x_low_ + 1;
|
||||
@@ -228,16 +222,13 @@ void MipiRgb::draw_pixels_at(int x_start, int y_start, int w, int h, const uint8
|
||||
display::ColorBitness bitness, bool big_endian, int x_offset, int y_offset, int x_pad) {
|
||||
if (w <= 0 || h <= 0 || this->is_failed())
|
||||
return;
|
||||
// RGB565 in the configured byte order at rotation 0 copies as is; anything else, or a block drawn under a
|
||||
// clipping region, goes per pixel
|
||||
if (bitness != display::COLOR_BITNESS_565 || order != display::COLOR_ORDER_RGB || big_endian != this->big_endian_ ||
|
||||
this->rotation_ != display::DISPLAY_ROTATION_0_DEGREES || this->is_clipping()) {
|
||||
Display::draw_pixels_at(x_start, y_start, w, h, ptr, order, bitness, big_endian, x_offset, y_offset, x_pad);
|
||||
this->mark_dirty_(x_start, y_start, w, h);
|
||||
this->flush_now_();
|
||||
this->flush_dirty_();
|
||||
} else if (this->buffer_ != nullptr) {
|
||||
// With a buffer the block goes through it, or a flush of the old contents would paint over it
|
||||
// Only the part on the panel
|
||||
const int first_col = std::max(0, -x_start), end_col = std::min(w, static_cast<int>(this->width_) - x_start);
|
||||
const int first_row = std::max(0, -y_start), end_row = std::min(h, static_cast<int>(this->height_) - y_start);
|
||||
if (first_col >= end_col || first_row >= end_row)
|
||||
@@ -247,8 +238,12 @@ void MipiRgb::draw_pixels_at(int x_start, int y_start, int w, int h, const uint8
|
||||
memcpy(this->buffer_ + (y_start + y) * this->width_ + x_start + first_col,
|
||||
ptr + ((y_offset + y) * stride + x_offset + first_col) * 2, (end_col - first_col) * 2);
|
||||
}
|
||||
this->mark_dirty_(x_start + first_col, y_start + first_row, end_col - first_col, end_row - first_row);
|
||||
this->flush_now_();
|
||||
if (this->updating_) {
|
||||
this->mark_dirty_(x_start + first_col, y_start + first_row, end_col - first_col, end_row - first_row);
|
||||
} else {
|
||||
this->write_to_display_(x_start + first_col, y_start + first_row, end_col - first_col, end_row - first_row, ptr,
|
||||
x_offset + first_col, y_offset + first_row, x_pad + w - end_col);
|
||||
}
|
||||
} else {
|
||||
this->write_to_display_(x_start, y_start, w, h, ptr, x_offset, y_offset, x_pad);
|
||||
}
|
||||
@@ -291,26 +286,6 @@ bool MipiRgb::check_buffer_() {
|
||||
return true;
|
||||
}
|
||||
|
||||
// Maps drawn coordinates to the buffer the way draw_pixel_at() stores them.
|
||||
void MipiRgb::rotate_(int &x, int &y) const {
|
||||
switch (this->rotation_) {
|
||||
case display::DISPLAY_ROTATION_0_DEGREES:
|
||||
break;
|
||||
case display::DISPLAY_ROTATION_90_DEGREES:
|
||||
std::swap(x, y);
|
||||
x = this->width_ - x - 1;
|
||||
break;
|
||||
case display::DISPLAY_ROTATION_180_DEGREES:
|
||||
x = this->width_ - x - 1;
|
||||
y = this->height_ - y - 1;
|
||||
break;
|
||||
case display::DISPLAY_ROTATION_270_DEGREES:
|
||||
std::swap(x, y);
|
||||
y = this->height_ - y - 1;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
// Widen the dirty box to the drawn rectangle, even where the buffer already held the same values.
|
||||
void MipiRgb::mark_dirty_(int x_start, int y_start, int w, int h) {
|
||||
int x1 = x_start, y1 = y_start;
|
||||
|
||||
@@ -80,8 +80,25 @@ class MipiRgb : public display::Display {
|
||||
}
|
||||
/// Send the region touched since the last flush to the panel.
|
||||
void flush_dirty_();
|
||||
void flush_now_();
|
||||
void rotate_(int &x, int &y) const;
|
||||
// Maps drawn coordinates to the buffer the way draw_pixel_at() stores them
|
||||
void rotate_(int &x, int &y) const {
|
||||
switch (this->rotation_) {
|
||||
case display::DISPLAY_ROTATION_0_DEGREES:
|
||||
break;
|
||||
case display::DISPLAY_ROTATION_90_DEGREES:
|
||||
std::swap(x, y);
|
||||
x = this->width_ - x - 1;
|
||||
break;
|
||||
case display::DISPLAY_ROTATION_180_DEGREES:
|
||||
x = this->width_ - x - 1;
|
||||
y = this->height_ - y - 1;
|
||||
break;
|
||||
case display::DISPLAY_ROTATION_270_DEGREES:
|
||||
std::swap(x, y);
|
||||
y = this->height_ - y - 1;
|
||||
break;
|
||||
}
|
||||
}
|
||||
void mark_dirty_(int x_start, int y_start, int w, int h);
|
||||
void dump_pins_(uint8_t start, uint8_t end, const char *name, uint8_t offset);
|
||||
void setup_enables_();
|
||||
@@ -104,11 +121,11 @@ class MipiRgb : public display::Display {
|
||||
bool invert_colors_{};
|
||||
display::ColorOrder color_mode_{display::COLOR_ORDER_BGR};
|
||||
bool big_endian_{true};
|
||||
bool updating_{false};
|
||||
size_t width_;
|
||||
size_t height_;
|
||||
uint16_t *buffer_{nullptr};
|
||||
std::vector<GPIOPin *> enable_pins_{};
|
||||
bool updating_{false};
|
||||
uint16_t x_low_{1};
|
||||
uint16_t y_low_{1};
|
||||
uint16_t x_high_{0};
|
||||
|
||||
@@ -671,15 +671,12 @@ class MipiSpiBuffer
|
||||
}
|
||||
|
||||
protected:
|
||||
// Convert per pixel into the buffer
|
||||
void draw_pixels_slow(int x_start, int y_start, int w, int h, const uint8_t *ptr, display::ColorOrder order,
|
||||
display::ColorBitness bitness, bool big_endian, int x_offset, int y_offset,
|
||||
int x_pad) override {
|
||||
display::Display::draw_pixels_at(x_start, y_start, w, h, ptr, order, bitness, big_endian, x_offset, y_offset,
|
||||
x_pad);
|
||||
}
|
||||
// Rotate the coordinates to match the display orientation.
|
||||
|
||||
// Convert a color to the buffer pixel format.
|
||||
static BUFFERTYPE convert_color(const Color &color) {
|
||||
if constexpr (BUFFERPIXEL == PIXEL_MODE_8) {
|
||||
|
||||
@@ -51,8 +51,6 @@ void RpiDpiRgb::draw_pixels_at(int x_start, int y_start, int w, int h, const uin
|
||||
display::ColorBitness bitness, bool big_endian, int x_offset, int y_offset, int x_pad) {
|
||||
if (w <= 0 || h <= 0)
|
||||
return;
|
||||
// Big endian RGB565 at rotation 0 copies as is; anything else, or a block drawn under a clipping region, goes
|
||||
// per pixel
|
||||
if (bitness != display::COLOR_BITNESS_565 || order != display::COLOR_ORDER_RGB || !big_endian ||
|
||||
this->rotation_ != display::DISPLAY_ROTATION_0_DEGREES || this->is_clipping()) {
|
||||
display::Display::draw_pixels_at(x_start, y_start, w, h, ptr, order, bitness, big_endian, x_offset, y_offset,
|
||||
|
||||
@@ -54,8 +54,6 @@ void ST7701S::draw_pixels_at(int x_start, int y_start, int w, int h, const uint8
|
||||
display::ColorBitness bitness, bool big_endian, int x_offset, int y_offset, int x_pad) {
|
||||
if (w <= 0 || h <= 0)
|
||||
return;
|
||||
// Big endian RGB565 at rotation 0 copies as is; anything else, or a block drawn under a clipping region, goes
|
||||
// per pixel
|
||||
if (bitness != display::COLOR_BITNESS_565 || order != display::COLOR_ORDER_RGB || !big_endian ||
|
||||
this->rotation_ != display::DISPLAY_ROTATION_0_DEGREES || this->is_clipping()) {
|
||||
display::Display::draw_pixels_at(x_start, y_start, w, h, ptr, order, bitness, big_endian, x_offset, y_offset,
|
||||
|
||||
Reference in New Issue
Block a user